feat: refactor user preferences management
- Marked all user preferences actions as complete in TODO.md. - Updated `user-preferences-client.ts` to remove outdated mutation methods, now handled by server actions. - Deleted unused API routes for column visibility, kanban filters, and view preferences. - Refactored `UserPreferencesContext.tsx` to utilize server actions for updates, improving performance with `useTransition`.
This commit is contained in:
18
TODO.md
18
TODO.md
@@ -187,15 +187,15 @@
|
||||
- [ ] **Nettoyage** : Modifier composants Daily pour `useTransition`
|
||||
|
||||
#### Actions User Preferences (Priorité 3)
|
||||
- [ ] Créer `actions/preferences.ts` pour les toggles
|
||||
- [ ] `updateViewPreferences(preferences)` - Préférences d'affichage
|
||||
- [ ] `updateKanbanFilters(filters)` - Filtres Kanban
|
||||
- [ ] `updateColumnVisibility(columns)` - Visibilité colonnes
|
||||
- [ ] `updateTheme(theme)` - Changement de thème
|
||||
- [ ] Remplacer les hooks par server actions directes
|
||||
- [ ] **Nettoyage** : Supprimer routes `/api/user-preferences/*` (PUT/PATCH)
|
||||
- [ ] **Nettoyage** : Simplifier `user-preferences-client.ts` (GET uniquement)
|
||||
- [ ] **Nettoyage** : Modifier `useUserPreferences.ts` pour server actions
|
||||
- [x] Créer `actions/preferences.ts` pour les toggles
|
||||
- [x] `updateViewPreferences(preferences)` - Préférences d'affichage
|
||||
- [x] `updateKanbanFilters(filters)` - Filtres Kanban
|
||||
- [x] `updateColumnVisibility(columns)` - Visibilité colonnes
|
||||
- [x] `updateTheme(theme)` - Changement de thème
|
||||
- [x] Remplacer les hooks par server actions directes
|
||||
- [x] **Nettoyage** : Supprimer routes `/api/user-preferences/*` (PUT/PATCH)
|
||||
- [x] **Nettoyage** : Simplifier `user-preferences-client.ts` (GET uniquement)
|
||||
- [x] **Nettoyage** : Modifier `UserPreferencesContext.tsx` pour server actions
|
||||
|
||||
#### Actions Tags (Priorité 4)
|
||||
- [ ] Créer `actions/tags.ts` pour la gestion tags
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { httpClient } from './base/http-client';
|
||||
import { UserPreferences, KanbanFilters, ViewPreferences, ColumnVisibility } from '@/lib/types';
|
||||
import { UserPreferences } from '@/lib/types';
|
||||
|
||||
export interface UserPreferencesResponse {
|
||||
success: boolean;
|
||||
@@ -8,14 +8,9 @@ export interface UserPreferencesResponse {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface UserPreferencesUpdateResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client HTTP pour les préférences utilisateur
|
||||
* Client HTTP pour les préférences utilisateur (lecture seule)
|
||||
* Les mutations sont gérées par les server actions dans actions/preferences.ts
|
||||
*/
|
||||
export const userPreferencesClient = {
|
||||
/**
|
||||
@@ -29,49 +24,5 @@ export const userPreferencesClient = {
|
||||
}
|
||||
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sauvegarde toutes les préférences utilisateur
|
||||
*/
|
||||
async savePreferences(preferences: UserPreferences): Promise<void> {
|
||||
const response = await httpClient.put<UserPreferencesUpdateResponse>('/user-preferences', preferences);
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error || 'Erreur lors de la sauvegarde des préférences');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Met à jour les filtres Kanban
|
||||
*/
|
||||
async updateKanbanFilters(filters: Partial<KanbanFilters>): Promise<void> {
|
||||
const response = await httpClient.patch<UserPreferencesUpdateResponse>('/user-preferences/kanban-filters', filters);
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error || 'Erreur lors de la mise à jour des filtres Kanban');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Met à jour les préférences de vue
|
||||
*/
|
||||
async updateViewPreferences(preferences: Partial<ViewPreferences>): Promise<void> {
|
||||
const response = await httpClient.patch<UserPreferencesUpdateResponse>('/user-preferences/view-preferences', preferences);
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error || 'Erreur lors de la mise à jour des préférences de vue');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Met à jour la visibilité des colonnes
|
||||
*/
|
||||
async updateColumnVisibility(visibility: Partial<ColumnVisibility>): Promise<void> {
|
||||
const response = await httpClient.patch<UserPreferencesUpdateResponse>('/user-preferences/column-visibility', visibility);
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error || 'Erreur lors de la mise à jour de la visibilité des colonnes');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
218
src/actions/preferences.ts
Normal file
218
src/actions/preferences.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
'use server';
|
||||
|
||||
import { userPreferencesService } from '@/services/user-preferences';
|
||||
import { KanbanFilters, ViewPreferences, ColumnVisibility, TaskStatus } from '@/lib/types';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
/**
|
||||
* Met à jour les préférences de vue
|
||||
*/
|
||||
export async function updateViewPreferences(updates: Partial<ViewPreferences>): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateViewPreferences(updates);
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur updateViewPreferences:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les filtres Kanban
|
||||
*/
|
||||
export async function updateKanbanFilters(updates: Partial<KanbanFilters>): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateKanbanFilters(updates);
|
||||
revalidatePath('/kanban');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur updateKanbanFilters:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour la visibilité des colonnes
|
||||
*/
|
||||
export async function updateColumnVisibility(updates: Partial<ColumnVisibility>): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const newColumnVisibility: ColumnVisibility = {
|
||||
...preferences.columnVisibility,
|
||||
...updates
|
||||
};
|
||||
|
||||
await userPreferencesService.saveColumnVisibility(newColumnVisibility);
|
||||
revalidatePath('/kanban');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur updateColumnVisibility:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle la visibilité des objectifs
|
||||
*/
|
||||
export async function toggleObjectivesVisibility(): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const showObjectives = !preferences.viewPreferences.showObjectives;
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ showObjectives });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur toggleObjectivesVisibility:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle le mode collapse des objectifs
|
||||
*/
|
||||
export async function toggleObjectivesCollapse(): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const collapseObjectives = !preferences.viewPreferences.collapseObjectives;
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ collapseObjectives });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur toggleObjectivesCollapse:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change le thème (light/dark)
|
||||
*/
|
||||
export async function setTheme(theme: 'light' | 'dark'): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateViewPreferences({ theme });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur setTheme:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle le thème entre light et dark
|
||||
*/
|
||||
export async function toggleTheme(): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const newTheme = preferences.viewPreferences.theme === 'dark' ? 'light' : 'dark';
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ theme: newTheme });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur toggleTheme:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle la taille de police
|
||||
*/
|
||||
export async function toggleFontSize(): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const fontSizes: ('small' | 'medium' | 'large')[] = ['small', 'medium', 'large'];
|
||||
const currentIndex = fontSizes.indexOf(preferences.viewPreferences.fontSize);
|
||||
const nextIndex = (currentIndex + 1) % fontSizes.length;
|
||||
const newFontSize = fontSizes[nextIndex];
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ fontSize: newFontSize });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur toggleFontSize:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle la visibilité d'une colonne Kanban
|
||||
*/
|
||||
export async function toggleColumnVisibility(status: TaskStatus): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const hiddenStatuses = new Set(preferences.columnVisibility.hiddenStatuses);
|
||||
|
||||
if (hiddenStatuses.has(status)) {
|
||||
hiddenStatuses.delete(status);
|
||||
} else {
|
||||
hiddenStatuses.add(status);
|
||||
}
|
||||
|
||||
await userPreferencesService.saveColumnVisibility({
|
||||
hiddenStatuses: Array.from(hiddenStatuses)
|
||||
});
|
||||
|
||||
revalidatePath('/kanban');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Erreur toggleColumnVisibility:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur inconnue'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { userPreferencesService } from '@/services/user-preferences';
|
||||
|
||||
/**
|
||||
* PATCH /api/user-preferences/column-visibility - Met à jour partiellement la visibilité des colonnes
|
||||
*/
|
||||
export async function PATCH(request: NextRequest) {
|
||||
try {
|
||||
const updates = await request.json();
|
||||
|
||||
const current = await userPreferencesService.getColumnVisibility();
|
||||
await userPreferencesService.saveColumnVisibility({ ...current, ...updates });
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Visibilité des colonnes mise à jour avec succès'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la visibilité des colonnes:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Erreur lors de la mise à jour de la visibilité des colonnes'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { userPreferencesService } from '@/services/user-preferences';
|
||||
|
||||
/**
|
||||
* GET /api/user-preferences/kanban-filters - Récupère les filtres Kanban
|
||||
*/
|
||||
export async function GET() {
|
||||
try {
|
||||
const filters = await userPreferencesService.getKanbanFilters();
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: filters
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération des filtres Kanban:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Erreur lors de la récupération des filtres Kanban'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/user-preferences/kanban-filters - Met à jour les filtres Kanban
|
||||
*/
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const filters = await request.json();
|
||||
|
||||
await userPreferencesService.saveKanbanFilters(filters);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Filtres Kanban sauvegardés avec succès'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la sauvegarde des filtres Kanban:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Erreur lors de la sauvegarde des filtres Kanban'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/user-preferences/kanban-filters - Met à jour partiellement les filtres Kanban
|
||||
*/
|
||||
export async function PATCH(request: NextRequest) {
|
||||
try {
|
||||
const updates = await request.json();
|
||||
|
||||
const current = await userPreferencesService.getKanbanFilters();
|
||||
await userPreferencesService.saveKanbanFilters({ ...current, ...updates });
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Filtres Kanban mis à jour avec succès'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour des filtres Kanban:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Erreur lors de la mise à jour des filtres Kanban'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { userPreferencesService } from '@/services/user-preferences';
|
||||
|
||||
/**
|
||||
* PATCH /api/user-preferences/view-preferences - Met à jour partiellement les préférences de vue
|
||||
*/
|
||||
export async function PATCH(request: NextRequest) {
|
||||
try {
|
||||
const updates = await request.json();
|
||||
|
||||
const current = await userPreferencesService.getViewPreferences();
|
||||
await userPreferencesService.saveViewPreferences({ ...current, ...updates });
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Préférences de vue mises à jour avec succès'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour des préférences de vue:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Erreur lors de la mise à jour des préférences de vue'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,37 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext, ReactNode, useState, useCallback, useEffect } from 'react';
|
||||
import { userPreferencesClient } from '@/clients/user-preferences-client';
|
||||
import { createContext, useContext, ReactNode, useState, useCallback, useEffect, useTransition } from 'react';
|
||||
import { UserPreferences, KanbanFilters, ViewPreferences, ColumnVisibility, TaskStatus } from '@/lib/types';
|
||||
import {
|
||||
updateViewPreferences as updateViewPreferencesAction,
|
||||
updateKanbanFilters as updateKanbanFiltersAction,
|
||||
updateColumnVisibility as updateColumnVisibilityAction,
|
||||
toggleObjectivesVisibility as toggleObjectivesVisibilityAction,
|
||||
toggleObjectivesCollapse as toggleObjectivesCollapseAction,
|
||||
toggleTheme as toggleThemeAction,
|
||||
setTheme as setThemeAction,
|
||||
toggleFontSize as toggleFontSizeAction,
|
||||
toggleColumnVisibility as toggleColumnVisibilityAction
|
||||
} from '@/actions/preferences';
|
||||
|
||||
interface UserPreferencesContextType {
|
||||
preferences: UserPreferences;
|
||||
isPending: boolean;
|
||||
|
||||
// Kanban Filters
|
||||
updateKanbanFilters: (updates: Partial<KanbanFilters>) => Promise<void>;
|
||||
updateKanbanFilters: (updates: Partial<KanbanFilters>) => void;
|
||||
|
||||
// View Preferences
|
||||
updateViewPreferences: (updates: Partial<ViewPreferences>) => Promise<void>;
|
||||
toggleObjectivesVisibility: () => Promise<void>;
|
||||
toggleObjectivesCollapse: () => Promise<void>;
|
||||
toggleTheme: () => Promise<void>;
|
||||
setTheme: (theme: 'light' | 'dark') => Promise<void>;
|
||||
toggleFontSize: () => Promise<void>;
|
||||
updateViewPreferences: (updates: Partial<ViewPreferences>) => void;
|
||||
toggleObjectivesVisibility: () => void;
|
||||
toggleObjectivesCollapse: () => void;
|
||||
toggleTheme: () => void;
|
||||
setTheme: (theme: 'light' | 'dark') => void;
|
||||
toggleFontSize: () => void;
|
||||
|
||||
// Column Visibility
|
||||
updateColumnVisibility: (updates: Partial<ColumnVisibility>) => Promise<void>;
|
||||
toggleColumnVisibility: (status: TaskStatus) => Promise<void>;
|
||||
updateColumnVisibility: (updates: Partial<ColumnVisibility>) => void;
|
||||
toggleColumnVisibility: (status: TaskStatus) => void;
|
||||
isColumnVisible: (status: TaskStatus) => boolean;
|
||||
}
|
||||
|
||||
@@ -33,6 +44,7 @@ interface UserPreferencesProviderProps {
|
||||
|
||||
export function UserPreferencesProvider({ children, initialPreferences }: UserPreferencesProviderProps) {
|
||||
const [preferences, setPreferences] = useState<UserPreferences>(initialPreferences);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
// Synchroniser le thème avec le ThemeProvider global (si disponible)
|
||||
useEffect(() => {
|
||||
@@ -44,87 +56,114 @@ export function UserPreferencesProvider({ children, initialPreferences }: UserPr
|
||||
|
||||
// === KANBAN FILTERS ===
|
||||
|
||||
const updateKanbanFilters = useCallback(async (updates: Partial<KanbanFilters>) => {
|
||||
const newFilters = { ...preferences.kanbanFilters, ...updates };
|
||||
setPreferences(prev => ({ ...prev, kanbanFilters: newFilters }));
|
||||
|
||||
try {
|
||||
await userPreferencesClient.updateKanbanFilters(updates);
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde des filtres Kanban:', error);
|
||||
// Revert optimistic update on error
|
||||
setPreferences(prev => ({ ...prev, kanbanFilters: preferences.kanbanFilters }));
|
||||
}
|
||||
const updateKanbanFilters = useCallback((updates: Partial<KanbanFilters>) => {
|
||||
startTransition(async () => {
|
||||
const originalFilters = preferences.kanbanFilters;
|
||||
|
||||
// Optimistic update
|
||||
setPreferences(prev => ({
|
||||
...prev,
|
||||
kanbanFilters: { ...prev.kanbanFilters, ...updates }
|
||||
}));
|
||||
|
||||
try {
|
||||
const result = await updateKanbanFiltersAction(updates);
|
||||
if (!result.success) {
|
||||
console.error('Erreur server action:', result.error);
|
||||
setPreferences(prev => ({ ...prev, kanbanFilters: originalFilters }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour des filtres Kanban:', error);
|
||||
setPreferences(prev => ({ ...prev, kanbanFilters: originalFilters }));
|
||||
}
|
||||
});
|
||||
}, [preferences.kanbanFilters]);
|
||||
|
||||
// === VIEW PREFERENCES ===
|
||||
|
||||
const updateViewPreferences = useCallback(async (updates: Partial<ViewPreferences>) => {
|
||||
const newPreferences = { ...preferences.viewPreferences, ...updates };
|
||||
setPreferences(prev => ({ ...prev, viewPreferences: newPreferences }));
|
||||
|
||||
try {
|
||||
await userPreferencesClient.updateViewPreferences(updates);
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde des préférences de vue:', error);
|
||||
// Revert optimistic update on error
|
||||
setPreferences(prev => ({ ...prev, viewPreferences: preferences.viewPreferences }));
|
||||
}
|
||||
const updateViewPreferences = useCallback((updates: Partial<ViewPreferences>) => {
|
||||
startTransition(async () => {
|
||||
const originalPreferences = preferences.viewPreferences;
|
||||
|
||||
// Optimistic update
|
||||
setPreferences(prev => ({
|
||||
...prev,
|
||||
viewPreferences: { ...prev.viewPreferences, ...updates }
|
||||
}));
|
||||
|
||||
try {
|
||||
const result = await updateViewPreferencesAction(updates);
|
||||
if (!result.success) {
|
||||
console.error('Erreur server action:', result.error);
|
||||
setPreferences(prev => ({ ...prev, viewPreferences: originalPreferences }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour des préférences de vue:', error);
|
||||
setPreferences(prev => ({ ...prev, viewPreferences: originalPreferences }));
|
||||
}
|
||||
});
|
||||
}, [preferences.viewPreferences]);
|
||||
|
||||
const toggleObjectivesVisibility = useCallback(async () => {
|
||||
const newValue = !preferences.viewPreferences.showObjectives;
|
||||
await updateViewPreferences({ showObjectives: newValue });
|
||||
}, [preferences.viewPreferences.showObjectives, updateViewPreferences]);
|
||||
const toggleObjectivesVisibility = useCallback(() => {
|
||||
startTransition(async () => {
|
||||
await toggleObjectivesVisibilityAction();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleObjectivesCollapse = useCallback(async () => {
|
||||
const newValue = !preferences.viewPreferences.objectivesCollapsed;
|
||||
await updateViewPreferences({ objectivesCollapsed: newValue });
|
||||
}, [preferences.viewPreferences.objectivesCollapsed, updateViewPreferences]);
|
||||
const toggleObjectivesCollapse = useCallback(() => {
|
||||
startTransition(async () => {
|
||||
await toggleObjectivesCollapseAction();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleTheme = useCallback(async () => {
|
||||
const newTheme = preferences.viewPreferences.theme === 'dark' ? 'light' : 'dark';
|
||||
await updateViewPreferences({ theme: newTheme });
|
||||
}, [preferences.viewPreferences.theme, updateViewPreferences]);
|
||||
const toggleTheme = useCallback(() => {
|
||||
startTransition(async () => {
|
||||
await toggleThemeAction();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setTheme = useCallback(async (theme: 'light' | 'dark') => {
|
||||
await updateViewPreferences({ theme });
|
||||
}, [updateViewPreferences]);
|
||||
const setTheme = useCallback((theme: 'light' | 'dark') => {
|
||||
startTransition(async () => {
|
||||
await setThemeAction(theme);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleFontSize = useCallback(async () => {
|
||||
const fontSizes: ('small' | 'medium' | 'large')[] = ['small', 'medium', 'large'];
|
||||
const currentIndex = fontSizes.indexOf(preferences.viewPreferences.fontSize);
|
||||
const nextIndex = (currentIndex + 1) % fontSizes.length;
|
||||
const newFontSize = fontSizes[nextIndex];
|
||||
await updateViewPreferences({ fontSize: newFontSize });
|
||||
}, [preferences.viewPreferences.fontSize, updateViewPreferences]);
|
||||
const toggleFontSize = useCallback(() => {
|
||||
startTransition(async () => {
|
||||
await toggleFontSizeAction();
|
||||
});
|
||||
}, []);
|
||||
|
||||
// === COLUMN VISIBILITY ===
|
||||
|
||||
const updateColumnVisibility = useCallback(async (updates: Partial<ColumnVisibility>) => {
|
||||
const newVisibility = { ...preferences.columnVisibility, ...updates };
|
||||
setPreferences(prev => ({ ...prev, columnVisibility: newVisibility }));
|
||||
|
||||
try {
|
||||
await userPreferencesClient.updateColumnVisibility(updates);
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde de la visibilité des colonnes:', error);
|
||||
// Revert optimistic update on error
|
||||
setPreferences(prev => ({ ...prev, columnVisibility: preferences.columnVisibility }));
|
||||
}
|
||||
const updateColumnVisibility = useCallback((updates: Partial<ColumnVisibility>) => {
|
||||
startTransition(async () => {
|
||||
const originalVisibility = preferences.columnVisibility;
|
||||
|
||||
// Optimistic update
|
||||
setPreferences(prev => ({
|
||||
...prev,
|
||||
columnVisibility: { ...prev.columnVisibility, ...updates }
|
||||
}));
|
||||
|
||||
try {
|
||||
const result = await updateColumnVisibilityAction(updates);
|
||||
if (!result.success) {
|
||||
console.error('Erreur server action:', result.error);
|
||||
setPreferences(prev => ({ ...prev, columnVisibility: originalVisibility }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la visibilité des colonnes:', error);
|
||||
setPreferences(prev => ({ ...prev, columnVisibility: originalVisibility }));
|
||||
}
|
||||
});
|
||||
}, [preferences.columnVisibility]);
|
||||
|
||||
const toggleColumnVisibility = useCallback(async (status: TaskStatus) => {
|
||||
const hiddenStatuses = new Set(preferences.columnVisibility.hiddenStatuses);
|
||||
|
||||
if (hiddenStatuses.has(status)) {
|
||||
hiddenStatuses.delete(status);
|
||||
} else {
|
||||
hiddenStatuses.add(status);
|
||||
}
|
||||
|
||||
await updateColumnVisibility({ hiddenStatuses: Array.from(hiddenStatuses) });
|
||||
}, [preferences.columnVisibility.hiddenStatuses, updateColumnVisibility]);
|
||||
const toggleColumnVisibility = useCallback((status: TaskStatus) => {
|
||||
startTransition(async () => {
|
||||
await toggleColumnVisibilityAction(status);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const isColumnVisible = useCallback((status: TaskStatus) => {
|
||||
return !preferences.columnVisibility.hiddenStatuses.includes(status);
|
||||
@@ -132,6 +171,7 @@ export function UserPreferencesProvider({ children, initialPreferences }: UserPr
|
||||
|
||||
const contextValue: UserPreferencesContextType = {
|
||||
preferences,
|
||||
isPending,
|
||||
updateKanbanFilters,
|
||||
updateViewPreferences,
|
||||
toggleObjectivesVisibility,
|
||||
|
||||
Reference in New Issue
Block a user