feat: product barcode images
This commit is contained in:
@ -4,7 +4,10 @@ const path = "src/lib/client/zod.gen.ts";
|
|||||||
let content = fs.readFileSync(path, "utf8");
|
let content = fs.readFileSync(path, "utf8");
|
||||||
|
|
||||||
// Replace only for the upload schema
|
// 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);
|
fs.writeFileSync(path, content);
|
||||||
console.log("✅ Fixed zod schema for upload_file");
|
console.log("✅ Fixed zod schema for upload_file");
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export type ProductsFiltersForm = {
|
|||||||
|
|
||||||
type ProductsContextState = {
|
type ProductsContextState = {
|
||||||
productsFiltersForm: UseFormReturnType<ProductsFiltersForm>;
|
productsFiltersForm: UseFormReturnType<ProductsFiltersForm>;
|
||||||
|
refetch: () => void;
|
||||||
products: ProductSchema[];
|
products: ProductSchema[];
|
||||||
productsCrud: ProductsCrud;
|
productsCrud: ProductsCrud;
|
||||||
paginationInfo?: PaginationInfoSchema;
|
paginationInfo?: PaginationInfoSchema;
|
||||||
@ -37,7 +38,7 @@ const useProductsContextState = (): ProductsContextState => {
|
|||||||
500
|
500
|
||||||
);
|
);
|
||||||
|
|
||||||
const { products, paginationInfo, queryKey } = useProductsList({
|
const { products, paginationInfo, queryKey, refetch } = useProductsList({
|
||||||
clientId: productsFiltersForm.values.client?.id,
|
clientId: productsFiltersForm.values.client?.id,
|
||||||
searchInput: debouncedSearchInput,
|
searchInput: debouncedSearchInput,
|
||||||
page: productsFiltersForm.values.page,
|
page: productsFiltersForm.values.page,
|
||||||
@ -47,6 +48,7 @@ const useProductsContextState = (): ProductsContextState => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
productsFiltersForm,
|
productsFiltersForm,
|
||||||
|
refetch,
|
||||||
products,
|
products,
|
||||||
productsCrud,
|
productsCrud,
|
||||||
paginationInfo,
|
paginationInfo,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { ProductSchema } from "@/lib/client";
|
|||||||
import { notifications } from "@/lib/notifications";
|
import { notifications } from "@/lib/notifications";
|
||||||
|
|
||||||
const useProductsActions = () => {
|
const useProductsActions = () => {
|
||||||
const { productsCrud, productsFiltersForm } = useProductsContext();
|
const { productsCrud, productsFiltersForm, refetch } = useProductsContext();
|
||||||
|
|
||||||
const onCreateClick = () => {
|
const onCreateClick = () => {
|
||||||
if (!productsFiltersForm.values.client) {
|
if (!productsFiltersForm.values.client) {
|
||||||
@ -19,6 +19,7 @@ const useProductsActions = () => {
|
|||||||
innerProps: {
|
innerProps: {
|
||||||
onCreate: productsCrud.onCreate,
|
onCreate: productsCrud.onCreate,
|
||||||
clientId: productsFiltersForm.values.client.id,
|
clientId: productsFiltersForm.values.client.id,
|
||||||
|
refetchProducts: refetch,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -33,6 +34,7 @@ const useProductsActions = () => {
|
|||||||
onChange: updated => productsCrud.onUpdate(product.id, updated),
|
onChange: updated => productsCrud.onUpdate(product.id, updated),
|
||||||
clientId: product.clientId,
|
clientId: product.clientId,
|
||||||
entity: product,
|
entity: product,
|
||||||
|
refetchProducts: refetch,
|
||||||
isEditing: true,
|
isEditing: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import {
|
|||||||
deleteDealTag,
|
deleteDealTag,
|
||||||
deleteMarketplace,
|
deleteMarketplace,
|
||||||
deleteProduct,
|
deleteProduct,
|
||||||
|
deleteProductBarcodeImage,
|
||||||
deleteProject,
|
deleteProject,
|
||||||
deleteService,
|
deleteService,
|
||||||
deleteServiceCategory,
|
deleteServiceCategory,
|
||||||
@ -84,6 +85,7 @@ import {
|
|||||||
updateServiceCategory,
|
updateServiceCategory,
|
||||||
updateServicesKit,
|
updateServicesKit,
|
||||||
updateStatus,
|
updateStatus,
|
||||||
|
uploadProductBarcodeImage,
|
||||||
uploadProductImage,
|
uploadProductImage,
|
||||||
type Options,
|
type Options,
|
||||||
} from "../sdk.gen";
|
} from "../sdk.gen";
|
||||||
@ -172,6 +174,9 @@ import type {
|
|||||||
DeleteMarketplaceData,
|
DeleteMarketplaceData,
|
||||||
DeleteMarketplaceError,
|
DeleteMarketplaceError,
|
||||||
DeleteMarketplaceResponse2,
|
DeleteMarketplaceResponse2,
|
||||||
|
DeleteProductBarcodeImageData,
|
||||||
|
DeleteProductBarcodeImageError,
|
||||||
|
DeleteProductBarcodeImageResponse,
|
||||||
DeleteProductData,
|
DeleteProductData,
|
||||||
DeleteProductError,
|
DeleteProductError,
|
||||||
DeleteProductResponse2,
|
DeleteProductResponse2,
|
||||||
@ -275,6 +280,9 @@ import type {
|
|||||||
UpdateStatusData,
|
UpdateStatusData,
|
||||||
UpdateStatusError,
|
UpdateStatusError,
|
||||||
UpdateStatusResponse2,
|
UpdateStatusResponse2,
|
||||||
|
UploadProductBarcodeImageData,
|
||||||
|
UploadProductBarcodeImageError,
|
||||||
|
UploadProductBarcodeImageResponse,
|
||||||
UploadProductImageData,
|
UploadProductImageData,
|
||||||
UploadProductImageError,
|
UploadProductImageError,
|
||||||
UploadProductImageResponse,
|
UploadProductImageResponse,
|
||||||
@ -2292,6 +2300,84 @@ export const getProductBarcodePdfMutation = (
|
|||||||
return mutationOptions;
|
return mutationOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const uploadProductBarcodeImageQueryKey = (
|
||||||
|
options: Options<UploadProductBarcodeImageData>
|
||||||
|
) => createQueryKey("uploadProductBarcodeImage", options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload Product Barcode Image
|
||||||
|
*/
|
||||||
|
export const uploadProductBarcodeImageOptions = (
|
||||||
|
options: Options<UploadProductBarcodeImageData>
|
||||||
|
) => {
|
||||||
|
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<Options<UploadProductBarcodeImageData>>
|
||||||
|
): UseMutationOptions<
|
||||||
|
UploadProductBarcodeImageResponse,
|
||||||
|
AxiosError<UploadProductBarcodeImageError>,
|
||||||
|
Options<UploadProductBarcodeImageData>
|
||||||
|
> => {
|
||||||
|
const mutationOptions: UseMutationOptions<
|
||||||
|
UploadProductBarcodeImageResponse,
|
||||||
|
AxiosError<UploadProductBarcodeImageError>,
|
||||||
|
Options<UploadProductBarcodeImageData>
|
||||||
|
> = {
|
||||||
|
mutationFn: async localOptions => {
|
||||||
|
const { data } = await uploadProductBarcodeImage({
|
||||||
|
...options,
|
||||||
|
...localOptions,
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Product Barcode Image
|
||||||
|
*/
|
||||||
|
export const deleteProductBarcodeImageMutation = (
|
||||||
|
options?: Partial<Options<DeleteProductBarcodeImageData>>
|
||||||
|
): UseMutationOptions<
|
||||||
|
DeleteProductBarcodeImageResponse,
|
||||||
|
AxiosError<DeleteProductBarcodeImageError>,
|
||||||
|
Options<DeleteProductBarcodeImageData>
|
||||||
|
> => {
|
||||||
|
const mutationOptions: UseMutationOptions<
|
||||||
|
DeleteProductBarcodeImageResponse,
|
||||||
|
AxiosError<DeleteProductBarcodeImageError>,
|
||||||
|
Options<DeleteProductBarcodeImageData>
|
||||||
|
> = {
|
||||||
|
mutationFn: async localOptions => {
|
||||||
|
const { data } = await deleteProductBarcodeImage({
|
||||||
|
...options,
|
||||||
|
...localOptions,
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
export const getServicesQueryKey = (options?: Options<GetServicesData>) =>
|
export const getServicesQueryKey = (options?: Options<GetServicesData>) =>
|
||||||
createQueryKey("getServices", options);
|
createQueryKey("getServices", options);
|
||||||
|
|
||||||
|
|||||||
@ -92,6 +92,9 @@ import type {
|
|||||||
DeleteMarketplaceData,
|
DeleteMarketplaceData,
|
||||||
DeleteMarketplaceErrors,
|
DeleteMarketplaceErrors,
|
||||||
DeleteMarketplaceResponses,
|
DeleteMarketplaceResponses,
|
||||||
|
DeleteProductBarcodeImageData,
|
||||||
|
DeleteProductBarcodeImageErrors,
|
||||||
|
DeleteProductBarcodeImageResponses,
|
||||||
DeleteProductData,
|
DeleteProductData,
|
||||||
DeleteProductErrors,
|
DeleteProductErrors,
|
||||||
DeleteProductResponses,
|
DeleteProductResponses,
|
||||||
@ -220,6 +223,9 @@ import type {
|
|||||||
UpdateStatusData,
|
UpdateStatusData,
|
||||||
UpdateStatusErrors,
|
UpdateStatusErrors,
|
||||||
UpdateStatusResponses,
|
UpdateStatusResponses,
|
||||||
|
UploadProductBarcodeImageData,
|
||||||
|
UploadProductBarcodeImageErrors,
|
||||||
|
UploadProductBarcodeImageResponses,
|
||||||
UploadProductImageData,
|
UploadProductImageData,
|
||||||
UploadProductImageErrors,
|
UploadProductImageErrors,
|
||||||
UploadProductImageResponses,
|
UploadProductImageResponses,
|
||||||
@ -281,6 +287,8 @@ import {
|
|||||||
zDeleteDealTagResponse2,
|
zDeleteDealTagResponse2,
|
||||||
zDeleteMarketplaceData,
|
zDeleteMarketplaceData,
|
||||||
zDeleteMarketplaceResponse2,
|
zDeleteMarketplaceResponse2,
|
||||||
|
zDeleteProductBarcodeImageData,
|
||||||
|
zDeleteProductBarcodeImageResponse,
|
||||||
zDeleteProductData,
|
zDeleteProductData,
|
||||||
zDeleteProductResponse2,
|
zDeleteProductResponse2,
|
||||||
zDeleteProjectData,
|
zDeleteProjectData,
|
||||||
@ -373,6 +381,8 @@ import {
|
|||||||
zUpdateServicesKitResponse2,
|
zUpdateServicesKitResponse2,
|
||||||
zUpdateStatusData,
|
zUpdateStatusData,
|
||||||
zUpdateStatusResponse2,
|
zUpdateStatusResponse2,
|
||||||
|
zUploadProductBarcodeImageData,
|
||||||
|
zUploadProductBarcodeImageResponse,
|
||||||
zUploadProductImageData,
|
zUploadProductImageData,
|
||||||
zUploadProductImageResponse,
|
zUploadProductImageResponse,
|
||||||
} from "./zod.gen";
|
} from "./zod.gen";
|
||||||
@ -1719,7 +1729,7 @@ export const uploadProductImage = <ThrowOnError extends boolean = false>(
|
|||||||
responseValidator: async data => {
|
responseValidator: async data => {
|
||||||
return await zUploadProductImageResponse.parseAsync(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,
|
...options,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": null,
|
"Content-Type": null,
|
||||||
@ -1755,6 +1765,57 @@ export const getProductBarcodePdf = <ThrowOnError extends boolean = false>(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload Product Barcode Image
|
||||||
|
*/
|
||||||
|
export const uploadProductBarcodeImage = <ThrowOnError extends boolean = false>(
|
||||||
|
options: Options<UploadProductBarcodeImageData, ThrowOnError>
|
||||||
|
) => {
|
||||||
|
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 = <ThrowOnError extends boolean = false>(
|
||||||
|
options: Options<DeleteProductBarcodeImageData, ThrowOnError>
|
||||||
|
) => {
|
||||||
|
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
|
* Get Services
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -63,6 +63,20 @@ export type BarcodeTemplateSizeSchema = {
|
|||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BarcodeUploadImageResponse
|
||||||
|
*/
|
||||||
|
export type BarcodeUploadImageResponse = {
|
||||||
|
/**
|
||||||
|
* Message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
/**
|
||||||
|
* Imageurl
|
||||||
|
*/
|
||||||
|
imageUrl?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BaseMarketplaceSchema
|
* BaseMarketplaceSchema
|
||||||
*/
|
*/
|
||||||
@ -103,6 +117,16 @@ export type BoardSchema = {
|
|||||||
projectId: number;
|
projectId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Body_upload_product_barcode_image
|
||||||
|
*/
|
||||||
|
export type BodyUploadProductBarcodeImage = {
|
||||||
|
/**
|
||||||
|
* Upload File
|
||||||
|
*/
|
||||||
|
upload_file: Blob | File;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Body_upload_product_image
|
* Body_upload_product_image
|
||||||
*/
|
*/
|
||||||
@ -639,15 +663,7 @@ export type CreateProductSchema = {
|
|||||||
/**
|
/**
|
||||||
* Barcodes
|
* Barcodes
|
||||||
*/
|
*/
|
||||||
barcodes: Array<string>;
|
barcodes?: Array<string>;
|
||||||
/**
|
|
||||||
* Imageurl
|
|
||||||
*/
|
|
||||||
imageUrl?: string | null;
|
|
||||||
/**
|
|
||||||
* Images
|
|
||||||
*/
|
|
||||||
images?: Array<ProductImageSchema> | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1090,6 +1106,16 @@ export type DealTagSchema = {
|
|||||||
tagColor: DealTagColorSchema;
|
tagColor: DealTagColorSchema;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteBarcodeImageResponse
|
||||||
|
*/
|
||||||
|
export type DeleteBarcodeImageResponse = {
|
||||||
|
/**
|
||||||
|
* Message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteBarcodeTemplateResponse
|
* DeleteBarcodeTemplateResponse
|
||||||
*/
|
*/
|
||||||
@ -1538,6 +1564,20 @@ export type PaginationInfoSchema = {
|
|||||||
totalItems: number;
|
totalItems: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProductBarcodeImageSchema
|
||||||
|
*/
|
||||||
|
export type ProductBarcodeImageSchema = {
|
||||||
|
/**
|
||||||
|
* Productid
|
||||||
|
*/
|
||||||
|
productId: number;
|
||||||
|
/**
|
||||||
|
* Imageurl
|
||||||
|
*/
|
||||||
|
imageUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProductImageSchema
|
* ProductImageSchema
|
||||||
*/
|
*/
|
||||||
@ -1603,7 +1643,7 @@ export type ProductSchema = {
|
|||||||
/**
|
/**
|
||||||
* Barcodes
|
* Barcodes
|
||||||
*/
|
*/
|
||||||
barcodes: Array<string>;
|
barcodes?: Array<string>;
|
||||||
/**
|
/**
|
||||||
* Imageurl
|
* Imageurl
|
||||||
*/
|
*/
|
||||||
@ -1612,6 +1652,11 @@ export type ProductSchema = {
|
|||||||
* Images
|
* Images
|
||||||
*/
|
*/
|
||||||
images?: Array<ProductImageSchema> | null;
|
images?: Array<ProductImageSchema> | null;
|
||||||
|
/**
|
||||||
|
* Barcodeimageurl
|
||||||
|
*/
|
||||||
|
barcodeImageUrl?: string | null;
|
||||||
|
barcodeImage?: ProductBarcodeImageSchema | null;
|
||||||
/**
|
/**
|
||||||
* Id
|
* Id
|
||||||
*/
|
*/
|
||||||
@ -4073,12 +4118,12 @@ export type UploadProductImageData = {
|
|||||||
body: BodyUploadProductImage;
|
body: BodyUploadProductImage;
|
||||||
path: {
|
path: {
|
||||||
/**
|
/**
|
||||||
* Productid
|
* Pk
|
||||||
*/
|
*/
|
||||||
productId: number;
|
pk: number;
|
||||||
};
|
};
|
||||||
query?: never;
|
query?: never;
|
||||||
url: "/crm/v1/fulfillment-base/product/images/upload/{productId}";
|
url: "/crm/v1/fulfillment-base/product{pk}/images/upload";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UploadProductImageErrors = {
|
export type UploadProductImageErrors = {
|
||||||
@ -4128,6 +4173,70 @@ export type GetProductBarcodePdfResponses = {
|
|||||||
export type GetProductBarcodePdfResponse2 =
|
export type GetProductBarcodePdfResponse2 =
|
||||||
GetProductBarcodePdfResponses[keyof GetProductBarcodePdfResponses];
|
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 = {
|
export type GetServicesData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
|
|||||||
@ -32,6 +32,14 @@ export const zBarcodeTemplateSchema = z.object({
|
|||||||
id: z.int(),
|
id: z.int(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BarcodeUploadImageResponse
|
||||||
|
*/
|
||||||
|
export const zBarcodeUploadImageResponse = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
imageUrl: z.optional(z.union([z.string(), z.null()])),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BaseMarketplaceSchema
|
* BaseMarketplaceSchema
|
||||||
*/
|
*/
|
||||||
@ -51,6 +59,13 @@ export const zBoardSchema = z.object({
|
|||||||
projectId: z.int(),
|
projectId: z.int(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Body_upload_product_barcode_image
|
||||||
|
*/
|
||||||
|
export const zBodyUploadProductBarcodeImage = z.object({
|
||||||
|
upload_file: z.any(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Body_upload_product_image
|
* Body_upload_product_image
|
||||||
*/
|
*/
|
||||||
@ -250,6 +265,14 @@ export const zProductImageSchema = z.object({
|
|||||||
imageUrl: z.string(),
|
imageUrl: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProductBarcodeImageSchema
|
||||||
|
*/
|
||||||
|
export const zProductBarcodeImageSchema = z.object({
|
||||||
|
productId: z.int(),
|
||||||
|
imageUrl: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProductSchema
|
* ProductSchema
|
||||||
*/
|
*/
|
||||||
@ -264,9 +287,11 @@ export const zProductSchema = z.object({
|
|||||||
composition: z.union([z.string(), z.null()]),
|
composition: z.union([z.string(), z.null()]),
|
||||||
size: z.union([z.string(), z.null()]),
|
size: z.union([z.string(), z.null()]),
|
||||||
additionalInfo: 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()])),
|
imageUrl: z.optional(z.union([z.string(), z.null()])),
|
||||||
images: z.optional(z.union([z.array(zProductImageSchema), 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(),
|
id: z.int(),
|
||||||
barcodeTemplate: zBarcodeTemplateSchema,
|
barcodeTemplate: zBarcodeTemplateSchema,
|
||||||
});
|
});
|
||||||
@ -526,9 +551,7 @@ export const zCreateProductSchema = z.object({
|
|||||||
composition: z.union([z.string(), z.null()]),
|
composition: z.union([z.string(), z.null()]),
|
||||||
size: z.union([z.string(), z.null()]),
|
size: z.union([z.string(), z.null()]),
|
||||||
additionalInfo: 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()])),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -746,6 +769,13 @@ export const zDealProductAddKitResponse = z.object({
|
|||||||
message: z.string(),
|
message: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteBarcodeImageResponse
|
||||||
|
*/
|
||||||
|
export const zDeleteBarcodeImageResponse = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteBarcodeTemplateResponse
|
* DeleteBarcodeTemplateResponse
|
||||||
*/
|
*/
|
||||||
@ -2161,7 +2191,7 @@ export const zUpdateProductResponse2 = zUpdateProductResponse;
|
|||||||
export const zUploadProductImageData = z.object({
|
export const zUploadProductImageData = z.object({
|
||||||
body: zBodyUploadProductImage,
|
body: zBodyUploadProductImage,
|
||||||
path: z.object({
|
path: z.object({
|
||||||
productId: z.int(),
|
pk: z.int(),
|
||||||
}),
|
}),
|
||||||
query: z.optional(z.never()),
|
query: z.optional(z.never()),
|
||||||
});
|
});
|
||||||
@ -2182,6 +2212,32 @@ export const zGetProductBarcodePdfData = z.object({
|
|||||||
*/
|
*/
|
||||||
export const zGetProductBarcodePdfResponse2 = zGetProductBarcodePdfResponse;
|
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({
|
export const zGetServicesData = z.object({
|
||||||
body: z.optional(z.never()),
|
body: z.optional(z.never()),
|
||||||
path: z.optional(z.never()),
|
path: z.optional(z.never()),
|
||||||
|
|||||||
@ -22,6 +22,7 @@ const ProductsActions: FC = () => {
|
|||||||
onCreate: productsCrud.onCreate,
|
onCreate: productsCrud.onCreate,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
clientId: deal.client.id,
|
clientId: deal.client.id,
|
||||||
|
refetchProducts: dealProductsList.refetch,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -29,6 +29,7 @@ const ProductViewActions: FC<Props> = ({ dealProduct }) => {
|
|||||||
entity: dealProduct.product,
|
entity: dealProduct.product,
|
||||||
isEditing: true,
|
isEditing: true,
|
||||||
clientId: dealProduct.product.clientId,
|
clientId: dealProduct.product.clientId,
|
||||||
|
refetchProducts: dealProductsList.refetch,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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<string>;
|
||||||
|
productId?: number;
|
||||||
|
onUploaded?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
||||||
|
|
||||||
|
const BarcodeImageDropzone: FC<Props> = ({
|
||||||
|
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
|
||||||
|
<object
|
||||||
|
style={{
|
||||||
|
aspectRatio: BARCODE_IMAGE_RATIO,
|
||||||
|
width: "240px",
|
||||||
|
}}
|
||||||
|
data={imageUrlInputProps?.value}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Dropzone
|
||||||
|
accept={["application/pdf"]}
|
||||||
|
multiple={false}
|
||||||
|
onDrop={onDrop}>
|
||||||
|
<Group
|
||||||
|
justify="center"
|
||||||
|
gap="xl"
|
||||||
|
style={{ pointerEvents: "none" }}>
|
||||||
|
<Dropzone.Accept>
|
||||||
|
<IconUpload
|
||||||
|
style={{
|
||||||
|
width: rem(52),
|
||||||
|
height: rem(52),
|
||||||
|
color: "var(--mantine-color-blue-6)",
|
||||||
|
}}
|
||||||
|
stroke={1.5}
|
||||||
|
/>
|
||||||
|
</Dropzone.Accept>
|
||||||
|
<Dropzone.Reject>
|
||||||
|
<IconX
|
||||||
|
style={{
|
||||||
|
width: rem(52),
|
||||||
|
height: rem(52),
|
||||||
|
color: "var(--mantine-color-red-6)",
|
||||||
|
}}
|
||||||
|
stroke={1.5}
|
||||||
|
/>
|
||||||
|
</Dropzone.Reject>
|
||||||
|
<Dropzone.Idle>
|
||||||
|
<IconPhoto
|
||||||
|
style={{
|
||||||
|
width: rem(52),
|
||||||
|
height: rem(52),
|
||||||
|
color: "var(--mantine-color-dimmed)",
|
||||||
|
}}
|
||||||
|
stroke={1.5}
|
||||||
|
/>
|
||||||
|
</Dropzone.Idle>
|
||||||
|
|
||||||
|
<div style={{ textAlign: "center" }}>
|
||||||
|
<Text
|
||||||
|
size="xl"
|
||||||
|
inline>
|
||||||
|
Перенесите или нажмите чтоб выбрать файл <br />
|
||||||
|
Pdf-файл должен содержать 1 страницу размером 58 х
|
||||||
|
40
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</Group>
|
||||||
|
</Dropzone>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
gap={"xs"}
|
||||||
|
direction={"column"}>
|
||||||
|
<Fieldset legend={"Штрихкод"}>
|
||||||
|
<Flex justify={"center"}>
|
||||||
|
{imageDropzoneProps.isLoading ? <Loader /> : getBody()}
|
||||||
|
</Flex>
|
||||||
|
</Fieldset>
|
||||||
|
{imageUrlInputProps?.value && (
|
||||||
|
<>
|
||||||
|
<InlineButton
|
||||||
|
onClick={() => imageUrlInputProps?.onChange("")}>
|
||||||
|
Заменить штрихкод
|
||||||
|
</InlineButton>
|
||||||
|
<InlineButton onClick={onDeleteBarcodeImage}>
|
||||||
|
Удалить штрихкод
|
||||||
|
</InlineButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BarcodeImageDropzone;
|
||||||
@ -9,6 +9,7 @@ import useImageDropzone from "./useImageDropzone";
|
|||||||
interface RestProps {
|
interface RestProps {
|
||||||
imageUrlInputProps?: BaseFormInputProps<string>;
|
imageUrlInputProps?: BaseFormInputProps<string>;
|
||||||
productId?: number;
|
productId?: number;
|
||||||
|
onUploaded?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
||||||
@ -16,6 +17,7 @@ type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
|||||||
const ProductImageDropzone: FC<Props> = ({
|
const ProductImageDropzone: FC<Props> = ({
|
||||||
imageUrlInputProps,
|
imageUrlInputProps,
|
||||||
productId,
|
productId,
|
||||||
|
onUploaded,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const imageDropzoneProps = useImageDropzone({
|
const imageDropzoneProps = useImageDropzone({
|
||||||
imageUrlInputProps,
|
imageUrlInputProps,
|
||||||
@ -34,7 +36,7 @@ const ProductImageDropzone: FC<Props> = ({
|
|||||||
|
|
||||||
uploadProductImage({
|
uploadProductImage({
|
||||||
path: {
|
path: {
|
||||||
productId,
|
pk: productId,
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
upload_file: file,
|
upload_file: file,
|
||||||
@ -50,6 +52,7 @@ const ProductImageDropzone: FC<Props> = ({
|
|||||||
}
|
}
|
||||||
imageUrlInputProps?.onChange(data?.imageUrl);
|
imageUrlInputProps?.onChange(data?.imageUrl);
|
||||||
setShowDropzone(false);
|
setShowDropzone(false);
|
||||||
|
onUploaded && onUploaded();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Fieldset, Flex, Stack, TagsInput, TextInput } from "@mantine/core";
|
import { Flex } from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm } from "@mantine/form";
|
||||||
import { ContextModalProps } from "@mantine/modals";
|
import { ContextModalProps } from "@mantine/modals";
|
||||||
import BarcodeTemplateSelect from "@/app/products/components/shared/BarcodeTemplateSelect/BarcodeTemplateSelect";
|
|
||||||
import {
|
import {
|
||||||
BarcodeTemplateSchema,
|
BarcodeTemplateSchema,
|
||||||
CreateProductSchema,
|
CreateProductSchema,
|
||||||
@ -14,11 +13,11 @@ import {
|
|||||||
import BaseFormModal, {
|
import BaseFormModal, {
|
||||||
CreateEditFormProps,
|
CreateEditFormProps,
|
||||||
} from "@/modals/base/BaseFormModal/BaseFormModal";
|
} 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, {
|
import ProductEditorSegmentedControl, {
|
||||||
ProductEditorTab,
|
ProductEditorTab,
|
||||||
} from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ProductEditorSegmentedControl";
|
} from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals/ProductEditorModal/components/ProductEditorSegmentedControl";
|
||||||
import BaseFormInputProps from "@/utils/baseFormInputProps";
|
|
||||||
|
|
||||||
type Props = CreateEditFormProps<
|
type Props = CreateEditFormProps<
|
||||||
CreateProductSchema,
|
CreateProductSchema,
|
||||||
@ -26,6 +25,7 @@ type Props = CreateEditFormProps<
|
|||||||
ProductSchema
|
ProductSchema
|
||||||
> & {
|
> & {
|
||||||
clientId: number;
|
clientId: number;
|
||||||
|
refetchProducts: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProductForm = Partial<
|
type ProductForm = Partial<
|
||||||
@ -64,92 +64,18 @@ const ProductEditorModal = ({
|
|||||||
initialValues,
|
initialValues,
|
||||||
validate: {
|
validate: {
|
||||||
name: name =>
|
name: name =>
|
||||||
!name || name.trim() !== ""
|
(!name || name.trim() === "") &&
|
||||||
? null
|
"Необходимо ввести название товара",
|
||||||
: "Необходимо ввести название товара",
|
barcodeTemplate: barcodeTemplate =>
|
||||||
|
!barcodeTemplate && "Необходимо выбрать шаблон штрихкода",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const characteristicsTab = (
|
|
||||||
<>
|
|
||||||
<Fieldset legend={"Основные характеристики"}>
|
|
||||||
<Stack gap={"xs"}>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите название товара"}
|
|
||||||
label={"Название товара"}
|
|
||||||
{...form.getInputProps("name")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите артикул"}
|
|
||||||
label={"Артикул"}
|
|
||||||
{...form.getInputProps("article")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите складской артикул"}
|
|
||||||
label={"Складской артикул"}
|
|
||||||
{...form.getInputProps("factoryArticle")}
|
|
||||||
/>
|
|
||||||
<BarcodeTemplateSelect
|
|
||||||
placeholder={"Выберите шаблон штрихкода"}
|
|
||||||
label={"Шаблон штрихкода"}
|
|
||||||
{...form.getInputProps("barcodeTemplate")}
|
|
||||||
onChange={template => {
|
|
||||||
form.setFieldValue("barcodeTemplate", template);
|
|
||||||
form.setFieldValue(
|
|
||||||
"barcodeTemplateId",
|
|
||||||
template?.id
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<TagsInput
|
|
||||||
placeholder={
|
|
||||||
!form.values.barcodes?.length
|
|
||||||
? "Добавьте штрихкоды к товару"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
label={"Штрихкоды"}
|
|
||||||
{...form.getInputProps("barcodes")}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Fieldset>
|
|
||||||
<Fieldset legend={"Дополнительные характеристики"}>
|
|
||||||
<Stack gap={"xs"}>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите бренд"}
|
|
||||||
label={"Бренд"}
|
|
||||||
{...form.getInputProps("brand")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите состав"}
|
|
||||||
label={"Состав"}
|
|
||||||
{...form.getInputProps("composition")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите цвет"}
|
|
||||||
label={"Цвет"}
|
|
||||||
{...form.getInputProps("color")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите размер"}
|
|
||||||
label={"Размер"}
|
|
||||||
{...form.getInputProps("size")}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={"Введите доп. информацию"}
|
|
||||||
label={"Доп. информация"}
|
|
||||||
{...form.getInputProps("additionalInfo")}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Fieldset>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const imageTab = isEditing && (
|
const imageTab = isEditing && (
|
||||||
<ProductImageDropzone
|
<ImagesTab
|
||||||
imageUrlInputProps={
|
form={form}
|
||||||
form.getInputProps("imageUrl") as BaseFormInputProps<string>
|
|
||||||
}
|
|
||||||
productId={innerProps.entity.id}
|
productId={innerProps.entity.id}
|
||||||
|
onUploaded={innerProps.refetchProducts}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -169,9 +95,11 @@ const ProductEditorModal = ({
|
|||||||
onChange={setEditorTab}
|
onChange={setEditorTab}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{editorTab === ProductEditorTab.CHARACTERISTICS
|
{editorTab === ProductEditorTab.CHARACTERISTICS ? (
|
||||||
? characteristicsTab
|
<CharacteristicsTab form={form} />
|
||||||
: imageTab}
|
) : (
|
||||||
|
imageTab
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</BaseFormModal>
|
</BaseFormModal>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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<Partial<ProductSchema>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CharacteristicsTab: FC<Props> = ({ form }) => (
|
||||||
|
<>
|
||||||
|
<Fieldset legend={"Основные характеристики"}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите название товара"}
|
||||||
|
label={"Название товара"}
|
||||||
|
{...form.getInputProps("name")}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите артикул"}
|
||||||
|
label={"Артикул"}
|
||||||
|
{...form.getInputProps("article")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите складской артикул"}
|
||||||
|
label={"Складской артикул"}
|
||||||
|
{...form.getInputProps("factoryArticle")}
|
||||||
|
/>
|
||||||
|
<BarcodeTemplateSelect
|
||||||
|
placeholder={"Выберите шаблон штрихкода"}
|
||||||
|
label={"Шаблон штрихкода"}
|
||||||
|
{...form.getInputProps("barcodeTemplate")}
|
||||||
|
onChange={template => {
|
||||||
|
form.setFieldValue("barcodeTemplate", template);
|
||||||
|
form.setFieldValue(
|
||||||
|
"barcodeTemplateId",
|
||||||
|
template?.id
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
<TagsInput
|
||||||
|
placeholder={
|
||||||
|
!form.values.barcodes?.length
|
||||||
|
? "Добавьте штрихкоды к товару"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
label={"Штрихкоды"}
|
||||||
|
{...form.getInputProps("barcodes")}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Fieldset>
|
||||||
|
<Fieldset legend={"Дополнительные характеристики"}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите бренд"}
|
||||||
|
label={"Бренд"}
|
||||||
|
{...form.getInputProps("brand")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите состав"}
|
||||||
|
label={"Состав"}
|
||||||
|
{...form.getInputProps("composition")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите цвет"}
|
||||||
|
label={"Цвет"}
|
||||||
|
{...form.getInputProps("color")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите размер"}
|
||||||
|
label={"Размер"}
|
||||||
|
{...form.getInputProps("size")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={"Введите доп. информацию"}
|
||||||
|
label={"Доп. информация"}
|
||||||
|
{...form.getInputProps("additionalInfo")}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Fieldset>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default CharacteristicsTab;
|
||||||
@ -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<Partial<ProductSchema>>;
|
||||||
|
productId: number;
|
||||||
|
onUploaded: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImagesTab: FC<Props> = ({ form, productId, onUploaded }) => (
|
||||||
|
<Stack>
|
||||||
|
<ProductImageDropzone
|
||||||
|
imageUrlInputProps={
|
||||||
|
form.getInputProps("imageUrl") as BaseFormInputProps<string>
|
||||||
|
}
|
||||||
|
productId={productId}
|
||||||
|
onUploaded={onUploaded}
|
||||||
|
/>
|
||||||
|
<BarcodeImageDropzone
|
||||||
|
imageUrlInputProps={
|
||||||
|
form.getInputProps(
|
||||||
|
"barcodeImageUrl"
|
||||||
|
) as BaseFormInputProps<string>
|
||||||
|
}
|
||||||
|
productId={productId}
|
||||||
|
onUploaded={onUploaded}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ImagesTab;
|
||||||
Reference in New Issue
Block a user