-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from bhavik-goplani/develop
Develop: Added viewing and creating sections for surveys
- Loading branch information
Showing
9 changed files
with
471 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' | ||
import { cookies } from 'next/headers' | ||
import { CreateSection } from '@/components/section-dashboard/create-section' | ||
import { DataTable } from '@/components/section-dashboard/data-table' | ||
import { Section, columns } from '@/components/section-dashboard/columns' | ||
|
||
export const dynamic = 'force-dynamic' | ||
|
||
export default async function Page({ params }: { params: { survey_id: string } }) { | ||
const cookieStore = cookies() | ||
const supabase = createServerComponentClient<Database>({ cookies: () => cookieStore }) | ||
|
||
async function getSections() : Promise<Section[]> { | ||
let { data: Section, error } = await supabase | ||
.from('Section') | ||
.select('*') | ||
.eq('survey_id', params.survey_id) | ||
if (error) console.log('error', error) | ||
return Section as Section[] | ||
} | ||
|
||
const data = await getSections() | ||
return ( | ||
<> | ||
<div className="container mx-auto py-10"> | ||
<div className='flex justify-between'> | ||
<h1 className="text-2xl font-semibold tracking-tight">Sections</h1> | ||
<CreateSection survey_id={params.survey_id} /> | ||
</div> | ||
<div className='py-4'> | ||
<DataTable columns={columns} data={data} /> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
'use client' | ||
|
||
import { ColumnDef } from "@tanstack/react-table" | ||
import { ArrowUpDown, MoreHorizontal } from "lucide-react" | ||
import { Button } from "@/components/ui/button" | ||
import { | ||
DropdownMenu, | ||
DropdownMenuContent, | ||
DropdownMenuLabel, | ||
DropdownMenuItem, | ||
DropdownMenuSeparator, | ||
DropdownMenuTrigger, | ||
} from "@/components/ui/dropdown-menu" | ||
import * as React from "react" | ||
import { toast } from "@/components/ui/use-toast" | ||
import { useRouter } from 'next/navigation' | ||
import Link from 'next/link'; | ||
import { | ||
AlertDialog, | ||
AlertDialogCancel, | ||
AlertDialogContent, | ||
AlertDialogDescription, | ||
AlertDialogFooter, | ||
AlertDialogHeader, | ||
AlertDialogTitle, | ||
} from "@/components/ui/alert-dialog" | ||
|
||
export type Section = { | ||
paper_prob: number; | ||
rock_prob: number; | ||
scissor_prob: number; | ||
section_id: string; | ||
survey_id: string; | ||
trial_no: number; | ||
} | ||
|
||
export const columns: ColumnDef<Section>[] = [ | ||
{ | ||
accessorKey: "rock_prob", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} | ||
> | ||
Rock Probability | ||
<ArrowUpDown className="ml-2 h-4 w-4" /> | ||
</Button> | ||
) | ||
}, | ||
}, | ||
{ | ||
accessorKey: "paper_prob", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} | ||
> | ||
Paper Probability | ||
<ArrowUpDown className="ml-2 h-4 w-4" /> | ||
</Button> | ||
) | ||
}, | ||
}, | ||
{ | ||
accessorKey: "scissor_prob", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} | ||
> | ||
Scissors Probability | ||
<ArrowUpDown className="ml-2 h-4 w-4" /> | ||
</Button> | ||
) | ||
}, | ||
}, | ||
{ | ||
accessorKey: "trial_no", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} | ||
> | ||
Trial Number | ||
<ArrowUpDown className="ml-2 h-4 w-4" /> | ||
</Button> | ||
) | ||
}, | ||
}, | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
'use client' | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog" | ||
|
||
import { | ||
Form, | ||
FormControl, | ||
FormDescription, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form" | ||
|
||
import * as z from "zod" | ||
import { Button } from "@/components/ui/button" | ||
import { Input } from "@/components/ui/input" | ||
import { zodResolver } from "@hookform/resolvers/zod" | ||
import { useForm } from "react-hook-form" | ||
import { useRouter } from 'next/navigation' | ||
import * as React from "react" | ||
import { useToast } from "@/components/ui/use-toast" | ||
|
||
const formSchema = z.object({ | ||
rockProbability: z.number().min(0.00).max(1.00), | ||
paperProbability: z.number().min(0.00).max(1.00), | ||
scissorsProbability: z.number().min(0.00).max(1.00), | ||
trialNumber: z.number().min(1).max(100), | ||
}) | ||
|
||
export function CreateSection( {survey_id} : {survey_id: string} ) { | ||
|
||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
defaultValues: { | ||
rockProbability: 0.0, | ||
paperProbability: 0.0, | ||
scissorsProbability: 0.0, | ||
trialNumber: 1, | ||
}, | ||
}, | ||
) | ||
|
||
const [isOpen, setIsOpen] = React.useState(false) | ||
const { reset } = form | ||
const router = useRouter() | ||
const { toast } = useToast() | ||
|
||
async function onSubmit (values: z.infer<typeof formSchema>) { | ||
reset() | ||
setIsOpen(false) | ||
|
||
const sum = values.rockProbability + values.paperProbability + values.scissorsProbability; | ||
if (sum != 1) { | ||
return toast({ | ||
title: "Error", | ||
description: "Probabilities must sum to 1.", | ||
variant: "destructive", | ||
}) | ||
} | ||
|
||
const res = await fetch('/api/section', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ | ||
rockProbability: values.rockProbability, | ||
paperProbability: values.paperProbability, | ||
scissorsProbability: values.scissorsProbability, | ||
trialNumber: values.trialNumber, | ||
survey_id: survey_id, | ||
}), | ||
}); | ||
if (res.ok) { | ||
router.refresh() | ||
return toast({ | ||
title: "Section created.", | ||
description: "Your section has been created.", | ||
}) | ||
} else { | ||
return toast({ | ||
title: "Error", | ||
description: "Something went wrong.", | ||
variant: "destructive", | ||
}) | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<Dialog open={isOpen} onOpenChange={(open) => { | ||
setIsOpen(open); | ||
if (!open) { | ||
reset(); // Reset form values when dialog closes | ||
} | ||
}}> | ||
<DialogTrigger asChild> | ||
<Button variant="outline">Create New Section</Button> | ||
</DialogTrigger> | ||
<DialogContent className="sm:max-w-[425px]"> | ||
<DialogHeader> | ||
<DialogTitle>Create New Section</DialogTitle> | ||
</DialogHeader> | ||
<Form {...form}> | ||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8"> | ||
<FormField | ||
control={form.control} | ||
name="rockProbability" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Probability of Rock</FormLabel> | ||
<FormControl> | ||
<Input | ||
type="number" | ||
value={field.value} | ||
step = "0.01" | ||
onChange={event => field.onChange(event.target.value === "" ? null : Number(event.target.value))} | ||
/> | ||
</FormControl> | ||
<FormDescription> | ||
This is the probability of rock out of 1. | ||
</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="paperProbability" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Probability of Paper</FormLabel> | ||
<FormControl> | ||
<Input | ||
type="number" | ||
value={field.value} | ||
step = "0.01" | ||
onChange={event => field.onChange(event.target.value === "" ? null : Number(event.target.value))} | ||
/> | ||
</FormControl> | ||
<FormDescription> | ||
This is the probability of paper out of 1. | ||
</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="scissorsProbability" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Probability of Scissor</FormLabel> | ||
<FormControl> | ||
<Input | ||
type="number" | ||
value={field.value} | ||
step = "0.01" | ||
onChange={event => field.onChange(event.target.value === "" ? null : Number(event.target.value))} | ||
/> | ||
</FormControl> | ||
<FormDescription> | ||
This is the probability of scissors out of 1. | ||
</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="trialNumber" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Trial Number</FormLabel> | ||
<FormControl> | ||
<Input | ||
type="number" | ||
value={field.value} | ||
onChange={event => field.onChange(event.target.value === "" ? null : Number(event.target.value))} | ||
/> | ||
</FormControl> | ||
<FormDescription> | ||
This is the number of trials. | ||
</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button type="submit">Submit</Button> | ||
</form> | ||
</Form> | ||
</DialogContent> | ||
</Dialog> | ||
</> | ||
); | ||
} |
Oops, something went wrong.