feature/adds-admin-add-article #1
@@ -54,6 +54,7 @@ function validateContentFile(file: File): string | null {
|
||||
|
||||
export const CreateArticleForm = () => {
|
||||
const [coverImageFile, setCoverImageFile] = useState<File | null>(null);
|
||||
const [coverImageUploading, setCoverImageUploading] = useState(false);
|
||||
const [contentFile, setContentFile] = useState<File | null>(null);
|
||||
const coverImageUrlRef = useRef<string | null>(null);
|
||||
|
||||
@@ -78,10 +79,8 @@ export const CreateArticleForm = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const title = useWatch({
|
||||
control: form.control,
|
||||
name: 'title',
|
||||
});
|
||||
const title = useWatch({ control: form.control, name: 'title' });
|
||||
const coverImageUrl = useWatch({ control: form.control, name: 'coverImageUrl' });
|
||||
useEffect(() => {
|
||||
if (!title) return;
|
||||
form.setValue('slug', slugify(title).toLowerCase());
|
||||
@@ -93,6 +92,7 @@ export const CreateArticleForm = () => {
|
||||
coverImageUrlRef.current = null;
|
||||
}
|
||||
setCoverImageFile(null);
|
||||
setCoverImageUploading(false);
|
||||
setContentFile(null);
|
||||
}, []);
|
||||
|
||||
@@ -128,10 +128,13 @@ export const CreateArticleForm = () => {
|
||||
setCoverImageFile(file);
|
||||
if (!file) {
|
||||
setCoverImageFile(null);
|
||||
setCoverImageUploading(false);
|
||||
form.setValue('coverImageUrl', '');
|
||||
return;
|
||||
}
|
||||
setCoverImageUploading(true);
|
||||
const fileMetadataResult = await uploadFile(file);
|
||||
setCoverImageUploading(false);
|
||||
if (!fileMetadataResult.ok) {
|
||||
setCoverImageFile(null);
|
||||
form.setValue('coverImageUrl', '');
|
||||
@@ -255,6 +258,8 @@ export const CreateArticleForm = () => {
|
||||
label='Cover image'
|
||||
description='PNG, JPG, GIF, WebP accepted'
|
||||
error={form.formState.errors.coverImageUrl?.message}
|
||||
previewUrl={coverImageUrl || undefined}
|
||||
isUploading={coverImageUploading}
|
||||
icon={
|
||||
<Image
|
||||
src={ImageLogo}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
} from '@/ui/components/shadcn/field';
|
||||
import { Spinner } from '@/ui/components/shadcn/spinner';
|
||||
import {
|
||||
FileUpload,
|
||||
FileUploadDropzone,
|
||||
@@ -29,6 +30,8 @@ export interface FileUploadFieldProps {
|
||||
description?: string;
|
||||
error?: string;
|
||||
icon?: React.ReactNode;
|
||||
previewUrl?: string;
|
||||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
export const FileUploadField: React.FC<FileUploadFieldProps> = ({
|
||||
@@ -41,6 +44,8 @@ export const FileUploadField: React.FC<FileUploadFieldProps> = ({
|
||||
description,
|
||||
error,
|
||||
icon,
|
||||
previewUrl,
|
||||
isUploading,
|
||||
}) => {
|
||||
const handleAccept = useCallback(
|
||||
(files: File[]) => {
|
||||
@@ -90,7 +95,24 @@ export const FileUploadField: React.FC<FileUploadFieldProps> = ({
|
||||
<FileUploadList>
|
||||
{file && (
|
||||
<FileUploadItem value={file}>
|
||||
<FileUploadItemPreview />
|
||||
<FileUploadItemPreview
|
||||
render={
|
||||
isUploading
|
||||
? () => (
|
||||
<Spinner className='size-5 text-muted-foreground' />
|
||||
)
|
||||
: previewUrl
|
||||
? () => (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={previewUrl}
|
||||
alt='Uploaded image'
|
||||
className='size-full object-cover'
|
||||
/>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<FileUploadItemMetadata size='sm' />
|
||||
<FileUploadItemDelete asChild>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user