# TASK-FE-010: Admin Panel & Settings UI **ID:** TASK-FE-010 **Title:** Admin Panel for User & Master Data Management **Category:** Administration **Priority:** P2 (Medium) **Effort:** 5-7 days **Dependencies:** TASK-FE-002, TASK-FE-005, TASK-BE-012, TASK-BE-013 **Assigned To:** Frontend Developer --- ## ๐Ÿ“‹ Overview Build comprehensive Admin Panel for managing users, roles, master data (organizations, projects, contracts, disciplines, document types), system settings, and viewing audit logs. --- ## ๐ŸŽฏ Objectives 1. Create admin layout with separate navigation 2. Build User Management UI (CRUD users, assign roles) 3. Implement Master Data Management screens 4. Create System Settings interface 5. Build Audit Logs viewer 6. Add bulk operations and data import/export --- ## โœ… Acceptance Criteria - [ ] Admin area accessible only to admins - [ ] User management (create/edit/delete/deactivate) - [ ] Role assignment with permission preview - [ ] Master data CRUD (Organizations, Projects, etc.) - [ ] Audit logs searchable and filterable - [ ] System settings editable - [ ] CSV import/export for bulk operations --- ## ๐Ÿ”ง Implementation Steps ### Step 1: Admin Layout ```typescript // File: src/app/(admin)/layout.tsx import { AdminSidebar } from '@/components/admin/sidebar'; import { redirect } from 'next/navigation'; import { getServerSession } from 'next-auth'; export default async function AdminLayout({ children, }: { children: React.ReactNode; }) { const session = await getServerSession(); // Check if user has admin role if (!session?.user?.roles?.some((r) => r.role_name === 'ADMIN')) { redirect('/'); } return (
{children}
); } ``` ### Step 2: User Management Page ```typescript // File: src/app/(admin)/admin/users/page.tsx 'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { DataTable } from '@/components/common/data-table'; import { UserDialog } from '@/components/admin/user-dialog'; import { ColumnDef } from '@tanstack/react-table'; import { Badge } from '@/components/ui/badge'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { MoreHorizontal, Plus } from 'lucide-react'; export default function UsersPage() { const [users, setUsers] = useState([]); const [dialogOpen, setDialogOpen] = useState(false); const [selectedUser, setSelectedUser] = useState(null); const columns: ColumnDef[] = [ { accessorKey: 'username', header: 'Username', }, { accessorKey: 'email', header: 'Email', }, { accessorKey: 'first_name', header: 'Name', cell: ({ row }) => `${row.original.first_name} ${row.original.last_name}`, }, { accessorKey: 'is_active', header: 'Status', cell: ({ row }) => ( {row.original.is_active ? 'Active' : 'Inactive'} ), }, { id: 'roles', header: 'Roles', cell: ({ row }) => (
{row.original.roles?.map((role: any) => ( {role.role_name} ))}
), }, { id: 'actions', cell: ({ row }) => ( { setSelectedUser(row.original); setDialogOpen(true); }} > Edit handleDeactivate(row.original.user_id)} > {row.original.is_active ? 'Deactivate' : 'Activate'} Delete ), }, ]; return (

User Management

Manage system users and their roles

); } ``` ### Step 3: User Create/Edit Dialog ```typescript // File: src/components/admin/user-dialog.tsx 'use client'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Checkbox } from '@/components/ui/checkbox'; const userSchema = z.object({ username: z.string().min(3), email: z.string().email(), first_name: z.string().min(1), last_name: z.string().min(1), password: z.string().min(6).optional(), is_active: z.boolean().default(true), roles: z.array(z.number()), }); type UserFormData = z.infer; interface UserDialogProps { open: boolean; onOpenChange: (open: boolean) => void; user?: any; } export function UserDialog({ open, onOpenChange, user }: UserDialogProps) { const { register, handleSubmit, setValue, watch, formState: { errors }, } = useForm({ resolver: zodResolver(userSchema), defaultValues: user || {}, }); const availableRoles = [ { role_id: 1, role_name: 'ADMIN', description: 'System Administrator' }, { role_id: 2, role_name: 'USER', description: 'Regular User' }, { role_id: 3, role_name: 'APPROVER', description: 'Document Approver' }, ]; const selectedRoles = watch('roles') || []; const onSubmit = async (data: UserFormData) => { // Call API to create/update user console.log(data); onOpenChange(false); }; return ( {user ? 'Edit User' : 'Create New User'}
{errors.username && (

{errors.username.message}

)}
{errors.email && (

{errors.email.message}

)}
{!user && (
{errors.password && (

{errors.password.message}

)}
)}
{availableRoles.map((role) => ( ))}
); } ``` ### Step 4: Master Data Management (Organizations) ```typescript // File: src/app/(admin)/admin/organizations/page.tsx 'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { DataTable } from '@/components/common/data-table'; import { Card } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; export default function OrganizationsPage() { const [organizations, setOrganizations] = useState([]); const [dialogOpen, setDialogOpen] = useState(false); const [formData, setFormData] = useState({ org_code: '', org_name: '', org_name_th: '', description: '', }); const columns = [ { accessorKey: 'org_code', header: 'Code' }, { accessorKey: 'org_name', header: 'Name (EN)' }, { accessorKey: 'org_name_th', header: 'Name (TH)' }, { accessorKey: 'description', header: 'Description' }, ]; const handleSubmit = async () => { // Call API to create organization console.log(formData); setDialogOpen(false); }; return (

Organizations

Manage project organizations

Add Organization
setFormData({ ...formData, org_code: e.target.value }) } placeholder="e.g., เธเธ—เธ—." />
setFormData({ ...formData, org_name: e.target.value }) } />
setFormData({ ...formData, org_name_th: e.target.value }) } />
setFormData({ ...formData, description: e.target.value }) } />
); } ``` ### Step 5: Audit Logs Viewer ```typescript // File: src/app/(admin)/admin/audit-logs/page.tsx 'use client'; import { useState } from 'react'; import { Card } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; import { formatDistanceToNow } from 'date-fns'; export default function AuditLogsPage() { const [logs, setLogs] = useState([]); const [filters, setFilters] = useState({ user: '', action: '', entity: '', }); return (

Audit Logs

View system activity and changes

{/* Filters */}
{/* Logs List */}
{logs.map((log: any) => (
{log.user_name} {log.action} {log.entity_type}

{log.description}

{formatDistanceToNow(new Date(log.created_at), { addSuffix: true, })}

{log.ip_address && ( IP: {log.ip_address} )}
))}
); } ``` ### Step 6: Admin Sidebar Navigation ```typescript // File: src/components/admin/sidebar.tsx 'use client'; import Link from 'link'; import { usePathname } from 'next/navigation'; import { cn } from '@/lib/utils'; import { Users, Building2, Settings, FileText, Activity } from 'lucide-react'; const menuItems = [ { href: '/admin/users', label: 'Users', icon: Users }, { href: '/admin/organizations', label: 'Organizations', icon: Building2 }, { href: '/admin/projects', label: 'Projects', icon: FileText }, { href: '/admin/settings', label: 'Settings', icon: Settings }, { href: '/admin/audit-logs', label: 'Audit Logs', icon: Activity }, ]; export function AdminSidebar() { const pathname = usePathname(); return ( ); } ``` --- ## ๐Ÿ“ฆ Deliverables - [ ] Admin layout with sidebar navigation - [ ] User Management (CRUD, roles assignment) - [ ] Master Data Management screens: - [ ] Organizations - [ ] Projects - [ ] Contracts - [ ] Disciplines - [ ] Document Types - [ ] System Settings interface - [ ] Audit Logs viewer with filters - [ ] CSV import/export functionality --- ## ๐Ÿงช Testing ### Test Cases 1. **User Management** - Create new user - Assign multiple roles - Deactivate/activate user - Delete user 2. **Master Data** - Create organization - Edit organization details - Delete organization (check for dependencies) 3. **Audit Logs** - View all logs - Filter by user/action/entity - Search logs - Export logs --- ## ๐Ÿ”— Related Documents - [TASK-BE-012: Master Data Management](./TASK-BE-012-master-data-management.md) - [TASK-BE-013: User Management](./TASK-BE-013-user-management.md) - [ADR-004: RBAC Implementation](../../05-decisions/ADR-004-rbac-implementation.md) --- **Created:** 2025-12-01 **Status:** Ready