diff --git a/.eslintrc.js b/.eslintrc.js index 8fd3832a..9fd49666 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,6 +27,7 @@ module.exports = { 'plugin:@tanstack/eslint-plugin-query/recommended', ], rules: { + '@typescript-eslint/no-floating-promises': 'off', '@typescript-eslint/no-unused-vars': [ 'warn', { diff --git a/src/entities/project/filter/index.ts b/src/entities/project/filter/index.ts new file mode 100644 index 00000000..c51f0c57 --- /dev/null +++ b/src/entities/project/filter/index.ts @@ -0,0 +1,2 @@ +export * from './ui'; +export * from './model'; diff --git a/src/entities/project/filter/model.ts b/src/entities/project/filter/model.ts new file mode 100644 index 00000000..9c50ae52 --- /dev/null +++ b/src/entities/project/filter/model.ts @@ -0,0 +1,41 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +import { SelectOptions } from '~/shared/types'; + +export interface FilterType { + specs: string[]; + skills: SelectOptions[]; + date: string; +} + +export const defaultFilter: FilterType = { + specs: [], + skills: [], + date: '', +}; + +interface FilterStore { + filter: FilterType; + updateFilter: (filter: Partial) => void; + removeFilter: () => void; +} + +export const useFilterStore = create( + persist( + (set) => ({ + filter: defaultFilter, + updateFilter: (value: Partial) => { + set((state) => ({ + filter: { ...state.filter, ...value }, + })); + }, + removeFilter: () => { + set(() => ({ filter: defaultFilter })); + }, + }), + { + name: 'filter', + }, + ), +); diff --git a/src/features/project/filter/ui/Filter.tsx b/src/entities/project/filter/ui/Filter.tsx similarity index 68% rename from src/features/project/filter/ui/Filter.tsx rename to src/entities/project/filter/ui/Filter.tsx index 2b5f9f77..a0cc6c83 100644 --- a/src/features/project/filter/ui/Filter.tsx +++ b/src/entities/project/filter/ui/Filter.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ import { Button, IconButton, @@ -16,23 +15,24 @@ import { Stack, Input, } from '@chakra-ui/react'; -import { useQueryClient } from '@tanstack/react-query'; -import { useState } from 'react'; import { IoOptions } from 'react-icons/io5'; import { useIsMobile } from '~/shared/hooks'; +import { stringToServerDate } from '~/shared/lib/stringToServerDate'; import { Counter } from '~/shared/ui/Counter'; import { FilterSpecialization } from '~/shared/ui/FilterSpecialization'; import { SearchSelect } from '~/shared/ui/SearchSelect'; -export const Filter = () => { - const queryClient = useQueryClient(); +import { useFilterStore } from '../model'; + +interface FilterProps { + totalItems?: number | null; +} + +export const Filter = ({ totalItems = 0 }: FilterProps) => { const { isOpen, onOpen, onClose } = useDisclosure(); - const [userSpecs, setUserSpecs] = useState([]); - const [selectedItems, setSelectedItems] = useState<{ value: string; label: string }[]>( - [], - ); + const { filter, removeFilter, updateFilter } = useFilterStore(); const isMobile = useIsMobile(); return ( @@ -49,7 +49,11 @@ export const Filter = () => { <> - + } > @@ -71,9 +75,7 @@ export const Filter = () => { fontWeight="500" colorScheme="purple" onClick={() => { - setUserSpecs([]); - setSelectedItems([]); - queryClient.invalidateQueries(['skills']); + removeFilter(); }} > Сбросить @@ -85,7 +87,12 @@ export const Filter = () => { Специализация - + { + updateFilter({ specs: values }); + }} + /> @@ -93,8 +100,11 @@ export const Filter = () => { Профессиональные навыки { + updateFilter({ skills: values }); + }} /> @@ -108,13 +118,18 @@ export const Filter = () => { color="gray.500" placeholder="Выберите дату" type="date" + value={filter.date.split('T', 1)[0]} + onChange={(e) => { + const value = e.target.value; + updateFilter({ date: value ? stringToServerDate(value) : value }); + }} /> - diff --git a/src/features/project/filter/ui/index.ts b/src/entities/project/filter/ui/index.ts similarity index 100% rename from src/features/project/filter/ui/index.ts rename to src/entities/project/filter/ui/index.ts diff --git a/src/entities/project/index.ts b/src/entities/project/index.ts index df44694f..858e488a 100644 --- a/src/entities/project/index.ts +++ b/src/entities/project/index.ts @@ -3,3 +3,4 @@ export * from './contacts'; export * from './avatars-group'; export * from './api'; export * from './info'; +export * from './filter'; diff --git a/src/features/project/filter/index.ts b/src/features/project/filter/index.ts deleted file mode 100644 index 5ecdd1f3..00000000 --- a/src/features/project/filter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ui'; diff --git a/src/features/project/index.ts b/src/features/project/index.ts index ac4de8f0..54117eb3 100644 --- a/src/features/project/index.ts +++ b/src/features/project/index.ts @@ -1,3 +1,2 @@ -export * from './filter'; export * from './search'; export * from './add'; diff --git a/src/features/project/search/SearchProject.tsx b/src/features/project/search/SearchProject.tsx index d3f3a366..e1bd6cca 100644 --- a/src/features/project/search/SearchProject.tsx +++ b/src/features/project/search/SearchProject.tsx @@ -1,8 +1,9 @@ import { SearchInput } from '~/shared/ui/SearchInput'; -export const SearchProject = () => { - const handleSumbit = (value: string) => { - console.log(value); - }; - return ; +interface SearchProjectProps { + onChange: (value: string) => void; +} + +export const SearchProject = ({ onChange }: SearchProjectProps) => { + return ; }; diff --git a/src/pages/projects/ui/ProjectsBase.tsx b/src/pages/projects/ui/ProjectsBase.tsx new file mode 100644 index 00000000..a7a9d510 --- /dev/null +++ b/src/pages/projects/ui/ProjectsBase.tsx @@ -0,0 +1,169 @@ +import { + Flex, + SimpleGrid, + Heading, + Container, + Box, + Skeleton, + Image, + Text, + Button, +} from '@chakra-ui/react'; +import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query'; +import React, { useEffect, useRef, useState } from 'react'; +import { Link, generatePath, useNavigate } from 'react-router-dom'; + +import { ProjectCard } from '~/widgets/project-card'; + +import { AddProject } from '~/features/project'; + +import { AvatarsGroup } from '~/entities/project'; + +import { useApi } from '~/shared/hooks'; +import { PATHS } from '~/shared/lib/router'; +import { STag } from '~/shared/ui/STag'; + +import NotAuth from './NotAuth.svg'; + +interface ProjectPageProps { + userId: string; +} + +export const ProjectsBase = ({ userId }: ProjectPageProps) => { + const targetRef = useRef(null); + const { projectsApi } = useApi(); + const [isEmptyData, setEmptyData] = useState(false); + const navigate = useNavigate(); + const dummyAvatars = [ + { firstName: 'Alex', lastName: 'Gordon', img: 'https://bit.ly/ryan-florence' }, + { firstName: 'Игорь', lastName: 'Крутой', img: 'https://bit.ly/sage-adebayo' }, + { firstName: 'Джек', lastName: 'Воробей', img: 'https://bit.ly/kent-c-dodds' }, + { firstName: 'Кларк', lastName: 'Кент', img: 'https://bit.ly/prosper-baba' }, + { firstName: 'Джеймс', lastName: 'Бонд', img: 'https://bit.ly/code-beast' }, + { firstName: 'Бернд', lastName: 'Шнайдер', img: 'https://bit.ly/dan-abramov' }, + ]; + + const { data, isLoading, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({ + queryKey: ['getAllProjects', userId], + queryFn: ({ pageParam = 1 }: QueryFunctionContext) => + projectsApi.getAllProjects({ page: pageParam, owner_id: userId }), + // getNextPageParam: (lastPage) => lastPage.page + 1, + onSuccess: (response) => { + setEmptyData(!response.pages[0].data.length); + }, + staleTime: 5000, + }); + + useEffect(() => { + const options = { + root: null, + rootMargin: '0px', + threshold: 1.0, + }; + + const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => { + const [entry] = entries; + if (entry.isIntersecting) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + fetchNextPage(); + } + }, options); + + if (targetRef.current) observer.observe(targetRef.current); + + return () => { + if (targetRef.current) observer.unobserve(targetRef.current); + }; + }, [data]); + + return ( + + + + Проекты + + + + + + + {isLoading ? ( + <> + + + + + ) : ( + + {isEmptyData ? ( + + + + Нет проектов + + + Здесь будут отображаться все ваши проекты в качестве участника и + организатора + + + + ) : ( + <> + {data?.pages.map((group, i) => ( + + {group.data.map((project) => { + return ( + + + + + + + + + ); + })} + + ))} + + )} + + {isFetchingNextPage && ( + <> + + + + + )} + + + )} + + ); +}; diff --git a/src/pages/projects/ui/ProjectsPage.tsx b/src/pages/projects/ui/ProjectsPage.tsx index d780a582..8b1e2c28 100644 --- a/src/pages/projects/ui/ProjectsPage.tsx +++ b/src/pages/projects/ui/ProjectsPage.tsx @@ -1,167 +1,8 @@ -import { - Flex, - SimpleGrid, - Heading, - Container, - Box, - Skeleton, - Image, - Text, - Button, -} from '@chakra-ui/react'; -import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query'; -import React, { useEffect, useRef, useState } from 'react'; -import { Link, generatePath, useNavigate } from 'react-router-dom'; +import { BasePageProps } from '~/shared/lib/router'; -import { ProjectCard } from '~/widgets/project-card'; +import { NotAuthProjectsPage } from './NotAuthProjectPage'; +import { ProjectBase } from './ProjectBase'; -import { AddProject } from '~/features/project'; - -import { AvatarsGroup } from '~/entities/project'; - -import { useApi, useAuth } from '~/shared/hooks'; -import { PATHS } from '~/shared/lib/router'; -import { STag } from '~/shared/ui/STag'; - -import NotAuth from './NotAuth.svg'; - -export const ProjectsPage = () => { - const targetRef = useRef(null); - const { projectsApi } = useApi(); - const { userId } = useAuth(); - const [isEmptyData, setEmptyData] = useState(false); - const navigate = useNavigate(); - const dummyAvatars = [ - { firstName: 'Alex', lastName: 'Gordon', img: 'https://bit.ly/ryan-florence' }, - { firstName: 'Игорь', lastName: 'Крутой', img: 'https://bit.ly/sage-adebayo' }, - { firstName: 'Джек', lastName: 'Воробей', img: 'https://bit.ly/kent-c-dodds' }, - { firstName: 'Кларк', lastName: 'Кент', img: 'https://bit.ly/prosper-baba' }, - { firstName: 'Джеймс', lastName: 'Бонд', img: 'https://bit.ly/code-beast' }, - { firstName: 'Бернд', lastName: 'Шнайдер', img: 'https://bit.ly/dan-abramov' }, - ]; - - const { data, isLoading, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({ - queryKey: ['getAllProjects', userId], - queryFn: ({ pageParam = 1 }: QueryFunctionContext) => - projectsApi.getAllProjects(pageParam, userId), - // getNextPageParam: (lastPage) => lastPage.page + 1, - onSuccess: (response) => { - setEmptyData(!response.pages[0].data.length); - }, - enabled: !!userId, - staleTime: 5000, - }); - - useEffect(() => { - const options = { - root: null, - rootMargin: '0px', - threshold: 1.0, - }; - - const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => { - const [entry] = entries; - if (entry.isIntersecting) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - fetchNextPage(); - } - }, options); - - if (targetRef.current) observer.observe(targetRef.current); - - return () => { - if (targetRef.current) observer.unobserve(targetRef.current); - }; - }, [data]); - - return ( - - - - Проекты - - - - - - - {isLoading ? ( - <> - - - - - ) : ( - - {isEmptyData ? ( - - - - Нет проектов - - - Здесь будут отображаться все ваши проекты в качестве участника и - организатора - - - - ) : ( - <> - {data?.pages.map((group, i) => ( - - {group.data.map((project) => { - return ( - - - - - - - - - ); - })} - - ))} - - )} - - {isFetchingNextPage && ( - <> - - - - - )} - - - )} - - ); +export const ProjectsPage = ({ user }: BasePageProps) => { + return !user.userId ? : ; }; diff --git a/src/pages/search/api/useGetAllProjects.tsx b/src/pages/search/api/useGetAllProjects.tsx new file mode 100644 index 00000000..ee72e1f0 --- /dev/null +++ b/src/pages/search/api/useGetAllProjects.tsx @@ -0,0 +1,26 @@ +import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query'; + +import { api } from '~/shared/contexts'; +import { SelectOptions } from '~/shared/types'; + +interface Search { + specs?: string[]; + skills?: SelectOptions[]; + date?: string; + searchText?: string; +} + +export const useGetAllProjects = ({ specs, skills, date, searchText }: Search) => + useInfiniteQuery({ + queryKey: ['getAllProjects', { specs, skills, date, searchText }], + queryFn: ({ pageParam = 1 }: QueryFunctionContext) => + api.projectsApi.getAllProjects({ + page: pageParam, + position_skill_ids: specs, + position_specialization_ids: skills?.map((skill) => skill.value), + startline_le: date, + query_text: searchText, + }), + getNextPageParam: (lastPage) => lastPage.page + 1, + staleTime: 5000, + }); diff --git a/src/pages/search/ui/SearchPage.desktop.tsx b/src/pages/search/ui/SearchPage.desktop.tsx index 75562f6b..b5ab0632 100644 --- a/src/pages/search/ui/SearchPage.desktop.tsx +++ b/src/pages/search/ui/SearchPage.desktop.tsx @@ -1,13 +1,22 @@ import { Flex, SimpleGrid, Heading } from '@chakra-ui/react'; +import { useState } from 'react'; import { ProjectCard } from '~/widgets/project-card'; -import { Filter, SearchProject } from '~/features/project'; +import { SearchProject } from '~/features/project'; + +import { Filter } from '~/entities/project'; import { data } from '~/shared/lib/data'; import { STag } from '~/shared/ui/STag'; export const SearchPageDesktop = () => { + const [searchText, setSearchText] = useState(''); + + const handleSumbit = (value: string) => { + setSearchText(value); + }; + return ( <> @@ -17,7 +26,7 @@ export const SearchPageDesktop = () => { - + diff --git a/src/pages/search/ui/SearchPage.tsx b/src/pages/search/ui/SearchPage.tsx index 5b736e5f..b68b3942 100644 --- a/src/pages/search/ui/SearchPage.tsx +++ b/src/pages/search/ui/SearchPage.tsx @@ -1,38 +1,35 @@ -import { - Flex, - SimpleGrid, - Container, - Button, - Portal, - Box, - Skeleton, -} from '@chakra-ui/react'; -import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query'; -import React, { useEffect, useRef } from 'react'; +import { Flex, SimpleGrid, Container, Button, Portal, Skeleton } from '@chakra-ui/react'; +import React, { useEffect, useRef, useState } from 'react'; import { Link, generatePath } from 'react-router-dom'; import { ProjectCard } from '~/widgets/project-card'; -import { SearchProject, Filter } from '~/features/project'; +import { SearchProject } from '~/features/project'; import { Notification, Settings } from '~/features/user'; +import { Filter, useFilterStore } from '~/entities/project'; import { Avatar, DummyAvatar } from '~/entities/user'; import { useApi, useLayoutRefs } from '~/shared/hooks'; import { BasePageProps, PATHS } from '~/shared/lib/router'; import { STag } from '~/shared/ui/STag'; +import { useGetAllProjects } from '../api/useGetAllProjects'; + export const SearchPage = ({ user }: BasePageProps) => { - const { userApi, projectsApi } = useApi(); + const { userApi } = useApi(); const targetRef = useRef(null); const layout = useLayoutRefs(); - const { data, isLoading, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({ - queryKey: ['getAllProjects'], - queryFn: ({ pageParam = 1 }: QueryFunctionContext) => - projectsApi.getAllProjects(pageParam), - getNextPageParam: (lastPage) => lastPage.page + 1, - staleTime: 5000, + const [searchText, setSearchText] = useState(''); + + const { filter } = useFilterStore(); + + const { data, isLoading, fetchNextPage, isFetchingNextPage } = useGetAllProjects({ + date: filter.date, + skills: filter.skills, + specs: filter.specs, + searchText, }); const dummyDate = { @@ -62,6 +59,10 @@ export const SearchPage = ({ user }: BasePageProps) => { }; }, [data]); + const handleSumbit = (value: string) => { + setSearchText(value); + }; + return ( <> @@ -77,8 +78,8 @@ export const SearchPage = ({ user }: BasePageProps) => { )} - - + + {isLoading || !data ? ( <> @@ -116,7 +117,7 @@ export const SearchPage = ({ user }: BasePageProps) => { )} - + {/* */} )} diff --git a/src/shared/api/clients/projects.ts b/src/shared/api/clients/projects.ts index f96db8e4..720b30a9 100644 --- a/src/shared/api/clients/projects.ts +++ b/src/shared/api/clients/projects.ts @@ -1,9 +1,12 @@ +import Qs from 'query-string'; + import { AddSkillsRequest, AddSkillsResponse, AfterPostNewProjectResponse, CreatePositionRequest, CreatePositionResponse, + GetAllProjectsRequest, GetAllProjectsResponse, GetCurrentProjectResponse, GetPositionSkillsResponse, @@ -106,10 +109,18 @@ export class ProjectsApiClient extends BaseApiClient { return data; } - async getAllProjects(page: number, owner_id?: string | null) { + async getAllProjects(request: GetAllProjectsRequest) { const { data } = await this.client.get( `/api/rest/projects/`, - { params: { page, owner_id } }, + { + params: request, + paramsSerializer: function (params) { + return Qs.stringify(params, { + skipNull: true, + skipEmptyString: true, + }); + }, + }, ); const { data: onlyData, ...others } = data; const newData = onlyData.map((project) => { diff --git a/src/shared/api/types/project.types.ts b/src/shared/api/types/project.types.ts index b99c0543..30318de7 100644 --- a/src/shared/api/types/project.types.ts +++ b/src/shared/api/types/project.types.ts @@ -6,6 +6,8 @@ export type AfterPostNewProjectResponse = paths['/api/rest/projects/']['post']['responses']['200']['content']['application/json']; export type GetAllProjectsResponse = paths['/api/rest/projects/']['get']['responses']['200']['content']['application/json']; +export type GetAllProjectsRequest = + paths['/api/rest/projects/']['get']['parameters']['query']; export type GetCurrentProjectResponse = paths['/api/rest/projects/{project_id}']['get']['responses']['200']['content']['application/json']; export type CreatePositionRequest = diff --git a/src/shared/types/SelectOptions.ts b/src/shared/types/SelectOptions.ts new file mode 100644 index 00000000..144d845d --- /dev/null +++ b/src/shared/types/SelectOptions.ts @@ -0,0 +1,4 @@ +export interface SelectOptions { + label: string; + value: string; +} diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts new file mode 100644 index 00000000..914371d6 --- /dev/null +++ b/src/shared/types/index.ts @@ -0,0 +1 @@ +export * from './SelectOptions'; diff --git a/src/shared/ui/Counter/Counter.tsx b/src/shared/ui/Counter/Counter.tsx index 3e4d42dc..9c279f2e 100644 --- a/src/shared/ui/Counter/Counter.tsx +++ b/src/shared/ui/Counter/Counter.tsx @@ -14,6 +14,7 @@ export function Counter(props: CounterType) { return ( storageApi.getSpecGroups(), - staleTime: 5000, + staleTime: Infinity, }); const { data: specs, isLoading: specsLoading } = useQuery({ @@ -49,7 +49,7 @@ export const FilterSpecialization = ({ isClosable: true, }); }, - staleTime: 50000, + staleTime: Infinity, }); const deleteSpecFilter = (id: string) => { diff --git a/src/shared/ui/FilterSpecialization/FilterSpecializationModal.tsx b/src/shared/ui/FilterSpecialization/FilterSpecializationModal.tsx index 3e80e8c4..4e6a38d7 100644 --- a/src/shared/ui/FilterSpecialization/FilterSpecializationModal.tsx +++ b/src/shared/ui/FilterSpecialization/FilterSpecializationModal.tsx @@ -19,6 +19,7 @@ import { Skeleton, Text, } from '@chakra-ui/react'; +import { useQueryClient } from '@tanstack/react-query'; import React, { useEffect, useRef, useState } from 'react'; import { FiChevronLeft } from 'react-icons/fi'; diff --git a/src/shared/ui/SearchSelect/SearchSelect.tsx b/src/shared/ui/SearchSelect/SearchSelect.tsx index bdd572d2..e00ca42d 100644 --- a/src/shared/ui/SearchSelect/SearchSelect.tsx +++ b/src/shared/ui/SearchSelect/SearchSelect.tsx @@ -5,17 +5,12 @@ import { AsyncSelect, GroupBase, LoadingIndicatorProps, - OptionBase, chakraComponents, } from 'chakra-react-select'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useApi } from '~/shared/hooks'; - -interface SelectOptions extends OptionBase { - label: string; - value: string; -} +import { SelectOptions } from '~/shared/types'; const asyncComponents = { LoadingIndicator: ( @@ -37,21 +32,17 @@ const asyncComponents = { interface SearchSelectProps { selectedItems: SelectOptions[]; setSelectedItems: (selectedItems: SelectOptions[]) => void; + isSearchFilter?: boolean; } export const SearchSelect = ({ selectedItems, setSelectedItems }: SearchSelectProps) => { const toast = useToast(); const { storageApi } = useApi(); - const [unSelectedItems, setUnSelectedItems] = useState< - { value: string; label: string }[] - >([]); + const [unSelectedItems, setUnSelectedItems] = useState([]); - useQuery({ + const { data } = useQuery({ queryKey: ['skills'], queryFn: () => storageApi.getSkills(), - onSuccess(data) { - setUnSelectedItems(data); - }, onError: (e: Error) => { toast({ title: 'Ошибка получения навыков', @@ -61,8 +52,19 @@ export const SearchSelect = ({ selectedItems, setSelectedItems }: SearchSelectPr isClosable: true, }); }, + staleTime: Infinity, }); + useEffect(() => { + if (data) { + const formatSelectedItems = selectedItems.map(({ value }) => value); + const formatUnSelectedItem = data.filter( + ({ value }) => !formatSelectedItems.includes(value), + ); + setUnSelectedItems(formatUnSelectedItem); + } + }, [data]); + const unSelectValue = (id: string) => { const unSelectedItem = selectedItems.find((item) => item.value === id); if (unSelectedItem) { diff --git a/src/widgets/project/add/AddProject.types.ts b/src/widgets/project/add/AddProject.types.ts index a0dbdab0..8470f81c 100644 --- a/src/widgets/project/add/AddProject.types.ts +++ b/src/widgets/project/add/AddProject.types.ts @@ -1,9 +1,4 @@ -import { OptionBase } from 'chakra-react-select'; - -interface SelectOptions extends OptionBase { - label: string; - value: string; -} +import { SelectOptions } from '~/shared/types'; export interface NewSpecialist { spec: string; diff --git a/src/widgets/project/add/tabs/Team.tsx b/src/widgets/project/add/tabs/Team.tsx index ae201d22..dd838645 100644 --- a/src/widgets/project/add/tabs/Team.tsx +++ b/src/widgets/project/add/tabs/Team.tsx @@ -5,6 +5,7 @@ import { Dispatch, SetStateAction, useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { useApi } from '~/shared/hooks'; +import { SelectOptions } from '~/shared/types'; import { FilterSpecialization } from '~/shared/ui/FilterSpecialization'; import { SearchSelect } from '~/shared/ui/SearchSelect'; import { STag } from '~/shared/ui/STag'; @@ -20,7 +21,7 @@ export const Team = (props: TeamProps) => { const { storageApi } = useApi(); const { newSpecialist, setNewSpecialist } = props; const [userSpecs, setUserSpecs] = useState([]); - const [userSkills, setUserSkills] = useState<{ value: string; label: string }[]>([]); + const [userSkills, setUserSkills] = useState([]); const { data: specs } = useQuery({ queryKey: ['specs'],