Skip to content

Commit

Permalink
added Table
Browse files Browse the repository at this point in the history
  • Loading branch information
talz-a committed Jan 20, 2025
1 parent 6c2d0a0 commit e58f5f3
Show file tree
Hide file tree
Showing 9 changed files with 1,054 additions and 723 deletions.
108 changes: 108 additions & 0 deletions apps/web/app/home/_components/add-student-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use client';

import { useEffect, useState } from 'react';
import { useActionState } from 'react';

import { Button } from '@kit/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@kit/ui/dialog';
import { Input } from '@kit/ui/input';
import { Label } from '@kit/ui/label';

import addStudent from '~/home/actions';

type State = {
errors?: {
name?: string[];
email?: string[];
};
message?: string | null;
success?: boolean;
};

const initialState: State = { message: null, errors: {}, success: false };

export default function AddStudentDialog() {
const [open, setOpen] = useState(false);
const [state, formAction] = useActionState(addStudent, initialState);

useEffect(() => {
if (state.success) {
setOpen(false);
}
}, [state.success]);

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline">Add Student</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Add Student</DialogTitle>
<DialogDescription>
Add a new student to your account.
</DialogDescription>
</DialogHeader>
<form action={formAction}>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<div className="col-span-3">
<Input
id="name"
name="name"
placeholder="Enter student name"
className={state.errors?.name ? 'border-red-500' : ''}
/>
{state.errors?.name && (
<p className="mt-1 text-sm text-red-500">
{state.errors.name[0]}
</p>
)}
</div>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="email" className="text-right">
Email
</Label>
<div className="col-span-3">
<Input
id="email"
name="email"
type="email"
placeholder="[email protected]"
className={state.errors?.email ? 'border-red-500' : ''}
/>
{state.errors?.email && (
<p className="mt-1 text-sm text-red-500">
{state.errors.email[0]}
</p>
)}
</div>
</div>
</div>
{state.message && (
<p
className={`text-sm ${state.success ? 'text-green-500' : 'text-red-500'} mb-4`}
>
{state.message}
</p>
)}
<DialogFooter>
<Button type="submit">Add Student</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}
80 changes: 80 additions & 0 deletions apps/web/app/home/_components/student-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from '@kit/ui/table';

import AddStudentDialog from '~/home/_components/add-student-dialog';
import { addStudent } from '~/home/actions';

export default async function StudentTable() {
const client = getSupabaseServerClient();
const { data, error } = await client.from('student').select('*');

if (error) {
return (
<div className="my-4 rounded-md bg-red-50 p-4">
<div className="flex">
<div className="text-sm text-red-700">
Failed to load students. Please try again later.
</div>
</div>
</div>
);
}

return (
<div className="rounded-md border">
<Table>
<TableCaption>List of registered students in your account</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead className="hidden md:table-cell">Account ID</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.length === 0 ? (
<TableRow>
<TableCell
colSpan={4}
className="text-center text-muted-foreground"
>
No students found. Add your first student to get started.
</TableCell>
</TableRow>
) : (
data.map((student) => (
<TableRow key={student.student_id}>
<TableCell className="font-medium">{student.name}</TableCell>
<TableCell>{student.email}</TableCell>
<TableCell className="hidden md:table-cell">
{student.account_id}
</TableCell>
<TableCell className="text-right"></TableCell>
</TableRow>
))
)}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total Students</TableCell>
<TableCell className="text-right font-medium">
{data.length}
</TableCell>
</TableRow>
</TableFooter>
</Table>
<div className="p-4">
<AddStudentDialog />
</div>
</div>
);
}
57 changes: 57 additions & 0 deletions apps/web/app/home/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use server';

import { revalidatePath } from 'next/cache';

import { z } from 'zod';

import { getSupabaseServerClient } from '@kit/supabase/server-client';

type State = {
errors?: {
name?: string[];
email?: string[];
};
message?: string | null;
success?: boolean;
};

export default async function addStudent(prevState: State, formData: FormData) {
const studentSchema = z.object({
name: z.string().min(2, 'Name is required'),
email: z.string().email('Valid email is required'),
});

const validateData = studentSchema.safeParse({
name: formData.get('name'),
email: formData.get('email'),
});

if (!validateData.success) {
return {
errors: validateData.error.flatten().fieldErrors,
message: 'Please fix the errors above',
success: false,
};
}

const client = getSupabaseServerClient();
const { data: userData } = await client.auth.getUser();

const { error } = await client.from('student').insert({
...validateData.data,
account_id: userData.user?.id,
});

if (error) {
return {
message: 'Failed to add student',
success: false,
};
}

revalidatePath('/home');
return {
message: 'Student added successfully',
success: true,
};
}
3 changes: 2 additions & 1 deletion apps/web/app/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { PageBody, PageHeader } from '@kit/ui/page';

import { DashboardDemo } from '~/home/_components/dashboard-demo';
import StudentTable from '~/home/_components/student-table';

export default function HomePage() {
return (
<>
<PageHeader title={'Dashboard'} description={'Your SaaS at a glance'} />

<PageBody>
<StudentTable />
<DashboardDemo />
</PageBody>
</>
Expand Down
Loading

0 comments on commit e58f5f3

Please sign in to comment.