280 lines
8.4 KiB
TypeScript
280 lines
8.4 KiB
TypeScript
|
|
/**
|
||
|
|
* Form Components Demo
|
||
|
|
*
|
||
|
|
* This component demonstrates how to use the new reusable form components.
|
||
|
|
* It shows examples of all the form field types and layout components.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import React from 'react';
|
||
|
|
import { useForm } from 'react-hook-form';
|
||
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||
|
|
import * as z from 'zod';
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import { Card } from '@/components/ui/card';
|
||
|
|
import {
|
||
|
|
FormField,
|
||
|
|
FormSelect,
|
||
|
|
FormCheckbox,
|
||
|
|
FormRadio,
|
||
|
|
FormDatePicker,
|
||
|
|
FormSection,
|
||
|
|
FormGrid,
|
||
|
|
FormGridItem,
|
||
|
|
SelectOption,
|
||
|
|
CheckboxOption,
|
||
|
|
RadioOption,
|
||
|
|
} from './index';
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// SCHEMA
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
const demoFormSchema = z.object({
|
||
|
|
title: z.string().min(1, 'Title is required'),
|
||
|
|
description: z.string().min(10, 'Description must be at least 10 characters'),
|
||
|
|
category: z.string().min(1, 'Category is required'),
|
||
|
|
priority: z.string().min(1, 'Priority is required'),
|
||
|
|
tags: z.array(z.string()).min(1, 'At least one tag is required'),
|
||
|
|
status: z.string().min(1, 'Status is required'),
|
||
|
|
dueDate: z.date().optional(),
|
||
|
|
isPublic: z.boolean().default(false),
|
||
|
|
notifications: z.array(z.string()).default([]),
|
||
|
|
});
|
||
|
|
|
||
|
|
type DemoFormData = z.infer<typeof demoFormSchema>;
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// OPTIONS DATA
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
const categoryOptions: SelectOption[] = [
|
||
|
|
{ value: 'feature', label: 'Feature Request' },
|
||
|
|
{ value: 'bug', label: 'Bug Report' },
|
||
|
|
{ value: 'improvement', label: 'Improvement' },
|
||
|
|
{ value: 'documentation', label: 'Documentation' },
|
||
|
|
];
|
||
|
|
|
||
|
|
const priorityOptions: RadioOption[] = [
|
||
|
|
{ value: 'low', label: 'Low' },
|
||
|
|
{ value: 'medium', label: 'Medium' },
|
||
|
|
{ value: 'high', label: 'High' },
|
||
|
|
{ value: 'urgent', label: 'Urgent' },
|
||
|
|
];
|
||
|
|
|
||
|
|
const tagOptions: CheckboxOption[] = [
|
||
|
|
{ value: 'frontend', label: 'Frontend' },
|
||
|
|
{ value: 'backend', label: 'Backend' },
|
||
|
|
{ value: 'ui', label: 'UI/UX' },
|
||
|
|
{ value: 'database', label: 'Database' },
|
||
|
|
{ value: 'security', label: 'Security' },
|
||
|
|
{ value: 'performance', label: 'Performance' },
|
||
|
|
];
|
||
|
|
|
||
|
|
const statusOptions: SelectOption[] = [
|
||
|
|
{ value: 'draft', label: 'Draft' },
|
||
|
|
{ value: 'in-progress', label: 'In Progress' },
|
||
|
|
{ value: 'review', label: 'Under Review' },
|
||
|
|
{ value: 'completed', label: 'Completed' },
|
||
|
|
];
|
||
|
|
|
||
|
|
const notificationOptions: CheckboxOption[] = [
|
||
|
|
{ value: 'email', label: 'Email Notifications' },
|
||
|
|
{ value: 'push', label: 'Push Notifications' },
|
||
|
|
{ value: 'sms', label: 'SMS Notifications' },
|
||
|
|
];
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// COMPONENT
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
export function FormComponentsDemo() {
|
||
|
|
const form = useForm<DemoFormData>({
|
||
|
|
resolver: zodResolver(demoFormSchema),
|
||
|
|
defaultValues: {
|
||
|
|
title: '',
|
||
|
|
description: '',
|
||
|
|
category: '',
|
||
|
|
priority: 'medium',
|
||
|
|
tags: [],
|
||
|
|
status: 'draft',
|
||
|
|
dueDate: undefined,
|
||
|
|
isPublic: false,
|
||
|
|
notifications: ['email'],
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
const onSubmit = (data: DemoFormData) => {
|
||
|
|
console.log('Form submitted:', data);
|
||
|
|
alert('Form submitted! Check console for data.');
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="max-w-4xl mx-auto p-6 space-y-6">
|
||
|
|
<div className="text-center">
|
||
|
|
<h1 className="text-3xl font-bold mb-2">Form Components Demo</h1>
|
||
|
|
<p className="text-muted-foreground">
|
||
|
|
Examples of using the new reusable form components
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||
|
|
{/* Basic Information Section */}
|
||
|
|
<FormSection
|
||
|
|
title="Basic Information"
|
||
|
|
description="Enter the basic details for your item"
|
||
|
|
variant="default"
|
||
|
|
>
|
||
|
|
<FormGrid cols={1} md={2} gap="md">
|
||
|
|
<FormGridItem>
|
||
|
|
<FormField
|
||
|
|
control={form.control}
|
||
|
|
name="title"
|
||
|
|
label="Title"
|
||
|
|
placeholder="Enter a descriptive title"
|
||
|
|
required
|
||
|
|
validation={{
|
||
|
|
required: 'Title is required',
|
||
|
|
minLength: { value: 3, message: 'Title must be at least 3 characters' },
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
|
||
|
|
<FormGridItem>
|
||
|
|
<FormSelect
|
||
|
|
control={form.control}
|
||
|
|
name="category"
|
||
|
|
label="Category"
|
||
|
|
placeholder="Select a category"
|
||
|
|
options={categoryOptions}
|
||
|
|
required
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
|
||
|
|
<FormGridItem span={2}>
|
||
|
|
<FormField
|
||
|
|
control={form.control}
|
||
|
|
name="description"
|
||
|
|
label="Description"
|
||
|
|
placeholder="Provide a detailed description"
|
||
|
|
fieldType="textarea"
|
||
|
|
required
|
||
|
|
validation={{
|
||
|
|
minLength: { value: 10, message: 'Description must be at least 10 characters' },
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
</FormGrid>
|
||
|
|
</FormSection>
|
||
|
|
|
||
|
|
{/* Priority and Status Section */}
|
||
|
|
<FormSection
|
||
|
|
title="Priority & Status"
|
||
|
|
description="Set the priority level and current status"
|
||
|
|
variant="bordered"
|
||
|
|
>
|
||
|
|
<FormGrid cols={1} md={2} gap="lg">
|
||
|
|
<FormGridItem>
|
||
|
|
<FormRadio
|
||
|
|
control={form.control}
|
||
|
|
name="priority"
|
||
|
|
label="Priority Level"
|
||
|
|
options={priorityOptions}
|
||
|
|
required
|
||
|
|
layout="vertical"
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
|
||
|
|
<FormGridItem>
|
||
|
|
<FormSelect
|
||
|
|
control={form.control}
|
||
|
|
name="status"
|
||
|
|
label="Status"
|
||
|
|
placeholder="Select current status"
|
||
|
|
options={statusOptions}
|
||
|
|
required
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
</FormGrid>
|
||
|
|
</FormSection>
|
||
|
|
|
||
|
|
{/* Tags and Settings Section */}
|
||
|
|
<FormSection
|
||
|
|
title="Tags & Settings"
|
||
|
|
description="Add relevant tags and configure settings"
|
||
|
|
variant="minimal"
|
||
|
|
collapsible
|
||
|
|
defaultExpanded={false}
|
||
|
|
>
|
||
|
|
<FormGrid cols={1} md={2} gap="md">
|
||
|
|
<FormGridItem>
|
||
|
|
<FormCheckbox
|
||
|
|
control={form.control}
|
||
|
|
name="tags"
|
||
|
|
label="Tags"
|
||
|
|
options={tagOptions}
|
||
|
|
required
|
||
|
|
layout="vertical"
|
||
|
|
columns={2}
|
||
|
|
/>
|
||
|
|
</FormGridItem>
|
||
|
|
|
||
|
|
<FormGridItem>
|
||
|
|
<FormDatePicker
|
||
|
|
control={form.control}
|
||
|
|
name="dueDate"
|
||
|
|
label="Due Date"
|
||
|
|
placeholder="Select due date"
|
||
|
|
mode="single"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div className="mt-4">
|
||
|
|
<FormCheckbox
|
||
|
|
control={form.control}
|
||
|
|
name="isPublic"
|
||
|
|
label="Make this item public"
|
||
|
|
single
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="mt-4">
|
||
|
|
<FormCheckbox
|
||
|
|
control={form.control}
|
||
|
|
name="notifications"
|
||
|
|
label="Notification Preferences"
|
||
|
|
options={notificationOptions}
|
||
|
|
layout="vertical"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</FormGridItem>
|
||
|
|
</FormGrid>
|
||
|
|
</FormSection>
|
||
|
|
|
||
|
|
{/* Form Actions */}
|
||
|
|
<Card className="p-4">
|
||
|
|
<div className="flex justify-end gap-3">
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="outline"
|
||
|
|
onClick={() => form.reset()}
|
||
|
|
>
|
||
|
|
Reset Form
|
||
|
|
</Button>
|
||
|
|
<Button type="submit">
|
||
|
|
Submit Form
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</Card>
|
||
|
|
</form>
|
||
|
|
|
||
|
|
{/* Form Data Display */}
|
||
|
|
<Card className="p-4">
|
||
|
|
<h3 className="text-lg font-semibold mb-3">Current Form Data</h3>
|
||
|
|
<pre className="bg-muted p-3 rounded text-sm overflow-auto">
|
||
|
|
{JSON.stringify(form.watch(), null, 2)}
|
||
|
|
</pre>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default FormComponentsDemo;
|