From a56ca779fc7f549cda8ba4fbc56a11157aa4fcbc Mon Sep 17 00:00:00 2001 From: andres Date: Mon, 1 Jan 2024 15:17:05 +0100 Subject: [PATCH] feat: use search params for filters instead of redux --- package.json | 2 +- pnpm-lock.yaml | 8 +- .../auth/check-email/check-email.tsx | 4 +- .../auth/new-password/new-password.tsx | 5 +- src/components/auth/sign-in/sign-in.tsx | 3 +- src/components/auth/sign-up/sign-up.tsx | 3 +- .../decks/deck-dialog/deck-dialog.stories.tsx | 3 +- src/components/decks/decks-table.tsx | 27 ++++-- .../delete-deck-dialog.stories.tsx | 3 +- .../personal-information.tsx | 4 +- src/components/ui/button/button.module.scss | 9 ++ src/components/ui/button/button.tsx | 4 +- src/components/ui/card/card.stories.tsx | 3 +- .../ui/checkbox/checkbox.stories.tsx | 3 +- src/components/ui/dialog/dialog.stories.tsx | 3 +- src/components/ui/pagination/pagination.tsx | 3 +- src/components/ui/slider/slider.tsx | 2 +- src/components/ui/table/table.stories.tsx | 3 +- src/hooks/index.ts | 1 + src/hooks/use-query-param/index.ts | 1 + src/hooks/use-query-param/use-query-param.ts | 36 ++++++++ src/main.tsx | 5 +- src/pages/decks-page/decks-page.tsx | 88 +++++++++++-------- .../decks-page/use-deck-search-params.ts | 75 ++++++++++++++++ src/services/decks/decks.service.ts | 32 +------ src/services/decks/decks.types.ts | 14 +-- src/services/store.ts | 3 +- src/utils/get-valuable.ts | 9 ++ src/utils/index.ts | 1 + 29 files changed, 247 insertions(+), 110 deletions(-) create mode 100644 src/hooks/index.ts create mode 100644 src/hooks/use-query-param/index.ts create mode 100644 src/hooks/use-query-param/use-query-param.ts create mode 100644 src/pages/decks-page/use-deck-search-params.ts create mode 100644 src/utils/get-valuable.ts diff --git a/package.json b/package.json index 6af8023..b54273a 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@hookform/devtools": "^4.3.1", "@it-incubator/eslint-config": "^1.0.2", "@it-incubator/prettier-config": "^0.1.2", - "@it-incubator/stylelint-config": "^1.0.1", + "@it-incubator/stylelint-config": "^1.0.2", "@storybook/addon-essentials": "^7.6.6", "@storybook/addon-interactions": "^7.6.6", "@storybook/addon-links": "^7.6.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b59ba5..d9c10c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,8 +83,8 @@ devDependencies: specifier: ^0.1.2 version: 0.1.2 '@it-incubator/stylelint-config': - specifier: ^1.0.1 - version: 1.0.1(stylelint-config-clean-order@5.2.0)(stylelint-config-standard-scss@12.0.0)(stylelint@16.1.0) + specifier: ^1.0.2 + version: 1.0.2(stylelint-config-clean-order@5.2.0)(stylelint-config-standard-scss@12.0.0)(stylelint@16.1.0) '@storybook/addon-essentials': specifier: ^7.6.6 version: 7.6.6(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) @@ -2178,8 +2178,8 @@ packages: prettier: 3.0.0 dev: true - /@it-incubator/stylelint-config@1.0.1(stylelint-config-clean-order@5.2.0)(stylelint-config-standard-scss@12.0.0)(stylelint@16.1.0): - resolution: {integrity: sha512-dZuCX0wXtuNwU0BoNM1fbfo9V9DIG4IhtZ67cOgTsv7/zXFOxXCPiOSx2SguCA7sg4P62/oq2pMQq/x/Y4Edag==} + /@it-incubator/stylelint-config@1.0.2(stylelint-config-clean-order@5.2.0)(stylelint-config-standard-scss@12.0.0)(stylelint@16.1.0): + resolution: {integrity: sha512-2LIducOMyfhFOGV1GvmpWjjvgRGhEtHw/qBv3Vjw+Nel8jCl9cpH2yJrdehK1QJSOkzvQGs2pPQViouW9FQUCA==} peerDependencies: stylelint: 16.1.0 stylelint-config-clean-order: 5.2.0 diff --git a/src/components/auth/check-email/check-email.tsx b/src/components/auth/check-email/check-email.tsx index c34a0b9..d895dfc 100644 --- a/src/components/auth/check-email/check-email.tsx +++ b/src/components/auth/check-email/check-email.tsx @@ -1,10 +1,10 @@ import { Link } from 'react-router-dom' +import s from './check-email.module.scss' + import { Email } from '../../../assets/icons' import { Button, Card, Typography } from '../../ui' -import s from './check-email.module.scss' - type Props = { email: string } diff --git a/src/components/auth/new-password/new-password.tsx b/src/components/auth/new-password/new-password.tsx index a73d999..a91fcec 100644 --- a/src/components/auth/new-password/new-password.tsx +++ b/src/components/auth/new-password/new-password.tsx @@ -1,14 +1,15 @@ import { useForm } from 'react-hook-form' -import { Button, Card, ControlledTextField, Typography } from '../../ui' import { DevTool } from '@hookform/devtools' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import s from './new-password.module.scss' +import { Button, Card, ControlledTextField, Typography } from '../../ui' + const schema = z.object({ - password: z.string().nonempty('Enter password'), + password: z.string().min(1, 'Enter password'), }) type FormType = z.infer diff --git a/src/components/auth/sign-in/sign-in.tsx b/src/components/auth/sign-in/sign-in.tsx index 2a47d2b..cc12a37 100644 --- a/src/components/auth/sign-in/sign-in.tsx +++ b/src/components/auth/sign-in/sign-in.tsx @@ -1,13 +1,14 @@ import { useForm } from 'react-hook-form' import { Link } from 'react-router-dom' -import { Button, Card, ControlledCheckbox, ControlledTextField, Typography } from '../../ui' import { DevTool } from '@hookform/devtools' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import s from './sign-in.module.scss' +import { Button, Card, ControlledCheckbox, ControlledTextField, Typography } from '../../ui' + const schema = z.object({ email: z.string().email('Invalid email address').nonempty('Enter email'), password: z.string().nonempty('Enter password'), diff --git a/src/components/auth/sign-up/sign-up.tsx b/src/components/auth/sign-up/sign-up.tsx index 57e3faa..909efb5 100644 --- a/src/components/auth/sign-up/sign-up.tsx +++ b/src/components/auth/sign-up/sign-up.tsx @@ -1,7 +1,6 @@ import { useForm } from 'react-hook-form' import { Link } from 'react-router-dom' -import { Button, Card, ControlledTextField, Typography } from '../../ui' import { DevTool } from '@hookform/devtools' import { zodResolver } from '@hookform/resolvers/zod' import { omit } from 'remeda' @@ -9,6 +8,8 @@ import { z } from 'zod' import s from './sign-up.module.scss' +import { Button, Card, ControlledTextField, Typography } from '../../ui' + const schema = z .object({ email: z.string().email('Invalid email address').nonempty('Enter email'), diff --git a/src/components/decks/deck-dialog/deck-dialog.stories.tsx b/src/components/decks/deck-dialog/deck-dialog.stories.tsx index d4d602f..cbbb1a7 100644 --- a/src/components/decks/deck-dialog/deck-dialog.stories.tsx +++ b/src/components/decks/deck-dialog/deck-dialog.stories.tsx @@ -1,9 +1,10 @@ import { useState } from 'react' -import { DeckDialog } from './' import { Button } from '@/components' import { Meta, StoryObj } from '@storybook/react' +import { DeckDialog } from './' + const meta = { component: DeckDialog, tags: ['autodocs'], diff --git a/src/components/decks/decks-table.tsx b/src/components/decks/decks-table.tsx index d81bf9b..a55ad40 100644 --- a/src/components/decks/decks-table.tsx +++ b/src/components/decks/decks-table.tsx @@ -2,7 +2,9 @@ import { Link } from 'react-router-dom' import { Edit2Outline, PlayCircleOutline, TrashOutline } from '@/assets' import { + Button, Column, + Sort, Table, TableBody, TableCell, @@ -43,15 +45,24 @@ type Props = { decks: Deck[] | undefined onDeleteClick: (id: string) => void onEditClick: (id: string) => void + onSort: (key: Sort) => void + sort: Sort } -export const DecksTable = ({ currentUserId, decks, onDeleteClick, onEditClick }: Props) => { +export const DecksTable = ({ + currentUserId, + decks, + onDeleteClick, + onEditClick, + onSort, + sort, +}: Props) => { const handleEditClick = (id: string) => () => onEditClick(id) const handleDeleteClick = (id: string) => () => onDeleteClick(id) return ( - + {decks?.map(deck => ( @@ -65,17 +76,17 @@ export const DecksTable = ({ currentUserId, decks, onDeleteClick, onEditClick }: {deck.author.name}
- + {deck.author.id === currentUserId && ( <> - - + + )}
diff --git a/src/components/decks/delete-deck-dialog/delete-deck-dialog.stories.tsx b/src/components/decks/delete-deck-dialog/delete-deck-dialog.stories.tsx index 22761e3..d3ee01f 100644 --- a/src/components/decks/delete-deck-dialog/delete-deck-dialog.stories.tsx +++ b/src/components/decks/delete-deck-dialog/delete-deck-dialog.stories.tsx @@ -1,9 +1,10 @@ import { useState } from 'react' -import { DeleteDeckDialog } from './' import { Button } from '@/components' import { Meta, StoryObj } from '@storybook/react' +import { DeleteDeckDialog } from './' + const meta = { component: DeleteDeckDialog, tags: ['autodocs'], diff --git a/src/components/profile/personal-information/personal-information.tsx b/src/components/profile/personal-information/personal-information.tsx index 042b931..2803672 100644 --- a/src/components/profile/personal-information/personal-information.tsx +++ b/src/components/profile/personal-information/personal-information.tsx @@ -1,8 +1,8 @@ +import s from './personal-information.module.scss' + import { Camera, Edit, Logout } from '../../../assets/icons' import { Button, Card, Typography } from '../../ui' -import s from './personal-information.module.scss' - type Props = { avatar: string email: string diff --git a/src/components/ui/button/button.module.scss b/src/components/ui/button/button.module.scss index e9540ca..d82cdf3 100644 --- a/src/components/ui/button/button.module.scss +++ b/src/components/ui/button/button.module.scss @@ -44,6 +44,7 @@ } .primary { + composes: button; color: var(--color-light-100); background-color: var(--color-accent-500); box-shadow: 0 4px 18px rgb(140 97 255 / 35%); @@ -58,6 +59,7 @@ } .secondary { + composes: button; color: var(--color-light-100); background-color: var(--color-dark-300); box-shadow: 0 2px 10px 0 #6d6d6d40; @@ -72,6 +74,7 @@ } .tertiary { + composes: button; color: var(--color-accent-500); background-color: var(--color-dark-900); border: 1px solid var(--color-accent-700); @@ -86,6 +89,8 @@ } .link { + composes: button; + padding: 0.375rem 0; font-weight: var(--font-weight-bold); @@ -93,3 +98,7 @@ color: var(--color-accent-500); text-decoration-line: underline; } + +.icon { + border-radius: 9999px; +} diff --git a/src/components/ui/button/button.tsx b/src/components/ui/button/button.tsx index 861fd4c..dbcad6e 100644 --- a/src/components/ui/button/button.tsx +++ b/src/components/ui/button/button.tsx @@ -16,7 +16,7 @@ export type ButtonProps = { children: ReactNode className?: string fullWidth?: boolean - variant?: 'link' | 'primary' | 'secondary' | 'tertiary' + variant?: 'icon' | 'link' | 'primary' | 'secondary' | 'tertiary' } & ComponentPropsWithoutRef const ButtonPolymorph = (props: ButtonProps, ref: any) => { @@ -31,7 +31,7 @@ const ButtonPolymorph = (props: ButtonProps return ( diff --git a/src/components/ui/card/card.stories.tsx b/src/components/ui/card/card.stories.tsx index 04f9afc..cc0656a 100644 --- a/src/components/ui/card/card.stories.tsx +++ b/src/components/ui/card/card.stories.tsx @@ -1,8 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react' -import { Card } from './' import { Typography } from '@/components' +import { Card } from './' + const meta = { component: Card, tags: ['autodocs'], diff --git a/src/components/ui/checkbox/checkbox.stories.tsx b/src/components/ui/checkbox/checkbox.stories.tsx index 6e50671..00bfbad 100644 --- a/src/components/ui/checkbox/checkbox.stories.tsx +++ b/src/components/ui/checkbox/checkbox.stories.tsx @@ -1,7 +1,8 @@ import { useState } from 'react' -import { Checkbox } from './checkbox' import { Meta, StoryObj } from '@storybook/react' + +import { Checkbox } from './checkbox' const meta = { component: Checkbox, tags: ['autodocs'], diff --git a/src/components/ui/dialog/dialog.stories.tsx b/src/components/ui/dialog/dialog.stories.tsx index 854d88f..b133210 100644 --- a/src/components/ui/dialog/dialog.stories.tsx +++ b/src/components/ui/dialog/dialog.stories.tsx @@ -1,8 +1,9 @@ import { useState } from 'react' -import { Dialog } from './' import { Meta, StoryObj } from '@storybook/react' +import { Dialog } from './' + const meta = { component: Dialog, tags: ['autodocs'], diff --git a/src/components/ui/pagination/pagination.tsx b/src/components/ui/pagination/pagination.tsx index eab5115..9a06780 100644 --- a/src/components/ui/pagination/pagination.tsx +++ b/src/components/ui/pagination/pagination.tsx @@ -1,11 +1,12 @@ import { FC } from 'react' -import { usePagination } from './usePagination' import { KeyboardArrowLeft, KeyboardArrowRight } from '@/assets' import { clsx } from 'clsx' import s from './pagination.module.scss' +import { usePagination } from './usePagination' + type PaginationConditionals = | { onPerPageChange: (itemPerPage: number) => void diff --git a/src/components/ui/slider/slider.tsx b/src/components/ui/slider/slider.tsx index 99d7ebe..0997068 100644 --- a/src/components/ui/slider/slider.tsx +++ b/src/components/ui/slider/slider.tsx @@ -7,7 +7,7 @@ import s from './slider.module.scss' const Slider = forwardRef< ElementRef, Omit, 'value'> & { - value?: (number | undefined)[] + value?: (null | number)[] } >(({ className, max, onValueChange, value, ...props }, ref) => { useEffect(() => { diff --git a/src/components/ui/table/table.stories.tsx b/src/components/ui/table/table.stories.tsx index 9ea1833..01f1efd 100644 --- a/src/components/ui/table/table.stories.tsx +++ b/src/components/ui/table/table.stories.tsx @@ -1,7 +1,8 @@ -import { Table, TableBody, TableCell, TableEmpty, TableHead, TableHeadCell, TableRow } from './' import { Typography } from '@/components' import { Meta } from '@storybook/react' +import { Table, TableBody, TableCell, TableEmpty, TableHead, TableHeadCell, TableRow } from './' + export default { component: Table, title: 'Components/Table', diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..25b14f1 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1 @@ +export * from './use-query-param' diff --git a/src/hooks/use-query-param/index.ts b/src/hooks/use-query-param/index.ts new file mode 100644 index 0000000..25b14f1 --- /dev/null +++ b/src/hooks/use-query-param/index.ts @@ -0,0 +1 @@ +export * from './use-query-param' diff --git a/src/hooks/use-query-param/use-query-param.ts b/src/hooks/use-query-param/use-query-param.ts new file mode 100644 index 0000000..83591e0 --- /dev/null +++ b/src/hooks/use-query-param/use-query-param.ts @@ -0,0 +1,36 @@ +import { isNil } from 'remeda' + +export function useQueryParam( + searchParams: URLSearchParams, + setSearchParams: (searchParams: URLSearchParams) => void, + param: string, + defaultValue?: T +): [T | null, (value: T | null) => void] { + const paramValue = searchParams.get(param) + const convertedValue = getConvertedValue(paramValue, defaultValue) + + const setParamValue = (value: T | null): void => { + if (isNil(value) || value === '') { + searchParams.delete(param) + } else { + searchParams.set(param, String(value)) + } + setSearchParams(searchParams) + } + + return [convertedValue, setParamValue] +} + +function getConvertedValue(value: null | string, defaultValue: T | undefined): T | null { + if (value === null) { + return defaultValue ?? null + } + if (value === 'true' || value === 'false') { + return (value === 'true') as unknown as T + } + if (!isNaN(Number(value))) { + return Number(value) as unknown as T + } + + return value as unknown as T +} diff --git a/src/main.tsx b/src/main.tsx index c4965f9..f27e98f 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,11 +1,12 @@ import { StrictMode } from 'react' -import { App } from './App' import { createRoot } from 'react-dom/client' +import './styles/index.scss' import '@fontsource/roboto/400.css' import '@fontsource/roboto/700.css' -import './styles/index.scss' + +import { App } from './App' createRoot(document.getElementById('root')!).render( diff --git a/src/pages/decks-page/decks-page.tsx b/src/pages/decks-page/decks-page.tsx index 0a3f0f4..700fdf9 100644 --- a/src/pages/decks-page/decks-page.tsx +++ b/src/pages/decks-page/decks-page.tsx @@ -5,6 +5,7 @@ import { DeckDialog } from '@/components/decks/deck-dialog' import { DeleteDeckDialog } from '@/components/decks/delete-deck-dialog' import { Pagination } from '@/components/ui/pagination' import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { useDeckSearchParams } from '@/pages/decks-page/use-deck-search-params' import { useMeQuery } from '@/services/auth/auth.service' import { Tab, @@ -13,15 +14,6 @@ import { useGetDecksQuery, useUpdateDeckMutation, } from '@/services/decks' -import { - selectDecksCurrentPage, - selectDecksCurrentTab, - selectDecksMaxCards, - selectDecksMinCards, - selectDecksSearch, -} from '@/services/decks/decks.selectors' -import { decksSlice } from '@/services/decks/decks.slice' -import { useAppDispatch, useAppSelector } from '@/services/store' import s from './decks-page.module.scss' @@ -33,40 +25,41 @@ export const DecksPage = () => { const showEditModal = !!deckToEditId - const dispatch = useAppDispatch() - const currentPage = useAppSelector(selectDecksCurrentPage) - const minCards = useAppSelector(selectDecksMinCards) - const maxCards = useAppSelector(selectDecksMaxCards) - const currentTab = useAppSelector(selectDecksCurrentTab) - const search = useAppSelector(selectDecksSearch) - const setCurrentPage = (page: number) => dispatch(decksSlice.actions.setCurrentPage(page)) - const setMinCards = (minCards: number) => dispatch(decksSlice.actions.setMinCards(minCards)) - const setMaxCards = (maxCards: number) => dispatch(decksSlice.actions.setMaxCards(maxCards)) - const setSearch = (search: string) => dispatch(decksSlice.actions.setSearch(search)) - const setCurrentTab = (tab: { authorId?: string; tab: Tab }) => - dispatch(decksSlice.actions.setCurrentTab(tab)) + const { + currentPage, + currentTab, + maxCardsCount, + minCardsCount, + rangeValue, + search, + setCurrentPage, + setCurrentTab, + setMaxCards, + setMinCards, + setRangeValue, + setSearch, + setSort, + sort, + } = useDeckSearchParams() - const resetFilters = () => { - dispatch(decksSlice.actions.resetFilters()) - setRangeValue([0, decks?.maxCardsCount || undefined]) - } - - const [rangeValue, setRangeValue] = useState([minCards, maxCards]) - - const handleSliderCommitted = (value: number[]) => { - setMinCards(value[0]) - setMaxCards(value[1]) - } const currentUserId = me?.id const authorId = currentTab === 'my' ? currentUserId : undefined const { currentData: decksCurrentData, data: decksData } = useGetDecksQuery({ authorId, currentPage, - maxCardsCount: maxCards, - minCardsCount: minCards, + maxCardsCount, + minCardsCount, name: search, + orderBy: sort ? `${sort.key}-${sort.direction}` : undefined, }) - + const resetFilters = () => { + setCurrentPage(null) + setSearch(null) + setMinCards(null) + setMaxCards(null) + setRangeValue([0, decks?.maxCardsCount ?? null]) + setSort(null) + } const decks = decksCurrentData ?? decksData const showConfirmDeleteModal = !!deckToDeleteId @@ -80,6 +73,16 @@ export const DecksPage = () => { const openCreateModal = () => setShowCreateModal(true) + const handleSearch = (search: null | string) => { + setCurrentPage(null) + setSearch(search) + } + const handleSliderCommitted = (value: number[]) => { + setCurrentPage(null) + setMinCards(value[0]) + setMaxCards(value[1]) + } + if (!decks || !me) { return } @@ -124,10 +127,15 @@ export const DecksPage = () => { />
- + setCurrentTab({ authorId: currentUserId, tab: value as Tab })} - value={currentTab} + onValueChange={value => setCurrentTab(value as Tab)} + value={currentTab ?? undefined} > My decks @@ -150,11 +158,13 @@ export const DecksPage = () => { decks={decks?.items} onDeleteClick={setDeckToDeleteId} onEditClick={setDeckToEditId} + onSort={setSort} + sort={sort} />
diff --git a/src/pages/decks-page/use-deck-search-params.ts b/src/pages/decks-page/use-deck-search-params.ts new file mode 100644 index 0000000..118fca3 --- /dev/null +++ b/src/pages/decks-page/use-deck-search-params.ts @@ -0,0 +1,75 @@ +import { useState } from 'react' +import { useSearchParams } from 'react-router-dom' + +import { Sort } from '@/components' +import { useQueryParam } from '@/hooks' + +export function useDeckSearchParams() { + const [searchParams, setSearchParams] = useSearchParams() + const [currentPage, setCurrentPage] = useQueryParam( + searchParams, + setSearchParams, + 'page', + 1 + ) + const [minCardsCount, setMinCards] = useQueryParam( + searchParams, + setSearchParams, + 'minCards', + 0 + ) + const [maxCardsCount, setMaxCards] = useQueryParam( + searchParams, + setSearchParams, + 'maxCards' + ) + const [search, setSearch] = useQueryParam(searchParams, setSearchParams, 'search') + const [currentTab, setCurrentTab] = useQueryParam( + searchParams, + setSearchParams, + 'currentTab', + 'all' + ) + const [rangeValue, setRangeValue] = useState([minCardsCount, maxCardsCount]) + const [sortKey, setSortKey] = useQueryParam(searchParams, setSearchParams, 'sortKey') + const [sortDirection, setSortDirection] = useQueryParam<'asc' | 'desc'>( + searchParams, + setSearchParams, + 'sortDirection' + ) + const setSort = (sort: Sort) => { + if (!sort) { + setSortKey(null) + setSortDirection(null) + + return + } + setSortKey(sort.key) + setSortDirection(sort.direction) + } + + const sort: Sort = + sortDirection === null || sortKey === null + ? null + : { + direction: sortDirection, + key: sortKey, + } + + return { + currentPage, + currentTab, + maxCardsCount, + minCardsCount, + rangeValue, + search, + setCurrentPage, + setCurrentTab, + setMaxCards, + setMinCards, + setRangeValue, + setSearch, + setSort, + sort, + } +} diff --git a/src/services/decks/decks.service.ts b/src/services/decks/decks.service.ts index 7978d20..43184ec 100644 --- a/src/services/decks/decks.service.ts +++ b/src/services/decks/decks.service.ts @@ -8,6 +8,7 @@ import { baseApi, } from '@/services' import { RootState } from '@/services/store' +import { getValuable } from '@/utils' const decksService = baseApi.injectEndpoints({ endpoints: builder => ({ @@ -16,13 +17,10 @@ const decksService = baseApi.injectEndpoints({ async onQueryStarted(_, { dispatch, getState, queryFulfilled }) { const res = await queryFulfilled - console.log(decksService.util.selectCachedArgsForQuery(getState(), 'getDecks')) for (const { endpointName, originalArgs } of decksService.util.selectInvalidatedBy( getState(), [{ type: 'Decks' }] )) { - console.log(endpointName, originalArgs) - // we only want to update `getPosts` here if (endpointName !== 'getDecks') { continue } @@ -32,31 +30,6 @@ const decksService = baseApi.injectEndpoints({ }) ) } - - // console.log(args) - // const minCardsCount = state.decks.minCards - // const search = state.decks.search - // const currentPage = state.decks.currentPage - // const maxCardsCount = state.decks.maxCards - // const authorId = state.decks.authorId - // - // console.log(res) - // - // dispatch( - // decksService.util.updateQueryData( - // 'getDecks', - // { - // authorId, - // currentPage, - // maxCardsCount, - // minCardsCount, - // name: search, - // }, - // draft => { - // draft.items.unshift(res.data) - // } - // ) - // ) }, query: body => ({ body, @@ -81,7 +54,7 @@ const decksService = baseApi.injectEndpoints({ providesTags: ['Decks'], query: args => { return { - params: args ?? undefined, + params: args ? getValuable(args) : undefined, url: `v1/decks`, } }, @@ -91,7 +64,6 @@ const decksService = baseApi.injectEndpoints({ async onQueryStarted({ id, ...patch }, { dispatch, getState, queryFulfilled }) { const state = getState() as RootState - console.log(state) const minCardsCount = state.decks.minCards const search = state.decks.search const currentPage = state.decks.currentPage diff --git a/src/services/decks/decks.types.ts b/src/services/decks/decks.types.ts index b8c005c..777c54c 100644 --- a/src/services/decks/decks.types.ts +++ b/src/services/decks/decks.types.ts @@ -54,13 +54,13 @@ export type Card = { } export type GetDecksArgs = { - authorId?: string - currentPage?: number - itemsPerPage?: number - maxCardsCount?: number - minCardsCount?: number - name?: string - orderBy?: string + authorId?: null | string + currentPage?: null | number + itemsPerPage?: null | number + maxCardsCount?: null | number + minCardsCount?: null | number + name?: null | string + orderBy?: null | string } export type CreateDeckArgs = { diff --git a/src/services/store.ts b/src/services/store.ts index 29a6c32..7e3e2ef 100644 --- a/src/services/store.ts +++ b/src/services/store.ts @@ -1,10 +1,11 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' -import { baseApi } from './base-api' import { decksSlice } from '@/services/decks/decks.slice' import { configureStore } from '@reduxjs/toolkit' import { setupListeners } from '@reduxjs/toolkit/query/react' +import { baseApi } from './base-api' + export const store = configureStore({ middleware: getDefaultMiddleware => getDefaultMiddleware().concat(baseApi.middleware), reducer: { diff --git a/src/utils/get-valuable.ts b/src/utils/get-valuable.ts new file mode 100644 index 0000000..a41f3dd --- /dev/null +++ b/src/utils/get-valuable.ts @@ -0,0 +1,9 @@ +type Valuable = { [K in keyof T as T[K] extends null | undefined ? never : K]: T[K] } + +export function getValuable>(obj: T): V { + return Object.fromEntries( + Object.entries(obj).filter( + ([, v]) => !((typeof v === 'string' && !v.length) || v === null || typeof v === 'undefined') + ) + ) as V +} diff --git a/src/utils/index.ts b/src/utils/index.ts index edf1e3c..2d200ba 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1 +1,2 @@ export * from './date' +export * from './get-valuable'