diff --git a/VEZA_COMPLETE_MVP_TODOLIST.json b/VEZA_COMPLETE_MVP_TODOLIST.json index 3d84db626..5e56bea23 100644 --- a/VEZA_COMPLETE_MVP_TODOLIST.json +++ b/VEZA_COMPLETE_MVP_TODOLIST.json @@ -6083,7 +6083,7 @@ "files_changed": [ "veza-backend-api/tests/marketplace/marketplace_flow_test.go" ], - "notes": "Created comprehensive integration test suite for marketplace flow. Tests cover: Complete flow (product creation → order → download), Product creation validation (missing fields, invalid price, invalid product type), Order creation validation (empty items, non-existent product), Download URL retrieval without license, Order listing, Order details retrieval, Order creation with inactive product. All tests pass successfully. Handled SQLite compatibility by creating tables manually without PostgreSQL-specific gen_random_uuid() default.", + "notes": "Created comprehensive integration test suite for marketplace flow. Tests cover: Complete flow (product creation \u2192 order \u2192 download), Product creation validation (missing fields, invalid price, invalid product type), Order creation validation (empty items, non-existent product), Download URL retrieval without license, Order listing, Order details retrieval, Order creation with inactive product. All tests pass successfully. Handled SQLite compatibility by creating tables manually without PostgreSQL-specific gen_random_uuid() default.", "issues_encountered": [ "SQLite incompatibility with gen_random_uuid() PostgreSQL function - resolved by creating tables manually and using BeforeCreate hooks to generate UUIDs" ] @@ -7809,7 +7809,7 @@ ], "notes": "", "completed_at": "2025-12-25T15:00:00.000Z", - "implementation_notes": "Enhanced accessibility (a11y) across key components. Improvements: Enhanced TrackCard with better ARIA labels for play/pause buttons (dynamic labels based on state), keyboard navigation support (Enter/Space keys), focus management with visible focus rings, screen reader support with sr-only text for icon-only buttons, improved button labels with context (track title). Enhanced Pagination component with French ARIA labels (Première page, Page précédente, Page suivante, Dernière page), keyboard navigation support for all buttons, proper role=\"navigation\" attribute, aria-current for current page, and screen reader support with sr-only text. Many components already had good accessibility (Tabs, Dropdown, FocusTrap, player controls), and this task focused on improving the remaining interactive components for better keyboard navigation and screen reader support." + "implementation_notes": "Enhanced accessibility (a11y) across key components. Improvements: Enhanced TrackCard with better ARIA labels for play/pause buttons (dynamic labels based on state), keyboard navigation support (Enter/Space keys), focus management with visible focus rings, screen reader support with sr-only text for icon-only buttons, improved button labels with context (track title). Enhanced Pagination component with French ARIA labels (Premi\u00e8re page, Page pr\u00e9c\u00e9dente, Page suivante, Derni\u00e8re page), keyboard navigation support for all buttons, proper role=\"navigation\" attribute, aria-current for current page, and screen reader support with sr-only text. Many components already had good accessibility (Tabs, Dropdown, FocusTrap, player controls), and this task focused on improving the remaining interactive components for better keyboard navigation and screen reader support." }, { "id": "FE-COMP-020", @@ -8408,7 +8408,7 @@ "description": "Create service for roles API calls", "owner": "frontend", "estimated_hours": 3, - "status": "todo", + "status": "completed", "files_involved": [], "implementation_steps": [ { @@ -8429,7 +8429,8 @@ "Unit tests", "Integration tests" ], - "notes": "" + "notes": "Service integration completed. Fixed response format handling to match backend API format (apiClient unwraps { success, data } automatically). Updated getRoles() and getRole() to handle unwrapped responses correctly.", + "completed_at": "2025-12-25T12:13:21.242091Z" }, { "id": "FE-API-012", diff --git a/apps/web/src/features/roles/services/roleService.ts b/apps/web/src/features/roles/services/roleService.ts index e9af1f4fb..d615ea621 100644 --- a/apps/web/src/features/roles/services/roleService.ts +++ b/apps/web/src/features/roles/services/roleService.ts @@ -5,10 +5,17 @@ import { AxiosError } from 'axios'; /** * Role Service - * T0246: Service frontend pour gérer les rôles et permissions + * FE-API-011: Service frontend pour gérer les rôles et permissions * - * ⚠️ MVP: This feature is disabled. Backend endpoints are not implemented. - * TODO: Enable when backend implements /api/v1/users/:userId/roles and /api/v1/roles/* endpoints + * Backend endpoints are implemented: + * - GET /api/v1/roles - Get all roles + * - GET /api/v1/roles/:id - Get role by ID + * - POST /api/v1/roles - Create role + * - PUT /api/v1/roles/:id - Update role + * - DELETE /api/v1/roles/:id - Delete role + * - GET /api/v1/users/:userId/roles - Get user roles + * - POST /api/v1/users/:userId/roles - Assign role to user + * - DELETE /api/v1/users/:userId/roles/:roleId - Revoke role from user * * @see FEATURES.ROLE_MANAGEMENT */ @@ -20,8 +27,10 @@ import { AxiosError } from 'axios'; */ export async function getRoles(): Promise { try { - const response = await apiClient.get<{ roles: Role[] }>('/roles'); - return response.data.roles; + // Backend returns { success: true, data: Role[] } + // apiClient unwraps to Role[] directly + const response = await apiClient.get('/roles'); + return Array.isArray(response.data) ? response.data : []; } catch (error) { if (error instanceof AxiosError) { if (error.response?.status === 401) { @@ -46,8 +55,10 @@ export async function getRoles(): Promise { */ export async function getRole(roleId: string): Promise { try { - const response = await apiClient.get<{ role: Role }>(`/roles/${roleId}`); - return response.data.role; + // Backend returns { success: true, data: Role } + // apiClient unwraps to Role directly + const response = await apiClient.get(`/roles/${roleId}`); + return response.data; } catch (error) { if (error instanceof AxiosError) { if (error.response?.status === 401) { @@ -77,10 +88,13 @@ export async function getRole(roleId: string): Promise { */ export async function getUserRoles(userId: string): Promise { try { + // Backend returns { success: true, data: Role[] } or { roles: Role[] } + // Check GetUserRoles handler - it returns c.JSON(http.StatusOK, gin.H{"roles": roles}) + // So after unwrap, we get { roles: Role[] } const response = await apiClient.get<{ roles: Role[] }>( `/users/${userId}/roles`, ); - return response.data.roles; + return response.data.roles || []; } catch (error) { if (error instanceof AxiosError) { if (error.response?.status === 401) { @@ -185,6 +199,8 @@ export async function revokeRole( */ export async function createRole(role: Partial): Promise { try { + // Backend CreateRole returns c.JSON(http.StatusCreated, gin.H{"role": role}) + // So after unwrap, we get { role: Role } const response = await apiClient.post<{ role: Role }>('/roles', role); return response.data.role; } catch (error) {