feat: passport images for user
This commit is contained in:
		@@ -28,6 +28,7 @@ export type { BaseMarketplaceSchema } from './models/BaseMarketplaceSchema';
 | 
				
			|||||||
export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
 | 
					export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
 | 
				
			||||||
export type { BillPaymentStatus } from './models/BillPaymentStatus';
 | 
					export type { BillPaymentStatus } from './models/BillPaymentStatus';
 | 
				
			||||||
export type { BillStatusUpdateRequest } from './models/BillStatusUpdateRequest';
 | 
					export type { BillStatusUpdateRequest } from './models/BillStatusUpdateRequest';
 | 
				
			||||||
 | 
					export type { Body_upload_passport_image } from './models/Body_upload_passport_image';
 | 
				
			||||||
export type { Body_upload_product_barcode_image } from './models/Body_upload_product_barcode_image';
 | 
					export type { Body_upload_product_barcode_image } from './models/Body_upload_product_barcode_image';
 | 
				
			||||||
export type { Body_upload_product_image } from './models/Body_upload_product_image';
 | 
					export type { Body_upload_product_image } from './models/Body_upload_product_image';
 | 
				
			||||||
export type { CancelDealBillRequest } from './models/CancelDealBillRequest';
 | 
					export type { CancelDealBillRequest } from './models/CancelDealBillRequest';
 | 
				
			||||||
@@ -194,6 +195,7 @@ export type { MarketplaceCreateSchema } from './models/MarketplaceCreateSchema';
 | 
				
			|||||||
export type { MarketplaceSchema } from './models/MarketplaceSchema';
 | 
					export type { MarketplaceSchema } from './models/MarketplaceSchema';
 | 
				
			||||||
export type { NotificationChannel } from './models/NotificationChannel';
 | 
					export type { NotificationChannel } from './models/NotificationChannel';
 | 
				
			||||||
export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
 | 
					export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
 | 
				
			||||||
 | 
					export type { PassportImageSchema } from './models/PassportImageSchema';
 | 
				
			||||||
export type { PaymentRecordCreateSchema } from './models/PaymentRecordCreateSchema';
 | 
					export type { PaymentRecordCreateSchema } from './models/PaymentRecordCreateSchema';
 | 
				
			||||||
export type { PaymentRecordGetSchema } from './models/PaymentRecordGetSchema';
 | 
					export type { PaymentRecordGetSchema } from './models/PaymentRecordGetSchema';
 | 
				
			||||||
export type { PayRateSchema } from './models/PayRateSchema';
 | 
					export type { PayRateSchema } from './models/PayRateSchema';
 | 
				
			||||||
@@ -274,6 +276,7 @@ export type { UpdateTimeTrackingRecordRequest } from './models/UpdateTimeTrackin
 | 
				
			|||||||
export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse';
 | 
					export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse';
 | 
				
			||||||
export type { UpdateUserRequest } from './models/UpdateUserRequest';
 | 
					export type { UpdateUserRequest } from './models/UpdateUserRequest';
 | 
				
			||||||
export type { UpdateUserResponse } from './models/UpdateUserResponse';
 | 
					export type { UpdateUserResponse } from './models/UpdateUserResponse';
 | 
				
			||||||
 | 
					export type { UploadPassportImageResponse } from './models/UploadPassportImageResponse';
 | 
				
			||||||
export type { UserCreate } from './models/UserCreate';
 | 
					export type { UserCreate } from './models/UserCreate';
 | 
				
			||||||
export type { UserSchema } from './models/UserSchema';
 | 
					export type { UserSchema } from './models/UserSchema';
 | 
				
			||||||
export type { UserUpdate } from './models/UserUpdate';
 | 
					export type { UserUpdate } from './models/UserUpdate';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								src/client/models/Body_upload_passport_image.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/Body_upload_passport_image.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type Body_upload_passport_image = {
 | 
				
			||||||
 | 
					    upload_file: Blob;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/client/models/PassportImageSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/PassportImageSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type PassportImageSchema = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    userId: number;
 | 
				
			||||||
 | 
					    imageUrl: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/client/models/UploadPassportImageResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/UploadPassportImageResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UploadPassportImageResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					    imageUrl?: (string | null);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PassportImageSchema } from './PassportImageSchema';
 | 
				
			||||||
import type { PayRateSchema } from './PayRateSchema';
 | 
					import type { PayRateSchema } from './PayRateSchema';
 | 
				
			||||||
export type UserCreate = {
 | 
					export type UserCreate = {
 | 
				
			||||||
    telegramId: number;
 | 
					    telegramId: number;
 | 
				
			||||||
@@ -16,6 +17,8 @@ export type UserCreate = {
 | 
				
			|||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
    roleKey: string;
 | 
					    roleKey: string;
 | 
				
			||||||
    payRate?: (PayRateSchema | null);
 | 
					    payRate?: (PayRateSchema | null);
 | 
				
			||||||
 | 
					    passportImageUrl?: (string | null);
 | 
				
			||||||
 | 
					    passportImages?: (Array<PassportImageSchema> | null);
 | 
				
			||||||
    positionKey?: (string | null);
 | 
					    positionKey?: (string | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PassportImageSchema } from './PassportImageSchema';
 | 
				
			||||||
import type { PayRateSchema } from './PayRateSchema';
 | 
					import type { PayRateSchema } from './PayRateSchema';
 | 
				
			||||||
import type { PositionSchema } from './PositionSchema';
 | 
					import type { PositionSchema } from './PositionSchema';
 | 
				
			||||||
import type { RoleSchema } from './RoleSchema';
 | 
					import type { RoleSchema } from './RoleSchema';
 | 
				
			||||||
@@ -18,6 +19,8 @@ export type UserSchema = {
 | 
				
			|||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
    roleKey: string;
 | 
					    roleKey: string;
 | 
				
			||||||
    payRate?: (PayRateSchema | null);
 | 
					    payRate?: (PayRateSchema | null);
 | 
				
			||||||
 | 
					    passportImageUrl?: (string | null);
 | 
				
			||||||
 | 
					    passportImages?: (Array<PassportImageSchema> | null);
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    role: RoleSchema;
 | 
					    role: RoleSchema;
 | 
				
			||||||
    position?: (PositionSchema | null);
 | 
					    position?: (PositionSchema | null);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PassportImageSchema } from './PassportImageSchema';
 | 
				
			||||||
import type { PayRateSchema } from './PayRateSchema';
 | 
					import type { PayRateSchema } from './PayRateSchema';
 | 
				
			||||||
export type UserUpdate = {
 | 
					export type UserUpdate = {
 | 
				
			||||||
    telegramId: number;
 | 
					    telegramId: number;
 | 
				
			||||||
@@ -16,6 +17,8 @@ export type UserUpdate = {
 | 
				
			|||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
    roleKey: string;
 | 
					    roleKey: string;
 | 
				
			||||||
    payRate?: (PayRateSchema | null);
 | 
					    payRate?: (PayRateSchema | null);
 | 
				
			||||||
 | 
					    passportImageUrl?: (string | null);
 | 
				
			||||||
 | 
					    passportImages?: (Array<PassportImageSchema> | null);
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    positionKey?: (string | null);
 | 
					    positionKey?: (string | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,14 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { Body_upload_passport_image } from '../models/Body_upload_passport_image';
 | 
				
			||||||
import type { CreateUserRequest } from '../models/CreateUserRequest';
 | 
					import type { CreateUserRequest } from '../models/CreateUserRequest';
 | 
				
			||||||
import type { CreateUserResponse } from '../models/CreateUserResponse';
 | 
					import type { CreateUserResponse } from '../models/CreateUserResponse';
 | 
				
			||||||
import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
 | 
					import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
 | 
				
			||||||
import type { GetManagersResponse } from '../models/GetManagersResponse';
 | 
					import type { GetManagersResponse } from '../models/GetManagersResponse';
 | 
				
			||||||
import type { UpdateUserRequest } from '../models/UpdateUserRequest';
 | 
					import type { UpdateUserRequest } from '../models/UpdateUserRequest';
 | 
				
			||||||
import type { UpdateUserResponse } from '../models/UpdateUserResponse';
 | 
					import type { UpdateUserResponse } from '../models/UpdateUserResponse';
 | 
				
			||||||
 | 
					import type { UploadPassportImageResponse } from '../models/UploadPassportImageResponse';
 | 
				
			||||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
import { OpenAPI } from '../core/OpenAPI';
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
import { request as __request } from '../core/request';
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
@@ -74,4 +76,29 @@ export class UserService {
 | 
				
			|||||||
            url: '/user/get-managers',
 | 
					            url: '/user/get-managers',
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Upload Passport Image
 | 
				
			||||||
 | 
					     * @returns UploadPassportImageResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static uploadPassportImage({
 | 
				
			||||||
 | 
					        userId,
 | 
				
			||||||
 | 
					        formData,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        userId: number,
 | 
				
			||||||
 | 
					        formData: Body_upload_passport_image,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UploadPassportImageResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/user/passport-images/upload/{user_id}',
 | 
				
			||||||
 | 
					            path: {
 | 
				
			||||||
 | 
					                'user_id': userId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            formData: formData,
 | 
				
			||||||
 | 
					            mediaType: 'multipart/form-data',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,77 +1,34 @@
 | 
				
			|||||||
import { Dropzone, DropzoneProps, FileWithPath } from "@mantine/dropzone";
 | 
					import { Dropzone, DropzoneProps, FileWithPath } from "@mantine/dropzone";
 | 
				
			||||||
import { FC, useState } from "react";
 | 
					import { FC } from "react";
 | 
				
			||||||
import {
 | 
					import { Button, Fieldset, Flex, Group, Image, Loader, rem, Text } from "@mantine/core";
 | 
				
			||||||
    Button,
 | 
					 | 
				
			||||||
    Fieldset,
 | 
					 | 
				
			||||||
    Flex,
 | 
					 | 
				
			||||||
    Group,
 | 
					 | 
				
			||||||
    Image,
 | 
					 | 
				
			||||||
    Loader,
 | 
					 | 
				
			||||||
    rem,
 | 
					 | 
				
			||||||
    Text,
 | 
					 | 
				
			||||||
} from "@mantine/core";
 | 
					 | 
				
			||||||
import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react";
 | 
					import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react";
 | 
				
			||||||
import { omit } from "lodash";
 | 
					import { omit } from "lodash";
 | 
				
			||||||
import { BaseFormInputProps } from "../../types/utils.ts";
 | 
					import UseImageDropzone from "../../types/UseImageDropzone.tsx";
 | 
				
			||||||
import { notifications } from "../../shared/lib/notifications.ts";
 | 
					 | 
				
			||||||
import { ProductService } from "../../client";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface RestProps {
 | 
					interface RestProps {
 | 
				
			||||||
    imageUrlInputProps?: BaseFormInputProps<string>;
 | 
					    imageDropzone: UseImageDropzone;
 | 
				
			||||||
    productId?: number;
 | 
					    onDrop: (files: FileWithPath[]) => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
 | 
					type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ImageDropzone: FC<Props> = (props: Props) => {
 | 
					const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			||||||
    const [showDropzone, setShowDropzone] = useState(
 | 
					    const {
 | 
				
			||||||
        !(
 | 
					        showDropzone,
 | 
				
			||||||
            typeof props.imageUrlInputProps?.value === "string" &&
 | 
					        setShowDropzone,
 | 
				
			||||||
            props.imageUrlInputProps.value.trim() !== ""
 | 
					        isLoading,
 | 
				
			||||||
        )
 | 
					        imageUrlInputProps,
 | 
				
			||||||
    );
 | 
					    } = props.imageDropzone;
 | 
				
			||||||
    const [isLoading, setIsLoading] = useState(false);
 | 
					
 | 
				
			||||||
    const restProps = omit(props, [
 | 
					    const restProps = omit(props, [
 | 
				
			||||||
        "imageUrl",
 | 
					        "imageUrl",
 | 
				
			||||||
        "productId",
 | 
					        "productId",
 | 
				
			||||||
        "imageUrlInputProps",
 | 
					        "imageUrlInputProps",
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
    const onDrop = (files: FileWithPath[]) => {
 | 
					 | 
				
			||||||
        if (!props.productId || !props.imageUrlInputProps) return;
 | 
					 | 
				
			||||||
        if (files.length > 1) {
 | 
					 | 
				
			||||||
            notifications.error({ message: "Прикрепите одно изображение" });
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const file = files[0];
 | 
					 | 
				
			||||||
        // TODO check if file is image
 | 
					 | 
				
			||||||
        setIsLoading(true);
 | 
					 | 
				
			||||||
        ProductService.uploadProductImage({
 | 
					 | 
				
			||||||
            productId: props.productId,
 | 
					 | 
				
			||||||
            formData: {
 | 
					 | 
				
			||||||
                upload_file: file,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
            .then(({ ok, message, imageUrl }) => {
 | 
					 | 
				
			||||||
                notifications.guess(ok, { message });
 | 
					 | 
				
			||||||
                setIsLoading(false);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!ok || !imageUrl) {
 | 
					 | 
				
			||||||
                    setShowDropzone(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                props.imageUrlInputProps?.onChange(imageUrl);
 | 
					 | 
				
			||||||
                setShowDropzone(false);
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .catch(error => {
 | 
					 | 
				
			||||||
                notifications.error({ message: error.toString() });
 | 
					 | 
				
			||||||
                setShowDropzone(true);
 | 
					 | 
				
			||||||
                setIsLoading(false);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const getBody = () => {
 | 
					    const getBody = () => {
 | 
				
			||||||
        return props.imageUrlInputProps?.value && !showDropzone ? (
 | 
					        return imageUrlInputProps?.value && !showDropzone ? (
 | 
				
			||||||
            <Image src={props.imageUrlInputProps.value} />
 | 
					            <Image src={imageUrlInputProps.value} />
 | 
				
			||||||
        ) : (
 | 
					        ) : (
 | 
				
			||||||
            <Dropzone
 | 
					            <Dropzone
 | 
				
			||||||
                {...restProps}
 | 
					                {...restProps}
 | 
				
			||||||
@@ -87,7 +44,7 @@ const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			|||||||
                    "image/heic",
 | 
					                    "image/heic",
 | 
				
			||||||
                ]}
 | 
					                ]}
 | 
				
			||||||
                multiple={false}
 | 
					                multiple={false}
 | 
				
			||||||
                onDrop={onDrop}>
 | 
					                onDrop={props.onDrop}>
 | 
				
			||||||
                <Group
 | 
					                <Group
 | 
				
			||||||
                    justify="center"
 | 
					                    justify="center"
 | 
				
			||||||
                    gap="xl"
 | 
					                    gap="xl"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/hooks/useImageDropzone.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/hooks/useImageDropzone.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { BaseFormInputProps } from "../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					    imageUrlInputProps?: BaseFormInputProps<string>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useImageDropzone = ({ imageUrlInputProps }: Props) => {
 | 
				
			||||||
 | 
					    const [showDropzone, setShowDropzone] = useState(
 | 
				
			||||||
 | 
					        !(
 | 
				
			||||||
 | 
					            typeof imageUrlInputProps?.value === "string" &&
 | 
				
			||||||
 | 
					            imageUrlInputProps.value.trim() !== ""
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const [isLoading, setIsLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        showDropzone,
 | 
				
			||||||
 | 
					        setShowDropzone,
 | 
				
			||||||
 | 
					        isLoading,
 | 
				
			||||||
 | 
					        setIsLoading,
 | 
				
			||||||
 | 
					        imageUrlInputProps,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useImageDropzone;
 | 
				
			||||||
@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					import { DropzoneProps, FileWithPath } from "@mantine/dropzone";
 | 
				
			||||||
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { UserService } from "../../../../client";
 | 
				
			||||||
 | 
					import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import useImageDropzone from "../../../../hooks/useImageDropzone.tsx";
 | 
				
			||||||
 | 
					import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface RestProps {
 | 
				
			||||||
 | 
					    imageUrlInputProps?: BaseFormInputProps<string>;
 | 
				
			||||||
 | 
					    userId?: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ProductImageDropzone: FC<Props> = ({ imageUrlInputProps, userId }: Props) => {
 | 
				
			||||||
 | 
					    const imageDropzoneProps = useImageDropzone({
 | 
				
			||||||
 | 
					        imageUrlInputProps,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onDrop = (files: FileWithPath[]) => {
 | 
				
			||||||
 | 
					        if (!userId || !imageUrlInputProps) return;
 | 
				
			||||||
 | 
					        if (files.length > 1) {
 | 
				
			||||||
 | 
					            notifications.error({ message: "Прикрепите одно изображение" });
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const { setIsLoading, setShowDropzone } = imageDropzoneProps;
 | 
				
			||||||
 | 
					        const file = files[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setIsLoading(true);
 | 
				
			||||||
 | 
					        UserService.uploadPassportImage({
 | 
				
			||||||
 | 
					            userId: userId,
 | 
				
			||||||
 | 
					            formData: {
 | 
				
			||||||
 | 
					                upload_file: file,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message, imageUrl }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                setIsLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!ok || !imageUrl) {
 | 
				
			||||||
 | 
					                    setShowDropzone(true);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                imageUrlInputProps?.onChange(imageUrl);
 | 
				
			||||||
 | 
					                setShowDropzone(false);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(error => {
 | 
				
			||||||
 | 
					                notifications.error({ message: error.toString() });
 | 
				
			||||||
 | 
					                setShowDropzone(true);
 | 
				
			||||||
 | 
					                setIsLoading(false);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ImageDropzone onDrop={onDrop} imageDropzone={imageDropzoneProps} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ProductImageDropzone;
 | 
				
			||||||
@@ -10,6 +10,8 @@ import { capitalize } from "lodash";
 | 
				
			|||||||
import { IMaskInput } from "react-imask";
 | 
					import { IMaskInput } from "react-imask";
 | 
				
			||||||
import phone from "phone";
 | 
					import phone from "phone";
 | 
				
			||||||
import PayRateSelect from "../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
 | 
					import PayRateSelect from "../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
 | 
				
			||||||
 | 
					import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import PassportImageDropzone from "../../components/PassportImageDropzone/PassportImageDropzone.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = CreateEditFormProps<UserSchema>;
 | 
					type Props = CreateEditFormProps<UserSchema>;
 | 
				
			||||||
const UserFormModal = ({
 | 
					const UserFormModal = ({
 | 
				
			||||||
@@ -107,6 +109,10 @@ const UserFormModal = ({
 | 
				
			|||||||
                                    {...form.getInputProps("phoneNumber")}
 | 
					                                    {...form.getInputProps("phoneNumber")}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                            </Input.Wrapper>
 | 
					                            </Input.Wrapper>
 | 
				
			||||||
 | 
					                        </Stack>
 | 
				
			||||||
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					                    <Fieldset legend={"Паспортные данные"}>
 | 
				
			||||||
 | 
					                        <Stack>
 | 
				
			||||||
                            <Input.Wrapper
 | 
					                            <Input.Wrapper
 | 
				
			||||||
                                label={"Серия и номер паспорта"}
 | 
					                                label={"Серия и номер паспорта"}
 | 
				
			||||||
                                error={form.getInputProps("passportData").error}>
 | 
					                                error={form.getInputProps("passportData").error}>
 | 
				
			||||||
@@ -117,6 +123,18 @@ const UserFormModal = ({
 | 
				
			|||||||
                                    {...form.getInputProps("passportData")}
 | 
					                                    {...form.getInputProps("passportData")}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                            </Input.Wrapper>
 | 
					                            </Input.Wrapper>
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                isEditing && (
 | 
				
			||||||
 | 
					                                    <PassportImageDropzone
 | 
				
			||||||
 | 
					                                        imageUrlInputProps={
 | 
				
			||||||
 | 
					                                            form.getInputProps(
 | 
				
			||||||
 | 
					                                                "passportImageUrl",
 | 
				
			||||||
 | 
					                                            ) as BaseFormInputProps<string>
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        userId={innerProps?.element.id}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                )
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        </Stack>
 | 
					                        </Stack>
 | 
				
			||||||
                    </Fieldset>
 | 
					                    </Fieldset>
 | 
				
			||||||
                    <Fieldset legend={"Роль и должность"}>
 | 
					                    <Fieldset legend={"Роль и должность"}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					import { DropzoneProps, FileWithPath } from "@mantine/dropzone";
 | 
				
			||||||
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { ProductService } from "../../../../client";
 | 
				
			||||||
 | 
					import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import useImageDropzone from "../../../../hooks/useImageDropzone.tsx";
 | 
				
			||||||
 | 
					import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface RestProps {
 | 
				
			||||||
 | 
					    imageUrlInputProps?: BaseFormInputProps<string>;
 | 
				
			||||||
 | 
					    productId?: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ProductImageDropzone: FC<Props> = ({ imageUrlInputProps, productId }: Props) => {
 | 
				
			||||||
 | 
					    const imageDropzoneProps = useImageDropzone({
 | 
				
			||||||
 | 
					        imageUrlInputProps,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					        ProductService.uploadProductImage({
 | 
				
			||||||
 | 
					            productId,
 | 
				
			||||||
 | 
					            formData: {
 | 
				
			||||||
 | 
					                upload_file: file,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message, imageUrl }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                setIsLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!ok || !imageUrl) {
 | 
				
			||||||
 | 
					                    setShowDropzone(true);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                imageUrlInputProps?.onChange(imageUrl);
 | 
				
			||||||
 | 
					                setShowDropzone(false);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(error => {
 | 
				
			||||||
 | 
					                notifications.error({ message: error.toString() });
 | 
				
			||||||
 | 
					                setShowDropzone(true);
 | 
				
			||||||
 | 
					                setIsLoading(false);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ImageDropzone onDrop={onDrop} imageDropzone={imageDropzoneProps} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ProductImageDropzone;
 | 
				
			||||||
@@ -4,9 +4,9 @@ import { useForm } from "@mantine/form";
 | 
				
			|||||||
import { BaseProduct, CreateProductRequest } from "../../types.ts";
 | 
					import { BaseProduct, CreateProductRequest } from "../../types.ts";
 | 
				
			||||||
import { ProductSchema } from "../../../../client";
 | 
					import { ProductSchema } from "../../../../client";
 | 
				
			||||||
import BarcodeTemplateSelect from "../../../../components/Selects/BarcodeTemplateSelect/BarcodeTemplateSelect.tsx";
 | 
					import BarcodeTemplateSelect from "../../../../components/Selects/BarcodeTemplateSelect/BarcodeTemplateSelect.tsx";
 | 
				
			||||||
import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
 | 
					 | 
				
			||||||
import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
					import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
				
			||||||
import BarcodeImageDropzone from "../../../../components/BarcodeImageDropzone/BarcodeImageDropzone.tsx";
 | 
					import BarcodeImageDropzone from "../../../../components/BarcodeImageDropzone/BarcodeImageDropzone.tsx";
 | 
				
			||||||
 | 
					import ProductImageDropzone from "../../components/ProductImageDropzone/ProductImageDropzone.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CreateProps = {
 | 
					type CreateProps = {
 | 
				
			||||||
    clientId: number;
 | 
					    clientId: number;
 | 
				
			||||||
@@ -117,7 +117,7 @@ const CreateProductModal = ({
 | 
				
			|||||||
                        isEditProps && (
 | 
					                        isEditProps && (
 | 
				
			||||||
                            // <Fieldset legend={"Изображение"}>
 | 
					                            // <Fieldset legend={"Изображение"}>
 | 
				
			||||||
                            <>
 | 
					                            <>
 | 
				
			||||||
                                <ImageDropzone
 | 
					                                <ProductImageDropzone
 | 
				
			||||||
                                    imageUrlInputProps={
 | 
					                                    imageUrlInputProps={
 | 
				
			||||||
                                        form.getInputProps(
 | 
					                                        form.getInputProps(
 | 
				
			||||||
                                            "imageUrl",
 | 
					                                            "imageUrl",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/types/UseImageDropzone.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/types/UseImageDropzone.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import { Dispatch, SetStateAction } from "react";
 | 
				
			||||||
 | 
					import { BaseFormInputProps } from "./utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type UseImageDropzone = {
 | 
				
			||||||
 | 
					    showDropzone: boolean;
 | 
				
			||||||
 | 
					    setShowDropzone: Dispatch<SetStateAction<boolean>>;
 | 
				
			||||||
 | 
					    isLoading: boolean;
 | 
				
			||||||
 | 
					    setIsLoading: Dispatch<SetStateAction<boolean>>;
 | 
				
			||||||
 | 
					    imageUrlInputProps?: BaseFormInputProps<string>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UseImageDropzone;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user