feat: enhance task forms and Kanban components with dynamic priority loading
- Updated `CreateTaskForm` and `EditTaskForm` to load priority options dynamically using `getAllPriorities`, improving maintainability. - Refactored `KanbanFilters` to utilize dynamic priority options, enhancing filter functionality. - Modified `QuickAddTask` and `TaskCard` to display priorities using centralized configuration, ensuring consistency across the application. - Introduced new utility functions in `status-config.ts` for managing priority configurations, streamlining the task management process.
This commit is contained in:
@@ -7,7 +7,7 @@ import { Input } from '@/components/ui/Input';
|
|||||||
import { TagInput } from '@/components/ui/TagInput';
|
import { TagInput } from '@/components/ui/TagInput';
|
||||||
import { TaskPriority, TaskStatus } from '@/lib/types';
|
import { TaskPriority, TaskStatus } from '@/lib/types';
|
||||||
import { CreateTaskData } from '@/clients/tasks-client';
|
import { CreateTaskData } from '@/clients/tasks-client';
|
||||||
import { getAllStatuses } from '@/lib/status-config';
|
import { getAllStatuses, getAllPriorities } from '@/lib/status-config';
|
||||||
|
|
||||||
interface CreateTaskFormProps {
|
interface CreateTaskFormProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -120,10 +120,11 @@ export function CreateTaskForm({ isOpen, onClose, onSubmit, loading = false }: C
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full px-3 py-2 bg-slate-800/50 border border-slate-700/50 rounded-lg text-slate-100 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500/50 hover:border-slate-600/50 transition-all duration-200 backdrop-blur-sm"
|
className="w-full px-3 py-2 bg-slate-800/50 border border-slate-700/50 rounded-lg text-slate-100 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500/50 hover:border-slate-600/50 transition-all duration-200 backdrop-blur-sm"
|
||||||
>
|
>
|
||||||
<option value="low">Faible</option>
|
{getAllPriorities().map(priorityConfig => (
|
||||||
<option value="medium">Moyenne</option>
|
<option key={priorityConfig.key} value={priorityConfig.key}>
|
||||||
<option value="high">Élevée</option>
|
{priorityConfig.icon} {priorityConfig.label}
|
||||||
<option value="urgent">Urgente</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Input } from '@/components/ui/Input';
|
|||||||
import { TagInput } from '@/components/ui/TagInput';
|
import { TagInput } from '@/components/ui/TagInput';
|
||||||
import { Task, TaskPriority, TaskStatus } from '@/lib/types';
|
import { Task, TaskPriority, TaskStatus } from '@/lib/types';
|
||||||
import { UpdateTaskData } from '@/clients/tasks-client';
|
import { UpdateTaskData } from '@/clients/tasks-client';
|
||||||
import { getAllStatuses } from '@/lib/status-config';
|
import { getAllStatuses, getAllPriorities } from '@/lib/status-config';
|
||||||
|
|
||||||
interface EditTaskFormProps {
|
interface EditTaskFormProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -132,10 +132,11 @@ export function EditTaskForm({ isOpen, onClose, onSubmit, task, loading = false
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full px-3 py-2 bg-slate-800/50 border border-slate-700/50 rounded-lg text-slate-100 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500/50 hover:border-slate-600/50 transition-all duration-200 backdrop-blur-sm"
|
className="w-full px-3 py-2 bg-slate-800/50 border border-slate-700/50 rounded-lg text-slate-100 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-cyan-500/50 focus:border-cyan-500/50 hover:border-slate-600/50 transition-all duration-200 backdrop-blur-sm"
|
||||||
>
|
>
|
||||||
<option value="low">Faible</option>
|
{getAllPriorities().map(priorityConfig => (
|
||||||
<option value="medium">Moyenne</option>
|
<option key={priorityConfig.key} value={priorityConfig.key}>
|
||||||
<option value="high">Élevée</option>
|
{priorityConfig.icon} {priorityConfig.label}
|
||||||
<option value="urgent">Urgente</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { TaskPriority } from '@/lib/types';
|
|||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Input } from '@/components/ui/Input';
|
import { Input } from '@/components/ui/Input';
|
||||||
import { useTasksContext } from '@/contexts/TasksContext';
|
import { useTasksContext } from '@/contexts/TasksContext';
|
||||||
|
import { getAllPriorities, getPriorityColorHex } from '@/lib/status-config';
|
||||||
|
|
||||||
export interface KanbanFilters {
|
export interface KanbanFilters {
|
||||||
search?: string;
|
search?: string;
|
||||||
@@ -67,26 +68,17 @@ export function KanbanFilters({ filters, onFiltersChange }: KanbanFiltersProps)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePinnedTagChange = (tagName: string | undefined) => {
|
|
||||||
onFiltersChange({
|
|
||||||
...filters,
|
|
||||||
pinnedTag: tagName
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClearFilters = () => {
|
const handleClearFilters = () => {
|
||||||
onFiltersChange({});
|
onFiltersChange({});
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasActiveFilters = filters.search || filters.tags?.length || filters.priorities?.length;
|
|
||||||
const activeFiltersCount = (filters.tags?.length || 0) + (filters.priorities?.length || 0) + (filters.search ? 1 : 0);
|
const activeFiltersCount = (filters.tags?.length || 0) + (filters.priorities?.length || 0) + (filters.search ? 1 : 0);
|
||||||
|
|
||||||
const priorityOptions: { value: TaskPriority; label: string; color: string }[] = [
|
const priorityOptions = getAllPriorities().map(priorityConfig => ({
|
||||||
{ value: 'urgent', label: 'Urgent', color: 'bg-red-500' },
|
value: priorityConfig.key,
|
||||||
{ value: 'high', label: 'Haute', color: 'bg-orange-500' },
|
label: priorityConfig.label,
|
||||||
{ value: 'medium', label: 'Moyenne', color: 'bg-yellow-500' },
|
color: priorityConfig.color
|
||||||
{ value: 'low', label: 'Basse', color: 'bg-blue-500' }
|
}));
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-slate-900/50 border-b border-slate-700/50 backdrop-blur-sm">
|
<div className="bg-slate-900/50 border-b border-slate-700/50 backdrop-blur-sm">
|
||||||
@@ -198,7 +190,10 @@ export function KanbanFilters({ filters, onFiltersChange }: KanbanFiltersProps)
|
|||||||
: 'border-slate-600 bg-slate-800/50 text-slate-400 hover:border-slate-500'
|
: 'border-slate-600 bg-slate-800/50 text-slate-400 hover:border-slate-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className={`w-2 h-2 rounded-full ${priority.color}`} />
|
<div
|
||||||
|
className="w-2 h-2 rounded-full"
|
||||||
|
style={{ backgroundColor: getPriorityColorHex(priority.color) }}
|
||||||
|
/>
|
||||||
{priority.label}
|
{priority.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Card } from '@/components/ui/Card';
|
|||||||
import { TagInput } from '@/components/ui/TagInput';
|
import { TagInput } from '@/components/ui/TagInput';
|
||||||
import { TaskStatus, TaskPriority } from '@/lib/types';
|
import { TaskStatus, TaskPriority } from '@/lib/types';
|
||||||
import { CreateTaskData } from '@/clients/tasks-client';
|
import { CreateTaskData } from '@/clients/tasks-client';
|
||||||
|
import { getAllPriorities, getPriorityConfig } from '@/lib/status-config';
|
||||||
|
|
||||||
interface QuickAddTaskProps {
|
interface QuickAddTaskProps {
|
||||||
status: TaskStatus;
|
status: TaskStatus;
|
||||||
@@ -136,10 +137,11 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
|||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="bg-transparent border-none outline-none text-xs font-mono text-slate-400"
|
className="bg-transparent border-none outline-none text-xs font-mono text-slate-400"
|
||||||
>
|
>
|
||||||
<option value="low">L</option>
|
{getAllPriorities().map(priorityConfig => (
|
||||||
<option value="medium">M</option>
|
<option key={priorityConfig.key} value={priorityConfig.key}>
|
||||||
<option value="high">H</option>
|
{priorityConfig.icon} {priorityConfig.label}
|
||||||
<option value="urgent">U</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Badge } from '@/components/ui/Badge';
|
|||||||
import { TagDisplay } from '@/components/ui/TagDisplay';
|
import { TagDisplay } from '@/components/ui/TagDisplay';
|
||||||
import { useTasksContext } from '@/contexts/TasksContext';
|
import { useTasksContext } from '@/contexts/TasksContext';
|
||||||
import { useDraggable } from '@dnd-kit/core';
|
import { useDraggable } from '@dnd-kit/core';
|
||||||
|
import { getPriorityConfig } from '@/lib/status-config';
|
||||||
|
|
||||||
interface TaskCardProps {
|
interface TaskCardProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
@@ -159,11 +160,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Indicateur de priorité compact */}
|
{/* Indicateur de priorité compact */}
|
||||||
<div className={`w-1.5 h-1.5 rounded-full ${
|
<div className={`w-1.5 h-1.5 rounded-full bg-${getPriorityConfig(task.priority).color}-400`} />
|
||||||
task.priority === 'high' ? 'bg-red-400' :
|
|
||||||
task.priority === 'medium' ? 'bg-yellow-400' :
|
|
||||||
'bg-slate-500'
|
|
||||||
}`} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -237,11 +234,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Indicateur de priorité tech */}
|
{/* Indicateur de priorité tech */}
|
||||||
<div className={`w-2 h-2 rounded-full animate-pulse ${
|
<div className={`w-2 h-2 rounded-full animate-pulse bg-${getPriorityConfig(task.priority).color}-400 shadow-${getPriorityConfig(task.priority).color}-400/50 shadow-sm`} />
|
||||||
task.priority === 'high' ? 'bg-red-400 shadow-red-400/50 shadow-sm' :
|
|
||||||
task.priority === 'medium' ? 'bg-yellow-400 shadow-yellow-400/50 shadow-sm' :
|
|
||||||
'bg-slate-500'
|
|
||||||
}`} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TaskStatus } from './types';
|
import { TaskStatus, TaskPriority } from './types';
|
||||||
|
|
||||||
export interface StatusConfig {
|
export interface StatusConfig {
|
||||||
key: TaskStatus;
|
key: TaskStatus;
|
||||||
@@ -114,3 +114,74 @@ export const getBadgeVariant = (color: StatusConfig['color']): 'success' | 'prim
|
|||||||
default: return 'default';
|
default: return 'default';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configuration des priorités
|
||||||
|
export interface PriorityConfig {
|
||||||
|
key: TaskPriority;
|
||||||
|
label: string;
|
||||||
|
icon: string;
|
||||||
|
color: 'blue' | 'yellow' | 'purple' | 'red';
|
||||||
|
order: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PRIORITY_CONFIG: Record<TaskPriority, PriorityConfig> = {
|
||||||
|
low: {
|
||||||
|
key: 'low',
|
||||||
|
label: 'Faible',
|
||||||
|
icon: '🔵',
|
||||||
|
color: 'blue',
|
||||||
|
order: 1
|
||||||
|
},
|
||||||
|
medium: {
|
||||||
|
key: 'medium',
|
||||||
|
label: 'Moyenne',
|
||||||
|
icon: '🟡',
|
||||||
|
color: 'yellow',
|
||||||
|
order: 2
|
||||||
|
},
|
||||||
|
high: {
|
||||||
|
key: 'high',
|
||||||
|
label: 'Élevée',
|
||||||
|
icon: '🟣',
|
||||||
|
color: 'purple',
|
||||||
|
order: 3
|
||||||
|
},
|
||||||
|
urgent: {
|
||||||
|
key: 'urgent',
|
||||||
|
label: 'Urgente',
|
||||||
|
icon: '🔴',
|
||||||
|
color: 'red',
|
||||||
|
order: 4
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// Utilitaires pour les priorités
|
||||||
|
export const getPriorityConfig = (priority: TaskPriority): PriorityConfig => {
|
||||||
|
return PRIORITY_CONFIG[priority];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllPriorities = (): PriorityConfig[] => {
|
||||||
|
return Object.values(PRIORITY_CONFIG).sort((a, b) => a.order - b.order);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPriorityLabel = (priority: TaskPriority): string => {
|
||||||
|
return PRIORITY_CONFIG[priority].label;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPriorityIcon = (priority: TaskPriority): string => {
|
||||||
|
return PRIORITY_CONFIG[priority].icon;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPriorityColor = (priority: TaskPriority): PriorityConfig['color'] => {
|
||||||
|
return PRIORITY_CONFIG[priority].color;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPriorityColorHex = (color: PriorityConfig['color']): string => {
|
||||||
|
const colorMap = {
|
||||||
|
blue: '#60a5fa',
|
||||||
|
yellow: '#fbbf24',
|
||||||
|
purple: '#a78bfa',
|
||||||
|
red: '#f87171'
|
||||||
|
};
|
||||||
|
return colorMap[color];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Types de base pour les tâches
|
// Types de base pour les tâches
|
||||||
// Note: TaskStatus est maintenant géré 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';
|
||||||
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';
|
||||||
|
|||||||
Reference in New Issue
Block a user