251208:0010 Backend & Frontend Debug
This commit is contained in:
95
frontend/app/(dashboard)/dashboard/can/page.tsx
Normal file
95
frontend/app/(dashboard)/dashboard/can/page.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
// File: app/(dashboard)/dashboard/can/page.tsx
|
||||
'use client';
|
||||
|
||||
import { useAuthStore } from '@/lib/stores/auth-store';
|
||||
import { Can } from '@/components/common/can';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export default function CanTestPage() {
|
||||
const { user } = useAuthStore();
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-2xl font-bold">RBAC / Permission Test Page</h1>
|
||||
|
||||
{/* User Info Card */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Current User Info</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-semibold">Username:</span>
|
||||
<span>{user?.username || 'Not logged in'}</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<span className="font-semibold">Role:</span>
|
||||
<Badge variant="outline">{user?.role || 'None'}</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<span className="font-semibold">Permissions:</span>
|
||||
<span>{user?.permissions?.join(', ') || 'No explicit permissions'}</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Permission Tests */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Component Visibility Tests (using <Can />)</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
|
||||
<div className="p-4 border rounded bg-gray-50 flex flex-col gap-2">
|
||||
<p className="text-sm font-medium">1. Admin Role Check</p>
|
||||
<Can role="Admin" fallback={<span className="text-red-500 text-sm">❌ You are NOT an Admin (Hidden)</span>}>
|
||||
<Button variant="default" className="w-fit">✅ Visible to Admin Only</Button>
|
||||
</Can>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded bg-gray-50 flex flex-col gap-2">
|
||||
<p className="text-sm font-medium">2. 'document:create' Permission</p>
|
||||
<Can permission="document:create" fallback={<span className="text-red-500 text-sm">❌ Missing 'document:create' (Hidden)</span>}>
|
||||
<Button variant="secondary" className="w-fit">✅ Visible with 'document:create'</Button>
|
||||
</Can>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded bg-gray-50 flex flex-col gap-2">
|
||||
<p className="text-sm font-medium">3. 'document:delete' Permission</p>
|
||||
<Can permission="document:delete" fallback={<span className="text-red-500 text-sm">❌ Missing 'document:delete' (Hidden)</span>}>
|
||||
<Button variant="destructive" className="w-fit">✅ Visible with 'document:delete'</Button>
|
||||
</Can>
|
||||
</div>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Toast Test */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Toast Notification Test</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex gap-4">
|
||||
<Button
|
||||
onClick={() => toast.success("Operation Successful", { description: "This is a success toast message." })}
|
||||
>
|
||||
Trigger Success Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => toast.error("Operation Failed", { description: "This is an error toast message." })}
|
||||
>
|
||||
Trigger Error Toast
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="p-4 bg-blue-50 text-blue-800 rounded">
|
||||
<strong>Tip:</strong> You can mock different roles by modifying the user state in local storage or using the `setAuth` method in console.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { StatsCards } from "@/components/dashboard/stats-cards";
|
||||
import { RecentActivity } from "@/components/dashboard/recent-activity";
|
||||
import { PendingTasks } from "@/components/dashboard/pending-tasks";
|
||||
import { QuickActions } from "@/components/dashboard/quick-actions";
|
||||
import { dashboardApi } from "@/lib/api/dashboard";
|
||||
import { useDashboardStats, useRecentActivity, usePendingTasks } from "@/hooks/use-dashboard";
|
||||
|
||||
export default async function DashboardPage() {
|
||||
// Fetch data in parallel
|
||||
const [stats, activities, tasks] = await Promise.all([
|
||||
dashboardApi.getStats(),
|
||||
dashboardApi.getRecentActivity(),
|
||||
dashboardApi.getPendingTasks(),
|
||||
]);
|
||||
export default function DashboardPage() {
|
||||
const { data: stats, isLoading: statsLoading } = useDashboardStats();
|
||||
const { data: activities, isLoading: activityLoading } = useRecentActivity();
|
||||
const { data: tasks, isLoading: tasksLoading } = usePendingTasks();
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
@@ -24,14 +23,14 @@ export default async function DashboardPage() {
|
||||
<QuickActions />
|
||||
</div>
|
||||
|
||||
<StatsCards stats={stats} />
|
||||
<StatsCards stats={stats} isLoading={statsLoading} />
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2">
|
||||
<RecentActivity activities={activities} />
|
||||
<RecentActivity activities={activities} isLoading={activityLoading} />
|
||||
</div>
|
||||
<div className="lg:col-span-1">
|
||||
<PendingTasks tasks={tasks} />
|
||||
<PendingTasks tasks={tasks} isLoading={tasksLoading} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user