Skip to content

Commit

Permalink
feat: add option to sort projects
Browse files Browse the repository at this point in the history
  • Loading branch information
IgorGoryany committed Sep 23, 2024
1 parent 83bea58 commit eb99905
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 65 deletions.
4 changes: 3 additions & 1 deletion src/components/DashboardPage/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { tr } from './DashboardPage.i18n';
export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: ExternalPageProps) => {
const { preset } = useFiltersPreset({ defaultPresetFallback });

const { currentPreset, queryState } = useUrlFilterParams({
const { currentPreset, queryState, projectsSort } = useUrlFilterParams({
preset,
});

Expand All @@ -33,6 +33,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
...queryState,
limit: 10,
},
projectsSort,
},
{
getNextPageParam: ({ pagination }) => pagination.offset,
Expand Down Expand Up @@ -85,6 +86,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
counter={goalsCount}
filterPreset={preset}
enableLayoutToggle
enableProjectsSort
enableHideProjectToggle
/>
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/FiltersPanel/FiltersPanel.i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"Estimate": "Estimate",
"Limit": "Limit",
"Preset": "Preset",
"Sort": "Sort",
"Goals sort": "Goals sort",
"Projects sort": "Projects sort",
"Issuer": "Issuer",
"Participant": "Participant",
"Filter": "Filter",
Expand Down
3 changes: 2 additions & 1 deletion src/components/FiltersPanel/FiltersPanel.i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"Estimate": "Срок",
"Limit": "Лимит",
"Preset": "Пресет",
"Sort": "Сортировка",
"Goals sort": "Сортировка целей",
"Projects sort": "Сортировка проектов",
"Issuer": "Автор",
"Participant": "Участник",
"Filter": "Фильтр",
Expand Down
56 changes: 51 additions & 5 deletions src/components/FiltersPanel/FiltersPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import {
} from '@taskany/bricks/harmony';
import { nullable, useLatest } from '@taskany/bricks';

import { FilterQueryState, QueryState, useUrlFilterParams } from '../../hooks/useUrlFilterParams';
import {
FilterQueryState,
QueryState,
SortableGoalsProps,
SortableProjectsProps,
useUrlFilterParams,
} from '../../hooks/useUrlFilterParams';
import { FilterById } from '../../../trpc/inferredTypes';
import {
filtersPanel,
Expand Down Expand Up @@ -52,8 +58,9 @@ export const FiltersPanel: FC<{
filterPreset?: FilterById;
enableViewToggle?: boolean;
enableLayoutToggle?: boolean;
enableHideProjectToggle?: boolean;
children?: ReactNode;
enableHideProjectToggle?: boolean;
enableProjectsSort?: boolean;
}> = memo(
({
children,
Expand All @@ -62,6 +69,7 @@ export const FiltersPanel: FC<{
counter = 0,
enableViewToggle,
enableLayoutToggle,
enableProjectsSort,
enableHideProjectToggle,
filterPreset,
}) => {
Expand All @@ -72,8 +80,10 @@ export const FiltersPanel: FC<{
currentPreset,
queryString,
queryState,
projectsSort,
resetQueryState,
batchQueryState,
setProjectsSortFilter,
setSortFilter,
queryFilterState,
groupBy,
Expand Down Expand Up @@ -242,7 +252,7 @@ export const FiltersPanel: FC<{
</>
))}

<FiltersBarDropdownTitle>{tr('Sort')}</FiltersBarDropdownTitle>
<FiltersBarDropdownTitle>{tr('Goals sort')}</FiltersBarDropdownTitle>
<FiltersBarDropdownContent>
<SortList
value={filterQuery?.sort}
Expand All @@ -255,16 +265,52 @@ export const FiltersPanel: FC<{
const paramExistingIndex = sortParams.findIndex(({ key: k }) => key === k);

if (paramExistingIndex > -1) {
sortParams[paramExistingIndex] = { key, dir };
sortParams[paramExistingIndex] = {
key: key as SortableGoalsProps,
dir,
};
} else {
sortParams.push({ key, dir });
sortParams.push({ key: key as SortableGoalsProps, dir });
}
}

setSortFilter(sortParams);
}}
/>
</FiltersBarDropdownContent>
{nullable(enableProjectsSort, () => (
<>
<FiltersBarDropdownTitle>{tr('Projects sort')}</FiltersBarDropdownTitle>
<FiltersBarDropdownContent>
<SortList
variant="projects"
value={projectsSort}
onChange={(key, dir) => {
let sortParams = (projectsSort ?? []).slice();

if (!dir) {
sortParams = sortParams.filter(({ key: k }) => key !== k);
} else {
const paramExistingIndex = sortParams.findIndex(
({ key: k }) => key === k,
);

if (paramExistingIndex > -1) {
sortParams[paramExistingIndex] = {
key: key as SortableProjectsProps,
dir,
};
} else {
sortParams.push({ key: key as SortableProjectsProps, dir });
}
}

setProjectsSortFilter(sortParams);
}}
/>
</FiltersBarDropdownContent>
</>
))}
<FiltersBarDropdownTitle>{tr('Visibility')}</FiltersBarDropdownTitle>
<FiltersBarDropdownContent>
<Checkbox
Expand Down
1 change: 1 addition & 0 deletions src/components/GoalsPage/GoalsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const GoalsPage = ({ user, ssrTime, defaultPresetFallback, baseQueryState
counter={data?.filtered || 0}
filterPreset={preset}
enableViewToggle
enableProjectsSort={groupedView}
/>
}
>
Expand Down
3 changes: 2 additions & 1 deletion src/components/GroupedGoalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const projectsSize = 20;
export const GroupedGoalList: React.FC<GroupedGoalListProps> = ({ filterPreset }) => {
const { setPreview, on } = useGoalPreview();

const { queryState } = useUrlFilterParams({
const { queryState, projectsSort } = useUrlFilterParams({
preset: filterPreset,
});

Expand All @@ -31,6 +31,7 @@ export const GroupedGoalList: React.FC<GroupedGoalListProps> = ({ filterPreset }
limit: projectsSize,
goalsQuery: queryState,
firstLevel: !!queryState?.project?.length,
projectsSort,
},
{
getNextPageParam: ({ pagination }) => pagination.offset,
Expand Down
5 changes: 4 additions & 1 deletion src/components/SortList/SortList.i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"Activity": "Activity",
"Owner": "Owner",
"UpdatedAt": "Updated",
"CreatedAt": "Created"
"CreatedAt": "Created",
"Stargizers": "Stargizers",
"Goals": "Goals",
"Watchers": "Watchers"
}
5 changes: 4 additions & 1 deletion src/components/SortList/SortList.i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"Activity": "Автор",
"Owner": "Ответственный",
"UpdatedAt": "Обновлено",
"CreatedAt": "Создано"
"CreatedAt": "Создано",
"Stargizers": "В избранном",
"Goals": "Цели",
"Watchers": "Отслеживается"
}
58 changes: 43 additions & 15 deletions src/components/SortList/SortList.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,80 @@
import React, { useCallback, useMemo } from 'react';
import { AutoComplete, AutoCompleteList } from '@taskany/bricks/harmony';

import type { FilterQueryState, SortableProps, SortDirection } from '../../hooks/useUrlFilterParams';
import type {
FilterQueryState,
SortableBaseProps,
SortableGoalsProps,
SortableProjectsProps,
SortDirection,
} from '../../hooks/useUrlFilterParams';
import { SortButton } from '../SortButton/SortButton';

import { tr } from './SortList.i18n';
import styles from './SortList.module.css';

interface SortListProps {
value?: FilterQueryState['sort'];
onChange: (key: SortableProps, dir: SortDirection | null) => void;
interface SortListProps<T extends FilterQueryState['sort'] | FilterQueryState['projectsSort']> {
variant?: 'goals' | 'projects';
value?: T;
onChange: (key: SortableGoalsProps | SortableProjectsProps, dir: SortDirection | null) => void;
}

interface SingleSortItem {
id: SortableProps;
id: SortableGoalsProps | SortableProjectsProps;
title: string;
dir: SortDirection | null;
}

export const SortList: React.FC<SortListProps> = ({ value, onChange }) => {
export const SortList = <T extends FilterQueryState['sort'] | FilterQueryState['projectsSort']>({
variant = 'goals',
value,
onChange,
}: SortListProps<T>) => {
const { itemsToRender, sortItems } = useMemo(() => {
const sortItems = {
const baseSortItems: Record<SortableBaseProps, string> = {
title: tr('Title'),
state: tr('State'),
priority: tr('Priority'),
project: tr('Project'),
activity: tr('Activity'),
owner: tr('Owner'),
updatedAt: tr('UpdatedAt'),
createdAt: tr('CreatedAt'),
};
const sortGoalsItems: Record<Exclude<SortableGoalsProps, SortableProjectsProps>, string> = {
state: tr('State'),
activity: tr('Activity'),
priority: tr('Priority'),
project: tr('Project'),
};

const sortProjectItems: Record<Exclude<SortableProjectsProps, SortableGoalsProps>, string> = {
stargizers: tr('Stargizers'),
watchers: tr('Watchers'),
goals: tr('Goals'),
};

const sortItems =
variant === 'goals' ? { ...baseSortItems, ...sortGoalsItems } : { ...baseSortItems, ...sortProjectItems };

return {
sortItems,
itemsToRender: (Object.entries(sortItems) as Array<[SortableProps, string]>).map(([id, title]) => ({
itemsToRender: (
Object.entries(sortItems) as Array<[SortableGoalsProps | SortableProjectsProps, string]>
).map(([id, title]) => ({
id,
title,
dir: null,
})),
};
}, []);
}, [variant]);

const selected: SingleSortItem[] | undefined = useMemo(() => {
return value?.map(({ key, dir }) => ({ id: key, title: sortItems[key], dir }));
return value?.map(({ key, dir }) => ({
id: key,
title: sortItems[key as SortableBaseProps],
dir,
}));
}, [value, sortItems]);

const handleChange = useCallback(
(key: SortableProps) => (dir: SortDirection | null) => {
(key: SortableGoalsProps | SortableProjectsProps) => (dir: SortDirection | null) => {
onChange(key, dir);
},
[onChange],
Expand Down
Loading

0 comments on commit eb99905

Please sign in to comment.