Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/demo-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Local command:
```bash
npm run seo:check
npm run links:check
npm run smoke:live
```

## Build Preview Commands
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"security:scan": "node scripts/check-secrets.js",
"seo:check": "node scripts/check-seo.js",
"links:check": "node scripts/check-links.js",
"smoke:live": "node scripts/run-live-smoke.js",
"preview": "vite preview",
"preview:pages": "node scripts/serve-pages-preview.js",
"test": "vitest --config vitest.config.ts"
Expand Down
42 changes: 42 additions & 0 deletions scripts/run-live-smoke.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { spawnSync } from 'node:child_process';
import { existsSync } from 'node:fs';
import { join } from 'node:path';

const liveUrl = 'https://iron-mark.github.io/Hackathon-Smart-Profile-Management-System/';
const liveBasePath = '/Hackathon-Smart-Profile-Management-System/';
const smokeSpecs = [
'tests/deep-links.spec.ts',
'tests/seo.spec.ts',
'tests/public-demo-responsive.spec.ts',
];

const command = join(
process.cwd(),
'node_modules',
'playwright',
'cli.js'
);

if (!existsSync(command)) {
console.error('Playwright is not installed. Run npm ci before live smoke checks.');
process.exit(1);
}

const result = spawnSync(
process.execPath,
[command, 'test', ...smokeSpecs, '--reporter=line'],
{
stdio: 'inherit',
env: {
...process.env,
PLAYWRIGHT_BASE_URL: liveUrl,
PLAYWRIGHT_BASE_PATH: liveBasePath,
},
}
);

if (result.error) {
console.error(result.error.message);
}

process.exit(result.status ?? 1);
96 changes: 96 additions & 0 deletions src/components/ui/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as React from "react"

import { cn } from "@/lib/utils"

function Table({ className, ...props }: React.ComponentProps<"table">) {
return (
<div data-slot="table-container" className="relative w-full overflow-x-auto">
<table
data-slot="table"
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
)
}

function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
return <thead data-slot="table-header" className={cn("[&_tr]:border-b", className)} {...props} />
}

function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
return (
<tbody
data-slot="table-body"
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
)
}

function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
return (
<tfoot
data-slot="table-footer"
className={cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className)}
{...props}
/>
)
}

function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
return (
<tr
data-slot="table-row"
className={cn(
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
className
)}
{...props}
/>
)
}

function TableHead({ className, ...props }: React.ComponentProps<"th">) {
return (
<th
data-slot="table-head"
className={cn(
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
/>
)
}

function TableCell({ className, ...props }: React.ComponentProps<"td">) {
return (
<td
data-slot="table-cell"
className={cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)}
{...props}
/>
)
}

function TableCaption({ className, ...props }: React.ComponentProps<"caption">) {
return (
<caption
data-slot="table-caption"
className={cn("text-muted-foreground mt-4 text-sm", className)}
{...props}
/>
)
}

export {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
}
2 changes: 1 addition & 1 deletion src/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-foreground",
className
)}
{...props}
Expand Down
68 changes: 39 additions & 29 deletions src/pages/admin/accounts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ import {
SelectValue
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
deleteDemoAuthUser,
deleteDemoStoredFilesForUser,
Expand Down Expand Up @@ -385,42 +393,44 @@ export default function AdminAccountsPage() {
</CardHeader>
<CardContent>
<div className="overflow-x-auto">
<table className="w-full text-left table-auto">
<thead>
<tr className="border-b">
<th className="px-4 py-2">Name</th>
<th className="px-4 py-2">Email</th>
<th className="px-4 py-2">Role</th>
<th className="px-4 py-2">Status</th>
<th className="px-4 py-2 text-right">Actions</th>
</tr>
</thead>
<tbody>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{isLoading ? (
Array.from({ length: 3 }).map((_, i) => (
<tr key={i} className="border-b">
<td className="px-4 py-4"><Skeleton className="h-4 w-32" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-40" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-24" /></td>
<td className="px-4 py-4"><Skeleton className="h-6 w-16 rounded-full" /></td>
<td className="px-4 py-4 text-right"><Skeleton className="h-8 w-24 ml-auto" /></td>
</tr>
<TableRow key={i}>
<TableCell className="py-4"><Skeleton className="h-4 w-32" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-40" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-24" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-6 w-16 rounded-full" /></TableCell>
<TableCell className="py-4 text-right">
<Skeleton className="ml-auto h-8 w-24" />
</TableCell>
</TableRow>
))
) : (
users.map((user) => {
const deleteBlockReason = getDeleteBlockReason(user);

return (
<tr key={user.id} className="border-b hover:bg-muted/60">
<td className="px-4 py-2 font-medium">{user.name}</td>
<td className="px-4 py-2">{user.email}</td>
<td className="px-4 py-2 capitalize">{user.type || "faculty"}</td>
<td className="px-4 py-2">
<TableRow key={user.id}>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell className="capitalize">{user.type || "faculty"}</TableCell>
<TableCell>
<Badge variant="outline" className="bg-emerald-50 text-emerald-700 dark:bg-emerald-950/50 dark:text-emerald-200">
Active
</Badge>
</td>
<td className="px-4 py-2 text-right">
</TableCell>
<TableCell className="text-right">
<Button
variant="outline"
size="sm"
Expand All @@ -438,13 +448,13 @@ export default function AdminAccountsPage() {
>
Delete
</Button>
</td>
</tr>
</TableCell>
</TableRow>
);
})
)}
</tbody>
</table>
</TableBody>
</Table>
</div>
{!isLoading && users.length === 0 && (
<p className="text-center text-muted-foreground py-4">
Expand Down
77 changes: 43 additions & 34 deletions src/pages/admin/approvals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { SidebarProvider } from "@/components/ui/sidebar";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import getFromDatabase from "@/tools/database/getFromDatabase";
import updateDatabase from "@/tools/database/updateDatabase";
import getFileFromFolder from "@/tools/buckets/getFileFromFolder";
Expand Down Expand Up @@ -101,42 +109,43 @@ export default function AdminApprovalsPage() {
<CardTitle>Faculty Submissions</CardTitle>
</CardHeader>
<CardContent>
<table className="w-full text-left table-auto">
<thead>
<tr className="border-b">
<th className="px-4 py-2">Faculty Name</th>
<th className="px-4 py-2">Document Type</th>
<th className="px-4 py-2">File Name</th>
<th className="px-4 py-2">Date Submitted</th>
<th className="px-4 py-2">Status</th>
<th className="px-4 py-2 text-right">Actions</th>
</tr>
</thead>
<tbody>
<Table>
<TableHeader>
<TableRow>
<TableHead>Faculty Name</TableHead>
<TableHead>Document Type</TableHead>
<TableHead>File Name</TableHead>
<TableHead>Date Submitted</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{isLoading ? (
Array.from({ length: 5 }).map((_, i) => (
<tr key={i} className="border-b">
<td className="px-4 py-4"><Skeleton className="h-4 w-32" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-40" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-40" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-24" /></td>
<td className="px-4 py-4"><Skeleton className="h-4 w-20" /></td>
<td className="px-4 py-4 text-right"><Skeleton className="h-8 w-24 ml-auto" /></td>
</tr>
<TableRow key={i}>
<TableCell className="py-4"><Skeleton className="h-4 w-32" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-40" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-40" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-24" /></TableCell>
<TableCell className="py-4"><Skeleton className="h-4 w-20" /></TableCell>
<TableCell className="py-4 text-right">
<Skeleton className="ml-auto h-8 w-24" />
</TableCell>
</TableRow>
))
) : (
submissions.map((submission) => (
<tr
<TableRow
key={submission.id}
className="border-b hover:bg-muted/60"
>
<td className="px-4 py-2">{submission.facultyName}</td>
<td className="px-4 py-2">{submission.document_type}</td>
<td className="px-4 py-2">{submission.file_name}</td>
<td className="px-4 py-2">
<TableCell>{submission.facultyName}</TableCell>
<TableCell>{submission.document_type}</TableCell>
<TableCell>{submission.file_name}</TableCell>
<TableCell>
{new Date(submission.submitted_at).toLocaleDateString()}
</td>
<td className="px-4 py-2">
</TableCell>
<TableCell>
<Badge
variant={
submission.status === "Pending"
Expand All @@ -148,8 +157,8 @@ export default function AdminApprovalsPage() {
>
{submission.status}
</Badge>
</td>
<td className="px-4 py-2 text-right">
</TableCell>
<TableCell className="text-right">
{submission.status === "Pending" && (
<>
<Button
Expand Down Expand Up @@ -186,12 +195,12 @@ export default function AdminApprovalsPage() {
>
View
</Button>
</td>
</tr>
</TableCell>
</TableRow>
))
)}
</tbody>
</table>
</TableBody>
</Table>
{!isLoading && submissions.length === 0 && (
<p className="text-center text-muted-foreground py-4">
No submissions found.
Expand Down
Loading