From 000cb77acdf1e1025c987f91d6868369eaceed5e Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Tue, 14 Jan 2025 19:10:05 +0300 Subject: [PATCH] use zustand for contacts --- apps/web/actions/contacts.ts | 19 +++++++-- .../hooks/contacts/use-customer-contacts.ts | 40 ++++++++----------- apps/web/package.json | 3 +- apps/web/store/contacts.ts | 21 ++++++++++ apps/web/store/index.ts | 6 +++ pnpm-lock.yaml | 26 ++++++++++++ 6 files changed, 88 insertions(+), 27 deletions(-) create mode 100644 apps/web/store/contacts.ts create mode 100644 apps/web/store/index.ts diff --git a/apps/web/actions/contacts.ts b/apps/web/actions/contacts.ts index 6815c9e..ef6677e 100644 --- a/apps/web/actions/contacts.ts +++ b/apps/web/actions/contacts.ts @@ -3,16 +3,29 @@ import { authOptions } from '@/config/auth'; import { getCustomerClients, getCustomerMasters } from '@repo/graphql/api'; import { getServerSession } from 'next-auth/next'; -export async function getContacts() { +export async function getClients() { + const session = await getServerSession(authOptions); + + if (session) { + const { user } = session; + const getCustomerClientsResponse = await getCustomerClients({ telegramId: user?.telegramId }); + + return { + clients: getCustomerClientsResponse?.clients, + }; + } + + return null; +} + +export async function getMasters() { const session = await getServerSession(authOptions); if (session) { const { user } = session; const getCustomerMastersResponse = await getCustomerMasters({ telegramId: user?.telegramId }); - const getCustomerClientsResponse = await getCustomerClients({ telegramId: user?.telegramId }); return { - clients: getCustomerClientsResponse?.clients, masters: getCustomerMastersResponse?.masters, }; } diff --git a/apps/web/hooks/contacts/use-customer-contacts.ts b/apps/web/hooks/contacts/use-customer-contacts.ts index dadc8f4..af59c1d 100644 --- a/apps/web/hooks/contacts/use-customer-contacts.ts +++ b/apps/web/hooks/contacts/use-customer-contacts.ts @@ -1,43 +1,37 @@ /* eslint-disable promise/prefer-await-to-then */ 'use client'; -import { getContacts } from '@/actions/contacts'; +import { getClients, getMasters } from '@/actions/contacts'; import { ContactsFilterContext } from '@/context/contacts-filter'; -import type * as GQL from '@repo/graphql/types'; +import { useBoundStore } from '@/store'; import { sift } from 'radash'; -import { use, useEffect, useMemo, useState } from 'react'; - -type Clients = NonNullable['clients']; -type Masters = NonNullable['masters']; +import { use, useEffect, useMemo } from 'react'; export function useCustomerContacts() { - const [contacts, setContacts] = useState<{ clients: Clients; masters: Masters }>({ - clients: [], - masters: [], - }); - const { filter } = use(ContactsFilterContext); + const { clients = [], masters = [], setClients, setMasters } = useBoundStore(); useEffect(() => { - getContacts().then((response) => { - setContacts({ - clients: response?.clients || [], - masters: response?.masters || [], + if ((filter === 'masters' || filter === 'all') && !masters) + getMasters().then((response) => { + if (response?.masters) setMasters(response.masters); }); - }); - }, []); + + if ((filter === 'clients' || filter === 'all') && !clients) + getClients().then((response) => { + if (response?.clients) setClients(response.clients); + }); + }, [filter]); const filteredContacts = useMemo(() => { - const { clients, masters } = contacts; - switch (filter) { case 'clients': - return sift(clients); + return clients ? sift(clients) : []; case 'masters': - return sift(masters); + return masters ? sift(masters) : []; default: - return [...sift(clients), ...sift(masters)]; + return [...(clients ? sift(clients) : []), ...(masters ? sift(masters) : [])]; } - }, [contacts, filter]); + }, [clients, masters, filter]); return { contacts: filteredContacts }; } diff --git a/apps/web/package.json b/apps/web/package.json index aa7ffae..07f4f7b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -26,7 +26,8 @@ "react": "catalog:", "react-dom": "catalog:", "use-debounce": "^10.0.4", - "zod": "catalog:" + "zod": "catalog:", + "zustand": "^5.0.3" }, "devDependencies": { "@playwright/test": "^1.49.1", diff --git a/apps/web/store/contacts.ts b/apps/web/store/contacts.ts new file mode 100644 index 0000000..a1e80a9 --- /dev/null +++ b/apps/web/store/contacts.ts @@ -0,0 +1,21 @@ +import type * as GQL from '@repo/graphql/types'; +import { type StateCreator } from 'zustand'; + +export type ContactsStore = { + clients: Clients | null; + masters: Masters | null; + setClients: (clients: Clients) => void; + setMasters: (masters: Masters) => void; +}; + +type Clients = NonNullable['clients']; +type Masters = NonNullable['masters']; + +export const createContactsSlice: StateCreator = (set) => { + return { + clients: null, + masters: null, + setClients: (clients) => set({ clients }), + setMasters: (masters) => set({ masters }), + }; +}; diff --git a/apps/web/store/index.ts b/apps/web/store/index.ts new file mode 100644 index 0000000..972153a --- /dev/null +++ b/apps/web/store/index.ts @@ -0,0 +1,6 @@ +import { type ContactsStore, createContactsSlice } from './contacts'; +import { create } from 'zustand'; + +type Store = ContactsStore; + +export const useBoundStore = create()((...a) => ({ ...createContactsSlice(...a) })); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b94b1d..1e2ef75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,6 +177,9 @@ importers: zod: specifier: 'catalog:' version: 3.24.1 + zustand: + specifier: ^5.0.3 + version: 5.0.3(@types/react@19.0.1)(react@19.0.0) devDependencies: '@playwright/test': specifier: ^1.49.1 @@ -6305,6 +6308,24 @@ packages: zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -13059,3 +13080,8 @@ snapshots: zen-observable@0.8.15: {} zod@3.24.1: {} + + zustand@5.0.3(@types/react@19.0.1)(react@19.0.0): + optionalDependencies: + '@types/react': 19.0.1 + react: 19.0.0