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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,4 +24,24 @@ export const getPluralForm = (amount: number, one: string, twoFour: string, many
|
|||||||
default:
|
default:
|
||||||
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