feat: create first project modal

This commit is contained in:
2025-11-07 10:13:32 +04:00
parent 1a1f584b81
commit b0eab6cce7
8 changed files with 156 additions and 40 deletions

View File

@ -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();

View File

@ -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<ModuleNames>;
};
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,

View File

@ -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;

View File

@ -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<Props>) => {
const form = useForm<CreateProjectSchema>({
initialValues: {
name: "",
},
validate: {
name: name =>
(!name || name.trim().length === 0) && "Введите название",
},
});
const onClose = () => context.closeModal(id);
return (
<form
onSubmit={form.onSubmit(values =>
innerProps.onSubmit(values, onClose)
)}>
<Flex
gap={"xs"}
direction={"column"}>
<Logo title={"Fulfillment & Delivery"} />
<Divider />
<Space />
<Center>
<Title order={4}>Создайте свой первый проект</Title>
</Center>
<Space />
<Divider />
<Space />
<TextInput
label={"Название"}
placeholder={"Введите название"}
{...form.getInputProps("name")}
/>
<Space />
<Button
variant={"filled"}
type={"submit"}>
<Text>Сохранить</Text>
</Button>
</Flex>
</form>
);
};
export default CreateFirstProjectModal;

View File

@ -5,35 +5,33 @@ type Props = {
title?: string;
};
const Logo = ({ title }: Props) => {
return (
<Stack
align="center"
gap={0}>
<Image
src="/favicon.svg"
alt="LogiDex Logo"
w={70}
h={80}
/>
<Title
ta={"center"}
order={4}
my={"xs"}>
LogiDex
</Title>
{title && (
<Center>
<Text
fz={"xs"}
mb={"lg"}
style={{ color: myColor[6], textAlign: "center" }}>
{title}
</Text>
</Center>
)}
</Stack>
);
};
const Logo = ({ title }: Props) => (
<Stack
align="center"
gap={0}>
<Image
src="/favicon.svg"
alt="LogiDex Logo"
w={70}
h={80}
/>
<Title
ta={"center"}
order={4}
my={"xs"}>
LogiDex
</Title>
{title && (
<Center>
<Text
fz={"xs"}
mb={"lg"}
style={{ color: myColor[6], textAlign: "center" }}>
{title}
</Text>
</Center>
)}
</Stack>
);
export default Logo;

View File

@ -15,7 +15,10 @@ type Props = {
};
export type ProjectsCrud = {
onCreate: (data: Partial<CreateProjectSchema>) => void;
onCreate: (
data: Partial<CreateProjectSchema>,
onSuccess?: () => void
) => void;
onUpdate: (projectId: number, project: UpdateProjectSchema) => void;
onDelete: (project: ProjectSchema, onSuccess?: () => void) => void;
};

View File

@ -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,
};
};

View File

@ -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,
};