feat(guides): scaffold new guide form, hook, and update schemas
- Add useNewGuide hook with state and handlers for guide, frames, and steps - Add title, description, and file upload inputs to NewGuide - Add FileUpload component and supporting hooks - Add guideId to FrameSchema, remove steps and order - Remove content field and frames array from GuideSchema - Remove order field from StepsSchema
This commit is contained in:
parent
fc63290806
commit
8a8d495432
4 changed files with 97 additions and 6 deletions
8
src/features/guides/components/FileUpload.tsx
Normal file
8
src/features/guides/components/FileUpload.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export default function FileUpload() {
|
||||
return (
|
||||
<label>
|
||||
<span>File</span>
|
||||
<input type="file" name="file" accept="images/*" multiple />
|
||||
</label>
|
||||
);
|
||||
}
|
||||
74
src/features/guides/hooks/useNewGuide.ts
Normal file
74
src/features/guides/hooks/useNewGuide.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import { useState } from "react";
|
||||
import { Frame, type Guide, type Steps } from "../../../lib/schemas";
|
||||
|
||||
export default function useNewGuide() {
|
||||
const [guide, setGuide] = useState<Guide>({
|
||||
id: crypto.randomUUID(),
|
||||
title: "",
|
||||
description: "",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
deletedAt: undefined,
|
||||
});
|
||||
const [frames, setFrames] = useState<Frame[]>([]);
|
||||
const [steps, setSteps] = useState<Steps[]>([]);
|
||||
|
||||
const handleUpdateTitle = (title: string) => {
|
||||
setGuide((prev) => ({ ...prev, title }));
|
||||
};
|
||||
|
||||
const handleUpdateDescription = (description: string) => {
|
||||
setGuide((prev) => ({ ...prev, description }));
|
||||
};
|
||||
|
||||
const handleAddFrames = (newFiles: File[]) => {
|
||||
const newFrameObjects = newFiles.map((file) => ({
|
||||
id: crypto.randomUUID(),
|
||||
file: file,
|
||||
guideId: guide.id,
|
||||
}));
|
||||
|
||||
setFrames((prev) => [...prev, ...newFrameObjects]);
|
||||
};
|
||||
|
||||
const handleRemoveFrame = (frameId: string) => {
|
||||
setFrames((prev) => prev.filter((frame) => frame.id !== frameId));
|
||||
};
|
||||
|
||||
const handleAddSteps = (frameId: string) => {
|
||||
setSteps((prev) => [
|
||||
...prev,
|
||||
{
|
||||
id: crypto.randomUUID(),
|
||||
text: "",
|
||||
frameId: frameId,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const handleUpdateStepText = (stepId: string, text: string) => {
|
||||
setSteps((prev) =>
|
||||
prev.map((step) => (step.id === stepId ? { ...step, text } : step)),
|
||||
);
|
||||
};
|
||||
|
||||
const handleRemoveStep = (stepId: string) => {
|
||||
setSteps((prev) => prev.filter((step) => step.id !== stepId));
|
||||
};
|
||||
|
||||
return {
|
||||
guide,
|
||||
setGuide,
|
||||
frames,
|
||||
setFrames,
|
||||
steps,
|
||||
setSteps,
|
||||
handleUpdateTitle,
|
||||
handleUpdateDescription,
|
||||
handleAddFrames,
|
||||
handleAddSteps,
|
||||
handleRemoveFrame,
|
||||
handleUpdateStepText,
|
||||
handleRemoveStep,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,20 @@
|
|||
import FileUpload from "../components/FileUpload";
|
||||
|
||||
export default function NewGuide() {
|
||||
return (
|
||||
<div>
|
||||
<h1>New Guide</h1>
|
||||
<form>
|
||||
<label>
|
||||
<span>Title</span>
|
||||
<input type="text" name="title" />
|
||||
</label>
|
||||
<label>
|
||||
<span>Description</span>
|
||||
<textarea name="description" />
|
||||
</label>
|
||||
|
||||
<FileUpload />
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,26 +3,22 @@ import { z } from "zod";
|
|||
export const StepsSchema = z.object({
|
||||
id: z.uuid().default(() => crypto.randomUUID()),
|
||||
text: z.string().min(1, "Text is required"),
|
||||
order: z.number(),
|
||||
frameId: z.uuid(),
|
||||
});
|
||||
|
||||
export const FrameSchema = z.object({
|
||||
id: z.uuid().default(() => crypto.randomUUID()),
|
||||
file: z.instanceof(File),
|
||||
steps: z.array(StepsSchema).min(1, "Steps are required"),
|
||||
order: z.number(),
|
||||
guideId: z.uuid(),
|
||||
});
|
||||
|
||||
export const GuideSchema = z.object({
|
||||
id: z.uuid().default(() => crypto.randomUUID()),
|
||||
title: z.string().min(1, "Title is required"),
|
||||
description: z.string().optional(),
|
||||
content: z.string().optional(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
deletedAt: z.date().optional(),
|
||||
frames: z.array(FrameSchema).min(1, "Frames are required"),
|
||||
});
|
||||
|
||||
export type Steps = z.infer<typeof StepsSchema>;
|
||||
|
|
|
|||
Loading…
Reference in a new issue