crap
This commit is contained in:
		@@ -9,10 +9,16 @@ export type { OpenAPIConfig } from './core/OpenAPI';
 | 
			
		||||
 | 
			
		||||
export type { AuthLoginRequest } from './models/AuthLoginRequest';
 | 
			
		||||
export type { AuthLoginResponse } from './models/AuthLoginResponse';
 | 
			
		||||
export type { ClientCreateRequest } from './models/ClientCreateRequest';
 | 
			
		||||
export type { ClientCreateResponse } from './models/ClientCreateResponse';
 | 
			
		||||
export type { ClientDeleteRequest } from './models/ClientDeleteRequest';
 | 
			
		||||
export type { ClientDeleteResponse } from './models/ClientDeleteResponse';
 | 
			
		||||
export type { ClientDetailsSchema } from './models/ClientDetailsSchema';
 | 
			
		||||
export type { ClientGetAllResponse } from './models/ClientGetAllResponse';
 | 
			
		||||
export type { ClientSchema } from './models/ClientSchema';
 | 
			
		||||
export type { ClientUpdateDetailsRequest } from './models/ClientUpdateDetailsRequest';
 | 
			
		||||
export type { ClientUpdateRequest } from './models/ClientUpdateRequest';
 | 
			
		||||
export type { ClientUpdateResponse } from './models/ClientUpdateResponse';
 | 
			
		||||
export type { DealAddServicesRequest } from './models/DealAddServicesRequest';
 | 
			
		||||
export type { DealAddServicesResponse } from './models/DealAddServicesResponse';
 | 
			
		||||
export type { DealChangeStatusRequest } from './models/DealChangeStatusRequest';
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ClientCreateRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ClientCreateRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ClientSchema } from './ClientSchema';
 | 
			
		||||
export type ClientCreateRequest = {
 | 
			
		||||
    data: ClientSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ClientCreateResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ClientCreateResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ClientCreateResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								src/client/models/ClientDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/ClientDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ClientDeleteRequest = {
 | 
			
		||||
    clientId: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ClientDeleteResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ClientDeleteResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ClientDeleteResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ClientUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ClientUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ClientSchema } from './ClientSchema';
 | 
			
		||||
export type ClientUpdateRequest = {
 | 
			
		||||
    data: ClientSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ClientUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ClientUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ClientUpdateResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -2,8 +2,14 @@
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ClientCreateRequest } from '../models/ClientCreateRequest';
 | 
			
		||||
import type { ClientCreateResponse } from '../models/ClientCreateResponse';
 | 
			
		||||
import type { ClientDeleteRequest } from '../models/ClientDeleteRequest';
 | 
			
		||||
import type { ClientDeleteResponse } from '../models/ClientDeleteResponse';
 | 
			
		||||
import type { ClientGetAllResponse } from '../models/ClientGetAllResponse';
 | 
			
		||||
import type { ClientUpdateDetailsRequest } from '../models/ClientUpdateDetailsRequest';
 | 
			
		||||
import type { ClientUpdateRequest } from '../models/ClientUpdateRequest';
 | 
			
		||||
import type { ClientUpdateResponse } from '../models/ClientUpdateResponse';
 | 
			
		||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
			
		||||
import { OpenAPI } from '../core/OpenAPI';
 | 
			
		||||
import { request as __request } from '../core/request';
 | 
			
		||||
@@ -60,4 +66,64 @@ export class ClientService {
 | 
			
		||||
            url: '/client/get-all',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Create Client
 | 
			
		||||
     * @returns ClientCreateResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static createClient({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ClientCreateRequest,
 | 
			
		||||
    }): CancelablePromise<ClientCreateResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/client/create',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Update Client
 | 
			
		||||
     * @returns ClientUpdateResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static updateClient({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ClientUpdateRequest,
 | 
			
		||||
    }): CancelablePromise<ClientUpdateResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/client/update',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete Client
 | 
			
		||||
     * @returns ClientDeleteResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static deleteClient({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ClientDeleteRequest,
 | 
			
		||||
    }): CancelablePromise<ClientDeleteResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/client/delete',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,21 @@
 | 
			
		||||
.navbar {
 | 
			
		||||
    width: rem(80px);
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding: var(--mantine-spacing-md);
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    border-right: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbarMain {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    margin-top: rem(50px);
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.link {
 | 
			
		||||
    width: rem(50px);
 | 
			
		||||
    //width: rem(50px);
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: rem(50px);
 | 
			
		||||
    border-radius: var(--mantine-radius-md);
 | 
			
		||||
    display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ export function Navbar() {
 | 
			
		||||
                </Stack>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <Stack justify="center" gap={0}>
 | 
			
		||||
            <Stack w={"100%"} justify="center" gap={0}>
 | 
			
		||||
                <NavbarLink label={"Сменить тему"} onClick={toggleColorScheme}
 | 
			
		||||
                            icon={colorScheme == "dark" ? IconSun : IconMoon} href={"#"} index={-1}/>
 | 
			
		||||
                <NavbarLink index={-1} href={"#"} onClick={onLogoutClick} icon={IconLogout} label="Выйти"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,12 @@ import EnterDeadlineModal from "./EnterDeadlineModal/EnterDeadlineModal.tsx";
 | 
			
		||||
import CreateServiceCategoryModal from "../pages/ServicesPage/modals/CreateServiceCategoryModal.tsx";
 | 
			
		||||
import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.tsx";
 | 
			
		||||
import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx";
 | 
			
		||||
import ProductFormModal from "../pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx";
 | 
			
		||||
 | 
			
		||||
export const modals = {
 | 
			
		||||
    enterDeadline: EnterDeadlineModal,
 | 
			
		||||
    createServiceCategory: CreateServiceCategoryModal,
 | 
			
		||||
    createService: CreateServiceModal,
 | 
			
		||||
    createProduct: createProductModal
 | 
			
		||||
    createProduct: createProductModal,
 | 
			
		||||
    productFormModal: ProductFormModal,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,12 @@
 | 
			
		||||
.container {
 | 
			
		||||
    /*background: rebeccapurple;*/
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    gap: rem(10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.top-panel {
 | 
			
		||||
    padding: rem(5);
 | 
			
		||||
    gap: rem(10);
 | 
			
		||||
    display: flex;
 | 
			
		||||
}
 | 
			
		||||
@@ -2,17 +2,82 @@ import {FC} from "react";
 | 
			
		||||
import ClientsTable from "./components/ClientsTable/ClientsTable.tsx";
 | 
			
		||||
import useClientsList from "./hooks/useClientsList.tsx";
 | 
			
		||||
import PageBlock from "../../components/PageBlock/PageBlock.tsx";
 | 
			
		||||
import styles from './ClientsPage.module.css';
 | 
			
		||||
import {Button} from "@mantine/core";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
import {ClientSchema, ClientService} from "../../client";
 | 
			
		||||
import {notifications} from "../../shared/lib/notifications.ts";
 | 
			
		||||
 | 
			
		||||
const ClientsPage: FC = () => {
 | 
			
		||||
    const {clients} = useClientsList();
 | 
			
		||||
    const {clients, refetch} = useClientsList();
 | 
			
		||||
    const onCreate = (client: ClientSchema) => {
 | 
			
		||||
        ClientService
 | 
			
		||||
            .createClient({
 | 
			
		||||
                requestBody: {
 | 
			
		||||
                    data: client
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message});
 | 
			
		||||
                if (ok)
 | 
			
		||||
                    await refetch()
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
    const onChange = (client: ClientSchema) => {
 | 
			
		||||
        ClientService
 | 
			
		||||
            .updateClient({
 | 
			
		||||
                requestBody: {
 | 
			
		||||
                    data: client
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message});
 | 
			
		||||
                if (ok)
 | 
			
		||||
                    await refetch()
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
    const onDelete = (client: ClientSchema) => {
 | 
			
		||||
        ClientService
 | 
			
		||||
            .deleteClient({
 | 
			
		||||
                requestBody: {
 | 
			
		||||
                    clientId: client.id
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message});
 | 
			
		||||
                if (ok)
 | 
			
		||||
                    await refetch()
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
    const onCreateClick = () => {
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: 'productFormModal',
 | 
			
		||||
            title: "Создание клиента",
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                onCreate
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
        <div className={styles['container']}>
 | 
			
		||||
            <PageBlock>
 | 
			
		||||
 | 
			
		||||
                <ClientsTable data={clients}/>
 | 
			
		||||
                <div className={styles['top-panel']}>
 | 
			
		||||
                    <Button
 | 
			
		||||
                        onClick={onCreateClick}
 | 
			
		||||
                        variant={"default"}
 | 
			
		||||
                    >
 | 
			
		||||
                        Создать клиента
 | 
			
		||||
                    </Button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </PageBlock>
 | 
			
		||||
 | 
			
		||||
        </>
 | 
			
		||||
            <PageBlock>
 | 
			
		||||
                <ClientsTable
 | 
			
		||||
                    onChange={onChange}
 | 
			
		||||
                    onDelete={onDelete}
 | 
			
		||||
                    items={clients}
 | 
			
		||||
                />
 | 
			
		||||
            </PageBlock>
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
export default ClientsPage;
 | 
			
		||||
@@ -3,25 +3,57 @@ import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import {useClientsTableColumns} from "./columns.tsx";
 | 
			
		||||
import {MRT_TableOptions} from "mantine-react-table";
 | 
			
		||||
import {ClientSchema} from "../../../../client";
 | 
			
		||||
import {ActionIcon, Flex, Tooltip} from "@mantine/core";
 | 
			
		||||
import {IconEdit, IconTrash} from "@tabler/icons-react";
 | 
			
		||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    data: ClientSchema[];
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
const ClientsTable: FC<Props> = ({data}) => {
 | 
			
		||||
const ClientsTable: FC<CRUDTableProps<ClientSchema>> = ({
 | 
			
		||||
                                                            items,
 | 
			
		||||
                                                            onDelete,
 | 
			
		||||
                                                            onChange
 | 
			
		||||
                                                        }) => {
 | 
			
		||||
    const columns = useClientsTableColumns();
 | 
			
		||||
    const onEditClick = (client: ClientSchema) => {
 | 
			
		||||
        if (!onChange) return;
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: "productFormModal",
 | 
			
		||||
            title: 'Создание клиента',
 | 
			
		||||
            withCloseButton: false,
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                onChange: (newClient) => onChange(newClient),
 | 
			
		||||
                element: client,
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <BaseTable
 | 
			
		||||
                striped
 | 
			
		||||
                data={data}
 | 
			
		||||
                data={items}
 | 
			
		||||
                columns={columns}
 | 
			
		||||
                restProps={{
 | 
			
		||||
                    enableSorting: false,
 | 
			
		||||
                    enableColumnActions: false,
 | 
			
		||||
                    enableRowSelection: true,
 | 
			
		||||
                    enableColumnResizing: true,
 | 
			
		||||
                    layoutMode: "grid"
 | 
			
		||||
                    enableRowActions: true,
 | 
			
		||||
                    renderRowActions: ({row}) => (
 | 
			
		||||
                        <Flex gap="md">
 | 
			
		||||
                            <Tooltip label="Редактировать">
 | 
			
		||||
                                <ActionIcon
 | 
			
		||||
                                    onClick={() => onEditClick(row.original)}
 | 
			
		||||
                                    variant={"default"}>
 | 
			
		||||
                                    <IconEdit/>
 | 
			
		||||
                                </ActionIcon>
 | 
			
		||||
                            </Tooltip>
 | 
			
		||||
                            <Tooltip label="Удалить">
 | 
			
		||||
                                <ActionIcon onClick={() => {
 | 
			
		||||
                                    if (onDelete) onDelete(row.original);
 | 
			
		||||
                                }} variant={"default"}>
 | 
			
		||||
                                    <IconTrash/>
 | 
			
		||||
                                </ActionIcon>
 | 
			
		||||
                            </Tooltip>
 | 
			
		||||
                        </Flex>
 | 
			
		||||
                    )
 | 
			
		||||
                } as MRT_TableOptions<ClientSchema>}
 | 
			
		||||
            />
 | 
			
		||||
        </>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								src/pages/ClientsPage/modals/BaseFormModal/BaseFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/pages/ClientsPage/modals/BaseFormModal/BaseFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
import {UseFormReturnType} from "@mantine/form";
 | 
			
		||||
import {Button, Flex, rem} from "@mantine/core";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
 | 
			
		||||
type CreateProps<T> = {
 | 
			
		||||
    onCreate(values: T): void;
 | 
			
		||||
}
 | 
			
		||||
type EditProps<T> = {
 | 
			
		||||
    onChange(values: T): void;
 | 
			
		||||
    element: T;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type CreateEditFormProps<T> = CreateProps<T> | EditProps<T>;
 | 
			
		||||
 | 
			
		||||
type BaseProps<T> = {
 | 
			
		||||
    form: UseFormReturnType<T>
 | 
			
		||||
    onClose: () => void;
 | 
			
		||||
    closeOnSubmit?: boolean;
 | 
			
		||||
    children: React.JSX.Element;
 | 
			
		||||
}
 | 
			
		||||
type Props<T> = BaseProps<T> & (CreateProps<T> | EditProps<T>);
 | 
			
		||||
 | 
			
		||||
const BaseFormModal = <T, >(props: Props<T>) => {
 | 
			
		||||
    const {closeOnSubmit = false} = props;
 | 
			
		||||
    const isEditing = 'onChange' in props;
 | 
			
		||||
 | 
			
		||||
    const onSubmit = (values: T) => {
 | 
			
		||||
        if (isEditing) {
 | 
			
		||||
            props.onChange(values);
 | 
			
		||||
        } else {
 | 
			
		||||
            props.onCreate(values);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (closeOnSubmit) props.onClose();
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <form onSubmit={props.form.onSubmit((values) => onSubmit(values))}>
 | 
			
		||||
            <Flex gap={rem(10)} direction={"column"}>
 | 
			
		||||
                {props.children}
 | 
			
		||||
                <Flex justify={"flex-end"} gap={rem(10)}>
 | 
			
		||||
                    <Button
 | 
			
		||||
                        variant={"subtle"}
 | 
			
		||||
                        onClick={() => props.onClose()}
 | 
			
		||||
                    >
 | 
			
		||||
                        Отменить
 | 
			
		||||
                    </Button>
 | 
			
		||||
                    <Button
 | 
			
		||||
                        type={"submit"}
 | 
			
		||||
                        variant={"default"}
 | 
			
		||||
                    >
 | 
			
		||||
                        Сохранить
 | 
			
		||||
                    </Button>
 | 
			
		||||
                </Flex>
 | 
			
		||||
            </Flex>
 | 
			
		||||
        </form>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
type BodyProps = {
 | 
			
		||||
    children: React.JSX.Element;
 | 
			
		||||
}
 | 
			
		||||
const Body: FC<BodyProps> = ({children}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Flex gap={rem(10)} direction={"column"}>
 | 
			
		||||
            {children}
 | 
			
		||||
        </Flex>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
BaseFormModal.Body = Body;
 | 
			
		||||
export default BaseFormModal;
 | 
			
		||||
							
								
								
									
										105
									
								
								src/pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
import {ContextModalProps} from "@mantine/modals";
 | 
			
		||||
import {Fieldset, NumberInput, TextInput} from "@mantine/core";
 | 
			
		||||
import {useForm} from "@mantine/form";
 | 
			
		||||
import {ClientSchema} from "../../../../client";
 | 
			
		||||
import {getDigitsCount} from "../../../../shared/lib/utils.ts";
 | 
			
		||||
import BaseFormModal, {CreateEditFormProps} from "../BaseFormModal/BaseFormModal.tsx";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type Props = CreateEditFormProps<ClientSchema>;
 | 
			
		||||
 | 
			
		||||
const ClientFormModal = ({
 | 
			
		||||
                             context,
 | 
			
		||||
                             id,
 | 
			
		||||
                             innerProps,
 | 
			
		||||
                         }: ContextModalProps<Props>) => {
 | 
			
		||||
    const isEditing = 'onChange' in innerProps;
 | 
			
		||||
 | 
			
		||||
    const initialValues: ClientSchema = isEditing ? {
 | 
			
		||||
        id: innerProps.element.id,
 | 
			
		||||
        name: innerProps.element.name,
 | 
			
		||||
        details: {
 | 
			
		||||
            address: innerProps.element.details?.address,
 | 
			
		||||
            phoneNumber: innerProps.element.details?.phoneNumber,
 | 
			
		||||
            email: innerProps.element.details?.email,
 | 
			
		||||
            inn: innerProps.element.details?.inn
 | 
			
		||||
        }
 | 
			
		||||
    } : {
 | 
			
		||||
        id: -1,
 | 
			
		||||
        name: '',
 | 
			
		||||
        details: {
 | 
			
		||||
            address: '',
 | 
			
		||||
            phoneNumber: '',
 | 
			
		||||
            email: '',
 | 
			
		||||
            inn: undefined
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const form = useForm<ClientSchema>({
 | 
			
		||||
        initialValues: initialValues,
 | 
			
		||||
        validate: {
 | 
			
		||||
            name: (name: string) => name.trim() !== '' ? null : "Необходимо ввести название клиента",
 | 
			
		||||
            details: {
 | 
			
		||||
                address: (address: string | undefined | null) => (address && address.trim() !== '') ? null : "Необходимо ввести адрес",
 | 
			
		||||
                phoneNumber: (phoneNumber: string | undefined | null) => (phoneNumber && phoneNumber.trim() !== '') ? null : "Необходимо ввести номер телефона",
 | 
			
		||||
                email: (email: string | undefined | null) => (email && email.trim() !== '') ? null : "Необходимо ввести почту",
 | 
			
		||||
                inn: (inn: number | undefined | null) => (inn && getDigitsCount(inn) >= 10) ? null : "ИНН должен содержать не менее 10 цифр",
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    const onClose = () => {
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseFormModal
 | 
			
		||||
            {...innerProps}
 | 
			
		||||
            closeOnSubmit
 | 
			
		||||
            form={form}
 | 
			
		||||
            onClose={onClose}
 | 
			
		||||
        >
 | 
			
		||||
            <BaseFormModal.Body>
 | 
			
		||||
                <>
 | 
			
		||||
                    <Fieldset legend={"Основная информация"}>
 | 
			
		||||
                        <TextInput
 | 
			
		||||
                            required
 | 
			
		||||
                            label={"Название клиента"}
 | 
			
		||||
                            placeholder={"Введите название клиента"}
 | 
			
		||||
                            {...form.getInputProps('name')}
 | 
			
		||||
                        />
 | 
			
		||||
                    </Fieldset>
 | 
			
		||||
                    <Fieldset legend={"Дополнительная информация"}>
 | 
			
		||||
                        <TextInput
 | 
			
		||||
                            required
 | 
			
		||||
                            label={"Адрес"}
 | 
			
		||||
                            placeholder={"Введите адрес"}
 | 
			
		||||
                            {...form.getInputProps('details.address')}
 | 
			
		||||
                        />
 | 
			
		||||
                        <TextInput
 | 
			
		||||
                            required
 | 
			
		||||
                            label={"Номер телефона"}
 | 
			
		||||
                            placeholder={"Введите номер телефона"}
 | 
			
		||||
                            {...form.getInputProps('details.phoneNumber')}
 | 
			
		||||
                        />
 | 
			
		||||
                        <TextInput
 | 
			
		||||
                            required
 | 
			
		||||
                            label={"Почта"}
 | 
			
		||||
                            placeholder={"Введите почту"}
 | 
			
		||||
                            {...form.getInputProps('details.email')}
 | 
			
		||||
                        />
 | 
			
		||||
                        <NumberInput
 | 
			
		||||
                            required
 | 
			
		||||
                            hideControls
 | 
			
		||||
                            label={"ИНН"}
 | 
			
		||||
                            placeholder={"Введите ИНН"}
 | 
			
		||||
                            {...form.getInputProps('details.inn')}
 | 
			
		||||
                        />
 | 
			
		||||
                    </Fieldset>
 | 
			
		||||
                </>
 | 
			
		||||
 | 
			
		||||
            </BaseFormModal.Body>
 | 
			
		||||
        </BaseFormModal>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ClientFormModal;
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import {FC, ReactNode} from "react";
 | 
			
		||||
import {AppShell, rem} from "@mantine/core";
 | 
			
		||||
import {AppShell} from "@mantine/core";
 | 
			
		||||
import {Navbar} from "../../components/Navbar/Navbar.tsx";
 | 
			
		||||
import {useSelector} from "react-redux";
 | 
			
		||||
import {RootState} from "../../redux/store.ts";
 | 
			
		||||
@@ -13,7 +13,7 @@ const PageWrapper: FC<Props> = ({children}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <AppShell
 | 
			
		||||
            layout={"alt"}
 | 
			
		||||
            navbar={{width: rem('80px'), breakpoint: "sm"}}
 | 
			
		||||
            navbar={{width: '5%', breakpoint: "sm"}}
 | 
			
		||||
        >
 | 
			
		||||
 | 
			
		||||
            <AppShell.Navbar>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,3 +5,8 @@ export const dateWithoutTimezone = (date: Date) => {
 | 
			
		||||
        .slice(0, -1);
 | 
			
		||||
    return withoutTimezone;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getDigitsCount = (num: number): number => {
 | 
			
		||||
    if (num === 0) return 1;
 | 
			
		||||
    return Math.floor(Math.log10(Math.abs(num))) + 1;
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user