Skip to content
This repository has been archived by the owner on Apr 14, 2024. It is now read-only.

Filter #98

Merged
merged 8 commits into from
Mar 18, 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
2 changes: 1 addition & 1 deletion .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .pnp.loader.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

550 changes: 550 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-version.cjs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
nodeLinker: pnp

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"

yarnPath: .yarn/releases/yarn-3.6.3.cjs
11 changes: 8 additions & 3 deletions src/entities/project/filter/ui/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { IoOptions } from 'react-icons/io5';
import type { GetUserResponse } from '~/shared/api/model';
import { useIsMobile } from '~/shared/hooks';
import { stringToServerDate } from '~/shared/lib/adapters';
import type { FilterSpecOptions } from '~/shared/types';
import { Counter } from '~/shared/ui/Counter';
import { FilterSpecialization } from '~/shared/ui/FilterSpecialization';
import { SearchSelect } from '~/shared/ui/SearchSelect';

import { useFilterStore } from '../model';
Expand All @@ -33,7 +33,12 @@ interface FilterProps {
user?: GetUserResponse;
}

export const Filter = ({ user, isLoading, totalItems = 0 }: FilterProps) => {
export const Filter = ({
user,
FilterSpec,
isLoading,
totalItems = 0,
}: FilterProps & FilterSpecOptions) => {
const { isOpen, onOpen, onClose } = useDisclosure();

const { filter, removeFilter, updateFilter, initialStore } = useFilterStore();
Expand Down Expand Up @@ -98,7 +103,7 @@ export const Filter = ({ user, isLoading, totalItems = 0 }: FilterProps) => {
<Heading variant="h2" mb={3}>
Специализация
</Heading>
<FilterSpecialization
<FilterSpec
userSpecs={filter.specs}
setUserSpecs={(values) => {
updateFilter({ specs: values });
Expand Down
1 change: 1 addition & 0 deletions src/entities/storage/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './useGetSpecs';
export * from './useGetSkills';
export * from './useGetAllSkills';
export * from './useGetSkillsbyIds';
export * from './useGetSpecsGroups';
12 changes: 12 additions & 0 deletions src/entities/storage/api/useGetSpecsGroups.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useQuery } from '@tanstack/react-query';

import { api } from '~/shared/api';

export const useGetSpecsGroups = () =>
useQuery({
queryKey: ['specs', 'groups'],
queryFn: async () => {
const { data } = await api.storageApi.getSpecGroups();
return data;
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import {
TagLabel,
IconButton,
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { useState } from 'react';

import { useGetSpecs } from '~/entities/storage';

import { useApi } from '~/shared/hooks';
import { useGetSpecs, useGetSpecsGroups } from '~/entities/storage';

import { FilterSpecializationModal } from './FilterSpecializationModal';

interface FilterSpecializationProps {
export interface FilterSpecializationProps {
singleChecked?: boolean;
doubleChecked?: boolean;
userSpecs: string[];
Expand All @@ -31,16 +28,10 @@ export const FilterSpecialization = ({
doubleChecked,
VictoriaBorovskaya marked this conversation as resolved.
Show resolved Hide resolved
}: FilterSpecializationProps) => {
const [specFilter, setSpecFilter] = useState(false);
const { storageApi } = useApi();
const [searchText, setSearchText] = useState('');

const { data: specGroup, isFetching: specGroupLoading } = useQuery({
queryKey: ['specGroups'],
queryFn: () => storageApi.getSpecGroups(),
staleTime: Infinity,
});

const { data: specs, isFetching: specsLoading } = useGetSpecs({
const { data: specGroup } = useGetSpecsGroups();
const { data: specs } = useGetSpecs({
query_text: searchText,
});

Expand Down Expand Up @@ -98,11 +89,9 @@ export const FilterSpecialization = ({
</Flex>

<FilterSpecializationModal
specsLoading={specsLoading}
specGroupLoading={specGroupLoading}
isVisible={specFilter}
changeVisible={setSpecFilter}
stateGroup={specGroup?.data}
stateGroup={specGroup}
state={specs}
userFilter={userSpecs}
resetSpec={() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Box,
Button,
Checkbox,
CheckboxGroup,
Container,
Flex,
Heading,
Expand All @@ -16,23 +10,17 @@ import {
Modal,
ModalContent,
ModalOverlay,
Skeleton,
Text,
} from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import React, { useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { FiChevronLeft } from 'react-icons/fi';

import { DummyNotFound } from '~/entities/dummy';

import type { GetSpecGroupsDataResponse, GetSpecsDataResponse } from '~/shared/api/model';
import { Counter } from '~/shared/ui/Counter';
import type { GetSpecGroupsDataResponse, GetSpecsDataResponse } from '~/shared/api';
import { SearchInput } from '~/shared/ui/SearchInput';

import { GroupItem } from './GroupItem';

interface FilterSpecializationModalProps {
isVisible: boolean;
specGroupLoading: boolean;
specsLoading: boolean;
changeVisible: (status: boolean) => void;
state?: GetSpecsDataResponse;
stateGroup?: GetSpecGroupsDataResponse;
Expand All @@ -55,8 +43,6 @@ export const FilterSpecializationModal = (props: FilterSpecializationModalProps)
saveSpec,
userFilter,
singleChecked,
specsLoading,
specGroupLoading,
doubleChecked,
searchText,
setSearchText,
Expand All @@ -67,26 +53,15 @@ export const FilterSpecializationModal = (props: FilterSpecializationModalProps)
const [filteredGroupsState, setFilteredGroupsState] =
useState<GetSpecGroupsDataResponse>([]);
const [filteredState, setFilteredState] = useState<GetSpecsDataResponse>([]);
const [selectCheckboxes, setSelectCheckboxes] = useState<string[]>([]);

const activeNestedCheckboxes = (group_id: string) =>
filteredState.filter(
(selector) =>
selector.group_id === group_id && selectCheckboxes.includes(selector.id),
).length;

useEffect(() => {
setSelectCheckboxes([...userFilter]);
}, [userFilter, isVisible]);

useEffect(() => {
if (state && stateGroup) {
const visibleSpecsGroupsIds = state.map(({ group_id }) => group_id);
const visibleSpecsGroups = stateGroup.filter(({ id }) =>
visibleSpecsGroupsIds.includes(id),
);
const activeCheckbox = state.filter(({ id }) => selectCheckboxes.includes(id));
const inactiveCheckbox = state.filter(({ id }) => !selectCheckboxes.includes(id));
const activeCheckbox = state.filter(({ id }) => userFilter.includes(id));
const inactiveCheckbox = state.filter(({ id }) => !userFilter.includes(id));

const activeSectionTitles = activeCheckbox.map(({ group_id }) => group_id);

Expand All @@ -102,25 +77,6 @@ export const FilterSpecializationModal = (props: FilterSpecializationModalProps)
}
}, [isVisible, state]);

const handleCheckbox = (e: React.ChangeEvent<HTMLInputElement>) => {
const id = e.target.value;
if (selectCheckboxes.includes(id)) {
setSelectCheckboxes(selectCheckboxes.filter((item) => item !== id));
return;
}
if (singleChecked) {
setSelectCheckboxes([id]);
} else if (doubleChecked) {
setSelectCheckboxes(
[...selectCheckboxes, id].length <= 2
? [...selectCheckboxes, id]
: [...selectCheckboxes.splice(-1, 1), id],
);
} else {
setSelectCheckboxes([...selectCheckboxes, id]);
}
};

return (
<Modal
onClose={() => {
Expand Down Expand Up @@ -169,62 +125,26 @@ export const FilterSpecializationModal = (props: FilterSpecializationModalProps)
value={searchText}
/>
</Box>
{specGroupLoading || specsLoading ? (
<Skeleton height="150px" borderRadius="2xl" />
) : (
<Accordion allowMultiple bg="white" borderRadius="2xl">
<CheckboxGroup
variant="black"
colorScheme="purple"
value={selectCheckboxes}
>
{filteredGroupsState.length ? (
filteredGroupsState.map((spec) => (
<AccordionItem key={spec.id}>
<AccordionButton justifyContent="space-between">
<Flex gap={2} fontSize="sm" textAlign="left" alignItems="center">
<Heading fontSize="md" fontWeight="medium">
{spec.name}
</Heading>
{activeNestedCheckboxes(spec.id) > 0 && (
<Counter count={activeNestedCheckboxes(spec.id)} />
)}
</Flex>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={3}>
{filteredState.map((selector) => (
<React.Fragment key={selector.id}>
{selector.group_id === spec.id && (
<Checkbox
onChange={handleCheckbox}
p={4}
w="full"
py={2}
value={selector.id}
>
<Text fontWeight="medium" fontSize="sm">
{selector.name}
</Text>
</Checkbox>
)}
</React.Fragment>
))}
</AccordionPanel>
</AccordionItem>
))
) : (
<DummyNotFound text="Упс, специализация не найдена" />
)}
</CheckboxGroup>
</Accordion>
)}

<Accordion allowToggle bg="white" borderRadius="2xl">
{filteredGroupsState.map((group) => (
<GroupItem
key={group.id}
id={group.id}
name={group.name}
allSpecs={filteredState}
tempSpec={userFilter}
singleChecked={singleChecked}
doubleChecked={doubleChecked}
/>
))}
</Accordion>
</Container>
<Container maxW="md" py={6} bg="bg" position="sticky" bottom="0">
{filteredGroupsState.length > 0 && (
<Button
onClick={() => {
saveSpec(selectCheckboxes);
saveSpec(userFilter);
changeVisible(false);
setSearchText('');
}}
Expand Down
75 changes: 75 additions & 0 deletions src/features/filter/GroupItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Flex,
Heading,
} from '@chakra-ui/react';
import { useState } from 'react';

import { Counter } from '~/shared/ui/Counter';

import { SpecsGroups } from './SpecsGroups';

interface GroupItemProps {
name: string | null;
id: string;
allSpecs: {
id: string;
name: string | null;
group_id: string | null;
created_at: string;
}[];
tempSpec: string[];
singleChecked?: boolean;
doubleChecked?: boolean;
}

export const GroupItem = ({
name,
id,
tempSpec,
allSpecs,
singleChecked,
doubleChecked,
}: GroupItemProps) => {
const [_, setCheckboxChange] = useState(false);
const getCurrentSpecs = (id: string) => {
return allSpecs.filter(({ group_id }) => group_id === id);
};

const currentCount = allSpecs.filter(
(spec) => spec.group_id === id && tempSpec.includes(spec.id),
).length;

return (
<AccordionItem>
{({ isExpanded }) => (
<>
<AccordionButton justifyContent="space-between">
<Flex gap={2} fontSize="sm" textAlign="left" alignItems="center">
<Heading fontSize="md" fontWeight="medium">
{name}
</Heading>
{currentCount > 0 && <Counter count={currentCount} />}
</Flex>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={3}>
{isExpanded && (
<SpecsGroups
id={id}
tempSpec={tempSpec}
currentSpecs={getCurrentSpecs(id)}
updateCounter={setCheckboxChange}
singleChecked={singleChecked}
doubleChecked={doubleChecked}
/>
)}
</AccordionPanel>
</>
)}
</AccordionItem>
);
};
Loading
Loading