feat(frontend): Implement Phase 2 - Complete Projects UI with CRUD operations

Implemented comprehensive Projects UI with full CRUD functionality following
modern React best practices and using shadcn/ui components.

Changes:
- Created ProjectForm component with react-hook-form + zod validation
  - Auto-uppercase project key input
  - Comprehensive field validation (name, key, description)
  - Support for both create and edit modes
  - Toast notifications for success/error states

- Enhanced Projects List Page (app/(dashboard)/projects/page.tsx)
  - Beautiful card-based grid layout with hover effects
  - Skeleton loading states for better UX
  - Empty state with call-to-action
  - Project metadata display (key badge, created date)
  - Integrated ProjectForm in Dialog for creation

- Enhanced Project Detail Page (app/(dashboard)/projects/[id]/page.tsx)
  - Comprehensive project information display
  - Edit functionality with dialog form
  - Delete functionality with confirmation AlertDialog
  - Epics preview section with stats
  - Quick actions sidebar (Kanban, Epics)
  - Statistics card (Total/Active/Completed epics)
  - Skeleton loading states
  - Error handling with retry capability

- Added toast notifications (Sonner)
  - Installed and configured sonner package
  - Added Toaster component to root layout
  - Success/error notifications for all CRUD operations

- Installed required dependencies
  - date-fns for date formatting
  - sonner for toast notifications
  - shadcn/ui alert-dialog component

Technical highlights:
- TypeScript with strict type checking
- React Query for data fetching and caching
- Optimistic updates with automatic rollback
- Responsive design (mobile-friendly)
- Accessibility-focused components
- Clean error handling throughout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-04 21:26:02 +01:00
parent e52c8300de
commit 2b134b0d6f
11 changed files with 975 additions and 217 deletions

View File

@@ -4,26 +4,26 @@ import type { KanbanBoard } from '@/types/kanban';
export const projectsApi = {
getAll: async (page = 1, pageSize = 20): Promise<Project[]> => {
return api.get(`/projects?page=${page}&pageSize=${pageSize}`);
return api.get(`/api/v1/projects?page=${page}&pageSize=${pageSize}`);
},
getById: async (id: string): Promise<Project> => {
return api.get(`/projects/${id}`);
return api.get(`/api/v1/projects/${id}`);
},
create: async (data: CreateProjectDto): Promise<Project> => {
return api.post('/projects', data);
return api.post('/api/v1/projects', data);
},
update: async (id: string, data: UpdateProjectDto): Promise<Project> => {
return api.put(`/projects/${id}`, data);
return api.put(`/api/v1/projects/${id}`, data);
},
delete: async (id: string): Promise<void> => {
return api.delete(`/projects/${id}`);
return api.delete(`/api/v1/projects/${id}`);
},
getKanban: async (id: string): Promise<KanbanBoard> => {
return api.get(`/projects/${id}/kanban`);
return api.get(`/api/v1/projects/${id}/kanban`);
},
};