diff --git a/fix-zod.ts b/fix-zod.ts index e886928..46a0006 100644 --- a/fix-zod.ts +++ b/fix-zod.ts @@ -4,7 +4,10 @@ const path = "src/lib/client/zod.gen.ts"; let content = fs.readFileSync(path, "utf8"); // Replace only for the upload schema -content = content.replace("upload_file: z.string", "upload_file: z.any"); +const target = "upload_file: z.string"; +while (content.includes(target)) { + content = content.replace(target, "upload_file: z.any"); +} fs.writeFileSync(path, content); console.log("✅ Fixed zod schema for upload_file"); diff --git a/src/app/products/contexts/ProductsContext.tsx b/src/app/products/contexts/ProductsContext.tsx index 815b888..b970c1e 100644 --- a/src/app/products/contexts/ProductsContext.tsx +++ b/src/app/products/contexts/ProductsContext.tsx @@ -18,6 +18,7 @@ export type ProductsFiltersForm = { type ProductsContextState = { productsFiltersForm: UseFormReturnType; + refetch: () => void; products: ProductSchema[]; productsCrud: ProductsCrud; paginationInfo?: PaginationInfoSchema; @@ -37,7 +38,7 @@ const useProductsContextState = (): ProductsContextState => { 500 ); - const { products, paginationInfo, queryKey } = useProductsList({ + const { products, paginationInfo, queryKey, refetch } = useProductsList({ clientId: productsFiltersForm.values.client?.id, searchInput: debouncedSearchInput, page: productsFiltersForm.values.page, @@ -47,6 +48,7 @@ const useProductsContextState = (): ProductsContextState => { return { productsFiltersForm, + refetch, products, productsCrud, paginationInfo, diff --git a/src/app/products/hooks/useProductsActions.ts b/src/app/products/hooks/useProductsActions.ts index f15965c..5925a33 100644 --- a/src/app/products/hooks/useProductsActions.ts +++ b/src/app/products/hooks/useProductsActions.ts @@ -4,7 +4,7 @@ import { ProductSchema } from "@/lib/client"; import { notifications } from "@/lib/notifications"; const useProductsActions = () => { - const { productsCrud, productsFiltersForm } = useProductsContext(); + const { productsCrud, productsFiltersForm, refetch } = useProductsContext(); const onCreateClick = () => { if (!productsFiltersForm.values.client) { @@ -19,6 +19,7 @@ const useProductsActions = () => { innerProps: { onCreate: productsCrud.onCreate, clientId: productsFiltersForm.values.client.id, + refetchProducts: refetch, isEditing: false, }, }); @@ -33,6 +34,7 @@ const useProductsActions = () => { onChange: updated => productsCrud.onUpdate(product.id, updated), clientId: product.clientId, entity: product, + refetchProducts: refetch, isEditing: true, }, }); diff --git a/src/lib/client/@tanstack/react-query.gen.ts b/src/lib/client/@tanstack/react-query.gen.ts index 1a0f813..58dee69 100644 --- a/src/lib/client/@tanstack/react-query.gen.ts +++ b/src/lib/client/@tanstack/react-query.gen.ts @@ -39,6 +39,7 @@ import { deleteDealTag, deleteMarketplace, deleteProduct, + deleteProductBarcodeImage, deleteProject, deleteService, deleteServiceCategory, @@ -84,6 +85,7 @@ import { updateServiceCategory, updateServicesKit, updateStatus, + uploadProductBarcodeImage, uploadProductImage, type Options, } from "../sdk.gen"; @@ -172,6 +174,9 @@ import type { DeleteMarketplaceData, DeleteMarketplaceError, DeleteMarketplaceResponse2, + DeleteProductBarcodeImageData, + DeleteProductBarcodeImageError, + DeleteProductBarcodeImageResponse, DeleteProductData, DeleteProductError, DeleteProductResponse2, @@ -275,6 +280,9 @@ import type { UpdateStatusData, UpdateStatusError, UpdateStatusResponse2, + UploadProductBarcodeImageData, + UploadProductBarcodeImageError, + UploadProductBarcodeImageResponse, UploadProductImageData, UploadProductImageError, UploadProductImageResponse, @@ -2292,6 +2300,84 @@ export const getProductBarcodePdfMutation = ( return mutationOptions; }; +export const uploadProductBarcodeImageQueryKey = ( + options: Options +) => createQueryKey("uploadProductBarcodeImage", options); + +/** + * Upload Product Barcode Image + */ +export const uploadProductBarcodeImageOptions = ( + options: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await uploadProductBarcodeImage({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: uploadProductBarcodeImageQueryKey(options), + }); +}; + +/** + * Upload Product Barcode Image + */ +export const uploadProductBarcodeImageMutation = ( + options?: Partial> +): UseMutationOptions< + UploadProductBarcodeImageResponse, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + UploadProductBarcodeImageResponse, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await uploadProductBarcodeImage({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Delete Product Barcode Image + */ +export const deleteProductBarcodeImageMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteProductBarcodeImageResponse, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteProductBarcodeImageResponse, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await deleteProductBarcodeImage({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + export const getServicesQueryKey = (options?: Options) => createQueryKey("getServices", options); diff --git a/src/lib/client/sdk.gen.ts b/src/lib/client/sdk.gen.ts index f8a54db..146d982 100644 --- a/src/lib/client/sdk.gen.ts +++ b/src/lib/client/sdk.gen.ts @@ -92,6 +92,9 @@ import type { DeleteMarketplaceData, DeleteMarketplaceErrors, DeleteMarketplaceResponses, + DeleteProductBarcodeImageData, + DeleteProductBarcodeImageErrors, + DeleteProductBarcodeImageResponses, DeleteProductData, DeleteProductErrors, DeleteProductResponses, @@ -220,6 +223,9 @@ import type { UpdateStatusData, UpdateStatusErrors, UpdateStatusResponses, + UploadProductBarcodeImageData, + UploadProductBarcodeImageErrors, + UploadProductBarcodeImageResponses, UploadProductImageData, UploadProductImageErrors, UploadProductImageResponses, @@ -281,6 +287,8 @@ import { zDeleteDealTagResponse2, zDeleteMarketplaceData, zDeleteMarketplaceResponse2, + zDeleteProductBarcodeImageData, + zDeleteProductBarcodeImageResponse, zDeleteProductData, zDeleteProductResponse2, zDeleteProjectData, @@ -373,6 +381,8 @@ import { zUpdateServicesKitResponse2, zUpdateStatusData, zUpdateStatusResponse2, + zUploadProductBarcodeImageData, + zUploadProductBarcodeImageResponse, zUploadProductImageData, zUploadProductImageResponse, } from "./zod.gen"; @@ -1719,7 +1729,7 @@ export const uploadProductImage = ( responseValidator: async data => { return await zUploadProductImageResponse.parseAsync(data); }, - url: "/crm/v1/fulfillment-base/product/images/upload/{productId}", + url: "/crm/v1/fulfillment-base/product{pk}/images/upload", ...options, headers: { "Content-Type": null, @@ -1755,6 +1765,57 @@ export const getProductBarcodePdf = ( }); }; +/** + * Upload Product Barcode Image + */ +export const uploadProductBarcodeImage = ( + options: Options +) => { + return (options.client ?? _heyApiClient).post< + UploadProductBarcodeImageResponses, + UploadProductBarcodeImageErrors, + ThrowOnError + >({ + ...formDataBodySerializer, + requestValidator: async data => { + return await zUploadProductBarcodeImageData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zUploadProductBarcodeImageResponse.parseAsync(data); + }, + url: "/crm/v1/fulfillment-base/product{pk}/barcode/image/upload", + ...options, + headers: { + "Content-Type": null, + ...options.headers, + }, + }); +}; + +/** + * Delete Product Barcode Image + */ +export const deleteProductBarcodeImage = ( + options: Options +) => { + return (options.client ?? _heyApiClient).delete< + DeleteProductBarcodeImageResponses, + DeleteProductBarcodeImageErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zDeleteProductBarcodeImageData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zDeleteProductBarcodeImageResponse.parseAsync(data); + }, + url: "/crm/v1/fulfillment-base/product{pk}/barcode/image", + ...options, + }); +}; + /** * Get Services */ diff --git a/src/lib/client/types.gen.ts b/src/lib/client/types.gen.ts index a492b0a..902899f 100644 --- a/src/lib/client/types.gen.ts +++ b/src/lib/client/types.gen.ts @@ -63,6 +63,20 @@ export type BarcodeTemplateSizeSchema = { height: number; }; +/** + * BarcodeUploadImageResponse + */ +export type BarcodeUploadImageResponse = { + /** + * Message + */ + message: string; + /** + * Imageurl + */ + imageUrl?: string | null; +}; + /** * BaseMarketplaceSchema */ @@ -103,6 +117,16 @@ export type BoardSchema = { projectId: number; }; +/** + * Body_upload_product_barcode_image + */ +export type BodyUploadProductBarcodeImage = { + /** + * Upload File + */ + upload_file: Blob | File; +}; + /** * Body_upload_product_image */ @@ -639,15 +663,7 @@ export type CreateProductSchema = { /** * Barcodes */ - barcodes: Array; - /** - * Imageurl - */ - imageUrl?: string | null; - /** - * Images - */ - images?: Array | null; + barcodes?: Array; }; /** @@ -1090,6 +1106,16 @@ export type DealTagSchema = { tagColor: DealTagColorSchema; }; +/** + * DeleteBarcodeImageResponse + */ +export type DeleteBarcodeImageResponse = { + /** + * Message + */ + message: string; +}; + /** * DeleteBarcodeTemplateResponse */ @@ -1538,6 +1564,20 @@ export type PaginationInfoSchema = { totalItems: number; }; +/** + * ProductBarcodeImageSchema + */ +export type ProductBarcodeImageSchema = { + /** + * Productid + */ + productId: number; + /** + * Imageurl + */ + imageUrl: string; +}; + /** * ProductImageSchema */ @@ -1603,7 +1643,7 @@ export type ProductSchema = { /** * Barcodes */ - barcodes: Array; + barcodes?: Array; /** * Imageurl */ @@ -1612,6 +1652,11 @@ export type ProductSchema = { * Images */ images?: Array | null; + /** + * Barcodeimageurl + */ + barcodeImageUrl?: string | null; + barcodeImage?: ProductBarcodeImageSchema | null; /** * Id */ @@ -4073,12 +4118,12 @@ export type UploadProductImageData = { body: BodyUploadProductImage; path: { /** - * Productid + * Pk */ - productId: number; + pk: number; }; query?: never; - url: "/crm/v1/fulfillment-base/product/images/upload/{productId}"; + url: "/crm/v1/fulfillment-base/product{pk}/images/upload"; }; export type UploadProductImageErrors = { @@ -4128,6 +4173,70 @@ export type GetProductBarcodePdfResponses = { export type GetProductBarcodePdfResponse2 = GetProductBarcodePdfResponses[keyof GetProductBarcodePdfResponses]; +export type UploadProductBarcodeImageData = { + body: BodyUploadProductBarcodeImage; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/fulfillment-base/product{pk}/barcode/image/upload"; +}; + +export type UploadProductBarcodeImageErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UploadProductBarcodeImageError = + UploadProductBarcodeImageErrors[keyof UploadProductBarcodeImageErrors]; + +export type UploadProductBarcodeImageResponses = { + /** + * Successful Response + */ + 200: BarcodeUploadImageResponse; +}; + +export type UploadProductBarcodeImageResponse = + UploadProductBarcodeImageResponses[keyof UploadProductBarcodeImageResponses]; + +export type DeleteProductBarcodeImageData = { + body?: never; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/fulfillment-base/product{pk}/barcode/image"; +}; + +export type DeleteProductBarcodeImageErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteProductBarcodeImageError = + DeleteProductBarcodeImageErrors[keyof DeleteProductBarcodeImageErrors]; + +export type DeleteProductBarcodeImageResponses = { + /** + * Successful Response + */ + 200: DeleteBarcodeImageResponse; +}; + +export type DeleteProductBarcodeImageResponse = + DeleteProductBarcodeImageResponses[keyof DeleteProductBarcodeImageResponses]; + export type GetServicesData = { body?: never; path?: never; diff --git a/src/lib/client/zod.gen.ts b/src/lib/client/zod.gen.ts index a222183..954d107 100644 --- a/src/lib/client/zod.gen.ts +++ b/src/lib/client/zod.gen.ts @@ -32,6 +32,14 @@ export const zBarcodeTemplateSchema = z.object({ id: z.int(), }); +/** + * BarcodeUploadImageResponse + */ +export const zBarcodeUploadImageResponse = z.object({ + message: z.string(), + imageUrl: z.optional(z.union([z.string(), z.null()])), +}); + /** * BaseMarketplaceSchema */ @@ -51,6 +59,13 @@ export const zBoardSchema = z.object({ projectId: z.int(), }); +/** + * Body_upload_product_barcode_image + */ +export const zBodyUploadProductBarcodeImage = z.object({ + upload_file: z.any(), +}); + /** * Body_upload_product_image */ @@ -250,6 +265,14 @@ export const zProductImageSchema = z.object({ imageUrl: z.string(), }); +/** + * ProductBarcodeImageSchema + */ +export const zProductBarcodeImageSchema = z.object({ + productId: z.int(), + imageUrl: z.string(), +}); + /** * ProductSchema */ @@ -264,9 +287,11 @@ export const zProductSchema = z.object({ composition: z.union([z.string(), z.null()]), size: z.union([z.string(), z.null()]), additionalInfo: z.union([z.string(), z.null()]), - barcodes: z.array(z.string()), + barcodes: z.optional(z.array(z.string())).default([]), imageUrl: z.optional(z.union([z.string(), z.null()])), images: z.optional(z.union([z.array(zProductImageSchema), z.null()])), + barcodeImageUrl: z.optional(z.union([z.string(), z.null()])), + barcodeImage: z.optional(z.union([zProductBarcodeImageSchema, z.null()])), id: z.int(), barcodeTemplate: zBarcodeTemplateSchema, }); @@ -526,9 +551,7 @@ export const zCreateProductSchema = z.object({ composition: z.union([z.string(), z.null()]), size: z.union([z.string(), z.null()]), additionalInfo: z.union([z.string(), z.null()]), - barcodes: z.array(z.string()), - imageUrl: z.optional(z.union([z.string(), z.null()])), - images: z.optional(z.union([z.array(zProductImageSchema), z.null()])), + barcodes: z.optional(z.array(z.string())).default([]), }); /** @@ -746,6 +769,13 @@ export const zDealProductAddKitResponse = z.object({ message: z.string(), }); +/** + * DeleteBarcodeImageResponse + */ +export const zDeleteBarcodeImageResponse = z.object({ + message: z.string(), +}); + /** * DeleteBarcodeTemplateResponse */ @@ -2161,7 +2191,7 @@ export const zUpdateProductResponse2 = zUpdateProductResponse; export const zUploadProductImageData = z.object({ body: zBodyUploadProductImage, path: z.object({ - productId: z.int(), + pk: z.int(), }), query: z.optional(z.never()), }); @@ -2182,6 +2212,32 @@ export const zGetProductBarcodePdfData = z.object({ */ export const zGetProductBarcodePdfResponse2 = zGetProductBarcodePdfResponse; +export const zUploadProductBarcodeImageData = z.object({ + body: zBodyUploadProductBarcodeImage, + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zUploadProductBarcodeImageResponse = zBarcodeUploadImageResponse; + +export const zDeleteProductBarcodeImageData = z.object({ + body: z.optional(z.never()), + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zDeleteProductBarcodeImageResponse = zDeleteBarcodeImageResponse; + export const zGetServicesData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/DealInfoView/components/ProductsActions/ProductsActions.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/DealInfoView/components/ProductsActions/ProductsActions.tsx index 07a69ca..fc2914c 100644 --- a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/DealInfoView/components/ProductsActions/ProductsActions.tsx +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/DealInfoView/components/ProductsActions/ProductsActions.tsx @@ -22,6 +22,7 @@ const ProductsActions: FC = () => { onCreate: productsCrud.onCreate, isEditing: false, clientId: deal.client.id, + refetchProducts: dealProductsList.refetch, }, }); }; diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductView/components/ProductViewActions.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductView/components/ProductViewActions.tsx index 8c6e27b..93c1539 100644 --- a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductView/components/ProductViewActions.tsx +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductView/components/ProductViewActions.tsx @@ -29,6 +29,7 @@ const ProductViewActions: FC = ({ dealProduct }) => { entity: dealProduct.product, isEditing: true, clientId: dealProduct.product.clientId, + refetchProducts: dealProductsList.refetch, }, }); }; diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/BarcodeImageDropzone/BarcodeImageDropzone.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/BarcodeImageDropzone/BarcodeImageDropzone.tsx new file mode 100644 index 0000000..0d1ee86 --- /dev/null +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/BarcodeImageDropzone/BarcodeImageDropzone.tsx @@ -0,0 +1,182 @@ +import { FC } from "react"; +import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react"; +import { Fieldset, Flex, Group, Loader, rem, Text } from "@mantine/core"; +import { Dropzone, DropzoneProps, FileWithPath } from "@mantine/dropzone"; +import InlineButton from "@/components/ui/InlineButton/InlineButton"; +import { deleteProductBarcodeImage, uploadProductBarcodeImage } from "@/lib/client"; +import { notifications } from "@/lib/notifications"; +import useImageDropzone from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/useImageDropzone"; +import BaseFormInputProps from "@/utils/baseFormInputProps"; + + +// Barcode image aspects ratio should be equal 58/40 +const BARCODE_IMAGE_RATIO = 1.45; + +interface RestProps { + imageUrlInputProps?: BaseFormInputProps; + productId?: number; + onUploaded?: () => void; +} + +type Props = Omit & RestProps; + +const BarcodeImageDropzone: FC = ({ + productId, + imageUrlInputProps, + onUploaded, +}: Props) => { + const imageDropzoneProps = useImageDropzone({ + imageUrlInputProps, + }); + + const onDeleteBarcodeImage = () => { + if (!productId || !imageUrlInputProps) return; + const { setIsLoading } = imageDropzoneProps; + setIsLoading(true); + + deleteProductBarcodeImage({ + path: { + pk: productId, + }, + }) + .then(({ data }) => { + notifications.success({ message: data?.message }); + imageUrlInputProps.onChange(""); + setIsLoading(false); + onUploaded && onUploaded(); + }) + .catch(err => { + console.log(err); + notifications.error({ message: err.toString() }); + setIsLoading(false); + }); + }; + + const onDrop = (files: FileWithPath[]) => { + if (!productId || !imageUrlInputProps) return; + if (files.length > 1) { + notifications.error({ message: "Прикрепите одно изображение" }); + return; + } + const { setIsLoading, setShowDropzone } = imageDropzoneProps; + const file = files[0]; + + setIsLoading(true); + + uploadProductBarcodeImage({ + path: { + pk: productId, + }, + body: { + upload_file: file, + }, + }) + .then(({ data }) => { + notifications.success({ message: data?.message }); + setIsLoading(false); + + if (!data?.imageUrl) { + setShowDropzone(true); + return; + } + imageUrlInputProps.onChange(data?.imageUrl); + setShowDropzone(false); + onUploaded && onUploaded(); + }) + .catch(err => { + console.log(err); + notifications.error({ message: err.toString() }); + setShowDropzone(true); + setIsLoading(false); + }); + }; + + const getBody = () => { + return imageUrlInputProps?.value ? ( + // eslint-disable-next-line jsx-a11y/alt-text + + ) : ( + + + + + + + + + + + + +
+ + Перенесите или нажмите чтоб выбрать файл
+ Pdf-файл должен содержать 1 страницу размером 58 х + 40 +
+
+
+
+ ); + }; + + return ( + +
+ + {imageDropzoneProps.isLoading ? : getBody()} + +
+ {imageUrlInputProps?.value && ( + <> + imageUrlInputProps?.onChange("")}> + Заменить штрихкод + + + Удалить штрихкод + + + )} +
+ ); +}; + +export default BarcodeImageDropzone; diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/ProductImageDropzone.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/ProductImageDropzone.tsx similarity index 94% rename from src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/ProductImageDropzone.tsx rename to src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/ProductImageDropzone.tsx index c5d5b9b..e0f81b5 100644 --- a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/ProductImageDropzone.tsx +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/ProductImageDropzone.tsx @@ -9,6 +9,7 @@ import useImageDropzone from "./useImageDropzone"; interface RestProps { imageUrlInputProps?: BaseFormInputProps; productId?: number; + onUploaded?: () => void; } type Props = Omit & RestProps; @@ -16,6 +17,7 @@ type Props = Omit & RestProps; const ProductImageDropzone: FC = ({ imageUrlInputProps, productId, + onUploaded, }: Props) => { const imageDropzoneProps = useImageDropzone({ imageUrlInputProps, @@ -34,7 +36,7 @@ const ProductImageDropzone: FC = ({ uploadProductImage({ path: { - productId, + pk: productId, }, body: { upload_file: file, @@ -50,6 +52,7 @@ const ProductImageDropzone: FC = ({ } imageUrlInputProps?.onChange(data?.imageUrl); setShowDropzone(false); + onUploaded && onUploaded(); }) .catch(err => { console.log(err); diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/useImageDropzone.ts b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/useImageDropzone.ts similarity index 100% rename from src/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/useImageDropzone.ts rename to src/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/useImageDropzone.ts diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/ProductEditorModal.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/ProductEditorModal.tsx index 87eccf8..5fa96b1 100644 --- a/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/ProductEditorModal.tsx +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/ProductEditorModal.tsx @@ -1,10 +1,9 @@ "use client"; import { useState } from "react"; -import { Fieldset, Flex, Stack, TagsInput, TextInput } from "@mantine/core"; +import { Flex } from "@mantine/core"; import { useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; -import BarcodeTemplateSelect from "@/app/products/components/shared/BarcodeTemplateSelect/BarcodeTemplateSelect"; import { BarcodeTemplateSchema, CreateProductSchema, @@ -14,11 +13,11 @@ import { import BaseFormModal, { CreateEditFormProps, } from "@/modals/base/BaseFormModal/BaseFormModal"; -import ProductImageDropzone from "@/modules/dealModularEditorTabs/FulfillmentBase/desktop/components/ProductImageDropzone/ProductImageDropzone"; +import CharacteristicsTab from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/CharacteristicsTab"; +import ImagesTab from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ImagesTab"; import ProductEditorSegmentedControl, { ProductEditorTab, } from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ProductEditorSegmentedControl"; -import BaseFormInputProps from "@/utils/baseFormInputProps"; type Props = CreateEditFormProps< CreateProductSchema, @@ -26,6 +25,7 @@ type Props = CreateEditFormProps< ProductSchema > & { clientId: number; + refetchProducts: () => void; }; type ProductForm = Partial< @@ -64,92 +64,18 @@ const ProductEditorModal = ({ initialValues, validate: { name: name => - !name || name.trim() !== "" - ? null - : "Необходимо ввести название товара", + (!name || name.trim() === "") && + "Необходимо ввести название товара", + barcodeTemplate: barcodeTemplate => + !barcodeTemplate && "Необходимо выбрать шаблон штрихкода", }, }); - const characteristicsTab = ( - <> -
- - - - - { - form.setFieldValue("barcodeTemplate", template); - form.setFieldValue( - "barcodeTemplateId", - template?.id - ); - }} - /> - - -
-
- - - - - - - -
- - ); - const imageTab = isEditing && ( - - } + ); @@ -169,9 +95,11 @@ const ProductEditorModal = ({ onChange={setEditorTab} /> )} - {editorTab === ProductEditorTab.CHARACTERISTICS - ? characteristicsTab - : imageTab} + {editorTab === ProductEditorTab.CHARACTERISTICS ? ( + + ) : ( + imageTab + )} ); diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/CharacteristicsTab.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/CharacteristicsTab.tsx new file mode 100644 index 0000000..4eb4d1f --- /dev/null +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/CharacteristicsTab.tsx @@ -0,0 +1,87 @@ +import { FC } from "react"; +import { Fieldset, Stack, TagsInput, TextInput } from "@mantine/core"; +import BarcodeTemplateSelect from "@/app/products/components/shared/BarcodeTemplateSelect/BarcodeTemplateSelect"; +import { UseFormReturnType } from "@mantine/form"; +import { ProductSchema } from "@/lib/client"; + +type Props = { + form: UseFormReturnType>; +} + +const CharacteristicsTab: FC = ({ form }) => ( + <> +
+ + + + + { + form.setFieldValue("barcodeTemplate", template); + form.setFieldValue( + "barcodeTemplateId", + template?.id + ); + }} + withAsterisk + /> + + +
+
+ + + + + + + +
+ +) + +export default CharacteristicsTab; diff --git a/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ImagesTab.tsx b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ImagesTab.tsx new file mode 100644 index 0000000..b7aa3d5 --- /dev/null +++ b/src/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ImagesTab.tsx @@ -0,0 +1,36 @@ +import { FC } from "react"; +import { Stack } from "@mantine/core"; +import { UseFormReturnType } from "@mantine/form"; +import { ProductSchema } from "@/lib/client"; +import BarcodeImageDropzone from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/components/BarcodeImageDropzone/BarcodeImageDropzone"; +import ProductImageDropzone from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/components/ProductImageDropzone/ProductImageDropzone"; +import BaseFormInputProps from "@/utils/baseFormInputProps"; + +type Props = { + form: UseFormReturnType>; + productId: number; + onUploaded: () => void; +}; + +const ImagesTab: FC = ({ form, productId, onUploaded }) => ( + + + } + productId={productId} + onUploaded={onUploaded} + /> + + } + productId={productId} + onUploaded={onUploaded} + /> + +); + +export default ImagesTab;