feat: adding status archived and refacto type in one place only
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { httpClient } from './base/http-client';
|
import { httpClient } from './base/http-client';
|
||||||
import { Task, TaskStatus, TaskPriority } from '@/lib/types';
|
import { Task, TaskStatus, TaskPriority, TaskStats } from '@/lib/types';
|
||||||
|
|
||||||
export interface TaskFilters {
|
export interface TaskFilters {
|
||||||
status?: TaskStatus[];
|
status?: TaskStatus[];
|
||||||
@@ -12,15 +12,7 @@ export interface TaskFilters {
|
|||||||
export interface TasksResponse {
|
export interface TasksResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
data: Task[];
|
data: Task[];
|
||||||
stats: {
|
stats: TaskStats;
|
||||||
total: number;
|
|
||||||
completed: number;
|
|
||||||
inProgress: number;
|
|
||||||
todo: number;
|
|
||||||
cancelled: number;
|
|
||||||
freeze: number;
|
|
||||||
completionRate: number;
|
|
||||||
};
|
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,11 @@
|
|||||||
import { KanbanBoardContainer } from '@/components/kanban/BoardContainer';
|
import { KanbanBoardContainer } from '@/components/kanban/BoardContainer';
|
||||||
import { Header } from '@/components/ui/Header';
|
import { Header } from '@/components/ui/Header';
|
||||||
import { TasksProvider, useTasksContext } from '@/contexts/TasksContext';
|
import { TasksProvider, useTasksContext } from '@/contexts/TasksContext';
|
||||||
import { Task, Tag } from '@/lib/types';
|
import { Task, Tag, TaskStats } from '@/lib/types';
|
||||||
|
|
||||||
interface HomePageClientProps {
|
interface HomePageClientProps {
|
||||||
initialTasks: Task[];
|
initialTasks: Task[];
|
||||||
initialStats: {
|
initialStats: TaskStats;
|
||||||
total: number;
|
|
||||||
completed: number;
|
|
||||||
inProgress: number;
|
|
||||||
todo: number;
|
|
||||||
cancelled: number;
|
|
||||||
freeze: number;
|
|
||||||
completionRate: number;
|
|
||||||
};
|
|
||||||
initialTags: (Tag & { usage: number })[];
|
initialTags: (Tag & { usage: number })[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
import { Card, CardContent } from '@/components/ui/Card';
|
import { Card, CardContent } from '@/components/ui/Card';
|
||||||
|
import { TaskStats } from '@/lib/types';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
stats: {
|
stats: TaskStats;
|
||||||
total: number;
|
|
||||||
completed: number;
|
|
||||||
inProgress: number;
|
|
||||||
todo: number;
|
|
||||||
cancelled: number;
|
|
||||||
freeze: number;
|
|
||||||
completionRate: number;
|
|
||||||
};
|
|
||||||
syncing?: boolean;
|
syncing?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +91,13 @@ export function Header({ title, subtitle, stats, syncing = false }: HeaderProps)
|
|||||||
color="gray"
|
color="gray"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{stats.archived > 0 && (
|
||||||
|
<StatCard
|
||||||
|
label="ARCHIVE"
|
||||||
|
value={String(stats.archived).padStart(2, '0')}
|
||||||
|
color="gray"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<StatCard
|
<StatCard
|
||||||
label="RATE"
|
label="RATE"
|
||||||
value={`${stats.completionRate}%`}
|
value={`${stats.completionRate}%`}
|
||||||
|
|||||||
@@ -2,19 +2,11 @@
|
|||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { tasksClient, TaskFilters, CreateTaskData, UpdateTaskData } from '@/clients/tasks-client';
|
import { tasksClient, TaskFilters, CreateTaskData, UpdateTaskData } from '@/clients/tasks-client';
|
||||||
import { Task } from '@/lib/types';
|
import { Task, TaskStats } from '@/lib/types';
|
||||||
|
|
||||||
interface UseTasksState {
|
interface UseTasksState {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
stats: {
|
stats: TaskStats;
|
||||||
total: number;
|
|
||||||
completed: number;
|
|
||||||
inProgress: number;
|
|
||||||
todo: number;
|
|
||||||
cancelled: number;
|
|
||||||
freeze: number;
|
|
||||||
completionRate: number;
|
|
||||||
};
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
syncing: boolean; // Pour indiquer les opérations optimistes en cours
|
syncing: boolean; // Pour indiquer les opérations optimistes en cours
|
||||||
@@ -34,7 +26,7 @@ interface UseTasksActions {
|
|||||||
*/
|
*/
|
||||||
export function useTasks(
|
export function useTasks(
|
||||||
initialFilters?: TaskFilters,
|
initialFilters?: TaskFilters,
|
||||||
initialData?: { tasks: Task[]; stats: UseTasksState['stats'] }
|
initialData?: { tasks: Task[]; stats: TaskStats }
|
||||||
): UseTasksState & UseTasksActions {
|
): UseTasksState & UseTasksActions {
|
||||||
const [state, setState] = useState<UseTasksState>({
|
const [state, setState] = useState<UseTasksState>({
|
||||||
tasks: initialData?.tasks || [],
|
tasks: initialData?.tasks || [],
|
||||||
@@ -45,6 +37,7 @@ export function useTasks(
|
|||||||
todo: 0,
|
todo: 0,
|
||||||
cancelled: 0,
|
cancelled: 0,
|
||||||
freeze: 0,
|
freeze: 0,
|
||||||
|
archived: 0,
|
||||||
completionRate: 0
|
completionRate: 0
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -153,6 +146,7 @@ export function useTasks(
|
|||||||
todo: updatedTasks.filter(t => t.status === 'todo').length,
|
todo: updatedTasks.filter(t => t.status === 'todo').length,
|
||||||
cancelled: updatedTasks.filter(t => t.status === 'cancelled').length,
|
cancelled: updatedTasks.filter(t => t.status === 'cancelled').length,
|
||||||
freeze: updatedTasks.filter(t => t.status === 'freeze').length,
|
freeze: updatedTasks.filter(t => t.status === 'freeze').length,
|
||||||
|
archived: updatedTasks.filter(t => t.status === 'archived').length,
|
||||||
completionRate: updatedTasks.length > 0
|
completionRate: updatedTasks.length > 0
|
||||||
? Math.round((updatedTasks.filter(t => t.status === 'done').length / updatedTasks.length) * 100)
|
? Math.round((updatedTasks.filter(t => t.status === 'done').length / updatedTasks.length) * 100)
|
||||||
: 0
|
: 0
|
||||||
@@ -196,6 +190,7 @@ export function useTasks(
|
|||||||
todo: currentTasks.filter(t => t.status === 'todo').length,
|
todo: currentTasks.filter(t => t.status === 'todo').length,
|
||||||
cancelled: currentTasks.filter(t => t.status === 'cancelled').length,
|
cancelled: currentTasks.filter(t => t.status === 'cancelled').length,
|
||||||
freeze: currentTasks.filter(t => t.status === 'freeze').length,
|
freeze: currentTasks.filter(t => t.status === 'freeze').length,
|
||||||
|
archived: currentTasks.filter(t => t.status === 'archived').length,
|
||||||
completionRate: currentTasks.length > 0
|
completionRate: currentTasks.length > 0
|
||||||
? Math.round((currentTasks.filter(t => t.status === 'done').length / currentTasks.length) * 100)
|
? Math.round((currentTasks.filter(t => t.status === 'done').length / currentTasks.length) * 100)
|
||||||
: 0
|
: 0
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ export const STATUS_CONFIG: Record<TaskStatus, StatusConfig> = {
|
|||||||
icon: '✕',
|
icon: '✕',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
order: 5
|
order: 5
|
||||||
|
},
|
||||||
|
archived: {
|
||||||
|
key: 'archived',
|
||||||
|
label: 'Archivé',
|
||||||
|
icon: '📦',
|
||||||
|
color: 'gray',
|
||||||
|
order: 6
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
14
lib/types.ts
14
lib/types.ts
@@ -1,9 +1,21 @@
|
|||||||
// Types de base pour les tâches
|
// Types de base pour les tâches
|
||||||
// Note: TaskStatus et TaskPriority sont maintenant gérés par la configuration centralisée dans lib/status-config.ts
|
// Note: TaskStatus et TaskPriority sont maintenant gérés par la configuration centralisée dans lib/status-config.ts
|
||||||
export type TaskStatus = 'todo' | 'in_progress' | 'done' | 'cancelled' | 'freeze';
|
export type TaskStatus = 'todo' | 'in_progress' | 'done' | 'cancelled' | 'freeze' | 'archived';
|
||||||
export type TaskPriority = 'low' | 'medium' | 'high' | 'urgent';
|
export type TaskPriority = 'low' | 'medium' | 'high' | 'urgent';
|
||||||
export type TaskSource = 'reminders' | 'jira' | 'manual';
|
export type TaskSource = 'reminders' | 'jira' | 'manual';
|
||||||
|
|
||||||
|
// Interface centralisée pour les statistiques
|
||||||
|
export interface TaskStats {
|
||||||
|
total: number;
|
||||||
|
completed: number;
|
||||||
|
inProgress: number;
|
||||||
|
todo: number;
|
||||||
|
cancelled: number;
|
||||||
|
freeze: number;
|
||||||
|
archived: number;
|
||||||
|
completionRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
// Interface principale pour les tâches
|
// Interface principale pour les tâches
|
||||||
export interface Task {
|
export interface Task {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { createContext, useContext, ReactNode, useState, useMemo, useEffect } fr
|
|||||||
import { useTasks } from '@/hooks/useTasks';
|
import { useTasks } from '@/hooks/useTasks';
|
||||||
import { useTags } from '@/hooks/useTags';
|
import { useTags } from '@/hooks/useTags';
|
||||||
import { userPreferencesService } from '@/services/user-preferences';
|
import { userPreferencesService } from '@/services/user-preferences';
|
||||||
import { Task, Tag } from '@/lib/types';
|
import { Task, Tag, TaskStats } from '@/lib/types';
|
||||||
import { CreateTaskData, UpdateTaskData, TaskFilters } from '@/clients/tasks-client';
|
import { CreateTaskData, UpdateTaskData, TaskFilters } from '@/clients/tasks-client';
|
||||||
import { KanbanFilters } from '@/components/kanban/KanbanFilters';
|
import { KanbanFilters } from '@/components/kanban/KanbanFilters';
|
||||||
import { sortTasks, getSortOption, DEFAULT_SORT, createSortKey } from '@/lib/sort-config';
|
import { sortTasks, getSortOption, DEFAULT_SORT, createSortKey } from '@/lib/sort-config';
|
||||||
@@ -12,15 +12,7 @@ import { sortTasks, getSortOption, DEFAULT_SORT, createSortKey } from '@/lib/sor
|
|||||||
interface TasksContextType {
|
interface TasksContextType {
|
||||||
tasks: Task[]; // Toutes les tâches
|
tasks: Task[]; // Toutes les tâches
|
||||||
regularTasks: Task[]; // Tâches sans les épinglées (pour Kanban)
|
regularTasks: Task[]; // Tâches sans les épinglées (pour Kanban)
|
||||||
stats: {
|
stats: TaskStats;
|
||||||
total: number;
|
|
||||||
completed: number;
|
|
||||||
inProgress: number;
|
|
||||||
todo: number;
|
|
||||||
cancelled: number;
|
|
||||||
freeze: number;
|
|
||||||
completionRate: number;
|
|
||||||
};
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
syncing: boolean;
|
syncing: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
@@ -46,7 +38,7 @@ const TasksContext = createContext<TasksContextType | null>(null);
|
|||||||
interface TasksProviderProps {
|
interface TasksProviderProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
initialTasks: Task[];
|
initialTasks: Task[];
|
||||||
initialStats: TasksContextType['stats'];
|
initialStats: TaskStats;
|
||||||
initialTags?: (Tag & { usage: number })[];
|
initialTags?: (Tag & { usage: number })[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user