Skip to content

Commit

Permalink
Handle sorting of dynamically loaded cards
Browse files Browse the repository at this point in the history
  • Loading branch information
terotik committed Oct 12, 2024
1 parent bae3de8 commit 6aa7495
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 66 deletions.
65 changes: 54 additions & 11 deletions components/paths/CategoryCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useEffect } from 'react';

import { beautifyValue } from 'common/data/format';
import { Link } from 'common/links';
import ActionParameters from 'components/paths/ActionParameters';
Expand Down Expand Up @@ -56,7 +58,7 @@ const Identifier = styled.span`
`;

const PathsBasicNodeContent = (props) => {
const { node, pathsInstance } = props;
const { categoryId, node, pathsInstance, onLoaded } = props;
const yearRange = useReactiveVar(yearRangeVar);
const activeGoal = useReactiveVar(activeGoalVar);
const t = useTranslations();
Expand All @@ -70,6 +72,25 @@ const PathsBasicNodeContent = (props) => {
},
});

useEffect(() => {
if (data) {
const nodeMetric = new DimensionalMetric(data.node.metricDim!);
const defaultConfig = nodeMetric.getDefaultSliceConfig(activeGoal);
const thisYear = nodeMetric.getSingleYear(
yearRange[1],
defaultConfig.categories
);

const yearTotal =
thisYear.rows[0] &&
thisYear.rows.reduce(
(partialSum, a) => (a ? partialSum + a[0] : partialSum),
0
);
onLoaded(categoryId, yearTotal || 0);
}
}, [activeGoal, data, yearRange]);

if (loading) {
return <ContentLoader type="grow" />;
}
Expand Down Expand Up @@ -105,6 +126,7 @@ const PathsBasicNodeContent = (props) => {
)?.label;

const unit = nodeMetric.getUnit();

return (
<CardContentBlock>
<div>{nodeMetric.getName()}</div>
Expand All @@ -126,7 +148,7 @@ const PathsBasicNodeContent = (props) => {
};

const PathsActionNodeContent = (props) => {
const { node, pathsInstance } = props;
const { categoryId, node, pathsInstance, onLoaded } = props;
const yearRange = useReactiveVar(yearRangeVar);
const activeGoal = useReactiveVar(activeGoalVar);
const t = useTranslations();
Expand All @@ -140,6 +162,14 @@ const PathsActionNodeContent = (props) => {
},
});

useEffect(() => {
if (data) {
const pathsAction = new PathsActionNode(data.action);
const impact = pathsAction.getYearlyImpact(yearRange[1]) || 0;
onLoaded(categoryId, impact);
}
}, [activeGoal, data, yearRange]);

if (loading) {
return <ContentLoader type="grow" />;
}
Expand All @@ -148,15 +178,12 @@ const PathsActionNodeContent = (props) => {
}
if (data) {
const pathsAction = new PathsActionNode(data.action);
const impact = pathsAction.getYearlyImpact(yearRange[1]) || 0;
return (
<CardContentBlock>
{t('impact')} {yearRange[1]}
<h4>
{yearRange ? (
beautifyValue(pathsAction.getYearlyImpact(yearRange[1]))
) : (
<span>---</span>
)}
{yearRange ? beautifyValue(impact) : <span>---</span>}
{pathsAction.getUnit()}
</h4>
<ActionParameters parameters={data.action.parameters} />
Expand All @@ -167,7 +194,7 @@ const PathsActionNodeContent = (props) => {
};

const PathsNodeContent = (props) => {
const { node, paths } = props;
const { categoryId, node, paths, onLoaded } = props;

const { data, loading, error } = useQuery(GET_NODE_INFO, {
fetchPolicy: 'no-cache',
Expand All @@ -186,16 +213,30 @@ const PathsNodeContent = (props) => {
}
if (data) {
if (data.node.__typename === 'ActionNode') {
return <PathsActionNodeContent node={node} pathsInstance={paths} />;
return (
<PathsActionNodeContent
categoryId={categoryId}
node={node}
pathsInstance={paths}
onLoaded={onLoaded}
/>
);
} else if (data.node.__typename) {
return <PathsBasicNodeContent node={node} pathsInstance={paths} />;
return (
<PathsBasicNodeContent
categoryId={categoryId}
node={node}
pathsInstance={paths}
onLoaded={onLoaded}
/>
);
}
return null;
}
};

const CategoryCard = (props) => {
const { category, group, pathsInstance } = props;
const { category, group, pathsInstance, onLoaded } = props;
return (
<Card>
{group && (
Expand All @@ -220,8 +261,10 @@ const CategoryCard = (props) => {
)}
{category.kausalPathsNodeUuid && (
<PathsNodeContent
categoryId={category.id}
node={category.kausalPathsNodeUuid}
paths={pathsInstance}
onLoaded={onLoaded}
/>
)}
</div>
Expand Down
135 changes: 80 additions & 55 deletions components/paths/contentblocks/CategoryTypeListBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
'use client';
import React from 'react';
import React, { useState } from 'react';

import { MultiUseImageFragmentFragment } from 'common/__generated__/graphql';
import { CommonContentBlockProps } from 'common/blocks.types';
import { useTranslations } from 'next-intl';
import { readableColor } from 'polished';
import { Col, Container, Row } from 'reactstrap';
import { Col, Container, FormGroup, Input, Label, Row } from 'reactstrap';
import styled from 'styled-components';

import { getDeepParents } from '@/common/categories';
import {
activeGoalVar,
activeScenarioVar,
yearRangeVar,
} from '@/context/paths/cache';
import { usePaths } from '@/context/paths/paths';
import { usePlan } from '@/context/plan';
import {
CATEGORY_FRAGMENT,
RECURSIVE_CATEGORY_FRAGMENT,
} from '@/fragments/category.fragment';
import { GET_PATHS_ACTION_LIST } from '@/queries/paths/get-paths-actions';
import { getHttpHeaders } from '@/utils/paths/paths.utils';
import PathsActionNode from '@/utils/paths/PathsActionNode';
import { gql, useQuery, useReactiveVar } from '@apollo/client';
import { gql, useQuery } from '@apollo/client';
import { Theme } from '@kausal/themes/types';

import CategoryCard from '../CategoryCard';
Expand All @@ -34,6 +27,18 @@ const getColor = (theme: Theme, darkFallback = theme.themeColors.black) =>
const getBackgroundColor = (theme: Theme) =>
theme.section.categoryList?.background || theme.neutralLight;

const getSortOptions = (t: TFunction): SortActionsConfig[] => [
{
key: 'STANDARD',
label: t('actions-sort-default'),
},
{
key: 'IMPACT',
label: t('actions-sort-impact'),
sortKey: 'impactOnTargetYear',
},
];

const GET_CATEGORIES_FOR_CATEGORY_TYPE_LIST = gql`
query GetCategoriesForCategoryTypeList($plan: ID!, $categoryType: ID!) {
planCategories(plan: $plan, categoryType: $categoryType) {
Expand Down Expand Up @@ -124,63 +129,84 @@ export type CategoryListBlockCategory = {
};
};

const getPathsActionForCategory = (category, actions) => {
const pathsActionForCategory = actions.find(
(action) => action.id === category.kausalPathsNodeUuid
);
if (!pathsActionForCategory) {
return null;
}
return new PathsActionNode(pathsActionForCategory);
};

const getCategoryColor = (category) => {
// We have many ways to define the color of a category.
// For now get the color from category paths group data
return category.pathsAction?.data.group.color || '#eeeeee';
};

const CategoryList = (props) => {
const { categories, groups } = props;
console.log('category list props', props);
const plan = usePlan();
const paths = usePaths();
const activeGoal = useReactiveVar(activeGoalVar);
const activeScenario = useReactiveVar(activeScenarioVar);
const yearRange = useReactiveVar(yearRangeVar);

const pathsInstance = paths.instance.id;
const { data, loading } = useQuery(GET_PATHS_ACTION_LIST, {
fetchPolicy: 'no-cache',
variables: { goal: null },
context: {
uri: '/api/graphql-paths',
headers: getHttpHeaders({ instanceIdentifier: pathsInstance }),
},
});
const t = useTranslations();

if (loading) {
return <div>Loading...</div>; // Or any loading indicator you prefer
}
const pathsInstance = paths?.instance.id;
const sortOptions = getSortOptions(t);

const categoryData = categories?.map((cat) => {
const pathsAction = getPathsActionForCategory(cat, data.actions);
return {
...cat,
pathsAction: pathsAction,
};
});
const [sortBy, setSortBy] = useState<SortActionsConfig>(sortOptions[0]);
const [categoriesData, setCategoriesData] = useState(categories);
const [categoriesPathsData, setCategoriesPathsData] = useState(
categories.map((cat) => {
return { id: cat.id, impact: null };
})
);

const handleCardLoaded = (id, impact) => {
//console.log('handleCardLoaded', id, impact);
setCategoriesPathsData((prevCategories) => {
const updatedCategories = [...prevCategories];
const index = updatedCategories.findIndex((cat) => cat.id === id);
if (index !== -1) {
updatedCategories[index].impact = impact;
}
return updatedCategories;
});
console.log('categoriesPathsData', categoriesPathsData);
//setLoadedCards(prev => ({ ...prev, [id]: impact }));
};

const handleChangeSort = (sortBy: SortActionsBy) => {
console.log('sorting', sortBy);
const selectedSorter = sortOptions.find((option) => option.key === sortBy);
setSortBy(selectedSorter ?? sortOptions[0]);
const sortedCategories = [...categoriesData].sort(sortCategories);
console.log('sorted', sortedCategories);
setCategoriesData(sortedCategories);
};

const sortCategories = (a, b) => {
if (sortBy.key === 'IMPACT') {
const aValue = categoriesPathsData.find((cat) => cat.id === a.id)?.impact;
const bValue = categoriesPathsData.find((cat) => cat.id === b.id)?.impact;
console.log('aValue', aValue, 'bValue', bValue);
return aValue - bValue;
}
return 0;
};

return (
<>
<FormGroup>
<Label for="sort">{t('actions-sort-by')}</Label>
<Input
id="sort"
name="select"
type="select"
onChange={(e) => handleChangeSort(e.target.value as SortActionsBy)}
value={sortBy.key}
>
{sortOptions.map(
(sortOption) =>
!sortOption.isHidden && (
<option key={sortOption.key} value={sortOption.key}>
{sortOption.label}
</option>
)
)}
</Input>
</FormGroup>
{groups?.map((group) => (
<Row key={group?.id}>
{group?.id !== 'all' && (
<GroupHeader $color={group?.color || '#eeeeee'}>
{group.name}
</GroupHeader>
)}
{categoryData
{categoriesData
?.filter(
(cat) =>
(cat?.categoryPage?.live && hasParent(cat, group.id)) ||
Expand All @@ -201,6 +227,7 @@ const CategoryList = (props) => {
category={cat}
group={group}
pathsInstance={pathsInstance}
onLoaded={handleCardLoaded}
/>
</Col>
)
Expand Down Expand Up @@ -272,8 +299,6 @@ const CategoryTypeListBlock = (props: CategoryTypeListBlockProps) => {
return (
<CategoryListSection id={id}>
<Container>
<h5>[FILTERS HERE]</h5> <h5>[SORTING HERE]</h5>
<h5>-----</h5>
<Row>
<Col className="mb-4">{heading && <h2>{heading}</h2>}</Col>
</Row>
Expand Down

0 comments on commit 6aa7495

Please sign in to comment.