Skip to content

Commit

Permalink
feat: Add isPublished field to Quiz model and update related components
Browse files Browse the repository at this point in the history
  • Loading branch information
Alvalens committed Jan 10, 2025
1 parent 451f53a commit 830dc17
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 152 deletions.
10 changes: 10 additions & 0 deletions app/admin/dashboard/quiz/components/quizColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ export const columns: ColumnDef<QuizWithAuthor>[] = [
</div>
}
},
{
accessorKey: "isPublished",
header: "Published",
cell: ({ row }) => {
const quiz = row.original;
return <div className="py-4">
{quiz.isPublished ? "Yes" : "No"}
</div>
}
},
{
id: "total",
header: () => {
Expand Down
293 changes: 154 additions & 139 deletions app/admin/dashboard/quiz/components/quizForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,156 +10,171 @@ import { z } from 'zod';
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { QuizWithAllRelations } from '../lib/definition';
import { Checkbox } from '@/components/ui/checkbox'; // Import Checkbox component

interface QuizFormProps {
quiz?: QuizWithAllRelations,
type: "ADD" | "EDIT"
quiz?: QuizWithAllRelations,
type: "ADD" | "EDIT"
}

const schema = z.object({
title: z.string().min(3, { message: "Title must be at least 3 characters" }).nonempty({ message: "Title cannot be empty" }),
content: z.string().min(10, { message: "Content must be at least 10 characters" }).nonempty({ message: "Content cannot be empty" }),
image: z.string().url({ message: "Invalid URL" }),
quizType: z.string().nonempty({ message: "Quiz type is required" })
title: z.string().min(3, { message: "Title must be at least 3 characters" }).nonempty({ message: "Title cannot be empty" }),
content: z.string().min(10, { message: "Content must be at least 10 characters" }).nonempty({ message: "Content cannot be empty" }),
image: z.string().url({ message: "Invalid URL" }),
quizType: z.string().nonempty({ message: "Quiz type is required" }),
isPublished: z.boolean()
});


const QuizForm: FC<QuizFormProps> = ({ quiz, type }) => {
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: {
title: type === "ADD" ? '' : quiz?.title,
content: type === "ADD" ? '' : quiz?.content,
image: type === "ADD" ? '' : quiz?.image ?? '',
quizType: type === "ADD" ? '' : quiz?.quizType
}
})

async function onSubmit(values: z.infer<typeof schema>) {
let url = `/api/quizzes`;
if (type === "EDIT") url += `/${quiz?.id}`;
const response = await fetch(url, {
method: type === "ADD" ? "POST" : "PUT",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(values)
});
await response.json();
if (response.ok) {
if (response.ok) {
router.push('/admin/dashboard/quiz');
} else {
console.error('Failed to save the quiz:', response.statusText);
// Handle the error appropriately here, e.g., show a notification to the user
}
}
}
const router = useRouter();

return (
<>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-6">

<div className='space-y-1 md:space-y-2'>
<FormField
control={form.control}
name='title'
render={({ field }) => {
return <FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input className='shadow' placeholder='Title' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='space-y-1 md:space-y-2'>
<FormField
control={form.control}
name='content'
render={({ field }) => {
return <FormItem>
<FormLabel>Content</FormLabel>
<FormControl>
<Textarea className='shadow min-h-[7rem]' placeholder='Content' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='grid md:grid-cols-4 gap-4'>
<div className='space-y-1 md:space-y-2 col-span-2 lg:col-span-3'>
<FormField
control={form.control}
name='image'
render={({ field }) => {
return <FormItem>
<FormLabel>Image URL</FormLabel>
<FormControl>
<Input placeholder='Image URL' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='space-y-1 md:space-y-2 col-span-2 lg:col-span-1'>
<FormField
control={form.control}
name='quizType'
render={({ field }) => {
return <FormItem>
<FormLabel>Quiz Type</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger className="">
<SelectValue placeholder="Select a quiz type" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectGroup>
{/* {quizTypes.map(type => {
return <SelectItem key={type} value={type}>{type}</SelectItem>
})} */}
<SelectItem value="WEB">Web Development</SelectItem>
<SelectItem value="MOBILE">Mobile Development</SelectItem>
<SelectItem value="ML">Machine Learning</SelectItem>
<SelectItem value="UIUX">UI/UX</SelectItem>
<SelectItem value="OTHER">Other</SelectItem>

</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
</FormItem>

}} />

</div>
</div>

{/* <Button type='submit'>Submit</Button> */}
<div className='flex justify-end gap-4 mt-2'>
<Button type='button' onClick={() => router.back()} variant='ghost'>{type === "ADD" ? 'Cancel' : 'Back'}</Button>
<Button>Save</Button>
</div>
</form>
</Form>
</>
)
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: {
title: type === "ADD" ? '' : quiz?.title,
content: type === "ADD" ? '' : quiz?.content,
image: type === "ADD" ? '' : quiz?.image ?? '',
quizType: type === "ADD" ? '' : quiz?.quizType,
isPublished: type === "ADD" ? false : quiz?.isPublished ?? false
}
})

async function onSubmit(values: z.infer<typeof schema>) {
let url = `/api/quizzes`;
if (type === "EDIT") url += `/${quiz?.id}`;
const response = await fetch(url, {
method: type === "ADD" ? "POST" : "PUT",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(values)
});
await response.json();
if (response.ok) {
router.push('/admin/dashboard/quiz');
} else {
console.error('Failed to save the quiz:', response.statusText);
// Handle the error appropriately here, e.g., show a notification to the user
}
}
const router = useRouter();

return (
<>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-6">

<div className='space-y-1 md:space-y-2'>
<FormField
control={form.control}
name='title'
render={({ field }) => {
return <FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input className='shadow' placeholder='Title' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='space-y-1 md:space-y-2'>
<FormField
control={form.control}
name='content'
render={({ field }) => {
return <FormItem>
<FormLabel>Content</FormLabel>
<FormControl>
<Textarea className='shadow min-h-[7rem]' placeholder='Content' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='grid md:grid-cols-4 gap-4'>
<div className='space-y-1 md:space-y-2 col-span-2 lg:col-span-3'>
<FormField
control={form.control}
name='image'
render={({ field }) => {
return <FormItem>
<FormLabel>Image URL</FormLabel>
<FormControl>
<Input placeholder='Image URL' {...field} />
</FormControl>
<FormMessage />
</FormItem>

}} />
</div>
<div className='space-y-1 md:space-y-2 col-span-2 lg:col-span-1'>
<FormField
control={form.control}
name='quizType'
render={({ field }) => {
return <FormItem>
<FormLabel>Quiz Type</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger className="">
<SelectValue placeholder="Select a quiz type" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectGroup>
<SelectItem value="WEB">Web Development</SelectItem>
<SelectItem value="MOBILE">Mobile Development</SelectItem>
<SelectItem value="ML">Machine Learning</SelectItem>
<SelectItem value="UIUX">UI/UX</SelectItem>
<SelectItem value="OTHER">Other</SelectItem>

</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
</FormItem>

}} />

</div>
</div>

{/* Published Checkbox */}
<div className='flex items-center space-x-2'>
<FormField
control={form.control}
name='isPublished'
render={({ field }) => (
<FormItem className="flex items-center space-x-2">
<FormControl>
<Checkbox
checked={field.value}
onCheckedChange={(checked: boolean) => field.onChange(checked)}/>
</FormControl>
<FormLabel>Published</FormLabel>
</FormItem>
)}
/>
</div>

<div className='flex justify-end gap-4 mt-2'>
<Button type='button' onClick={() => router.back()} variant='ghost'>{type === "ADD" ? 'Cancel' : 'Back'}</Button>
<Button type="submit">Save</Button>
</div>
</form>
</Form>
</>
)
}

export default QuizForm
Empty file.
24 changes: 13 additions & 11 deletions app/api/quizzes/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@ export const GET = async (req: NextRequest, context: Context) => {
export const PUT = async (req: NextRequest, context: Context) => {
try {
const { id } = await context.params;
const { title, content, image, quizType } = await req.json();
const { title, content, image, quizType, isPublished } =
await req.json();
const validQuizTypes = ["WEB", "MOBILE", "ML", "UIUX", "OTHER"];
if (!validQuizTypes.includes(quizType)) {
return NextResponse.json({ success: false, message: "Invalid quiz type" }, { status: 400 });
}
await prisma.quiz.update({
where: {
id
},
data: {
title,
content,
image,
quizType
}
});
where: {
id,
},
data: {
title,
content,
image,
quizType,
isPublished,
},
});
return NextResponse.json({ success: true, message: "Quiz updated successfully" });
} catch (error) {
console.log(error);
Expand Down
4 changes: 3 additions & 1 deletion app/api/quizzes/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ export const GET = async (req: NextRequest) => {

export const POST = async (req: NextRequest) => {
try {
const { title, content, image, quizType } = await req.json();
const { title, content, image, quizType, isPublished } =
await req.json();
const validQuizTypes = ["WEB", "MOBILE", "ML", "UIUX", "OTHER"];
if (!validQuizTypes.includes(quizType)) {
return NextResponse.json({ success: false, message: "Invalid quiz type" }, { status: 400 });
Expand All @@ -88,6 +89,7 @@ export const POST = async (req: NextRequest) => {
content,
image,
quizType,
isPublished,
authorId: user_id,
}
});
Expand Down
Loading

0 comments on commit 830dc17

Please sign in to comment.