v0.1
This commit is contained in:
		@@ -32,6 +32,8 @@ export type { DealDeleteProductRequest } from './models/DealDeleteProductRequest
 | 
				
			|||||||
export type { DealDeleteProductResponse } from './models/DealDeleteProductResponse';
 | 
					export type { DealDeleteProductResponse } from './models/DealDeleteProductResponse';
 | 
				
			||||||
export type { DealDeleteProductsRequest } from './models/DealDeleteProductsRequest';
 | 
					export type { DealDeleteProductsRequest } from './models/DealDeleteProductsRequest';
 | 
				
			||||||
export type { DealDeleteProductsResponse } from './models/DealDeleteProductsResponse';
 | 
					export type { DealDeleteProductsResponse } from './models/DealDeleteProductsResponse';
 | 
				
			||||||
 | 
					export type { DealDeleteRequest } from './models/DealDeleteRequest';
 | 
				
			||||||
 | 
					export type { DealDeleteResponse } from './models/DealDeleteResponse';
 | 
				
			||||||
export type { DealDeleteServiceRequest } from './models/DealDeleteServiceRequest';
 | 
					export type { DealDeleteServiceRequest } from './models/DealDeleteServiceRequest';
 | 
				
			||||||
export type { DealDeleteServiceResponse } from './models/DealDeleteServiceResponse';
 | 
					export type { DealDeleteServiceResponse } from './models/DealDeleteServiceResponse';
 | 
				
			||||||
export type { DealDeleteServicesRequest } from './models/DealDeleteServicesRequest';
 | 
					export type { DealDeleteServicesRequest } from './models/DealDeleteServicesRequest';
 | 
				
			||||||
@@ -46,7 +48,6 @@ export type { DealServiceSchema } from './models/DealServiceSchema';
 | 
				
			|||||||
export type { DealStatusHistorySchema } from './models/DealStatusHistorySchema';
 | 
					export type { DealStatusHistorySchema } from './models/DealStatusHistorySchema';
 | 
				
			||||||
export type { DealSummary } from './models/DealSummary';
 | 
					export type { DealSummary } from './models/DealSummary';
 | 
				
			||||||
export type { DealSummaryReorderRequest } from './models/DealSummaryReorderRequest';
 | 
					export type { DealSummaryReorderRequest } from './models/DealSummaryReorderRequest';
 | 
				
			||||||
export type { DealSummaryReorderResponse } from './models/DealSummaryReorderResponse';
 | 
					 | 
				
			||||||
export type { DealSummaryResponse } from './models/DealSummaryResponse';
 | 
					export type { DealSummaryResponse } from './models/DealSummaryResponse';
 | 
				
			||||||
export type { DealUpdateGeneralInfoRequest } from './models/DealUpdateGeneralInfoRequest';
 | 
					export type { DealUpdateGeneralInfoRequest } from './models/DealUpdateGeneralInfoRequest';
 | 
				
			||||||
export type { DealUpdateGeneralInfoResponse } from './models/DealUpdateGeneralInfoResponse';
 | 
					export type { DealUpdateGeneralInfoResponse } from './models/DealUpdateGeneralInfoResponse';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								src/client/models/DealDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/DealDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealDeleteRequest = {
 | 
				
			||||||
 | 
					    dealId: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
export type DealSummaryReorderResponse = {
 | 
					export type DealDeleteResponse = {
 | 
				
			||||||
    ok: boolean;
 | 
					    ok: boolean;
 | 
				
			||||||
    message: string;
 | 
					    message: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -8,6 +8,7 @@ export type DealStatusHistorySchema = {
 | 
				
			|||||||
    changedAt: string;
 | 
					    changedAt: string;
 | 
				
			||||||
    fromStatus: number;
 | 
					    fromStatus: number;
 | 
				
			||||||
    toStatus: number;
 | 
					    toStatus: number;
 | 
				
			||||||
    nextStatusDeadline: string;
 | 
					    nextStatusDeadline: (string | null);
 | 
				
			||||||
 | 
					    comment?: (string | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ export type DealSummary = {
 | 
				
			|||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    clientName: string;
 | 
					    clientName: string;
 | 
				
			||||||
    changedAt: string;
 | 
					    changedAt: string;
 | 
				
			||||||
 | 
					    deadline: string;
 | 
				
			||||||
    status: number;
 | 
					    status: number;
 | 
				
			||||||
    totalPrice: number;
 | 
					    totalPrice: number;
 | 
				
			||||||
    rank: number;
 | 
					    rank: number;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,9 @@
 | 
				
			|||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
export type DealSummaryReorderRequest = {
 | 
					export type DealSummaryReorderRequest = {
 | 
				
			||||||
    dealId: number;
 | 
					    dealId: number;
 | 
				
			||||||
    newStatus: number;
 | 
					    status: number;
 | 
				
			||||||
    rank: number;
 | 
					    index: number;
 | 
				
			||||||
    nextStatusDeadline: string;
 | 
					    deadline: string;
 | 
				
			||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,8 @@ import type { DealDeleteProductRequest } from '../models/DealDeleteProductReques
 | 
				
			|||||||
import type { DealDeleteProductResponse } from '../models/DealDeleteProductResponse';
 | 
					import type { DealDeleteProductResponse } from '../models/DealDeleteProductResponse';
 | 
				
			||||||
import type { DealDeleteProductsRequest } from '../models/DealDeleteProductsRequest';
 | 
					import type { DealDeleteProductsRequest } from '../models/DealDeleteProductsRequest';
 | 
				
			||||||
import type { DealDeleteProductsResponse } from '../models/DealDeleteProductsResponse';
 | 
					import type { DealDeleteProductsResponse } from '../models/DealDeleteProductsResponse';
 | 
				
			||||||
 | 
					import type { DealDeleteRequest } from '../models/DealDeleteRequest';
 | 
				
			||||||
 | 
					import type { DealDeleteResponse } from '../models/DealDeleteResponse';
 | 
				
			||||||
import type { DealDeleteServiceRequest } from '../models/DealDeleteServiceRequest';
 | 
					import type { DealDeleteServiceRequest } from '../models/DealDeleteServiceRequest';
 | 
				
			||||||
import type { DealDeleteServiceResponse } from '../models/DealDeleteServiceResponse';
 | 
					import type { DealDeleteServiceResponse } from '../models/DealDeleteServiceResponse';
 | 
				
			||||||
import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest';
 | 
					import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest';
 | 
				
			||||||
@@ -24,7 +26,6 @@ import type { DealQuickCreateRequest } from '../models/DealQuickCreateRequest';
 | 
				
			|||||||
import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse';
 | 
					import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse';
 | 
				
			||||||
import type { DealSchema } from '../models/DealSchema';
 | 
					import type { DealSchema } from '../models/DealSchema';
 | 
				
			||||||
import type { DealSummaryReorderRequest } from '../models/DealSummaryReorderRequest';
 | 
					import type { DealSummaryReorderRequest } from '../models/DealSummaryReorderRequest';
 | 
				
			||||||
import type { DealSummaryReorderResponse } from '../models/DealSummaryReorderResponse';
 | 
					 | 
				
			||||||
import type { DealSummaryResponse } from '../models/DealSummaryResponse';
 | 
					import type { DealSummaryResponse } from '../models/DealSummaryResponse';
 | 
				
			||||||
import type { DealUpdateGeneralInfoRequest } from '../models/DealUpdateGeneralInfoRequest';
 | 
					import type { DealUpdateGeneralInfoRequest } from '../models/DealUpdateGeneralInfoRequest';
 | 
				
			||||||
import type { DealUpdateGeneralInfoResponse } from '../models/DealUpdateGeneralInfoResponse';
 | 
					import type { DealUpdateGeneralInfoResponse } from '../models/DealUpdateGeneralInfoResponse';
 | 
				
			||||||
@@ -56,6 +57,26 @@ export class DealService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete
 | 
				
			||||||
 | 
					     * @returns DealDeleteResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static deleteDeal({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: DealDeleteRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<DealDeleteResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/deal/delete',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Quick Create
 | 
					     * Quick Create
 | 
				
			||||||
     * @returns DealQuickCreateResponse Successful Response
 | 
					     * @returns DealQuickCreateResponse Successful Response
 | 
				
			||||||
@@ -109,14 +130,14 @@ export class DealService {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Reorder
 | 
					     * Reorder
 | 
				
			||||||
     * @returns DealSummaryReorderResponse Successful Response
 | 
					     * @returns DealSummaryResponse Successful Response
 | 
				
			||||||
     * @throws ApiError
 | 
					     * @throws ApiError
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static reorderDealSummaries({
 | 
					    public static reorderDealSummaries({
 | 
				
			||||||
        requestBody,
 | 
					        requestBody,
 | 
				
			||||||
    }: {
 | 
					    }: {
 | 
				
			||||||
        requestBody: DealSummaryReorderRequest,
 | 
					        requestBody: DealSummaryReorderRequest,
 | 
				
			||||||
    }): CancelablePromise<DealSummaryReorderResponse> {
 | 
					    }): CancelablePromise<DealSummaryResponse> {
 | 
				
			||||||
        return __request(OpenAPI, {
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
            method: 'POST',
 | 
					            method: 'POST',
 | 
				
			||||||
            url: '/deal/summaries/reorder',
 | 
					            url: '/deal/summaries/reorder',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,23 +6,29 @@ import CreateDealButton from "../CreateDealButton/CreateDealButton.tsx";
 | 
				
			|||||||
import {DealSummary} from "../../../client";
 | 
					import {DealSummary} from "../../../client";
 | 
				
			||||||
import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx";
 | 
					import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx";
 | 
				
			||||||
import classNames from "classnames";
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					import {getPluralForm} from "../../../shared/lib/utils.ts";
 | 
				
			||||||
 | 
					import {sum} from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    droppableId: string;
 | 
					    droppableId: string;
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
    withCreateButton?: boolean;
 | 
					    withCreateButton?: boolean;
 | 
				
			||||||
    summaries: DealSummary[];
 | 
					    summaries: DealSummary[];
 | 
				
			||||||
 | 
					    color: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Board: FC<Props> = ({droppableId, title, summaries, withCreateButton = false}) => {
 | 
					export const Board: FC<Props> = ({droppableId, title, summaries, color, withCreateButton = false}) => {
 | 
				
			||||||
 | 
					    const getDealsText = () => {
 | 
				
			||||||
 | 
					        const pluralForm = getPluralForm(summaries.length, 'сделка', 'сделки', 'сделок');
 | 
				
			||||||
 | 
					        return `${summaries.length} ${pluralForm}: ${sum(summaries.map(summary => summary.totalPrice))}₽`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={styles["container"]}>
 | 
					        <div className={styles["container"]}>
 | 
				
			||||||
            <div className={styles["header"]}>
 | 
					            <div className={styles["header"]}>
 | 
				
			||||||
                <Title size={"h4"}>{title}</Title>
 | 
					                <Title size={"h4"}>{title}</Title>
 | 
				
			||||||
                <Text>12 сделок: 500р</Text>
 | 
					                <Text>{getDealsText()}</Text>
 | 
				
			||||||
                <Divider size={"xl"} my={10} color={"blue"}/>
 | 
					                <Divider size={"xl"} my={10} color={color}/>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <Droppable
 | 
					            <Droppable
 | 
				
			||||||
                droppableId={droppableId}
 | 
					                droppableId={droppableId}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import {Text, Transition} from '@mantine/core';
 | 
				
			|||||||
import CreateDealFrom from "../CreateDealForm/CreateDealFrom.tsx";
 | 
					import CreateDealFrom from "../CreateDealForm/CreateDealFrom.tsx";
 | 
				
			||||||
import {DealService} from "../../../client";
 | 
					import {DealService} from "../../../client";
 | 
				
			||||||
import {dateWithoutTimezone} from "../../../shared/lib/utils.ts";
 | 
					import {dateWithoutTimezone} from "../../../shared/lib/utils.ts";
 | 
				
			||||||
 | 
					import {useQueryClient} from "@tanstack/react-query";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    onClick: () => void;
 | 
					    onClick: () => void;
 | 
				
			||||||
@@ -12,6 +13,8 @@ type Props = {
 | 
				
			|||||||
const CreateDealButton: FC<Props> = () => {
 | 
					const CreateDealButton: FC<Props> = () => {
 | 
				
			||||||
    const [isCreating, setIsCreating] = useState(false);
 | 
					    const [isCreating, setIsCreating] = useState(false);
 | 
				
			||||||
    const [isTransitionEnded, setIsTransitionEnded] = useState(true);
 | 
					    const [isTransitionEnded, setIsTransitionEnded] = useState(true);
 | 
				
			||||||
 | 
					    const queryClient = useQueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={styles['container']}
 | 
					        <div className={styles['container']}
 | 
				
			||||||
             onClick={() => {
 | 
					             onClick={() => {
 | 
				
			||||||
@@ -41,6 +44,9 @@ const CreateDealButton: FC<Props> = () => {
 | 
				
			|||||||
                                        ...quickDeal,
 | 
					                                        ...quickDeal,
 | 
				
			||||||
                                        acceptanceDate: dateWithoutTimezone(quickDeal.acceptanceDate)
 | 
					                                        acceptanceDate: dateWithoutTimezone(quickDeal.acceptanceDate)
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }).then(async () => {
 | 
				
			||||||
 | 
					                                    await queryClient.invalidateQueries({queryKey: ['getDealSummaries']});
 | 
				
			||||||
 | 
					                                    setIsCreating(false);
 | 
				
			||||||
                                })
 | 
					                                })
 | 
				
			||||||
                            }}
 | 
					                            }}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,26 @@ const DealSummaryCard: FC<Props> = ({dealSummary}) => {
 | 
				
			|||||||
                setSelectedDeal(deal);
 | 
					                setSelectedDeal(deal);
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const getDeadlineTextColor = (deadline: string) => {
 | 
				
			||||||
 | 
					        // generate three colors, yellow for 1 day, red for 0 days, green for more than 1 day
 | 
				
			||||||
 | 
					        const deadlineDate = new Date(deadline);
 | 
				
			||||||
 | 
					        const currentDate = new Date();
 | 
				
			||||||
 | 
					        const diff = deadlineDate.getTime() - currentDate.getTime();
 | 
				
			||||||
 | 
					        const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
 | 
				
			||||||
 | 
					        if (diffDays === 1) {
 | 
				
			||||||
 | 
					            return 'yellow.8';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (diffDays === 0) {
 | 
				
			||||||
 | 
					            return 'red.8';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 'green.8';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div onClick={() => onDealSummaryClick()} className={styles['container']}>
 | 
					        <div onClick={() => onDealSummaryClick()} className={styles['container']}>
 | 
				
			||||||
            <div className={styles['flex-row']}>
 | 
					            <div className={styles['flex-row']}>
 | 
				
			||||||
                <div className={styles['flex-item']}>
 | 
					                <div className={styles['flex-item']}>
 | 
				
			||||||
                    <Text size={"sm"} c={"gray.6"}>
 | 
					                    <Text size={"sm"} c={"gray.6"}>
 | 
				
			||||||
                        {dealSummary.clientName}
 | 
					                        Клиент: {dealSummary.clientName}
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className={styles['flex-item']}>
 | 
					                <div className={styles['flex-item']}>
 | 
				
			||||||
@@ -38,12 +52,12 @@ const DealSummaryCard: FC<Props> = ({dealSummary}) => {
 | 
				
			|||||||
            <div className={classNames(styles['flex-row'], styles['flex-row-right'])}>
 | 
					            <div className={classNames(styles['flex-row'], styles['flex-row-right'])}>
 | 
				
			||||||
                <div className={styles['flex-item']}>
 | 
					                <div className={styles['flex-item']}>
 | 
				
			||||||
                    <Text size={"sm"} c={"gray.6"}>
 | 
					                    <Text size={"sm"} c={"gray.6"}>
 | 
				
			||||||
                        {new Date(dealSummary.changedAt).toLocaleString('ru-RU')}
 | 
					                        {/*Создана: {new Date(dealSummary.changedAt).toLocaleString('ru-RU')}*/}
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className={styles['flex-item']}>
 | 
					                <div className={styles['flex-item']}>
 | 
				
			||||||
                    <Text size={"sm"} c={"yellow.8"}>
 | 
					                    <Text size={"sm"} c={getDeadlineTextColor(dealSummary.deadline)}>
 | 
				
			||||||
                        Нет задач
 | 
					                        {new Date(dealSummary.deadline).toLocaleString('ru-RU').slice(0, -3)}
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,11 +30,11 @@ function NavbarLink(props: NavbarLinkProps) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mockdata = [
 | 
					const mockdata = [
 | 
				
			||||||
    {
 | 
					    // {
 | 
				
			||||||
        icon: IconHome2,
 | 
					    //     icon: IconHome2,
 | 
				
			||||||
        label: 'Главная',
 | 
					    //     label: 'Главная',
 | 
				
			||||||
        href: '/'
 | 
					    //     href: '/'
 | 
				
			||||||
    },
 | 
					    // },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        icon: IconCash,
 | 
					        icon: IconCash,
 | 
				
			||||||
        label: 'Сделки',
 | 
					        label: 'Сделки',
 | 
				
			||||||
@@ -83,7 +83,7 @@ export function Navbar() {
 | 
				
			|||||||
        <nav className={classes.navbar}>
 | 
					        <nav className={classes.navbar}>
 | 
				
			||||||
            <Center>
 | 
					            <Center>
 | 
				
			||||||
                <Image
 | 
					                <Image
 | 
				
			||||||
                    style={{filter: "drop-shadow(0 0 30px #fff)"}}
 | 
					                    // style={{filter: "drop-shadow(0 0 30px #fff)"}}
 | 
				
			||||||
                    src={colorScheme == "dark" ? "/icons/logo-light.png" : "/icons/logo.png"}
 | 
					                    src={colorScheme == "dark" ? "/icons/logo-light.png" : "/icons/logo.png"}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </Center>
 | 
					            </Center>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,14 @@
 | 
				
			|||||||
.container {
 | 
					.container {
 | 
				
			||||||
    border-radius: rem(20);
 | 
					    border-radius: rem(20);
 | 
				
			||||||
    background-color: var(--mantine-color-body);
 | 
					    background-color: var(--mantine-color-body);
 | 
				
			||||||
    padding: rem(10);
 | 
					    padding: rem(15);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.container-fluid {
 | 
					.container-fluid {
 | 
				
			||||||
    flex: 1;
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.container-full-height {
 | 
				
			||||||
 | 
					    height: calc(100vh - (rem(20) * 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,14 +1,17 @@
 | 
				
			|||||||
import {FC, ReactNode} from "react";
 | 
					import {CSSProperties, FC, ReactNode} from "react";
 | 
				
			||||||
import styles from './PageBlock.module.css';
 | 
					import styles from './PageBlock.module.css';
 | 
				
			||||||
import classNames from "classnames";
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    children: ReactNode
 | 
					    children: ReactNode
 | 
				
			||||||
    fluid?: boolean;
 | 
					    fluid?: boolean;
 | 
				
			||||||
 | 
					    style?: CSSProperties;
 | 
				
			||||||
 | 
					    fullHeight?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const PageBlock: FC<Props> = ({children, fluid = true}) => {
 | 
					export const PageBlock: FC<Props> = ({children, style, fluid = true, fullHeight = false}) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={classNames(styles['container'], fluid && styles['container-fluid'])}>
 | 
					        <div style={style}
 | 
				
			||||||
 | 
					             className={classNames(styles['container'], fluid && styles['container-fluid'], fullHeight && styles['container-full-height'])}>
 | 
				
			||||||
            {children}
 | 
					            {children}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,16 +3,16 @@ import {Button, Flex, rem, Textarea} from "@mantine/core";
 | 
				
			|||||||
import {DateTimePicker, DateValue} from "@mantine/dates";
 | 
					import {DateTimePicker, DateValue} from "@mantine/dates";
 | 
				
			||||||
import {useForm} from "@mantine/form";
 | 
					import {useForm} from "@mantine/form";
 | 
				
			||||||
import {DealSummaryReorderRequest} from "../../client";
 | 
					import {DealSummaryReorderRequest} from "../../client";
 | 
				
			||||||
 | 
					import {dateWithoutTimezone} from "../../shared/lib/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Deadline = {
 | 
					type Deadline = {
 | 
				
			||||||
    datetime: DateValue,
 | 
					    deadline: DateValue,
 | 
				
			||||||
    comment: string
 | 
					    comment: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    request:DealSummaryReorderRequest,
 | 
					    request: Partial<DealSummaryReorderRequest>,
 | 
				
			||||||
    onSubmit: (
 | 
					    onSubmit: (
 | 
				
			||||||
        deadline: Deadline,
 | 
					 | 
				
			||||||
        request: DealSummaryReorderRequest,
 | 
					        request: DealSummaryReorderRequest,
 | 
				
			||||||
    ) => void;
 | 
					    ) => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -24,28 +24,37 @@ const EnterDeadlineModal = ({
 | 
				
			|||||||
                            }: ContextModalProps<Props>) => {
 | 
					                            }: ContextModalProps<Props>) => {
 | 
				
			||||||
    const form = useForm<Deadline>({
 | 
					    const form = useForm<Deadline>({
 | 
				
			||||||
        initialValues: {
 | 
					        initialValues: {
 | 
				
			||||||
            datetime: null,
 | 
					            deadline: null,
 | 
				
			||||||
            comment: '',
 | 
					            comment: '',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        validate: {
 | 
					        validate: {
 | 
				
			||||||
            datetime: (datetime) => datetime !== null ? null : 'Необходимо ввести дедлайн',
 | 
					            deadline: (datetime) => datetime !== null ? null : 'Необходимо ввести дедлайн',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    const onCancelClick = () => {
 | 
					    const onCancelClick = () => {
 | 
				
			||||||
        context.closeModal(id);
 | 
					        context.closeModal(id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const onSubmit = (values: Deadline) => {
 | 
					    const onSubmit = (values: Deadline) => {
 | 
				
			||||||
        innerProps.onSubmit(values, innerProps.request);
 | 
					        const {deadline, comment} = values;
 | 
				
			||||||
 | 
					        if (!deadline) return;
 | 
				
			||||||
 | 
					        innerProps.onSubmit({
 | 
				
			||||||
 | 
					            ...innerProps.request,
 | 
				
			||||||
 | 
					            deadline: dateWithoutTimezone(deadline),
 | 
				
			||||||
 | 
					            comment
 | 
				
			||||||
 | 
					        } as unknown as DealSummaryReorderRequest);
 | 
				
			||||||
 | 
					        context.closeModal(id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <form onSubmit={form.onSubmit((values) => onSubmit(values))}>
 | 
					        <form onSubmit={form.onSubmit((values) => onSubmit(values))}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Flex direction={'column'} gap={10}>
 | 
					            <Flex direction={'column'} gap={10}>
 | 
				
			||||||
                <Flex direction={'column'} gap={rem(10)}>
 | 
					                <Flex direction={'column'} gap={rem(10)}>
 | 
				
			||||||
                    <DateTimePicker
 | 
					                    <DateTimePicker
 | 
				
			||||||
                        required
 | 
					                        required
 | 
				
			||||||
                        label={'Дата и время'}
 | 
					                        label={'Дата и время'}
 | 
				
			||||||
                        placeholder={'Введите дату и время'}
 | 
					                        placeholder={'Введите дату и время'}
 | 
				
			||||||
                        {...form.getInputProps('date')}
 | 
					                        minDate={new Date()}
 | 
				
			||||||
 | 
					                        {...form.getInputProps('deadline')}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <Textarea
 | 
					                    <Textarea
 | 
				
			||||||
                        label={'Коментарий'}
 | 
					                        label={'Коментарий'}
 | 
				
			||||||
@@ -59,7 +68,9 @@ const EnterDeadlineModal = ({
 | 
				
			|||||||
                        variant={'default'}
 | 
					                        variant={'default'}
 | 
				
			||||||
                        onClick={onCancelClick}
 | 
					                        onClick={onCancelClick}
 | 
				
			||||||
                    >Отменить</Button>
 | 
					                    >Отменить</Button>
 | 
				
			||||||
                    <Button>Сохранить</Button>
 | 
					                    <Button
 | 
				
			||||||
 | 
					                        type={'submit'}
 | 
				
			||||||
 | 
					                    >Сохранить</Button>
 | 
				
			||||||
                </Flex>
 | 
					                </Flex>
 | 
				
			||||||
            </Flex>
 | 
					            </Flex>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ const DealStatusChangeTable: FC<Props> = (props: Props) => {
 | 
				
			|||||||
                enableBottomToolbar: false,
 | 
					                enableBottomToolbar: false,
 | 
				
			||||||
                enableColumnFilters: false,
 | 
					                enableColumnFilters: false,
 | 
				
			||||||
                enableColumnVisibilityToggle: false,
 | 
					                enableColumnVisibilityToggle: false,
 | 
				
			||||||
 | 
					                layoutMode:"grid"
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ import {useMemo} from "react";
 | 
				
			|||||||
import {MRT_ColumnDef} from "mantine-react-table";
 | 
					import {MRT_ColumnDef} from "mantine-react-table";
 | 
				
			||||||
import {DealStatusHistorySchema} from "../../../../client";
 | 
					import {DealStatusHistorySchema} from "../../../../client";
 | 
				
			||||||
import {DealStatus, DealStatusDictionary} from "../../../../shared/enums/DealStatus.ts";
 | 
					import {DealStatus, DealStatusDictionary} from "../../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
 | 
					import {Spoiler, Text} from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useDealStatusChangeTableColumns = () => {
 | 
					export const useDealStatusChangeTableColumns = () => {
 | 
				
			||||||
    return useMemo<MRT_ColumnDef<DealStatusHistorySchema>[]>(() => [
 | 
					    return useMemo<MRT_ColumnDef<DealStatusHistorySchema>[]>(() => [
 | 
				
			||||||
@@ -23,6 +24,17 @@ export const useDealStatusChangeTableColumns = () => {
 | 
				
			|||||||
            accessorKey: "toStatus",
 | 
					            accessorKey: "toStatus",
 | 
				
			||||||
            header: "В статус",
 | 
					            header: "В статус",
 | 
				
			||||||
            accessorFn: (row) => DealStatusDictionary[row.toStatus as DealStatus],
 | 
					            accessorFn: (row) => DealStatusDictionary[row.toStatus as DealStatus],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "comment",
 | 
				
			||||||
 | 
					            header: "Комментарий",
 | 
				
			||||||
 | 
					            Cell: ({row}) =>
 | 
				
			||||||
 | 
					            <Spoiler onDoubleClick={()=>{console.log("double click")}} maxHeight={80} showLabel={"Показать весь"} hideLabel={"Скрыть"}>
 | 
				
			||||||
 | 
					                <Text style={{wordWrap: "break-word", wordBreak: "break-all", whiteSpace: "normal"}} span>
 | 
				
			||||||
 | 
					                    {row.original.comment}<br/>
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					            </Spoiler>
 | 
				
			||||||
 | 
					            ,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ], []);
 | 
					    ], []);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
import {useQuery} from "@tanstack/react-query";
 | 
					import {useQuery} from "@tanstack/react-query";
 | 
				
			||||||
import {DealService, DealSummary} from "../../../client";
 | 
					import {DealService} from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useDealSummaries = (): DealSummary[] => {
 | 
					export const useDealSummaries = () => {
 | 
				
			||||||
    const {data: summaries = []} = useQuery({
 | 
					    const {data: summariesRaw = [], refetch} = useQuery({
 | 
				
			||||||
        queryKey: ['getDealSummaries'],
 | 
					        queryKey: ['getDealSummaries'],
 | 
				
			||||||
        queryFn: DealService.getDealSummaries,
 | 
					        queryFn: DealService.getDealSummaries,
 | 
				
			||||||
        select: data => data.summaries || [] // Трансформируем полученные данные
 | 
					        select: data => data.summaries || [] // Трансформируем полученные данные
 | 
				
			||||||
@@ -11,5 +11,5 @@ export const useDealSummaries = (): DealSummary[] => {
 | 
				
			|||||||
    // Теперь summaries будет содержать либо трансформированные данные, либо пустой массив по умолчанию
 | 
					    // Теперь summaries будет содержать либо трансформированные данные, либо пустой массив по умолчанию
 | 
				
			||||||
    // isLoading и isError могут быть использованы для отображения индикаторов загрузки или ошибки
 | 
					    // isLoading и isError могут быть использованы для отображения индикаторов загрузки или ошибки
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return summaries;
 | 
					    return {summariesRaw, refetch};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -20,3 +20,22 @@
 | 
				
			|||||||
    padding-right: 5%;
 | 
					    padding-right: 5%;
 | 
				
			||||||
    padding-left: 5%;
 | 
					    padding-left: 5%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.delete {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mixin light {
 | 
				
			||||||
 | 
					        border-color: var(--mantine-color-gray-1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @mixin dark {
 | 
				
			||||||
 | 
					        border-color: var(--mantine-color-dark-5);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    border: dashed var(--item-border-size) var(--mantine-color-default-border);
 | 
				
			||||||
 | 
					    border-radius: var(--item-border-radius);
 | 
				
			||||||
 | 
					    padding: rem(30);
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.delete-hidden {
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +1,77 @@
 | 
				
			|||||||
import {FC, useEffect, useState} from "react";
 | 
					import {FC, useEffect, useState} from "react";
 | 
				
			||||||
import styles from './LeadsPage.module.css';
 | 
					import styles from './LeadsPage.module.css';
 | 
				
			||||||
import Board from "../../../components/Dnd/Board/Board.tsx";
 | 
					import Board from "../../../components/Dnd/Board/Board.tsx";
 | 
				
			||||||
import {DragDropContext, DropResult, OnDragEndResponder, ResponderProvided} from "@hello-pangea/dnd";
 | 
					import {DragDropContext, Droppable, DropResult} from "@hello-pangea/dnd";
 | 
				
			||||||
import {useDealSummaries} from "../hooks/useDealSummaries.tsx";
 | 
					import {useDealSummaries} from "../hooks/useDealSummaries.tsx";
 | 
				
			||||||
import {DealStatus} from "../../../shared/enums/DealStatus.ts";
 | 
					import {DealStatus, getDealStatusByName} from "../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
					import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
				
			||||||
import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx";
 | 
					import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx";
 | 
				
			||||||
import {DealPageContextProvider} from "../contexts/DealPageContext.tsx";
 | 
					import {DealPageContextProvider} from "../contexts/DealPageContext.tsx";
 | 
				
			||||||
import {modals} from "@mantine/modals";
 | 
					import {modals} from "@mantine/modals";
 | 
				
			||||||
import {DealSummaryReorderRequest} from "../../../client";
 | 
					import {DealService, DealSummaryReorderRequest} from "../../../client";
 | 
				
			||||||
 | 
					import {Flex} from "@mantine/core";
 | 
				
			||||||
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					import {notifications} from "../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const LeadsPage: FC = () => {
 | 
					export const LeadsPage: FC = () => {
 | 
				
			||||||
    const summariesRaw = useDealSummaries();
 | 
					    const {summariesRaw, refetch} = useDealSummaries();
 | 
				
			||||||
    const [summaries, setSummaries] = useState(summariesRaw);
 | 
					    const [summaries, setSummaries] = useState(summariesRaw);
 | 
				
			||||||
 | 
					    const [isDragEnded, setIsDragEnded] = useState(true);
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        setSummaries(summariesRaw);
 | 
					        setSummaries(summariesRaw);
 | 
				
			||||||
    }, [summariesRaw]);
 | 
					    }, [summariesRaw]);
 | 
				
			||||||
    const onDragEnd = async (result: DropResult, provided: ResponderProvided) => {
 | 
					
 | 
				
			||||||
 | 
					    const onDelete = (dealId: number) => {
 | 
				
			||||||
 | 
					        const summary = summaries.find(summary => summary.id == dealId);
 | 
				
			||||||
 | 
					        if (!summary) return;
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление сделки",
 | 
				
			||||||
 | 
					            children:
 | 
				
			||||||
 | 
					                <Flex>
 | 
				
			||||||
 | 
					                    Вы действительно хотите удалить сделку {summary.name}?
 | 
				
			||||||
 | 
					                </Flex>,
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                DealService.deleteDeal({requestBody: {dealId: dealId}})
 | 
				
			||||||
 | 
					                    .then(async ({ok, message}) => {
 | 
				
			||||||
 | 
					                        notifications.guess(ok, {message});
 | 
				
			||||||
 | 
					                        if (!ok) return;
 | 
				
			||||||
 | 
					                        await refetch();
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            labels: {
 | 
				
			||||||
 | 
					                confirm: "Удалить",
 | 
				
			||||||
 | 
					                cancel: "Отмена"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const onDragEnd = async (result: DropResult) => {
 | 
				
			||||||
 | 
					        setIsDragEnded(true);
 | 
				
			||||||
 | 
					        if (!result.destination || result.destination == result.source) return;
 | 
				
			||||||
        const dealId = parseInt(result.draggableId);
 | 
					        const dealId = parseInt(result.draggableId);
 | 
				
			||||||
        
 | 
					        if (isNaN(dealId)) return;
 | 
				
			||||||
        const request: DealSummaryReorderRequest = {}
 | 
					
 | 
				
			||||||
 | 
					        const droppableId = result.destination.droppableId;
 | 
				
			||||||
 | 
					        if (droppableId === 'DELETE') {
 | 
				
			||||||
 | 
					            onDelete(dealId);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const request: Partial<DealSummaryReorderRequest> = {
 | 
				
			||||||
 | 
					            dealId: dealId,
 | 
				
			||||||
 | 
					            index: result.destination.index,
 | 
				
			||||||
 | 
					            status: getDealStatusByName(droppableId)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: 'enterDeadline',
 | 
					            modal: 'enterDeadline',
 | 
				
			||||||
            title: "Необходимо указать дедлайн",
 | 
					            title: "Необходимо указать дедлайн",
 | 
				
			||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onSubmit: (event) => console.log(event)
 | 
					                onSubmit: (event) => DealService.reorderDealSummaries({requestBody: event})
 | 
				
			||||||
 | 
					                    .then(async response => {
 | 
				
			||||||
 | 
					                        setSummaries(response.summaries);
 | 
				
			||||||
 | 
					                        await refetch();
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					                request: request
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,43 +80,89 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <DealPageContextProvider>
 | 
					            <DealPageContextProvider>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <PageBlock>
 | 
					                <PageBlock fullHeight>
 | 
				
			||||||
                    <div className={styles['container']}>
 | 
					                    <div className={styles['container']}>
 | 
				
			||||||
                        <div className={styles['boards']}>
 | 
					                        <DragDropContext
 | 
				
			||||||
                            <DragDropContext onDragEnd={onDragEnd}>
 | 
					                            onDragStart={() => {
 | 
				
			||||||
 | 
					                                setIsDragEnded(false);
 | 
				
			||||||
 | 
					                            }}
 | 
				
			||||||
 | 
					                            onDragEnd={onDragEnd}>
 | 
				
			||||||
 | 
					                            <div className={styles['boards']}>
 | 
				
			||||||
                                <Board
 | 
					                                <Board
 | 
				
			||||||
                                    withCreateButton
 | 
					                                    withCreateButton
 | 
				
			||||||
                                    summaries={summaries
 | 
					                                    summaries={summaries
 | 
				
			||||||
                                        .filter(summary => summary.status == DealStatus.AWAITING_ACCEPTANCE)}
 | 
					                                        .filter(summary => summary.status == DealStatus.AWAITING_ACCEPTANCE)}
 | 
				
			||||||
                                    title={"Ожидает приемки"}
 | 
					                                    title={"Ожидает приемки"}
 | 
				
			||||||
                                    droppableId={"AWAITING_ACCEPTANCE"}
 | 
					                                    droppableId={"AWAITING_ACCEPTANCE"}
 | 
				
			||||||
 | 
					                                    color={'#4A90E2'}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                <Board
 | 
					                                <Board
 | 
				
			||||||
                                    summaries={summaries
 | 
					                                    summaries={summaries
 | 
				
			||||||
                                        .filter(summary => summary.status == DealStatus.PACKAGING)}
 | 
					                                        .filter(summary => summary.status == DealStatus.PACKAGING)}
 | 
				
			||||||
                                    title={"Упаковка"}
 | 
					                                    title={"Упаковка"}
 | 
				
			||||||
                                    droppableId={"PACKAGING"}
 | 
					                                    droppableId={"PACKAGING"}
 | 
				
			||||||
 | 
					                                    color={'#F5A623'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                <Board
 | 
					                                <Board
 | 
				
			||||||
                                    summaries={summaries
 | 
					                                    summaries={summaries
 | 
				
			||||||
                                        .filter(summary => summary.status == DealStatus.AWAITING_SHIPMENT)}
 | 
					                                        .filter(summary => summary.status == DealStatus.AWAITING_SHIPMENT)}
 | 
				
			||||||
                                    title={"Ожидает отгрузки"}
 | 
					                                    title={"Ожидает отгрузки"}
 | 
				
			||||||
                                    droppableId={"AWAITING_SHIPMENT"}
 | 
					                                    droppableId={"AWAITING_SHIPMENT"}
 | 
				
			||||||
 | 
					                                    color={'#7ED321'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                <Board
 | 
					                                <Board
 | 
				
			||||||
                                    summaries={summaries
 | 
					                                    summaries={summaries
 | 
				
			||||||
                                        .filter(summary => summary.status == DealStatus.AWAITING_PAYMENT)}
 | 
					                                        .filter(summary => summary.status == DealStatus.AWAITING_PAYMENT)}
 | 
				
			||||||
                                    title={"Ожидает оплаты"}
 | 
					                                    title={"Ожидает оплаты"}
 | 
				
			||||||
                                    droppableId={"AWAITING_PAYMENT"}
 | 
					                                    droppableId={"AWAITING_PAYMENT"}
 | 
				
			||||||
 | 
					                                    color={'#D0021B'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                <Board
 | 
					                                <Board
 | 
				
			||||||
                                    summaries={summaries
 | 
					                                    summaries={summaries
 | 
				
			||||||
                                        .filter(summary => summary.status == DealStatus.COMPLETED)}
 | 
					                                        .filter(summary => summary.status == DealStatus.COMPLETED)}
 | 
				
			||||||
                                    title={"Завершена"}
 | 
					                                    title={"Завершена"}
 | 
				
			||||||
                                    droppableId={"COMPLETED"}
 | 
					                                    droppableId={"COMPLETED"}
 | 
				
			||||||
 | 
					                                    color={'#417505'}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                            </DragDropContext>
 | 
					                            </div>
 | 
				
			||||||
                        </div>
 | 
					                            <Flex justify={"flex-end"}>
 | 
				
			||||||
 | 
					                                <div
 | 
				
			||||||
 | 
					                                    className={
 | 
				
			||||||
 | 
					                                        classNames(
 | 
				
			||||||
 | 
					                                            styles['delete'],
 | 
				
			||||||
 | 
					                                            isDragEnded && styles['delete-hidden']
 | 
				
			||||||
 | 
					                                        )
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    <Droppable droppableId={"DELETE"}>
 | 
				
			||||||
 | 
					                                        {(provided) => (
 | 
				
			||||||
 | 
					                                            <>
 | 
				
			||||||
 | 
					                                                <div
 | 
				
			||||||
 | 
					                                                    {...provided.droppableProps}
 | 
				
			||||||
 | 
					                                                    ref={provided.innerRef}
 | 
				
			||||||
 | 
					                                                >
 | 
				
			||||||
 | 
					                                                    {!isDragEnded &&
 | 
				
			||||||
 | 
					                                                        <span>
 | 
				
			||||||
 | 
					                                                    Удалить
 | 
				
			||||||
 | 
					                                                    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                </div>
 | 
				
			||||||
 | 
					                                                {provided.placeholder}
 | 
				
			||||||
 | 
					                                            </>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        )}
 | 
				
			||||||
 | 
					                                    </Droppable>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					                        </DragDropContext>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </PageBlock>
 | 
					                </PageBlock>
 | 
				
			||||||
                <DealEditDrawer
 | 
					                <DealEditDrawer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ const LoginPage = () => {
 | 
				
			|||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
    if (authState.isAuthorized) {
 | 
					    if (authState.isAuthorized) {
 | 
				
			||||||
        navigate({to: "/"})
 | 
					        navigate({to: "/leads"})
 | 
				
			||||||
        return (<></>)
 | 
					        return (<></>)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
import {FC} from "react";
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					import {useNavigate} from "@tanstack/react-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MainPage: FC = () => {
 | 
					const MainPage: FC = () => {
 | 
				
			||||||
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
 | 
					    navigate({to: '/leads'});
 | 
				
			||||||
    return (<>
 | 
					    return (<>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,5 +9,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.container {
 | 
					.container {
 | 
				
			||||||
    padding: rem(20);
 | 
					    padding: rem(20);
 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,10 @@ const PageWrapper: FC<Props> = ({children}) => {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <AppShell
 | 
					        <AppShell
 | 
				
			||||||
            layout={"alt"}
 | 
					            layout={"alt"}
 | 
				
			||||||
            navbar={{
 | 
					            navbar={authState.isAuthorized ? {
 | 
				
			||||||
                width: '5%',
 | 
					                width: '5%',
 | 
				
			||||||
                breakpoint: "sm"
 | 
					                breakpoint: "sm"
 | 
				
			||||||
            }}
 | 
					            } : undefined}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <AppShell.Navbar>
 | 
					            <AppShell.Navbar>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.body-container {
 | 
					.body-container {
 | 
				
			||||||
    padding: rem(5);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.top-panel {
 | 
					.top-panel {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,4 +9,19 @@ export const dateWithoutTimezone = (date: Date) => {
 | 
				
			|||||||
export const getDigitsCount = (num: number): number => {
 | 
					export const getDigitsCount = (num: number): number => {
 | 
				
			||||||
    if (num === 0) return 1;
 | 
					    if (num === 0) return 1;
 | 
				
			||||||
    return Math.floor(Math.log10(Math.abs(num))) + 1;
 | 
					    return Math.floor(Math.log10(Math.abs(num))) + 1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const getPluralForm = (amount: number, one: string, twoFour: string, many: string): string => {
 | 
				
			||||||
 | 
					    if (amount % 100 >= 11 && amount % 100 <= 14) {
 | 
				
			||||||
 | 
					        return many;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (amount % 10) {
 | 
				
			||||||
 | 
					        case 1:
 | 
				
			||||||
 | 
					            return one;
 | 
				
			||||||
 | 
					        case 2:
 | 
				
			||||||
 | 
					        case 3:
 | 
				
			||||||
 | 
					        case 4:
 | 
				
			||||||
 | 
					            return twoFour;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return many;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
		Reference in New Issue
	
	Block a user