From 925f1b44073be7dd40fe8ca7cf590c6c288067dd Mon Sep 17 00:00:00 2001 From: fakz9 Date: Tue, 6 Aug 2024 04:55:24 +0300 Subject: [PATCH] feat: services kit and copy --- src/client/index.ts | 14 ++++ src/client/models/CreateServiceKitSchema.ts | 10 +++ src/client/models/CreateServicesKitRequest.ts | 9 ++ .../models/CreateServicesKitResponse.ts | 9 ++ src/client/models/DealAddKitRequest.ts | 9 ++ src/client/models/DealAddKitResponse.ts | 9 ++ src/client/models/DealProductAddKitRequest.ts | 10 +++ .../models/DealProductAddKitResponse.ts | 9 ++ src/client/models/DealServicesCopyRequest.ts | 10 +++ src/client/models/DealServicesCopyResponse.ts | 9 ++ .../models/GetAllServicesKitsResponse.ts | 9 ++ src/client/models/GetServiceKitSchema.ts | 12 +++ src/client/models/UpdateServiceKitSchema.ts | 11 +++ src/client/models/UpdateServicesKitRequest.ts | 9 ++ .../models/UpdateServicesKitResponse.ts | 9 ++ src/client/services/DealService.ts | 66 +++++++++++++++ src/client/services/ServiceService.ts | 56 +++++++++++++ .../ObjectMultiSelect/ObjectMultiSelect.tsx | 67 +++++++++++---- .../ServicesKitSelect/ServicesKitSelect.tsx | 17 ++++ .../ServicesMultiselect.tsx | 16 ++++ .../ServicesKitSelectModal.tsx | 60 ++++++++++++++ src/modals/modals.ts | 8 +- .../modals/SelectDealProductsModal.tsx | 64 ++++++++++++++ .../ProductAndServiceTab.tsx | 63 ++++++++++++++ .../DealServicesTable/DealServicesTable.tsx | 30 ++++++- .../ProductServicesTable.tsx | 18 +++- .../components/ProductView/ProductView.tsx | 26 +++++- .../ServiceTypeSegmentedControl.tsx | 14 +++- .../ServicesKitsTable/ServicesKitsTable.tsx | 61 ++++++++++++++ .../components/ServicesKitsTable/columns.tsx | 17 ++++ .../hooks/useServicesKitsList.tsx | 10 +++ .../modals/ServicesKitModalForm.tsx | 60 ++++++++++++++ src/pages/ServicesPage/ui/ServicesPage.tsx | 83 ++++++++++++++++--- 33 files changed, 844 insertions(+), 40 deletions(-) create mode 100644 src/client/models/CreateServiceKitSchema.ts create mode 100644 src/client/models/CreateServicesKitRequest.ts create mode 100644 src/client/models/CreateServicesKitResponse.ts create mode 100644 src/client/models/DealAddKitRequest.ts create mode 100644 src/client/models/DealAddKitResponse.ts create mode 100644 src/client/models/DealProductAddKitRequest.ts create mode 100644 src/client/models/DealProductAddKitResponse.ts create mode 100644 src/client/models/DealServicesCopyRequest.ts create mode 100644 src/client/models/DealServicesCopyResponse.ts create mode 100644 src/client/models/GetAllServicesKitsResponse.ts create mode 100644 src/client/models/GetServiceKitSchema.ts create mode 100644 src/client/models/UpdateServiceKitSchema.ts create mode 100644 src/client/models/UpdateServicesKitRequest.ts create mode 100644 src/client/models/UpdateServicesKitResponse.ts create mode 100644 src/components/Selects/ServicesKitSelect/ServicesKitSelect.tsx create mode 100644 src/components/Selects/ServicesMultiselect/ServicesMultiselect.tsx create mode 100644 src/modals/ServicesKitSelectModal/ServicesKitSelectModal.tsx create mode 100644 src/pages/LeadsPage/modals/SelectDealProductsModal.tsx create mode 100644 src/pages/ServicesPage/components/ServicesKitsTable/ServicesKitsTable.tsx create mode 100644 src/pages/ServicesPage/components/ServicesKitsTable/columns.tsx create mode 100644 src/pages/ServicesPage/hooks/useServicesKitsList.tsx create mode 100644 src/pages/ServicesPage/modals/ServicesKitModalForm.tsx diff --git a/src/client/index.ts b/src/client/index.ts index 7a82aec..a839705 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -43,8 +43,13 @@ export type { CreatePayRateRequest } from './models/CreatePayRateRequest'; export type { CreatePayRateResponse } from './models/CreatePayRateResponse'; export type { CreatePositionRequest } from './models/CreatePositionRequest'; export type { CreatePositionResponse } from './models/CreatePositionResponse'; +export type { CreateServiceKitSchema } from './models/CreateServiceKitSchema'; +export type { CreateServicesKitRequest } from './models/CreateServicesKitRequest'; +export type { CreateServicesKitResponse } from './models/CreateServicesKitResponse'; export type { CreateUserRequest } from './models/CreateUserRequest'; export type { CreateUserResponse } from './models/CreateUserResponse'; +export type { DealAddKitRequest } from './models/DealAddKitRequest'; +export type { DealAddKitResponse } from './models/DealAddKitResponse'; export type { DealAddProductRequest } from './models/DealAddProductRequest'; export type { DealAddProductResponse } from './models/DealAddProductResponse'; export type { DealAddServiceRequest } from './models/DealAddServiceRequest'; @@ -66,12 +71,16 @@ export type { DealDeleteServicesRequest } from './models/DealDeleteServicesReque export type { DealDeleteServicesResponse } from './models/DealDeleteServicesResponse'; export type { DealGeneralInfoSchema } from './models/DealGeneralInfoSchema'; export type { DealGetAllResponse } from './models/DealGetAllResponse'; +export type { DealProductAddKitRequest } from './models/DealProductAddKitRequest'; +export type { DealProductAddKitResponse } from './models/DealProductAddKitResponse'; export type { DealProductSchema } from './models/DealProductSchema'; export type { DealProductServiceSchema } from './models/DealProductServiceSchema'; export type { DealQuickCreateRequest } from './models/DealQuickCreateRequest'; export type { DealQuickCreateResponse } from './models/DealQuickCreateResponse'; export type { DealSchema } from './models/DealSchema'; export type { DealServiceSchema } from './models/DealServiceSchema'; +export type { DealServicesCopyRequest } from './models/DealServicesCopyRequest'; +export type { DealServicesCopyResponse } from './models/DealServicesCopyResponse'; export type { DealStatusHistorySchema } from './models/DealStatusHistorySchema'; export type { DealSummary } from './models/DealSummary'; export type { DealSummaryReorderRequest } from './models/DealSummaryReorderRequest'; @@ -100,6 +109,7 @@ export type { GetAllPayRatesResponse } from './models/GetAllPayRatesResponse'; export type { GetAllPayrollSchemeResponse } from './models/GetAllPayrollSchemeResponse'; export type { GetAllPositionsResponse } from './models/GetAllPositionsResponse'; export type { GetAllRolesResponse } from './models/GetAllRolesResponse'; +export type { GetAllServicesKitsResponse } from './models/GetAllServicesKitsResponse'; export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWarehousesResponse'; export type { GetAllUsersResponse } from './models/GetAllUsersResponse'; export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest'; @@ -109,6 +119,7 @@ export type { GetProductBarcodePdfRequest } from './models/GetProductBarcodePdfR export type { GetProductBarcodePdfResponse } from './models/GetProductBarcodePdfResponse'; export type { GetProductBarcodeRequest } from './models/GetProductBarcodeRequest'; export type { GetProductBarcodeResponse } from './models/GetProductBarcodeResponse'; +export type { GetServiceKitSchema } from './models/GetServiceKitSchema'; export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest'; export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse'; export type { HTTPValidationError } from './models/HTTPValidationError'; @@ -154,6 +165,9 @@ export type { TimeTrackingData } from './models/TimeTrackingData'; export type { TimeTrackingRecord } from './models/TimeTrackingRecord'; export type { UpdatePayRateRequest } from './models/UpdatePayRateRequest'; export type { UpdatePayRateResponse } from './models/UpdatePayRateResponse'; +export type { UpdateServiceKitSchema } from './models/UpdateServiceKitSchema'; +export type { UpdateServicesKitRequest } from './models/UpdateServicesKitRequest'; +export type { UpdateServicesKitResponse } from './models/UpdateServicesKitResponse'; export type { UpdateTimeTrackingRecordRequest } from './models/UpdateTimeTrackingRecordRequest'; export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse'; export type { UpdateUserRequest } from './models/UpdateUserRequest'; diff --git a/src/client/models/CreateServiceKitSchema.ts b/src/client/models/CreateServiceKitSchema.ts new file mode 100644 index 0000000..0a6e237 --- /dev/null +++ b/src/client/models/CreateServiceKitSchema.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateServiceKitSchema = { + name: string; + serviceType: number; + servicesIds: Array; +}; + diff --git a/src/client/models/CreateServicesKitRequest.ts b/src/client/models/CreateServicesKitRequest.ts new file mode 100644 index 0000000..2b778b0 --- /dev/null +++ b/src/client/models/CreateServicesKitRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { CreateServiceKitSchema } from './CreateServiceKitSchema'; +export type CreateServicesKitRequest = { + data: CreateServiceKitSchema; +}; + diff --git a/src/client/models/CreateServicesKitResponse.ts b/src/client/models/CreateServicesKitResponse.ts new file mode 100644 index 0000000..abf9448 --- /dev/null +++ b/src/client/models/CreateServicesKitResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateServicesKitResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DealAddKitRequest.ts b/src/client/models/DealAddKitRequest.ts new file mode 100644 index 0000000..fa817d1 --- /dev/null +++ b/src/client/models/DealAddKitRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealAddKitRequest = { + dealId: number; + kitId: number; +}; + diff --git a/src/client/models/DealAddKitResponse.ts b/src/client/models/DealAddKitResponse.ts new file mode 100644 index 0000000..7edc087 --- /dev/null +++ b/src/client/models/DealAddKitResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealAddKitResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DealProductAddKitRequest.ts b/src/client/models/DealProductAddKitRequest.ts new file mode 100644 index 0000000..4ec1598 --- /dev/null +++ b/src/client/models/DealProductAddKitRequest.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealProductAddKitRequest = { + dealId: number; + productId: number; + kitId: number; +}; + diff --git a/src/client/models/DealProductAddKitResponse.ts b/src/client/models/DealProductAddKitResponse.ts new file mode 100644 index 0000000..9d7ee54 --- /dev/null +++ b/src/client/models/DealProductAddKitResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealProductAddKitResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DealServicesCopyRequest.ts b/src/client/models/DealServicesCopyRequest.ts new file mode 100644 index 0000000..79a7f6e --- /dev/null +++ b/src/client/models/DealServicesCopyRequest.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealServicesCopyRequest = { + dealId: number; + sourceProductId: number; + destinationProductIds: Array; +}; + diff --git a/src/client/models/DealServicesCopyResponse.ts b/src/client/models/DealServicesCopyResponse.ts new file mode 100644 index 0000000..8132509 --- /dev/null +++ b/src/client/models/DealServicesCopyResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DealServicesCopyResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/GetAllServicesKitsResponse.ts b/src/client/models/GetAllServicesKitsResponse.ts new file mode 100644 index 0000000..0c2f7bc --- /dev/null +++ b/src/client/models/GetAllServicesKitsResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { GetServiceKitSchema } from './GetServiceKitSchema'; +export type GetAllServicesKitsResponse = { + servicesKits: Array; +}; + diff --git a/src/client/models/GetServiceKitSchema.ts b/src/client/models/GetServiceKitSchema.ts new file mode 100644 index 0000000..ca70bad --- /dev/null +++ b/src/client/models/GetServiceKitSchema.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ServiceSchema } from './ServiceSchema'; +export type GetServiceKitSchema = { + name: string; + serviceType: number; + id: number; + services: Array; +}; + diff --git a/src/client/models/UpdateServiceKitSchema.ts b/src/client/models/UpdateServiceKitSchema.ts new file mode 100644 index 0000000..82a743c --- /dev/null +++ b/src/client/models/UpdateServiceKitSchema.ts @@ -0,0 +1,11 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateServiceKitSchema = { + name: string; + serviceType: number; + id: number; + servicesIds: Array; +}; + diff --git a/src/client/models/UpdateServicesKitRequest.ts b/src/client/models/UpdateServicesKitRequest.ts new file mode 100644 index 0000000..445110b --- /dev/null +++ b/src/client/models/UpdateServicesKitRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { UpdateServiceKitSchema } from './UpdateServiceKitSchema'; +export type UpdateServicesKitRequest = { + data: UpdateServiceKitSchema; +}; + diff --git a/src/client/models/UpdateServicesKitResponse.ts b/src/client/models/UpdateServicesKitResponse.ts new file mode 100644 index 0000000..e27d701 --- /dev/null +++ b/src/client/models/UpdateServicesKitResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateServicesKitResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/services/DealService.ts b/src/client/services/DealService.ts index 825b1b1..497f3b8 100644 --- a/src/client/services/DealService.ts +++ b/src/client/services/DealService.ts @@ -2,6 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { DealAddKitRequest } from '../models/DealAddKitRequest'; +import type { DealAddKitResponse } from '../models/DealAddKitResponse'; import type { DealAddProductRequest } from '../models/DealAddProductRequest'; import type { DealAddProductResponse } from '../models/DealAddProductResponse'; import type { DealAddServiceRequest } from '../models/DealAddServiceRequest'; @@ -22,9 +24,13 @@ import type { DealDeleteServiceResponse } from '../models/DealDeleteServiceRespo import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest'; import type { DealDeleteServicesResponse } from '../models/DealDeleteServicesResponse'; import type { DealGetAllResponse } from '../models/DealGetAllResponse'; +import type { DealProductAddKitRequest } from '../models/DealProductAddKitRequest'; +import type { DealProductAddKitResponse } from '../models/DealProductAddKitResponse'; import type { DealQuickCreateRequest } from '../models/DealQuickCreateRequest'; import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse'; import type { DealSchema } from '../models/DealSchema'; +import type { DealServicesCopyRequest } from '../models/DealServicesCopyRequest'; +import type { DealServicesCopyResponse } from '../models/DealServicesCopyResponse'; import type { DealSummaryReorderRequest } from '../models/DealSummaryReorderRequest'; import type { DealSummaryResponse } from '../models/DealSummaryResponse'; import type { DealUpdateGeneralInfoRequest } from '../models/DealUpdateGeneralInfoRequest'; @@ -204,6 +210,26 @@ export class DealService { }, }); } + /** + * Add Kit To Deal + * @returns DealAddKitResponse Successful Response + * @throws ApiError + */ + public static addKitToDeal({ + requestBody, + }: { + requestBody: DealAddKitRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal/add-kit', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } /** * Services Add * @returns DealAddServicesResponse Successful Response @@ -324,6 +350,26 @@ export class DealService { }, }); } + /** + * Services Copy + * @returns DealServicesCopyResponse Successful Response + * @throws ApiError + */ + public static copyProductServices({ + requestBody, + }: { + requestBody: DealServicesCopyRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal/services/copy', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } /** * Products Update * @returns DealUpdateProductQuantityResponse Successful Response @@ -424,4 +470,24 @@ export class DealService { }, }); } + /** + * Add Kit To Deal Product + * @returns DealProductAddKitResponse Successful Response + * @throws ApiError + */ + public static addKitToDealProduct({ + requestBody, + }: { + requestBody: DealProductAddKitRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal/product/add-kit', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } } diff --git a/src/client/services/ServiceService.ts b/src/client/services/ServiceService.ts index d48b714..22867fd 100644 --- a/src/client/services/ServiceService.ts +++ b/src/client/services/ServiceService.ts @@ -3,6 +3,9 @@ /* tslint:disable */ /* eslint-disable */ import type { BaseEnumListSchema } from '../models/BaseEnumListSchema'; +import type { CreateServicesKitRequest } from '../models/CreateServicesKitRequest'; +import type { CreateServicesKitResponse } from '../models/CreateServicesKitResponse'; +import type { GetAllServicesKitsResponse } from '../models/GetAllServicesKitsResponse'; import type { ServiceCreateCategoryRequest } from '../models/ServiceCreateCategoryRequest'; import type { ServiceCreateCategoryResponse } from '../models/ServiceCreateCategoryResponse'; import type { ServiceCreateRequest } from '../models/ServiceCreateRequest'; @@ -13,6 +16,8 @@ import type { ServiceGetAllCategoriesResponse } from '../models/ServiceGetAllCat import type { ServiceGetAllResponse } from '../models/ServiceGetAllResponse'; import type { ServiceUpdateRequest } from '../models/ServiceUpdateRequest'; import type { ServiceUpdateResponse } from '../models/ServiceUpdateResponse'; +import type { UpdateServicesKitRequest } from '../models/UpdateServicesKitRequest'; +import type { UpdateServicesKitResponse } from '../models/UpdateServicesKitResponse'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; @@ -130,4 +135,55 @@ export class ServiceService { url: '/service/types/get-all', }); } + /** + * Get All Services Kits + * @returns GetAllServicesKitsResponse Successful Response + * @throws ApiError + */ + public static getAllServicesKits(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/service/kits/get-all', + }); + } + /** + * Create Services Kit + * @returns CreateServicesKitResponse Successful Response + * @throws ApiError + */ + public static createServicesKit({ + requestBody, + }: { + requestBody: CreateServicesKitRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/service/kits/create', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Services Kit + * @returns UpdateServicesKitResponse Successful Response + * @throws ApiError + */ + public static updateServicesKit({ + requestBody, + }: { + requestBody: UpdateServicesKitRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/service/kits/update', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } } diff --git a/src/components/ObjectMultiSelect/ObjectMultiSelect.tsx b/src/components/ObjectMultiSelect/ObjectMultiSelect.tsx index f72034b..1f13c42 100644 --- a/src/components/ObjectMultiSelect/ObjectMultiSelect.tsx +++ b/src/components/ObjectMultiSelect/ObjectMultiSelect.tsx @@ -1,42 +1,77 @@ import {MultiSelect, MultiSelectProps} from "@mantine/core"; import {useEffect, useMemo, useState} from "react"; -import {ObjectWithNameAndId} from "../../types/utils.ts"; +import {groupBy} from "lodash"; +interface ObjectWithIdAndName { + id: number, + name: string +} -export type MultiselectObjectType = T; +export type MultiselectObjectType = T; -type ControlledValueProps = { +type ControlledValueProps = { value: MultiselectObjectType[], onChange: (value: MultiselectObjectType[]) => void; } -type RestProps = { +type CustomLabelAndKeyProps = { + getLabelFn: (item: MultiselectObjectType) => string; + getValueFn: (item: MultiselectObjectType) => string; +} +type RestProps = { defaultValue?: MultiselectObjectType[] onChange: (value: MultiselectObjectType[]) => void; data: MultiselectObjectType[]; + groupBy?: (item: MultiselectObjectType) => string; + filterBy?: (item: MultiselectObjectType) => boolean; +} +const defaultGetLabelFn = (item: T): string => { + return item.name; } -export type ObjectMultiSelectProps = +const defaultGetValueFn = (item: T): string => { + return item.id.toString(); +} +export type ObjectMultiSelectProps = (RestProps & Partial>) - & Omit; + & Omit + & (T extends ObjectWithIdAndName ? Partial> : CustomLabelAndKeyProps); -const ObjectMultiSelect = (props: ObjectMultiSelectProps) => { +const ObjectMultiSelect = (props: ObjectMultiSelectProps) => { const isControlled = 'value' in props; + const haveGetValueFn = 'getValueFn' in props; + const haveGetLabelFn = 'getLabelFn' in props; + const [internalValue, setInternalValue] = useState[] | undefined>(props.defaultValue); const value = (isControlled ? props.value : internalValue) || []; - const data = useMemo(() => props.data.reduce((acc, item) => { - acc.push({ - label: item.name, - value: item.id.toString() - }); - return acc; - }, [] as { label: string, value: string }[]), [props.data]); + const getValueFn = (haveGetValueFn && props.getValueFn) || defaultGetValueFn; + const getLabelFn = (haveGetLabelFn && props.getLabelFn) || defaultGetLabelFn; + + const data = useMemo(() => { + const propsData = props.filterBy ? props.data.filter(props.filterBy) : props.data; + if (props.groupBy) { + + const groupedData = groupBy(propsData, props.groupBy); + return Object.entries(groupedData).map(([group, items]) => ({ + group, + items: items.map(item => ({ + label: getLabelFn(item), + value: getValueFn(item) + })) + })); + } else { + return propsData.map(item => ({ + label: getLabelFn(item), + value: getValueFn(item) + })); + } + }, [props.data, props.groupBy]); const handleOnChange = (event: string[]) => { - const objects = props.data.filter(item => event.includes(item.id.toString())); + const objects = props.data.filter(item => event.includes(getValueFn(item))); if (isControlled) { props.onChange(objects); return; @@ -51,7 +86,7 @@ const ObjectMultiSelect = (props: ObjectMultiSe return ( item.id.toString())} + value={value.map(item => getValueFn(item))} onChange={handleOnChange} data={data} /> diff --git a/src/components/Selects/ServicesKitSelect/ServicesKitSelect.tsx b/src/components/Selects/ServicesKitSelect/ServicesKitSelect.tsx new file mode 100644 index 0000000..832c1a4 --- /dev/null +++ b/src/components/Selects/ServicesKitSelect/ServicesKitSelect.tsx @@ -0,0 +1,17 @@ +import ObjectSelect, {ObjectSelectProps} from "../../ObjectSelect/ObjectSelect.tsx"; +import {GetServiceKitSchema} from "../../../client"; +import {FC} from "react"; +import useServicesKitsList from "../../../pages/ServicesPage/hooks/useServicesKitsList.tsx"; + +type Props = Omit, 'data'> +const ServicesKitSelect: FC = (props) => { + const {objects} = useServicesKitsList(); + return ( + + ) +} + +export default ServicesKitSelect; \ No newline at end of file diff --git a/src/components/Selects/ServicesMultiselect/ServicesMultiselect.tsx b/src/components/Selects/ServicesMultiselect/ServicesMultiselect.tsx new file mode 100644 index 0000000..97e2015 --- /dev/null +++ b/src/components/Selects/ServicesMultiselect/ServicesMultiselect.tsx @@ -0,0 +1,16 @@ +import ObjectMultiSelect, {ObjectMultiSelectProps} from "../../ObjectMultiSelect/ObjectMultiSelect.tsx"; +import {ServiceSchema} from "../../../client"; +import {FC} from "react"; +import useServicesList from "../../../pages/ServicesPage/hooks/useServicesList.tsx"; + +type Props = Omit, 'data'> +const ServicesMultiselect: FC = (props: Props) => { + const {services} = useServicesList(); + return ( + + ) +} +export default ServicesMultiselect; \ No newline at end of file diff --git a/src/modals/ServicesKitSelectModal/ServicesKitSelectModal.tsx b/src/modals/ServicesKitSelectModal/ServicesKitSelectModal.tsx new file mode 100644 index 0000000..92972a8 --- /dev/null +++ b/src/modals/ServicesKitSelectModal/ServicesKitSelectModal.tsx @@ -0,0 +1,60 @@ +import {GetServiceKitSchema} from "../../client"; +import {ContextModalProps} from "@mantine/modals"; +import {useState} from "react"; +import {Button, Flex, rem} from "@mantine/core"; +import ServicesKitSelect from "../../components/Selects/ServicesKitSelect/ServicesKitSelect.tsx"; +import {notifications} from "../../shared/lib/notifications.ts"; + +type Props = { + onSelect: (kit: GetServiceKitSchema) => void; + serviceType: number; +} + +const ServicesKitSelectModal = ({ + context, + id, + innerProps + }: ContextModalProps) => { + const [kit, setKit] = useState(); + const onSelectClick = () => { + if (!kit) { + notifications.error({message: "Выберите набор услуг"}); + return; + } + innerProps.onSelect(kit); + context.closeContextModal(id); + } + return ( + + + item.serviceType === innerProps.serviceType} + /> + + + + + + + + ) +} + +export default ServicesKitSelectModal; \ No newline at end of file diff --git a/src/modals/modals.ts b/src/modals/modals.ts index f194b1f..8980db3 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -16,6 +16,9 @@ import EmployeeTableModal from "./EmployeeTableModal/EmployeeTableModal.tsx"; import PositionFormModal from "./PositionFormModal/PositionFormModal.tsx"; import PayRateFormModal from "../pages/AdminPage/modals/PayRateFormModal/PayRateFormModal.tsx"; import CreatePaymentRecordModal from "../pages/AdminPage/modals/CreatePaymentRecordModal/CreatePaymentRecordModal.tsx"; +import ServiceKitModalForm from "../pages/ServicesPage/modals/ServicesKitModalForm.tsx"; +import ServicesKitSelectModal from "./ServicesKitSelectModal/ServicesKitSelectModal.tsx"; +import SelectDealProductsModal from "../pages/LeadsPage/modals/SelectDealProductsModal.tsx"; export const modals = { enterDeadline: EnterDeadlineModal, @@ -34,5 +37,8 @@ export const modals = { employeeTable: EmployeeTableModal, positionForm: PositionFormModal, payRateForm: PayRateFormModal, - createPaymentRecord: CreatePaymentRecordModal + createPaymentRecord: CreatePaymentRecordModal, + serviceKitModalForm: ServiceKitModalForm, + servicesKitSelectModal: ServicesKitSelectModal, + selectDealProductsModal: SelectDealProductsModal } diff --git a/src/pages/LeadsPage/modals/SelectDealProductsModal.tsx b/src/pages/LeadsPage/modals/SelectDealProductsModal.tsx new file mode 100644 index 0000000..2148078 --- /dev/null +++ b/src/pages/LeadsPage/modals/SelectDealProductsModal.tsx @@ -0,0 +1,64 @@ +import {DealProductSchema} from "../../../client"; +import {ContextModalProps} from "@mantine/modals"; +import {Button, Flex, rem} from "@mantine/core"; +import {useState} from "react"; +import ObjectMultiSelect from "../../../components/ObjectMultiSelect/ObjectMultiSelect.tsx"; +import {notifications} from "../../../shared/lib/notifications.ts"; + +type Props = { + dealProducts: DealProductSchema[]; + dealProduct: DealProductSchema; + onSelect: ( + sourceProduct: DealProductSchema, + destinationProducts: DealProductSchema[] + ) => void +} + +const SelectDealProductsModal = ({ + context, + id, + innerProps + }: ContextModalProps) => { + const [dealProducts, setDealProducts] = useState([]); + const onSelectClick = () => { + if (!dealProducts) { + notifications.error({message: "Выберите товары на которые необходимо продублировать услуги"}); + return; + } + innerProps.onSelect(innerProps.dealProduct, dealProducts); + context.closeContextModal(id); + } + return ( + + + + w={"100%"} + label={"Товары"} + placeholder={"Выберите товары на которые нужно продублировать услуги"} + onChange={setDealProducts} + value={dealProducts} + data={innerProps.dealProducts} + getLabelFn={item => item.product.name} + getValueFn={item => item.product.id.toString()} + filterBy={item => item !== innerProps.dealProduct} + /> + + + + + + + ) +} + +export default SelectDealProductsModal; \ No newline at end of file diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx b/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx index b560eb8..927f96b 100644 --- a/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx +++ b/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx @@ -5,6 +5,8 @@ import {Button, Flex, ScrollArea, Title} from "@mantine/core"; import DealServicesTable from "./components/DealServicesTable/DealServicesTable.tsx"; import useDealProductAndServiceTabState from "./hooks/useProductAndServiceTabState.tsx"; import {modals} from "@mantine/modals"; +import {DealProductSchema, DealService, GetServiceKitSchema} from "../../../../client"; +import {notifications} from "../../../../shared/lib/notifications.ts"; const ProductAndServiceTab: FC = () => { const {dealState, dealServicesState, dealProductsState} = useDealProductAndServiceTabState(); @@ -28,6 +30,64 @@ const ProductAndServiceTab: FC = () => { const dealServicesPrice = dealState.deal.services.reduce((acc, row) => acc + row.price * row.quantity, 0); return dealServicesPrice + productServicesPrice; } + const onCopyServices = ( + sourceProduct: DealProductSchema, + destinationProducts: DealProductSchema[] + ) => { + if (!dealState.deal) return; + DealService.copyProductServices({ + requestBody: { + dealId: dealState.deal.id, + destinationProductIds: destinationProducts.map(product => product.product.id), + sourceProductId: sourceProduct.product.id + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await dealState.refetch() + }) + } + const onCopyServicesClick = (product: DealProductSchema) => { + modals.openContextModal({ + modal: "selectDealProductsModal", + title: "Дублирование услуг", + size: "lg", + innerProps: { + dealProducts: dealState.deal?.products || [], + dealProduct: product, + onSelect: onCopyServices + }, + withCloseButton: false + }) + } + + const onKitAdd = (item: DealProductSchema, kit: GetServiceKitSchema) => { + if (!dealState.deal) return; + DealService.addKitToDealProduct({ + requestBody: { + dealId: dealState.deal.id, + kitId: kit.id, + productId: item.product.id + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await dealState.refetch(); + }); + } + const onDealKitAdd = (kit: GetServiceKitSchema) => { + if (!dealState.deal) return; + DealService.addKitToDeal({ + requestBody: { + dealId: dealState.deal.id, + kitId: kit.id, + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await dealState.refetch(); + }); + } return (
@@ -36,6 +96,8 @@ const ProductAndServiceTab: FC = () => { {dealState.deal?.products.map(product => ( {
diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx b/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx index cc6ae20..58312b1 100644 --- a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx +++ b/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx @@ -1,14 +1,18 @@ import {CRUDTableProps} from "../../../../../../types/CRUDTable.tsx"; -import {DealServiceSchema, UserSchema} from "../../../../../../client"; +import {DealServiceSchema, GetServiceKitSchema, UserSchema} from "../../../../../../client"; import {FC, useState} from "react"; import {ActionIcon, Button, Flex, Modal, NumberInput, rem, Text, Title, Tooltip} from "@mantine/core"; import {IconTrash, IconUsersGroup} from "@tabler/icons-react"; import {modals} from "@mantine/modals"; import {isNumber} from "lodash"; import SimpleUsersTable from "../../../../components/SimpleUsersTable/SimpleUsersTable.tsx"; +import {ServiceType} from "../../../../../../shared/enums/ServiceType.ts"; -type Props = CRUDTableProps; -const DealServicesTable: FC = ({items, onDelete, onCreate, onChange}) => { +type RestProps = { + onKitAdd?: (kit: GetServiceKitSchema) => void +}; +type Props = CRUDTableProps & RestProps; +const DealServicesTable: FC = ({items, onDelete, onCreate, onChange, onKitAdd}) => { const [currentService, setCurrentService] = useState(); const [employeesModalVisible, setEmployeesModalVisible] = useState(false); @@ -66,6 +70,17 @@ const DealServicesTable: FC = ({items, onDelete, onCreate, onChange}) => employees: items }); } + const onAddKitClick = () => { + if (!onKitAdd) return; + modals.openContextModal({ + modal: "servicesKitSelectModal", + innerProps: { + onSelect: onKitAdd, + serviceType: ServiceType.DEAL_SERVICE + }, + title: 'Печать штрихкода', + }) + } return ( <> = ({items, onDelete, onCreate, onChange}) => order={3} >Итог: {items.reduce((acc, item) => acc + (item.price * item.quantity), 0)}₽ - + + void; + onKitAdd?: () => void; } type Props = CRUDTableProps & RestProps; -const ProductServicesTable: FC = ({items, quantity, onCreate, onDelete, onChange}) => { +const ProductServicesTable: FC = ({ + items, + quantity, + onCreate, + onDelete, + onChange, + onCopyServices, + onKitAdd + }) => { const columns = useProductServicesTableColumns({data: items, quantity}); const serviceIds = items.map(service => service.service.id); @@ -85,6 +95,12 @@ const ProductServicesTable: FC = ({items, quantity, onCreate, onDelete, o enableBottomToolbar: true, renderBottomToolbar: ( + + - + { + serviceType === ServicesTab.SERVICES_KITS ? + : + <> + + + + } + {
- service.serviceType == serviceType)} - /> + { + serviceType === ServicesTab.SERVICES_KITS ? + + : + service.serviceType == serviceType)} + /> + }
)