From b0eab6cce72094db0dead19beecc4ee9e42edcea Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Fri, 7 Nov 2025 10:13:32 +0400 Subject: [PATCH] feat: create first project modal --- .../components/shared/PageBody/PageBody.tsx | 2 + src/app/deals/contexts/ProjectsContext.tsx | 16 +++-- src/app/deals/hooks/useCreateFirstProject.tsx | 36 ++++++++++ .../CreateFirstProjectModal.tsx | 72 +++++++++++++++++++ src/components/ui/Logo/Logo.tsx | 58 ++++++++------- src/hooks/cruds/useProjectsCrud.tsx | 5 +- src/hooks/lists/useProjectsList.ts | 5 +- src/modals/modals.ts | 2 + 8 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 src/app/deals/hooks/useCreateFirstProject.tsx create mode 100644 src/app/deals/modals/CreateFirstProjectModal/CreateFirstProjectModal.tsx diff --git a/src/app/deals/components/shared/PageBody/PageBody.tsx b/src/app/deals/components/shared/PageBody/PageBody.tsx index 4ebbe9c..7ddee98 100644 --- a/src/app/deals/components/shared/PageBody/PageBody.tsx +++ b/src/app/deals/components/shared/PageBody/PageBody.tsx @@ -10,10 +10,12 @@ import { import { useBoardsContext } from "@/app/deals/contexts/BoardsContext"; import { DealsContextProvider } from "@/app/deals/contexts/DealsContext"; import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; +import useCreateFirstProject from "@/app/deals/hooks/useCreateFirstProject"; import useView from "@/app/deals/hooks/useView"; import PageBlock from "@/components/layout/PageBlock/PageBlock"; const PageBody = () => { + useCreateFirstProject(); const { selectedBoard } = useBoardsContext(); const { selectedProject } = useProjectsContext(); diff --git a/src/app/deals/contexts/ProjectsContext.tsx b/src/app/deals/contexts/ProjectsContext.tsx index 19c527d..9cbcd85 100644 --- a/src/app/deals/contexts/ProjectsContext.tsx +++ b/src/app/deals/contexts/ProjectsContext.tsx @@ -10,16 +10,22 @@ import makeContext from "@/lib/contextFactory/contextFactory"; import { ModuleNames } from "@/modules/modules"; type ProjectsContextState = { + projects: ProjectSchema[]; + isLoading: boolean; selectedProject: ProjectSchema | null; setSelectedProjectId: (id: number | null) => void; refetchProjects: () => void; - projects: ProjectSchema[]; projectsCrud: ProjectsCrud; modulesSet: Set; }; const useProjectsContextState = (): ProjectsContextState => { - const { projects, refetch: refetchProjects, queryKey } = useProjectsList(); + const { + projects, + refetch: refetchProjects, + queryKey, + isLoading, + } = useProjectsList(); const isMobile = useIsMobile(); const pathname = usePathname(); const router = useRouter(); @@ -34,10 +40,7 @@ const useProjectsContextState = (): ProjectsContextState => { ); const modulesSet = useMemo( - () => - new Set( - selectedProject?.modules.map(m => m.key as ModuleNames) - ), + () => new Set(selectedProject?.modules.map(m => m.key as ModuleNames)), [selectedProject] ); @@ -54,6 +57,7 @@ const useProjectsContextState = (): ProjectsContextState => { return { projects, + isLoading, selectedProject, refetchProjects, setSelectedProjectId: handleSetSelectedProjectId, diff --git a/src/app/deals/hooks/useCreateFirstProject.tsx b/src/app/deals/hooks/useCreateFirstProject.tsx new file mode 100644 index 0000000..09ff7ca --- /dev/null +++ b/src/app/deals/hooks/useCreateFirstProject.tsx @@ -0,0 +1,36 @@ +import { useEffect, useMemo, useRef } from "react"; +import { modals } from "@mantine/modals"; +import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; + +const useCreateFirstProject = () => { + const hasOpened = useRef(false); + const { projects, projectsCrud, isLoading } = useProjectsContext(); + const shouldOpen = useMemo( + () => !isLoading && projects.length === 0, + [isLoading, projects] + ); + + useEffect(() => { + if (!shouldOpen || hasOpened.current) return; + + hasOpened.current = true; + + modals.openContextModal({ + modal: "createFirstProjectModal", + withCloseButton: false, + closeOnClickOutside: false, + closeOnEscape: false, + overlayProps: { + color: "black", + blur: 6, + backgroundOpacity: 0.45, + }, + innerProps: { + onSubmit: values => + projectsCrud.onCreate(values, modals.closeAll), + }, + }); + }, [shouldOpen]); +}; + +export default useCreateFirstProject; diff --git a/src/app/deals/modals/CreateFirstProjectModal/CreateFirstProjectModal.tsx b/src/app/deals/modals/CreateFirstProjectModal/CreateFirstProjectModal.tsx new file mode 100644 index 0000000..bcf64c3 --- /dev/null +++ b/src/app/deals/modals/CreateFirstProjectModal/CreateFirstProjectModal.tsx @@ -0,0 +1,72 @@ +"use client"; + +import { + Button, + Center, + Divider, + Flex, + Space, + Text, + TextInput, + Title, +} from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { ContextModalProps } from "@mantine/modals"; +import Logo from "@/components/ui/Logo/Logo"; +import { CreateProjectSchema } from "@/lib/client"; + +type Props = { + onSubmit: (values: CreateProjectSchema, onSuccess?: () => void) => void; +}; + +const CreateFirstProjectModal = ({ + id, + context, + innerProps, +}: ContextModalProps) => { + const form = useForm({ + initialValues: { + name: "", + }, + validate: { + name: name => + (!name || name.trim().length === 0) && "Введите название", + }, + }); + + const onClose = () => context.closeModal(id); + + return ( +
+ innerProps.onSubmit(values, onClose) + )}> + + + + +
+ Создайте свой первый проект +
+ + + + + + +
+
+ ); +}; + +export default CreateFirstProjectModal; diff --git a/src/components/ui/Logo/Logo.tsx b/src/components/ui/Logo/Logo.tsx index a3800a5..a624a0c 100644 --- a/src/components/ui/Logo/Logo.tsx +++ b/src/components/ui/Logo/Logo.tsx @@ -5,35 +5,33 @@ type Props = { title?: string; }; -const Logo = ({ title }: Props) => { - return ( - - LogiDex Logo - - LogiDex - - {title && ( -
- - {title} - -
- )} -
- ); -}; +const Logo = ({ title }: Props) => ( + + LogiDex Logo + + LogiDex + + {title && ( +
+ + {title} + +
+ )} +
+); export default Logo; diff --git a/src/hooks/cruds/useProjectsCrud.tsx b/src/hooks/cruds/useProjectsCrud.tsx index f3629b2..3f007cc 100644 --- a/src/hooks/cruds/useProjectsCrud.tsx +++ b/src/hooks/cruds/useProjectsCrud.tsx @@ -15,7 +15,10 @@ type Props = { }; export type ProjectsCrud = { - onCreate: (data: Partial) => void; + onCreate: ( + data: Partial, + onSuccess?: () => void + ) => void; onUpdate: (projectId: number, project: UpdateProjectSchema) => void; onDelete: (project: ProjectSchema, onSuccess?: () => void) => void; }; diff --git a/src/hooks/lists/useProjectsList.ts b/src/hooks/lists/useProjectsList.ts index 2d4a62d..c9b308d 100644 --- a/src/hooks/lists/useProjectsList.ts +++ b/src/hooks/lists/useProjectsList.ts @@ -7,9 +7,7 @@ import { const useProjectsList = () => { const queryClient = useQueryClient(); - const { data, refetch } = useQuery({ - ...getProjectsOptions(), - }); + const { data, refetch, isLoading } = useQuery(getProjectsOptions()); const queryKey = getProjectsQueryKey(); @@ -28,6 +26,7 @@ const useProjectsList = () => { setProjects, refetch, queryKey, + isLoading, }; }; diff --git a/src/modals/modals.ts b/src/modals/modals.ts index 29852f1..4ad4997 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -2,6 +2,7 @@ import BarcodeTemplateEditorModal from "@/app/barcode-templates/modals/BarcodeTe import MarketplaceEditorModal from "@/app/clients/drawers/ClientMarketplacesDrawer/modals/MarketplaceEditorModal"; import ClientEditorModal from "@/app/clients/modals/ClientFormModal/ClientFormModal"; import ColorPickerModal from "@/app/deals/modals/ColorPickerModal/ColorPickerModal"; +import CreateFirstProjectModal from "@/app/deals/modals/CreateFirstProjectModal/CreateFirstProjectModal"; import DealsBoardFiltersModal from "@/app/deals/modals/DealsBoardFiltersModal/DealsBoardFiltersModal"; import DealsScheduleFiltersModal from "@/app/deals/modals/DealsScheduleFiltersModal/DealsScheduleFiltersModal"; import DealsTableFiltersModal from "@/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal"; @@ -48,4 +49,5 @@ export const modals = { attributeEditorModal: AttributeEditorModal, moduleCreatorModal: ModuleCreatorModal, addAttributeModal: AddAttributeModal, + createFirstProjectModal: CreateFirstProjectModal, };