T07b: frontend feature pages — companies + contacts + settings + audit + dashboard + search
- 11 new feature pages (CompaniesList/Detail/Form, ContactsList/Detail/Form, SettingsProfile/Roles/Users, AuditLog, GlobalSearchResults) - 3 page updates (Dashboard with StatCard+ActivityFeed, Settings with tree nav+Outlet, TopBar with SearchDropdown) - 13 new routes in routes/index.tsx - i18n updates (de.json + en.json) with companies/contacts/settings/audit/search keys - 12 new test files + 2 existing test fixes (TopBar, AppShell) - 7 shared components (DataGrid, Tabs, SearchDropdown, CsvImportDialog, StatCard, ActivityFeed, UnsavedChangesGuard) - 16 new API hooks in hooks.ts - Verification: 141 tests pass, build succeeds, tsc --noEmit clean
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
# T07b Briefing — Frontend Feature Pages
|
||||
|
||||
## Project Root
|
||||
/a0/usr/workdir/dev-projects/leocrm
|
||||
|
||||
## Frontend Directory
|
||||
/a0/usr/workdir/dev-projects/leocrm/frontend/
|
||||
|
||||
## Task
|
||||
Build all feature pages for the LeoCRM SPA. T07a (shell, auth, routing, i18n, UI library) is complete.
|
||||
|
||||
## Tech Stack (already set up by T07a)
|
||||
- React 18 + Vite + TypeScript (strict)
|
||||
- TanStack Query v5 (hooks in src/api/hooks.ts)
|
||||
- Zustand (stores in src/store/)
|
||||
- react-i18next (de/en, src/i18n/)
|
||||
- React Hook Form + Zod
|
||||
- Tailwind CSS with design tokens
|
||||
- Vitest + @testing-library/react
|
||||
|
||||
## Existing API Hooks (src/api/hooks.ts)
|
||||
- useCompanies(page, pageSize, search) → { items, total, page, page_size }
|
||||
- useContacts(page, pageSize, search) → { items, total, page, page_size }
|
||||
- useUsers(page, pageSize) → paginated users
|
||||
- useCurrentUser() → current user
|
||||
- useNotifications() → notifications list
|
||||
- usePlugins() → plugins list
|
||||
- useLogin(), useLogout(), useSwitchTenant()
|
||||
- API client: src/api/client.ts (axios, withCredentials, 401→login, 422→validation)
|
||||
|
||||
## Backend API Endpoints
|
||||
- GET /api/v1/companies?page=1&page_size=25&search=...&industry=...&sort_by=...&sort_order=...
|
||||
- GET /api/v1/companies/{id} → CompanyDetailResponse (includes contacts[])
|
||||
- POST /api/v1/companies
|
||||
- PATCH /api/v1/companies/{id}
|
||||
- DELETE /api/v1/companies/{id}
|
||||
- GET /api/v1/companies/export?format=csv&search=...&industry=...
|
||||
- POST /api/v1/companies/import (CSV upload)
|
||||
- GET /api/v1/contacts?page=1&page_size=25&search=...
|
||||
- GET /api/v1/contacts/{id} → ContactDetailResponse (includes companies[])
|
||||
- POST /api/v1/contacts
|
||||
- PATCH /api/v1/contacts/{id}
|
||||
- DELETE /api/v1/contacts/{id}
|
||||
- GET /api/v1/users?page=1&page_size=25
|
||||
- GET /api/v1/users/{id}
|
||||
- POST /api/v1/users
|
||||
- PATCH /api/v1/users/{id}
|
||||
- DELETE /api/v1/users/{id}
|
||||
- GET /api/v1/notifications
|
||||
- GET /api/v1/plugins
|
||||
- GET /health
|
||||
|
||||
Note: No dedicated audit log or global search API endpoint exists yet. For audit log, create a frontend page that calls GET /api/v1/audit (may 404 — handle gracefully with empty state). For global search, call useCompanies and useContacts with search param in parallel.
|
||||
|
||||
## Company Schema (from backend)
|
||||
- name: string (required, 1-100)
|
||||
- account_number: string? (max 40)
|
||||
- industry: string? (max 50)
|
||||
- phone: string? (max 30)
|
||||
- email: string? (max 255)
|
||||
- website: string? (max 500)
|
||||
- description: string?
|
||||
- CompanyDetailResponse adds: contacts: list[dict]
|
||||
|
||||
## Files to Create/Modify
|
||||
|
||||
### New API Hooks (add to src/api/hooks.ts)
|
||||
- useCompany(id), useCreateCompany(), useUpdateCompany(), useDeleteCompany()
|
||||
- useContact(id), useCreateContact(), useUpdateContact(), useDeleteContact()
|
||||
- useCompanyExport(), useCompanyImport()
|
||||
- useAuditLog(page, pageSize, filters)
|
||||
- useGlobalSearch(query, entityTypes)
|
||||
|
||||
### New Pages (src/pages/)
|
||||
- CompaniesList.tsx — TanStack Table with search/filter/sort/pagination, empty state
|
||||
- CompanyDetail.tsx — Tabs: overview, contacts, files, activity
|
||||
- CompanyForm.tsx — Create/edit with React Hook Form + Zod
|
||||
- ContactsList.tsx — TanStack Table, loading skeleton
|
||||
- ContactDetail.tsx — Tabs: overview, companies, files, activity
|
||||
- ContactForm.tsx — Create/edit with multi-company assignment
|
||||
- AuditLog.tsx — Filterable table (date, user, action, entity)
|
||||
- GlobalSearchResults.tsx — Filters (entity type, date), highlighting
|
||||
- SettingsProfile.tsx — Update name, email, password, avatar
|
||||
- SettingsRoles.tsx — Role editor: create, assign permissions
|
||||
- SettingsUsers.tsx — User management: list, invite, change role, deactivate
|
||||
|
||||
### Modify Existing Pages
|
||||
- Dashboard.tsx — Expand with stat cards + recent activity feed
|
||||
- Settings.tsx — Add tree navigation (Profile, Roles, Users, System)
|
||||
|
||||
### New Components (src/components/)
|
||||
- SearchDropdown.tsx — Global search dropdown in topbar
|
||||
- StatCard.tsx — Dashboard stat card
|
||||
- ActivityFeed.tsx — Recent activity feed
|
||||
- Tabs.tsx — Reusable tab component for detail pages
|
||||
- DataGrid.tsx — Wrapper around TanStack Table for list pages
|
||||
- CsvImportDialog.tsx — CSV upload → preview → import
|
||||
- UnsavedChangesGuard.tsx — Warn on navigation away with unsaved changes
|
||||
|
||||
### Update Routes (src/routes/index.tsx)
|
||||
Add routes for all new pages under ProtectedRoute children:
|
||||
- /companies, /companies/:id, /companies/new, /companies/:id/edit
|
||||
- /contacts, /contacts/:id, /contacts/new, /contacts/:id/edit
|
||||
- /audit-log
|
||||
- /search?q=...
|
||||
- /settings/profile, /settings/roles, /settings/users
|
||||
|
||||
### Tests (src/__tests__/)
|
||||
- companies/CompaniesList.test.tsx, CompanyDetail.test.tsx, CompanyForm.test.tsx
|
||||
- contacts/ContactsList.test.tsx, ContactDetail.test.tsx, ContactForm.test.tsx
|
||||
- settings/SettingsProfile.test.tsx, SettingsRoles.test.tsx, SettingsUsers.test.tsx
|
||||
- dashboard/Dashboard.test.tsx
|
||||
- search/GlobalSearch.test.tsx
|
||||
- AuditLog.test.tsx
|
||||
|
||||
## Acceptance Criteria (23 total)
|
||||
1. Companies list renders with TanStack Table (search, filter, sort, pagination)
|
||||
2. Company detail renders with tabs (overview, contacts, files, activity)
|
||||
3. Company form validates required fields (name) with Zod
|
||||
4. Company import: CSV upload → preview → import → success toast
|
||||
5. Company export: download CSV with current filters
|
||||
6. Contacts list renders with TanStack Table
|
||||
7. Contact detail renders with tabs (overview, companies, files, activity)
|
||||
8. Contact form validates required fields (first_name, last_name, email) with Zod
|
||||
9. Contact can be assigned to multiple companies
|
||||
10. Settings renders with tree navigation (Profile, Roles, Users, System)
|
||||
11. Profile settings: update name, email, password, avatar
|
||||
12. Role editor: create role, assign permissions, save
|
||||
13. User management: list users, invite user, change role, deactivate
|
||||
14. Audit log renders with filterable table (date, user, action, entity)
|
||||
15. Dashboard renders with stat cards and recent activity feed
|
||||
16. Global search bar in topbar returns results dropdown
|
||||
17. Global search results page renders with filters (entity type, date)
|
||||
18. Search results highlight matched terms
|
||||
19. Search works across companies, contacts (v1 scope)
|
||||
20. Companies list: empty state shows helpful message + create button
|
||||
21. Contacts list: loading state shows skeleton rows
|
||||
22. Company form: error state shows inline validation errors
|
||||
23. Settings: unsaved changes warning when navigating away
|
||||
|
||||
## Test Commands
|
||||
```bash
|
||||
cd /a0/usr/workdir/dev-projects/leocrm/frontend && npx vitest run src/__tests__/companies/ src/__tests__/contacts/ src/__tests__/settings/ src/__tests__/dashboard/ src/__tests__/search/ --reporter=verbose
|
||||
cd /a0/usr/workdir/dev-projects/leocrm/frontend && npm run build
|
||||
cd /a0/usr/workdir/dev-projects/leocrm/frontend && npx tsc --noEmit
|
||||
```
|
||||
|
||||
## Rules
|
||||
- TypeScript only, no .js files
|
||||
- No Lorem Ipsum — use real German/English content
|
||||
- All interactive elements need ARIA labels
|
||||
- 44px minimum touch targets on mobile
|
||||
- Use existing UI components from T07a (Button, Input, Select, Modal, Toast, Table, Card, Badge, Avatar, Pagination, EmptyState, Skeleton, ConfirmDialog)
|
||||
- Use existing i18n setup — add new keys to de.json and en.json
|
||||
- Use existing API client (src/api/client.ts) — don't create new axios instances
|
||||
- Coverage target: 80%
|
||||
- Keep responses under 50 lines
|
||||
- Use files_create for new files, reference by path
|
||||
|
||||
## Deliverables
|
||||
1. All files created and tests passing
|
||||
2. npm run build succeeds with 0 errors
|
||||
3. tsc --noEmit passes with 0 errors
|
||||
4. Report: test results, AC coverage, files created, bugs encountered
|
||||
@@ -0,0 +1,158 @@
|
||||
# T07b Continuation — Frontend Feature Pages (Part 2)
|
||||
|
||||
## Project Root
|
||||
/a0/usr/workdir/dev-projects/leocrm
|
||||
|
||||
## Frontend Directory
|
||||
/a0/usr/workdir/dev-projects/leocrm/frontend/
|
||||
|
||||
## What's Already Done (DO NOT recreate)
|
||||
|
||||
### API Hooks (src/api/hooks.ts — 432 lines, modified)
|
||||
16 new hooks already added: useCompany, useCreateCompany, useUpdateCompany, useDeleteCompany, useContact, useCreateContact, useUpdateContact, useDeleteContact, useCompanyExport, useCompanyImport, useAuditLog, useGlobalSearch, plus CRUD for users.
|
||||
|
||||
### Shared Components (src/components/shared/ — all exist)
|
||||
- `Tabs.tsx` (2055 bytes) — Tab navigation component
|
||||
- `StatCard.tsx` (1107 bytes) — Dashboard stat card
|
||||
- `ActivityFeed.tsx` (1372 bytes) — Activity feed list
|
||||
- `DataGrid.tsx` (6067 bytes) — TanStack Table wrapper with search/sort/pagination
|
||||
- `SearchDropdown.tsx` (6275 bytes) — Debounced search dropdown with highlighting
|
||||
- `CsvImportDialog.tsx` (5429 bytes) — CSV upload + preview dialog
|
||||
- `UnsavedChangesGuard.tsx` (821 bytes) — useBlocker-based unsaved changes warning
|
||||
|
||||
### Dependencies
|
||||
- @tanstack/react-table@8.21.3 installed
|
||||
|
||||
## What Remains (ALL of this must be created)
|
||||
|
||||
### 1. Feature Pages (src/pages/)
|
||||
|
||||
**Companies:**
|
||||
- `CompaniesList.tsx` — Use DataGrid component, search/filter/sort/pagination, CSV import (CsvImportDialog) + export buttons, empty state with create button (AC 1, 4, 5, 20)
|
||||
- `CompanyDetail.tsx` — Tabs: overview, contacts, files, activity (AC 2)
|
||||
- `CompanyForm.tsx` — RHF + Zod, validate name required, unsaved changes guard (AC 3, 22)
|
||||
|
||||
**Contacts:**
|
||||
- `ContactsList.tsx` — Use DataGrid, loading skeleton rows, empty state (AC 6, 21)
|
||||
- `ContactDetail.tsx` — Tabs: overview, companies, files, activity (AC 7)
|
||||
- `ContactForm.tsx` — RHF + Zod, validate first_name/last_name/email, multi-company assignment (AC 8, 9)
|
||||
|
||||
**Settings:**
|
||||
- `SettingsProfile.tsx` — Update name, email, password, avatar (AC 11)
|
||||
- `SettingsRoles.tsx` — Create role, assign permissions, save (AC 12)
|
||||
- `SettingsUsers.tsx` — List users, invite user, change role, deactivate (AC 13)
|
||||
|
||||
**Other:**
|
||||
- `AuditLog.tsx` — Filterable table (date, user, action, entity). Call useAuditLog hook. Handle 404 gracefully with empty state (AC 14)
|
||||
- `GlobalSearchResults.tsx` — Filters (entity type, date), highlight matched terms. Call useGlobalSearch hook (AC 17, 18)
|
||||
|
||||
### 2. Page Updates
|
||||
|
||||
- `Dashboard.tsx` — Replace placeholder with stat cards (StatCard component) + recent activity feed (ActivityFeed component) (AC 15)
|
||||
- `Settings.tsx` — Add tree navigation (Profile, Roles, Users, System). Render child routes (AC 10)
|
||||
- `TopBar.tsx` — Add SearchDropdown in topbar for global search (AC 16)
|
||||
|
||||
### 3. Routes (src/routes/index.tsx)
|
||||
|
||||
Add these routes:
|
||||
```
|
||||
/companies → CompaniesList
|
||||
/companies/:id → CompanyDetail
|
||||
/companies/new → CompanyForm
|
||||
/companies/:id/edit → CompanyForm
|
||||
/contacts → ContactsList
|
||||
/contacts/:id → ContactDetail
|
||||
/contacts/new → ContactForm
|
||||
/contacts/:id/edit → ContactForm
|
||||
/audit-log → AuditLog
|
||||
/search → GlobalSearchResults
|
||||
/settings/profile → SettingsProfile
|
||||
/settings/roles → SettingsRoles
|
||||
/settings/users → SettingsUsers
|
||||
```
|
||||
|
||||
### 4. i18n Updates (src/i18n/locales/de.json + en.json)
|
||||
|
||||
Add translation keys for all new pages: companies, contacts, settings, audit_log, search, dashboard sections.
|
||||
|
||||
### 5. Tests (src/__tests__/)
|
||||
|
||||
Create test files:
|
||||
- `companies/CompaniesList.test.tsx`
|
||||
- `companies/CompanyDetail.test.tsx`
|
||||
- `companies/CompanyForm.test.tsx`
|
||||
- `contacts/ContactsList.test.tsx`
|
||||
- `contacts/ContactDetail.test.tsx`
|
||||
- `contacts/ContactForm.test.tsx`
|
||||
- `settings/SettingsProfile.test.tsx`
|
||||
- `settings/SettingsRoles.test.tsx`
|
||||
- `settings/SettingsUsers.test.tsx`
|
||||
- `dashboard/Dashboard.test.tsx`
|
||||
- `search/GlobalSearch.test.tsx`
|
||||
- `AuditLog.test.tsx`
|
||||
|
||||
### 6. Verification
|
||||
|
||||
Run these commands and report results:
|
||||
```bash
|
||||
cd /a0/usr/workdir/dev-projects/leocrm/frontend
|
||||
npx vitest run src/__tests__/ --reporter=verbose
|
||||
npm run build
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
## Tech Stack
|
||||
- React 18 + Vite + TypeScript
|
||||
- TanStack Query v5 (hooks in src/api/hooks.ts)
|
||||
- Zustand (stores in src/store/)
|
||||
- react-i18next (de/en locales)
|
||||
- React Hook Form + Zod
|
||||
- Tailwind CSS
|
||||
- Vitest + @testing-library/react
|
||||
- @tanstack/react-table v8
|
||||
|
||||
## Existing UI Components (src/components/ui/)
|
||||
Avatar, Badge, Button, Card, ConfirmDialog, EmptyState, Input, Modal, Pagination, Select, Skeleton, Table, Toast
|
||||
|
||||
## Existing Layout (src/components/layout/)
|
||||
AppShell, Sidebar, TopBar
|
||||
|
||||
## API Client (src/api/client.ts)
|
||||
Axios instance with interceptors. Base URL: http://localhost:8000. Auth via session cookie.
|
||||
|
||||
## Backend API Endpoints
|
||||
```
|
||||
GET/POST/PATCH/DELETE /api/v1/companies
|
||||
GET /api/v1/companies/{id} # includes contacts[]
|
||||
GET /api/v1/companies/export?format=csv
|
||||
POST /api/v1/companies/import # CSV upload
|
||||
GET/POST/PATCH/DELETE /api/v1/contacts
|
||||
GET /api/v1/contacts/{id} # includes companies[]
|
||||
GET/POST/PATCH/DELETE /api/v1/users
|
||||
GET /api/v1/users/{id}
|
||||
GET /api/v1/notifications
|
||||
GET /api/v1/plugins
|
||||
GET /health
|
||||
```
|
||||
Note: No /api/v1/audit endpoint exists yet. useAuditLog hook may 404 — handle gracefully.
|
||||
Note: No dedicated search endpoint. useGlobalSearch calls useCompanies + useContacts with search param.
|
||||
|
||||
## Company Schema
|
||||
```python
|
||||
name: str (required, 1-100 chars)
|
||||
account_number: str | None (max 40)
|
||||
industry: str | None (max 50)
|
||||
phone: str | None (max 30)
|
||||
email: str | None (max 255)
|
||||
website: str | None (max 500)
|
||||
description: str | None
|
||||
```
|
||||
|
||||
## Rules
|
||||
- TypeScript only, no .js files
|
||||
- No Lorem Ipsum — use real German/English content
|
||||
- Reuse existing UI components, don't recreate them
|
||||
- Keep responses under 50 lines — reference files by path
|
||||
- Use real content, not placeholder text
|
||||
- All 23 acceptance criteria must be covered
|
||||
- Test files must use @testing-library/react with vitest
|
||||
Reference in New Issue
Block a user