feat: client tab in deal editor
This commit is contained in:
@ -16,7 +16,11 @@ type UseClientsProps = {
|
||||
|
||||
export type ClientsCrud = {
|
||||
onCreate: (client: CreateClientSchema) => void;
|
||||
onUpdate: (clientId: number, client: UpdateClientSchema) => void;
|
||||
onUpdate: (
|
||||
clientId: number,
|
||||
client: UpdateClientSchema,
|
||||
onSuccess?: () => void
|
||||
) => void;
|
||||
onDelete: (client: ClientSchema) => void;
|
||||
};
|
||||
|
||||
|
||||
@ -5,8 +5,16 @@ import {
|
||||
getClientsQueryKey,
|
||||
} from "@/lib/client/@tanstack/react-query.gen";
|
||||
|
||||
const useClientsList = () => {
|
||||
const { data, refetch } = useQuery(getClientsOptions());
|
||||
type Props = {
|
||||
includeDeleted?: boolean;
|
||||
};
|
||||
|
||||
const useClientsList = (
|
||||
{ includeDeleted = false }: Props = { includeDeleted: false }
|
||||
) => {
|
||||
const { data, refetch } = useQuery(
|
||||
getClientsOptions({ query: { includeDeleted } })
|
||||
);
|
||||
const clients = useMemo(() => data?.items ?? [], [data]);
|
||||
|
||||
const queryKey = getClientsQueryKey();
|
||||
|
||||
@ -2,9 +2,15 @@ import { FC } from "react";
|
||||
import { IconCheck, IconX } from "@tabler/icons-react";
|
||||
import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||
import { ClientSchema } from "@/lib/client";
|
||||
import ClientSelect from "@/modules/dealModularEditorTabs/Clients/shared/components/ClientSelect";
|
||||
import { ModuleNames } from "@/modules/modules";
|
||||
|
||||
export type CreateDealForm = {
|
||||
name: string;
|
||||
client?: ClientSchema;
|
||||
clientId?: number;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@ -13,25 +19,42 @@ type Props = {
|
||||
};
|
||||
|
||||
const CreateCardForm: FC<Props> = ({ onSubmit, onCancel }) => {
|
||||
const { modulesSet } = useProjectsContext();
|
||||
|
||||
const form = useForm<CreateDealForm>({
|
||||
initialValues: {
|
||||
name: "",
|
||||
},
|
||||
validate: {
|
||||
name: value => !value && "Введите название",
|
||||
client: client =>
|
||||
modulesSet.has(ModuleNames.CLIENTS) &&
|
||||
!client &&
|
||||
"Выберите клиента",
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(values => {
|
||||
onSubmit(values);
|
||||
form.reset();
|
||||
})}>
|
||||
<form
|
||||
onSubmit={form.onSubmit(values => {
|
||||
onSubmit(values);
|
||||
form.reset();
|
||||
})}>
|
||||
<Stack>
|
||||
<TextInput
|
||||
placeholder={"Название"}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
{modulesSet.has(ModuleNames.CLIENTS) && (
|
||||
<ClientSelect
|
||||
placeholder={"Клиент"}
|
||||
{...form.getInputProps("client")}
|
||||
onChange={client => {
|
||||
form.setFieldValue("client", client);
|
||||
form.setFieldValue("clientId", client?.id);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Group wrap={"nowrap"}>
|
||||
<Button
|
||||
variant={"default"}
|
||||
|
||||
@ -3,6 +3,7 @@ import { useDealsContext } from "@/app/deals/contexts/DealsContext";
|
||||
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||
import { useDrawersContext } from "@/drawers/DrawersContext";
|
||||
import { DealSchema } from "@/lib/client";
|
||||
import { ModuleNames } from "@/modules/modules";
|
||||
import styles from "./DealCard.module.css";
|
||||
|
||||
type Props = {
|
||||
@ -10,7 +11,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const DealCard = ({ deal }: Props) => {
|
||||
const { selectedProject } = useProjectsContext();
|
||||
const { selectedProject, modulesSet } = useProjectsContext();
|
||||
const { dealsCrud } = useDealsContext();
|
||||
const { openDrawer } = useDrawersContext();
|
||||
|
||||
@ -47,6 +48,9 @@ const DealCard = ({ deal }: Props) => {
|
||||
</Group>
|
||||
<Stack className={styles["deal-data"]}>
|
||||
<Stack gap={0}>
|
||||
{modulesSet.has(ModuleNames.CLIENTS) && (
|
||||
<Text>{deal.client?.name}</Text>
|
||||
)}
|
||||
<Text>Wb электросталь</Text>
|
||||
<Text>19 000 руб.</Text>
|
||||
<Text>130 тов.</Text>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { ProjectsCrud, useProjectsCrud } from "@/hooks/cruds/useProjectsCrud";
|
||||
import useProjectsList from "@/hooks/lists/useProjectsList";
|
||||
import { ProjectSchema } from "@/lib/client";
|
||||
@ -12,6 +12,7 @@ type ProjectsContextState = {
|
||||
refetchProjects: () => void;
|
||||
projects: ProjectSchema[];
|
||||
projectsCrud: ProjectsCrud;
|
||||
modulesSet: Set<string>;
|
||||
};
|
||||
|
||||
const useProjectsContextState = (): ProjectsContextState => {
|
||||
@ -20,8 +21,16 @@ const useProjectsContextState = (): ProjectsContextState => {
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<number | null>(
|
||||
null
|
||||
);
|
||||
const selectedProject =
|
||||
projects.find(project => project.id === selectedProjectId) ?? null;
|
||||
const selectedProject = useMemo(
|
||||
() =>
|
||||
projects.find(project => project.id === selectedProjectId) ?? null,
|
||||
[projects, selectedProjectId]
|
||||
);
|
||||
|
||||
const modulesSet = useMemo(
|
||||
() => new Set(selectedProject?.builtInModules.map(m => m.key)),
|
||||
[selectedProject]
|
||||
);
|
||||
|
||||
if (selectedProject === null && projects.length > 0) {
|
||||
setSelectedProjectId(projects[0].id);
|
||||
@ -35,6 +44,7 @@ const useProjectsContextState = (): ProjectsContextState => {
|
||||
refetchProjects,
|
||||
setSelectedProjectId,
|
||||
projectsCrud,
|
||||
modulesSet,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import React, { FC } from "react";
|
||||
import { Flex, Stack, TextInput } from "@mantine/core";
|
||||
import { Stack, TextInput } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import Footer from "@/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/components/Footer";
|
||||
import BoardSelect from "@/components/selects/BoardSelect/BoardSelect";
|
||||
import StatusSelect from "@/components/selects/StatusSelect/StatusSelect";
|
||||
import FormFlexRow from "@/components/ui/FormFlexRow/FormFlexRow";
|
||||
import { BoardSchema, DealSchema, StatusSchema } from "@/lib/client";
|
||||
import { utcDateTimeToLocalString } from "@/utils/datetime";
|
||||
|
||||
@ -40,10 +41,7 @@ const GeneralTab: FC<Props> = ({ value, onDelete, onChange }) => {
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<Stack p={"md"}>
|
||||
<Flex
|
||||
gap={"md"}
|
||||
w={"100%"}
|
||||
direction={{ base: "column", sm: "row" }}>
|
||||
<FormFlexRow>
|
||||
<TextInput
|
||||
label={"Название"}
|
||||
{...form.getInputProps("name")}
|
||||
@ -55,11 +53,8 @@ const GeneralTab: FC<Props> = ({ value, onDelete, onChange }) => {
|
||||
readOnly
|
||||
flex={1}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
gap={"md"}
|
||||
w={"100%"}
|
||||
direction={{ base: "column", sm: "row" }}>
|
||||
</FormFlexRow>
|
||||
<FormFlexRow>
|
||||
<BoardSelect
|
||||
label={"Доска"}
|
||||
{...form.getInputProps("board")}
|
||||
@ -76,7 +71,7 @@ const GeneralTab: FC<Props> = ({ value, onDelete, onChange }) => {
|
||||
boardId={form.values.board?.id}
|
||||
flex={1}
|
||||
/>
|
||||
</Flex>
|
||||
</FormFlexRow>
|
||||
<Footer
|
||||
form={form}
|
||||
onDelete={() => onDelete(value)}
|
||||
|
||||
Reference in New Issue
Block a user