Skip to content

Commit 534b8ec

Browse files
committed
wip: update the component to use react-uploady config
1 parent 1fa617e commit 534b8ec

File tree

9 files changed

+229
-141
lines changed

9 files changed

+229
-141
lines changed

Diff for: .env.validator.js

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ const envSchema = z.object({
2222

2323
NEXT_PUBLIC_DEV_ENV_NAME: z.string().optional(),
2424
NEXT_PUBLIC_DEV_ENV_COLOR_SCHEME: z.string().optional(),
25+
26+
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME: z.string().optional(),
27+
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET: z.string().optional(),
2528
});
2629

2730
/**

Diff for: package.json

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
"@formkit/auto-animate": "1.0.0-beta.6",
4444
"@lukemorales/query-key-factory": "1.2.0",
4545
"@prisma/client": "4.15.0",
46+
"@rpldy/upload-drop-zone": "1.4.1",
47+
"@rpldy/uploady": "1.4.1",
4648
"@tanstack/react-query": "4.29.12",
4749
"@tanstack/react-query-devtools": "4.29.12",
4850
"axios": "1.4.0",

Diff for: src/components/FieldImageUpload/docs.stories.tsx

+50-33
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,50 @@ export default {
99
title: 'Fields/FieldImageUpload',
1010
};
1111

12-
export const Default = () => (
13-
<Formiz onSubmit={console.log} autoForm>
14-
<Stack spacing={6}>
15-
<FieldImageUpload
16-
name="demo"
17-
label="Profil picture"
18-
helper="This is an helper"
19-
required="Profil picture is required"
20-
width="360px"
21-
/>
22-
<FieldImageUpload
23-
name="demo-default-value"
24-
label="Default value"
25-
defaultValue="https://bit.ly/dan-abramov"
26-
width="360px"
27-
/>
28-
<FieldImageUpload
29-
name="demo-ratio"
30-
label="Custom aspect ratio and size"
31-
imageUploadProps={{ ratio: 1 }}
32-
w="240px"
33-
/>
34-
<Box>
35-
<Button type="submit">Submit</Button>
36-
</Box>
37-
</Stack>
38-
</Formiz>
39-
);
12+
export const Default = () => {
13+
const form = useForm({
14+
onValidSubmit(formValues) {
15+
console.log(formValues);
16+
},
17+
});
18+
19+
return (
20+
<Formiz connect={form} autoForm>
21+
<Stack spacing={6}>
22+
<FieldImageUpload
23+
name="demo"
24+
label="Profil picture"
25+
helper="This is an helper"
26+
required="Profil picture is required"
27+
width="360px"
28+
/>
29+
<FieldImageUpload
30+
name="demo-default-value"
31+
label="Default value"
32+
defaultValue="https://bit.ly/dan-abramov"
33+
width="360px"
34+
/>
35+
<FieldImageUpload
36+
name="demo-ratio"
37+
label="Custom aspect ratio and size"
38+
imageUploadProps={{ ratio: 1 }}
39+
w="240px"
40+
/>
41+
<Box>
42+
<Button type="submit">Submit</Button>
43+
</Box>
44+
</Stack>
45+
</Formiz>
46+
);
47+
};
4048

4149
export const CustomPlaceholder = () => {
50+
const form = useForm({
51+
onValidSubmit(formValues) {
52+
console.log(formValues);
53+
},
54+
});
55+
4256
const PlaceholderComponent = () => (
4357
<Center bgColor="gray.50" overflow="hidden">
4458
<Stack textAlign="center" spacing={2}>
@@ -56,7 +70,7 @@ export const CustomPlaceholder = () => {
5670
);
5771

5872
return (
59-
<Formiz onSubmit={console.log} autoForm>
73+
<Formiz connect={form} autoForm>
6074
<Stack spacing={6}>
6175
<FieldImageUpload
6276
name="demo"
@@ -73,19 +87,22 @@ export const CustomPlaceholder = () => {
7387
};
7488

7589
export const InvalidateFormWhileUploading = () => {
76-
const form = useForm();
90+
const form = useForm({
91+
onValidSubmit(formValues) {
92+
console.log(formValues);
93+
},
94+
});
7795

7896
return (
79-
<Formiz connect={form} onSubmit={console.log} autoForm>
97+
<Formiz connect={form} autoForm>
8098
<Stack spacing={2}>
8199
<FieldImageUpload
82100
name="demo"
83101
label="Invalidate during uploading"
84102
w="360px"
85103
imageUploadProps={{
86104
onUploadStateChange: (isUploading) =>
87-
isUploading &&
88-
form.invalidateFields({ demo: 'Image is uploading' }),
105+
isUploading && form.setErrors({ demo: 'Image is uploading' }),
89106
}}
90107
/>
91108
<Box>

Diff for: src/components/FieldImageUpload/index.tsx

+9-19
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { FC, useEffect, useState } from 'react';
22

33
import { InputGroup } from '@chakra-ui/react';
44
import { FieldProps, useField } from '@formiz/core';
55

66
import { FormGroup, FormGroupProps } from '@/components/FormGroup';
77
import { ImageUpload, ImageUploadProps } from '@/components/ImageUpload';
88

9-
export interface FieldImageUploadProps
10-
extends FieldProps,
11-
Omit<FormGroupProps, 'placeholder'> {
12-
imageUploadProps?: Omit<ImageUploadProps, 'value' | 'onChange'>;
13-
}
9+
export type FieldImageUploadProps = FieldProps &
10+
Omit<FormGroupProps, 'placeholder'> & {
11+
imageUploadProps?: Omit<ImageUploadProps, 'value' | 'onChange'>;
12+
};
1413

15-
export const FieldImageUpload = (props: FieldImageUploadProps) => {
14+
export const FieldImageUpload: FC<FieldImageUploadProps> = (props) => {
1615
const {
1716
errorMessage,
1817
id,
@@ -23,18 +22,9 @@ export const FieldImageUpload = (props: FieldImageUploadProps) => {
2322
value,
2423
otherProps,
2524
} = useField(props);
26-
const {
27-
children,
28-
label,
29-
type,
30-
placeholder,
31-
helper,
32-
leftIcon,
33-
rightIcon,
34-
color,
35-
imageUploadProps,
36-
...rest
37-
} = otherProps;
25+
26+
const { children, label, helper, color, imageUploadProps, ...rest } =
27+
otherProps;
3828
const { required } = props;
3929
const [isTouched, setIsTouched] = useState(false);
4030
const showError = !isValid && (isTouched || isSubmitted);

Diff for: src/components/ImageUpload/ImageUpload.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Input, InputProps, forwardRef } from '@chakra-ui/react';
2+
import { useFileInput } from '@rpldy/uploady';
3+
4+
export const ImageUploadInput = forwardRef<InputProps, 'input'>(
5+
(props, ref) => {
6+
useFileInput(ref as ExplicitAny);
7+
return <Input ref={ref} type="file" display="none" {...props} />;
8+
}
9+
);

Diff for: src/components/ImageUpload/cloudinary.service.ts

-28
This file was deleted.

Diff for: src/components/ImageUpload/docs.stories.tsx

+12-4
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,19 @@ export const Default = () => {
1515

1616
return (
1717
<Stack>
18-
<ImageUpload value={imageUrl} onChange={setImageUrl} w="240px" />
19-
<ImageUpload value={imageUrl} onChange={setImageUrl} w="360px" />
2018
<ImageUpload
2119
value={imageUrl}
22-
onChange={setImageUrl}
20+
onChange={(e) => setImageUrl(e.toString())}
21+
w="240px"
22+
/>
23+
<ImageUpload
24+
value={imageUrl}
25+
onChange={(e) => setImageUrl(e.toString())}
26+
w="360px"
27+
/>
28+
<ImageUpload
29+
value={imageUrl}
30+
onChange={(e) => setImageUrl(e.toString())}
2331
w="480px"
2432
ratio={1}
2533
/>
@@ -50,7 +58,7 @@ export const CustomPlaceholder = () => {
5058
<Stack>
5159
<ImageUpload
5260
value={imageUrl}
53-
onChange={setImageUrl}
61+
onChange={(e) => setImageUrl(e.toString())}
5462
placeholder={<PlaceholderComponent />}
5563
w="360px"
5664
/>

Diff for: src/components/ImageUpload/index.tsx

+50-57
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import {
88
IconButton,
99
Image,
1010
ImageProps,
11-
Input,
1211
} from '@chakra-ui/react';
12+
import Uploady from '@rpldy/uploady';
1313
import { FiX } from 'react-icons/fi';
1414

15-
import { Loader } from '@/app/layout';
1615
import { DefaultImagePlaceholder } from '@/components/ImageUpload/DefaultImagePlaceholder';
17-
import { uploadFile } from '@/components/ImageUpload/cloudinary.service';
16+
import { ImageUploadInput } from '@/components/ImageUpload/ImageUpload';
17+
import { Loader } from '@/layout/Loader';
1818

19-
export type ImageUploadProps = Omit<BoxProps, 'onChange' | 'placeholder'> &
19+
export type ImageUploadProps = BoxProps &
2020
Pick<AspectRatioProps, 'ratio'> & {
2121
value: string;
2222
onChange: (url: string) => void;
@@ -35,25 +35,11 @@ export const ImageUpload: React.FC<ImageUploadProps> = ({
3535
const fileInputRef = useRef<HTMLInputElement>(null);
3636
const [isUploading, setIsUploading] = useState(false);
3737

38+
// TODO: I think the onChange should handle the upload, and the form value should contain
39+
// the uploaded picture id (for future ref, like deleting on ccloudinary the uploaded image)
40+
// and the unique url
3841
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
39-
const file = e.target.files?.[0];
40-
if (!file) {
41-
return;
42-
}
43-
44-
try {
45-
setIsUploading(true);
46-
onUploadStateChange(true);
47-
48-
const imageUrl = await uploadFile(file);
49-
console.log({ imageUrl });
50-
onChange(imageUrl);
51-
} catch (err) {
52-
console.error(err);
53-
} finally {
54-
onUploadStateChange(false);
55-
setIsUploading(false);
56-
}
42+
// TODO
5743
};
5844

5945
const handleDelete = () => {
@@ -74,41 +60,48 @@ export const ImageUpload: React.FC<ImageUploadProps> = ({
7460
};
7561

7662
return (
77-
<Box
78-
position="relative"
79-
border="1px"
80-
borderStyle="dashed"
81-
borderColor="gray.200"
82-
borderRadius="16px"
83-
overflow="hidden"
84-
cursor="pointer"
85-
transition="border-color 150ms ease-in-out"
86-
_hover={{ borderColor: 'gray.400' }}
87-
{...rest}
63+
<Uploady
64+
destination={{
65+
url: `https://api.cloudinary.com/v1_1/s${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/upload`,
66+
params: {
67+
upload_preset: process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET,
68+
},
69+
}}
8870
>
89-
<Input
90-
ref={fileInputRef}
91-
type="file"
92-
display="none"
93-
onChange={handleChange}
94-
/>
95-
<AspectRatio ratio={ratio} onClick={() => fileInputRef.current?.click()}>
96-
<Image src={value} fallback={getFallback()} />
97-
</AspectRatio>
98-
{!!value && (
99-
<IconButton
100-
icon={<FiX />}
101-
position="absolute"
102-
top="0"
103-
right="0"
104-
size="lg"
105-
variant="ghost"
106-
aria-label="Remove photo"
107-
onClick={handleDelete}
108-
_active={{ bgColor: 'blackAlpha.600' }}
109-
_hover={{ bgColor: 'blackAlpha.300' }}
110-
/>
111-
)}
112-
</Box>
71+
<Box
72+
position="relative"
73+
border="1px"
74+
borderStyle="dashed"
75+
borderColor="gray.200"
76+
borderRadius="16px"
77+
overflow="hidden"
78+
cursor="pointer"
79+
transition="border-color 150ms ease-in-out"
80+
_hover={{ borderColor: 'gray.400' }}
81+
{...rest}
82+
>
83+
<ImageUploadInput ref={fileInputRef} onChange={handleChange} />
84+
<AspectRatio
85+
ratio={ratio}
86+
onClick={() => fileInputRef.current?.click()}
87+
>
88+
<Image src={value} fallback={getFallback()} />
89+
</AspectRatio>
90+
{!!value && (
91+
<IconButton
92+
icon={<FiX />}
93+
position="absolute"
94+
top="0"
95+
right="0"
96+
size="lg"
97+
variant="ghost"
98+
aria-label="Remove photo"
99+
onClick={handleDelete}
100+
_active={{ bgColor: 'blackAlpha.600' }}
101+
_hover={{ bgColor: 'blackAlpha.300' }}
102+
/>
103+
)}
104+
</Box>
105+
</Uploady>
113106
);
114107
};

0 commit comments

Comments
 (0)