feat: upload image on product
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
				
			|||||||
import {Dropzone, DropzoneProps, FileWithPath} from "@mantine/dropzone";
 | 
					import {Dropzone, DropzoneProps, FileWithPath} from "@mantine/dropzone";
 | 
				
			||||||
import {FC, useState} from "react";
 | 
					import {FC, useState} from "react";
 | 
				
			||||||
import {Button, Fieldset, Flex, Group, Image, rem, Text} from "@mantine/core";
 | 
					import {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 {BaseFormInputProps} from "../../types/utils.ts";
 | 
				
			||||||
@@ -20,8 +20,7 @@ const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			|||||||
        !(typeof props.imageUrlInputProps?.value === 'string' &&
 | 
					        !(typeof props.imageUrlInputProps?.value === 'string' &&
 | 
				
			||||||
            props.imageUrlInputProps.value.trim() !== '')
 | 
					            props.imageUrlInputProps.value.trim() !== '')
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    console.log(props.imageUrlInputProps);
 | 
					    const [isLoading, setIsLoading] = useState(false);
 | 
				
			||||||
    console.log(showDropzone);
 | 
					 | 
				
			||||||
    const restProps = omit(props, ['imageUrl', 'productId', 'imageUrlInputProps']);
 | 
					    const restProps = omit(props, ['imageUrl', 'productId', 'imageUrlInputProps']);
 | 
				
			||||||
    const onDrop = (files: FileWithPath[]) => {
 | 
					    const onDrop = (files: FileWithPath[]) => {
 | 
				
			||||||
        if (!props.productId || !props.imageUrlInputProps) return;
 | 
					        if (!props.productId || !props.imageUrlInputProps) return;
 | 
				
			||||||
@@ -31,6 +30,7 @@ const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        const file = files[0];
 | 
					        const file = files[0];
 | 
				
			||||||
        // TODO check if file is image
 | 
					        // TODO check if file is image
 | 
				
			||||||
 | 
					        setIsLoading(true);
 | 
				
			||||||
        ProductService.uploadProductImage({
 | 
					        ProductService.uploadProductImage({
 | 
				
			||||||
            productId: props.productId,
 | 
					            productId: props.productId,
 | 
				
			||||||
            formData: {
 | 
					            formData: {
 | 
				
			||||||
@@ -38,19 +38,37 @@ const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }).then(({ok, message, imageUrl}) => {
 | 
					        }).then(({ok, message, imageUrl}) => {
 | 
				
			||||||
            notifications.guess(ok, {message});
 | 
					            notifications.guess(ok, {message});
 | 
				
			||||||
 | 
					            setIsLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!ok || !imageUrl) {
 | 
					            if (!ok || !imageUrl) {
 | 
				
			||||||
 | 
					                setShowDropzone(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            props.imageUrlInputProps?.onChange(imageUrl);
 | 
					            props.imageUrlInputProps?.onChange(imageUrl);
 | 
				
			||||||
            setShowDropzone(false);
 | 
					            setShowDropzone(false);
 | 
				
			||||||
 | 
					        }).catch(error => {
 | 
				
			||||||
 | 
					            notifications.error({message: error.toString()});
 | 
				
			||||||
 | 
					            setShowDropzone(true);
 | 
				
			||||||
 | 
					            setIsLoading(false);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const getBody = () => {
 | 
					    const getBody = () => {
 | 
				
			||||||
        return props.imageUrlInputProps?.value && showDropzone ? (
 | 
					        return props.imageUrlInputProps?.value && !showDropzone ? (
 | 
				
			||||||
            <Image src={props.imageUrlInputProps.value}/>
 | 
					            <Image src={props.imageUrlInputProps.value}/>
 | 
				
			||||||
        ) : (
 | 
					        ) : (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Dropzone
 | 
					            <Dropzone
 | 
				
			||||||
                {...restProps}
 | 
					                {...restProps}
 | 
				
			||||||
 | 
					                accept={["image/png",
 | 
				
			||||||
 | 
					                    "image/jpeg",
 | 
				
			||||||
 | 
					                    "image/gif",
 | 
				
			||||||
 | 
					                    "image/bmp",
 | 
				
			||||||
 | 
					                    "image/tiff",
 | 
				
			||||||
 | 
					                    "image/x-icon",
 | 
				
			||||||
 | 
					                    "image/webp",
 | 
				
			||||||
 | 
					                    "image/svg+xml",
 | 
				
			||||||
 | 
					                    "image/heic"]}
 | 
				
			||||||
                multiple={false}
 | 
					                multiple={false}
 | 
				
			||||||
                onDrop={onDrop}
 | 
					                onDrop={onDrop}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,25 +93,30 @@ const ImageDropzone: FC<Props> = (props: Props) => {
 | 
				
			|||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    </Dropzone.Idle>
 | 
					                    </Dropzone.Idle>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <div>
 | 
					                    <div style={{textAlign: "center"}}>
 | 
				
			||||||
                        <Text size="xl" inline>
 | 
					                        <Text size="xl" inline>
 | 
				
			||||||
                            Drag images here or click to select files
 | 
					                            Перенесите изображение или нажмите чтоб выбрать файл
 | 
				
			||||||
                        </Text>
 | 
					 | 
				
			||||||
                        <Text size="sm" c="dimmed" inline mt={7}>
 | 
					 | 
				
			||||||
                            Attach as many files as you like, each file should not exceed 5mb
 | 
					 | 
				
			||||||
                        </Text>
 | 
					                        </Text>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </Group>
 | 
					                </Group>
 | 
				
			||||||
            </Dropzone>
 | 
					            </Dropzone>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Flex gap={rem(10)} direction={"column"}>
 | 
					        <Flex
 | 
				
			||||||
            <Fieldset legend={'Изображение'}>
 | 
					            gap={rem(10)}
 | 
				
			||||||
                {getBody()}
 | 
					            direction={"column"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <Fieldset
 | 
				
			||||||
 | 
					                legend={'Изображение'}>
 | 
				
			||||||
 | 
					                <Flex justify={"center"}>
 | 
				
			||||||
 | 
					                    {isLoading ? <Loader/> : getBody()}
 | 
				
			||||||
 | 
					                </Flex>
 | 
				
			||||||
            </Fieldset>
 | 
					            </Fieldset>
 | 
				
			||||||
            {!showDropzone &&
 | 
					            {!showDropzone &&
 | 
				
			||||||
                <Button variant={"default"}>Заменить изображение {}</Button>
 | 
					                <Button onClick={() => setShowDropzone(true)} variant={"default"}>Заменить изображение {}</Button>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        </Flex>
 | 
					        </Flex>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,3 +25,23 @@ export const getPluralForm = (amount: number, one: string, twoFour: string, many
 | 
				
			|||||||
            return many;
 | 
					            return many;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type KeysOf<T> = (keyof T)[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Универсальная функция для получения ключей интерфейса
 | 
				
			||||||
 | 
					export function getKeys<T extends object>(): KeysOf<T> {
 | 
				
			||||||
 | 
					    return Object.keys({} as T) as KeysOf<T>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const IMAGE_MIME_TYPES = [
 | 
				
			||||||
 | 
					    "image/png",
 | 
				
			||||||
 | 
					    "image/jpeg",
 | 
				
			||||||
 | 
					    "image/gif",
 | 
				
			||||||
 | 
					    "image/bmp",
 | 
				
			||||||
 | 
					    "image/tiff",
 | 
				
			||||||
 | 
					    "image/x-icon",
 | 
				
			||||||
 | 
					    "image/webp",
 | 
				
			||||||
 | 
					    "image/svg+xml",
 | 
				
			||||||
 | 
					    "image/heic"
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user