WIP
Some checks failed
Build and Test / run-test (20.x) (push) Failing after 1m36s

This commit is contained in:
2026-04-09 20:57:35 -03:00
parent 9c0006e2dc
commit 3f9613d98b
12 changed files with 1631 additions and 52 deletions

View File

@@ -4,6 +4,7 @@ import { saveArticle } from '@/lib/feature/article/article.external';
import { Button } from '@/ui/components/shadcn/button';
import {
Field,
FieldDescription,
FieldError,
FieldGroup,
FieldLabel,
@@ -14,19 +15,21 @@ import {
InputGroupTextarea,
} from '@/ui/components/shadcn/input-group';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { Controller, useForm, useWatch } from 'react-hook-form';
import slugify from 'slugify';
import { toast } from 'sonner';
import { z } from 'zod';
export const CreateArticleForm = () => {
const fileInputRef = useRef<HTMLInputElement>(null);
const formSchema = z.object({
title: z.string().min(3).max(255),
slug: z.string().min(3),
description: z.string().min(10),
coverImageUrl: z.string().url(),
content: z.string().min(10),
coverImageUrl: z.url(),
content: z.instanceof(File),
});
const form = useForm<z.infer<typeof formSchema>>({
@@ -36,7 +39,7 @@ export const CreateArticleForm = () => {
slug: '',
description: '',
coverImageUrl: '',
content: '',
content: undefined,
},
});
@@ -50,27 +53,41 @@ export const CreateArticleForm = () => {
form.setValue('slug', slugify(title).toLowerCase());
}, [form, title]);
async function onSubmit(data: z.infer<typeof formSchema>) {
try {
const result = await saveArticle(data);
toast.success('Article created successfully!', {
description: `Article "${result.title}" has been created.`,
position: 'bottom-right',
});
form.reset();
} catch (error) {
toast.error('Failed to create article', {
description:
error instanceof Error
? error.message
: 'An error occurred',
position: 'bottom-right',
});
}
}
const handleFormSubmit = useCallback(
async (data: z.infer<typeof formSchema>) => {
try {
const result = await saveArticle({
...data,
content: await data.content.text(),
});
toast.success('Article created successfully!', {
description: `Article "${result.title}" has been created.`,
position: 'bottom-right',
});
form.reset();
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
} catch (error) {
toast.error('Failed to create article', {
description:
error instanceof Error
? error.message
: 'An error occurred',
position: 'bottom-right',
});
}
},
[form]
);
return (
<form id='form-create-article' onSubmit={form.handleSubmit(onSubmit)}>
<form
id='form-create-article'
// eslint-disable-next-line react-hooks/refs
onSubmit={form.handleSubmit(handleFormSubmit)}
>
<FieldGroup>
<Controller
name='title'
@@ -166,18 +183,24 @@ export const CreateArticleForm = () => {
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor='form-create-article-content'>
Content
Content (Markdown File)
</FieldLabel>
<InputGroup>
<InputGroupTextarea
{...field}
id='form-create-article-content'
placeholder='Write your article content here...'
rows={12}
className='min-h-48 resize-none font-mono text-sm'
aria-invalid={fieldState.invalid}
/>
</InputGroup>
<Input
ref={fileInputRef}
id='form-create-article-content'
type='file'
accept='.md,.markdown'
aria-invalid={fieldState.invalid}
onChange={(event) =>
field.onChange(
event.target.files &&
event.target.files[0]
)
}
/>
<FieldDescription>
Select your article.
</FieldDescription>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}