Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to sort projects #2984

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading