feat(localization): update translation keys for phase management

- Revised translation keys in Albanian, German, English, Spanish, Portuguese, and Chinese for improved clarity and consistency in phase management.
- Adjusted phrases related to phase naming, options, and actions to enhance user experience across multiple languages.
- Added new keys for creating and canceling phases to align with recent UI updates in the ManagePhaseModal component.
This commit is contained in:
chamikaJ
2025-07-11 14:04:02 +05:30
parent 6b58709848
commit cc0ff20ca1
7 changed files with 272 additions and 159 deletions

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "Konfiguro Fazat", "configurePhases": "Konfiguro Fazat",
"phaseLabel": "Etiketa e Fazës", "phaseLabel": "Etiketa e Fazës",
"enterPhaseName": "Vendosni një emër për etiketën e fazës", "enterPhaseName": "Shkruani emrin e fazës",
"addOption": "Shto Opsion", "addOption": "Shto Opsion",
"phaseOptions": "Opsionet e Fazës:", "phaseOptions": "Opsionet e Fazës",
"dragToReorderPhases": "Zvarrit fazat për t'i rirenditur. Çdo fazë mund të ketë një ngjyrë të ndryshme.", "dragToReorderPhases": "Zvarrit fazat për t'i rirenditur. Çdo fazë mund të ketë një ngjyrë të ndryshme.",
"enterNewPhaseName": "Shkruani emrin e fazës së re...", "enterNewPhaseName": "Shkruani emrin e fazës së re...",
"addPhase": "Shto Fazë", "addPhase": "Shto Fazë",
"noPhasesFound": "Nuk u gjetën faza. Krijoni fazën tuaj të parë më sipër.", "noPhasesFound": "Nuk u gjetën faza",
"deletePhase": "Fshi Fazën", "deletePhase": "Fshi Fazën",
"deletePhaseConfirm": "Jeni të sigurt që doni të fshini këtë fazë? Ky veprim nuk mund të zhbëhet.", "deletePhaseConfirm": "Jeni të sigurt që doni të fshini këtë fazë? Ky veprim nuk mund të zhbëhet.",
"rename": "Riemëro", "rename": "Riemëro",
"delete": "Fshi", "delete": "Fshi",
"enterPhaseName": "Shkruani emrin e fazës", "create": "Krijo",
"cancel": "Anulo",
"selectColor": "Zgjidh ngjyrën", "selectColor": "Zgjidh ngjyrën",
"managePhases": "Menaxho Fazat", "managePhases": "Menaxho Fazat",
"close": "Mbyll" "close": "Mbyll"

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "Phasen konfigurieren", "configurePhases": "Phasen konfigurieren",
"phaseLabel": "Phasenbezeichnung", "phaseLabel": "Phasenbezeichnung",
"enterPhaseName": "Namen für Phasenbezeichnung eingeben", "enterPhaseName": "Phasennamen eingeben",
"addOption": "Option hinzufügen", "addOption": "Option hinzufügen",
"phaseOptions": "Phasenoptionen:", "phaseOptions": "Phasenoptionen",
"dragToReorderPhases": "Ziehen Sie Phasen, um sie neu zu ordnen. Jede Phase kann eine andere Farbe haben.", "dragToReorderPhases": "Ziehen Sie Phasen, um sie neu zu ordnen. Jede Phase kann eine andere Farbe haben.",
"enterNewPhaseName": "Neuen Phasennamen eingeben...", "enterNewPhaseName": "Neuen Phasennamen eingeben...",
"addPhase": "Phase hinzufügen", "addPhase": "Phase hinzufügen",
"noPhasesFound": "Keine Phasen gefunden. Erstellen Sie Ihre erste Phase oben.", "noPhasesFound": "Keine Phasen gefunden",
"deletePhase": "Phase löschen", "deletePhase": "Phase löschen",
"deletePhaseConfirm": "Sind Sie sicher, dass Sie diese Phase löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", "deletePhaseConfirm": "Sind Sie sicher, dass Sie diese Phase löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
"rename": "Umbenennen", "rename": "Umbenennen",
"delete": "Löschen", "delete": "Löschen",
"enterPhaseName": "Phasennamen eingeben", "create": "Erstellen",
"cancel": "Abbrechen",
"selectColor": "Farbe auswählen", "selectColor": "Farbe auswählen",
"managePhases": "Phasen verwalten", "managePhases": "Phasen verwalten",
"close": "Schließen" "close": "Schließen"

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "Configure Phases", "configurePhases": "Configure Phases",
"phaseLabel": "Phase Label", "phaseLabel": "Phase Label",
"enterPhaseName": "Enter a name for phase label", "enterPhaseName": "Enter phase name",
"addOption": "Add Option", "addOption": "Add Option",
"phaseOptions": "Phase Options:", "phaseOptions": "Phase Options",
"dragToReorderPhases": "Drag phases to reorder them. Each phase can have a different color.", "dragToReorderPhases": "Drag phases to reorder them. Each phase can have a different color.",
"enterNewPhaseName": "Enter new phase name...", "enterNewPhaseName": "Enter new phase name...",
"addPhase": "Add Phase", "addPhase": "Add Phase",
"noPhasesFound": "No phases found. Create your first phase above.", "noPhasesFound": "No phases found",
"deletePhase": "Delete Phase", "deletePhase": "Delete Phase",
"deletePhaseConfirm": "Are you sure you want to delete this phase? This action cannot be undone.", "deletePhaseConfirm": "Are you sure you want to delete this phase? This action cannot be undone.",
"rename": "Rename", "rename": "Rename",
"delete": "Delete", "delete": "Delete",
"enterPhaseName": "Enter phase name", "create": "Create",
"cancel": "Cancel",
"selectColor": "Select color", "selectColor": "Select color",
"managePhases": "Manage Phases", "managePhases": "Manage Phases",
"close": "Close" "close": "Close"

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "Configurar fases", "configurePhases": "Configurar fases",
"phaseLabel": "Etiqueta de fase", "phaseLabel": "Etiqueta de fase",
"enterPhaseName": "Ingrese un nombre para la etiqueta de fase", "enterPhaseName": "Introducir nombre de la fase",
"addOption": "Agregar opción", "addOption": "Agregar opción",
"phaseOptions": "Opciones de fase:", "phaseOptions": "Opciones de fase",
"dragToReorderPhases": "Arrastra las fases para reordenarlas. Cada fase puede tener un color diferente.", "dragToReorderPhases": "Arrastra las fases para reordenarlas. Cada fase puede tener un color diferente.",
"enterNewPhaseName": "Introducir nuevo nombre de fase...", "enterNewPhaseName": "Introducir nuevo nombre de fase...",
"addPhase": "Añadir Fase", "addPhase": "Añadir Fase",
"noPhasesFound": "No se encontraron fases. Crea tu primera fase arriba.", "noPhasesFound": "No se encontraron fases",
"deletePhase": "Eliminar Fase", "deletePhase": "Eliminar Fase",
"deletePhaseConfirm": "¿Estás seguro de que quieres eliminar esta fase? Esta acción no se puede deshacer.", "deletePhaseConfirm": "¿Estás seguro de que quieres eliminar esta fase? Esta acción no se puede deshacer.",
"rename": "Renombrar", "rename": "Renombrar",
"delete": "Eliminar", "delete": "Eliminar",
"enterPhaseName": "Introducir nombre de la fase", "create": "Crear",
"cancel": "Cancelar",
"selectColor": "Seleccionar color", "selectColor": "Seleccionar color",
"managePhases": "Gestionar Fases", "managePhases": "Gestionar Fases",
"close": "Cerrar" "close": "Cerrar"

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "Configurar fases", "configurePhases": "Configurar fases",
"phaseLabel": "Etiqueta de fase", "phaseLabel": "Etiqueta de fase",
"enterPhaseName": "Digite um nome para o rótulo da fase", "enterPhaseName": "Digite o nome da fase",
"addOption": "Adicionar Opção", "addOption": "Adicionar Opção",
"phaseOptions": "Opções de Fase:", "phaseOptions": "Opções de Fase",
"dragToReorderPhases": "Arraste as fases para reordená-las. Cada fase pode ter uma cor diferente.", "dragToReorderPhases": "Arraste as fases para reordená-las. Cada fase pode ter uma cor diferente.",
"enterNewPhaseName": "Digite o novo nome da fase...", "enterNewPhaseName": "Digite o novo nome da fase...",
"addPhase": "Adicionar Fase", "addPhase": "Adicionar Fase",
"noPhasesFound": "Nenhuma fase encontrada. Crie sua primeira fase acima.", "noPhasesFound": "Nenhuma fase encontrada",
"deletePhase": "Excluir Fase", "deletePhase": "Excluir Fase",
"deletePhaseConfirm": "Tem certeza de que deseja excluir esta fase? Esta ação não pode ser desfeita.", "deletePhaseConfirm": "Tem certeza de que deseja excluir esta fase? Esta ação não pode ser desfeita.",
"rename": "Renomear", "rename": "Renomear",
"delete": "Excluir", "delete": "Excluir",
"enterPhaseName": "Digite o nome da fase", "create": "Criar",
"cancel": "Cancelar",
"selectColor": "Selecionar cor", "selectColor": "Selecionar cor",
"managePhases": "Gerenciar Fases", "managePhases": "Gerenciar Fases",
"close": "Fechar" "close": "Fechar"

View File

@@ -1,18 +1,19 @@
{ {
"configurePhases": "配置阶段", "configurePhases": "配置阶段",
"phaseLabel": "阶段标签", "phaseLabel": "阶段标签",
"enterPhaseName": "输入阶段标签名称", "enterPhaseName": "输入阶段名称",
"addOption": "添加选项", "addOption": "添加选项",
"phaseOptions": "阶段选项", "phaseOptions": "阶段选项",
"dragToReorderPhases": "拖拽阶段以重新排序。每个阶段可以有不同的颜色。", "dragToReorderPhases": "拖拽阶段以重新排序。每个阶段可以有不同的颜色。",
"enterNewPhaseName": "输入新阶段名称...", "enterNewPhaseName": "输入新阶段名称...",
"addPhase": "添加阶段", "addPhase": "添加阶段",
"noPhasesFound": "未找到阶段。请在上面创建您的第一个阶段。", "noPhasesFound": "未找到阶段",
"deletePhase": "删除阶段", "deletePhase": "删除阶段",
"deletePhaseConfirm": "您确定要删除此阶段吗?此操作无法撤销。", "deletePhaseConfirm": "您确定要删除此阶段吗?此操作无法撤销。",
"rename": "重命名", "rename": "重命名",
"delete": "删除", "delete": "删除",
"enterPhaseName": "输入阶段名称", "create": "创建",
"cancel": "取消",
"selectColor": "选择颜色", "selectColor": "选择颜色",
"managePhases": "管理阶段", "managePhases": "管理阶段",
"close": "关闭" "close": "关闭"

View File

@@ -1,6 +1,6 @@
import React, { useState, useCallback, useRef, useEffect } from 'react'; import React, { useState, useCallback, useRef, useEffect } from 'react';
import { Modal, Form, Input, Button, Space, Divider, Typography, Flex, ColorPicker } from 'antd'; import { Modal, Form, Input, Button, Space, Divider, Typography, Flex, ColorPicker, Tooltip } from 'antd';
import { PlusOutlined, HolderOutlined } from '@ant-design/icons'; import { PlusOutlined, HolderOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { DndContext, DragEndEvent, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { DndContext, DragEndEvent, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
@@ -41,7 +41,7 @@ interface PhaseItemProps {
isDarkMode: boolean; isDarkMode: boolean;
} }
// Sortable Phase Item Component // Sortable Phase Item Component (compact with hover actions)
const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({ const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({
id, id,
phase, phase,
@@ -50,9 +50,11 @@ const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({
onColorChange, onColorChange,
isDarkMode, isDarkMode,
}) => { }) => {
const { t } = useTranslation('phases-drawer');
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [editName, setEditName] = useState(phase.name || ''); const [editName, setEditName] = useState(phase.name || '');
const [color, setColor] = useState(phase.color_code || PhaseColorCodes[0]); const [color, setColor] = useState(phase.color_code || PhaseColorCodes[0]);
const [isHovered, setIsHovered] = useState(false);
const inputRef = useRef<any>(null); const inputRef = useRef<any>(null);
const { const {
@@ -90,6 +92,10 @@ const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({
} }
}, [handleSave, handleCancel]); }, [handleSave, handleCancel]);
const handleClick = useCallback(() => {
setIsEditing(true);
}, []);
const handleColorChangeComplete = useCallback(() => { const handleColorChangeComplete = useCallback(() => {
if (color !== phase.color_code) { if (color !== phase.color_code) {
onColorChange(id, color); onColorChange(id, color);
@@ -111,82 +117,30 @@ const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({
<div <div
ref={setNodeRef} ref={setNodeRef}
style={style} style={style}
className={`p-3 rounded-md border transition-all duration-200 ${ className={`group relative py-1.5 px-2 rounded border transition-all duration-200 ${
isDarkMode isDarkMode
? 'bg-gray-800 border-gray-700 hover:bg-gray-750' ? 'bg-gray-700 border-gray-600 hover:bg-gray-600 hover:border-gray-500'
: 'bg-white border-gray-200 hover:bg-gray-50 shadow-sm' : 'bg-white border-gray-200 hover:bg-gray-50 hover:border-gray-300'
}`} } ${isDragging ? 'shadow-lg opacity-50 rotate-2 scale-105' : 'shadow-sm hover:shadow-md'}`}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
> >
{/* Header Row - Drag Handle, Phase Name, Actions */} <div className="flex items-center gap-2">
<div className="flex items-center gap-2 mb-2">
{/* Drag Handle */} {/* Drag Handle */}
<div <div
{...attributes} {...attributes}
{...listeners} {...listeners}
className={`cursor-grab active:cursor-grabbing p-1 rounded transition-colors ${ className={`flex-shrink-0 cursor-grab active:cursor-grabbing p-1 rounded transition-all duration-200 ${
isDarkMode isDarkMode
? 'text-gray-400 hover:text-gray-300 hover:bg-gray-700' ? 'text-gray-400 hover:text-gray-300 hover:bg-gray-600'
: 'text-gray-500 hover:text-gray-600 hover:bg-gray-100' : 'text-gray-400 hover:text-gray-600 hover:bg-gray-100'
}`} }`}
> >
<HolderOutlined /> <HolderOutlined className="text-sm" />
</div> </div>
{/* Phase Name */} {/* Phase Color */}
<div className="flex-1"> <div className="flex-shrink-0 flex items-center gap-1">
{isEditing ? (
<Input
ref={inputRef}
value={editName}
onChange={(e) => setEditName(e.target.value)}
onBlur={handleSave}
onKeyDown={handleKeyDown}
className="font-medium"
placeholder="Enter phase name"
/>
) : (
<Text
className={`text-sm font-medium cursor-pointer transition-colors ${
isDarkMode ? 'text-gray-100 hover:text-white' : 'text-gray-900 hover:text-gray-700'
}`}
onClick={() => setIsEditing(true)}
>
{phase.name}
</Text>
)}
</div>
{/* Actions */}
<Space size={4}>
<Button
type="text"
size="small"
onClick={() => setIsEditing(true)}
className={`text-xs ${isDarkMode ? 'text-gray-400 hover:text-gray-300' : 'text-gray-500 hover:text-gray-600'} hover:bg-transparent`}
>
Rename
</Button>
<Button
type="text"
size="small"
danger
onClick={() => onDelete(id)}
className="text-xs text-red-500 hover:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20"
>
Delete
</Button>
</Space>
</div>
{/* Color Row */}
<div className="flex items-center gap-1.5">
<Text
className={`text-xs font-medium ${
isDarkMode ? 'text-gray-400' : 'text-gray-600'
}`}
>
Color:
</Text>
<ColorPicker <ColorPicker
value={color} value={color}
onChange={(value) => setColor(value.toHexString())} onChange={(value) => setColor(value.toHexString())}
@@ -195,13 +149,75 @@ const SortablePhaseItem: React.FC<PhaseItemProps & { id: string }> = ({
className="phase-color-picker" className="phase-color-picker"
/> />
<div <div
className="w-3 h-3 rounded-full border ml-1 transition-all duration-200" className="w-2.5 h-2.5 rounded border shadow-sm"
style={{ style={{
backgroundColor: color, backgroundColor: color,
borderColor: isDarkMode ? '#374151' : '#e5e7eb', borderColor: isDarkMode ? '#6b7280' : '#d1d5db',
}} }}
/> />
</div> </div>
{/* Phase Name */}
<div className="flex-1 min-w-0">
{isEditing ? (
<Input
ref={inputRef}
value={editName}
onChange={(e) => setEditName(e.target.value)}
onBlur={handleSave}
onKeyDown={handleKeyDown}
className={`font-medium text-xs border-0 px-1 py-1 shadow-none ${
isDarkMode
? 'bg-transparent text-gray-200 placeholder-gray-400'
: 'bg-transparent text-gray-900 placeholder-gray-500'
}`}
placeholder={t('enterPhaseName')}
/>
) : (
<Text
className={`text-xs font-medium cursor-pointer transition-colors select-none ${
isDarkMode ? 'text-gray-200 hover:text-gray-100' : 'text-gray-800 hover:text-gray-900'
}`}
onClick={handleClick}
title={t('rename')}
>
{phase.name}
</Text>
)}
</div>
{/* Hover Actions */}
<div className={`flex items-center gap-1 transition-all duration-200 ${
isHovered || isEditing ? 'opacity-100' : 'opacity-0'
}`}>
<Tooltip title={t('rename')}>
<Button
type="text"
size="small"
icon={<EditOutlined />}
onClick={() => setIsEditing(true)}
className={`h-6 w-6 flex items-center justify-center transition-all duration-200 ${
isDarkMode
? 'text-gray-400 hover:text-gray-300 hover:bg-gray-600'
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-100'
}`}
/>
</Tooltip>
<Tooltip title={t('delete')}>
<Button
type="text"
size="small"
icon={<DeleteOutlined />}
onClick={() => onDelete(id)}
className={`h-6 w-6 flex items-center justify-center transition-all duration-200 ${
isDarkMode
? 'text-red-400 hover:text-red-300 hover:bg-red-800'
: 'text-red-500 hover:text-red-600 hover:bg-red-50'
}`}
/>
</Tooltip>
</div>
</div>
</div> </div>
); );
}; };
@@ -224,6 +240,8 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
const [initialPhaseName, setInitialPhaseName] = useState<string>(project?.phase_label || ''); const [initialPhaseName, setInitialPhaseName] = useState<string>(project?.phase_label || '');
const [sorting, setSorting] = useState(false); const [sorting, setSorting] = useState(false);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [newPhaseName, setNewPhaseName] = useState('');
const [showAddForm, setShowAddForm] = useState(false);
const finalProjectId = projectId || currentProjectId; const finalProjectId = projectId || currentProjectId;
@@ -285,17 +303,28 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
} }
}, [finalProjectId, phaseList, dispatch, refreshTasks]); }, [finalProjectId, phaseList, dispatch, refreshTasks]);
const handleAddPhase = useCallback(async () => { const handleCreatePhase = useCallback(async () => {
if (!finalProjectId) return; if (!newPhaseName.trim() || !finalProjectId) return;
try { try {
await dispatch(addPhaseOption({ projectId: finalProjectId })); await dispatch(addPhaseOption({ projectId: finalProjectId }));
await dispatch(fetchPhasesByProjectId(finalProjectId)); await dispatch(fetchPhasesByProjectId(finalProjectId));
await refreshTasks(); await refreshTasks();
setNewPhaseName('');
setShowAddForm(false);
} catch (error) { } catch (error) {
console.error('Error adding phase:', error); console.error('Error adding phase:', error);
} }
}, [finalProjectId, dispatch, refreshTasks]); }, [finalProjectId, dispatch, refreshTasks, newPhaseName]);
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
handleCreatePhase();
} else if (e.key === 'Escape') {
setNewPhaseName('');
setShowAddForm(false);
}
}, [handleCreatePhase]);
const handleRenamePhase = useCallback(async (id: string, name: string) => { const handleRenamePhase = useCallback(async (id: string, name: string) => {
if (!finalProjectId) return; if (!finalProjectId) return;
@@ -326,8 +355,11 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
if (!finalProjectId) return; if (!finalProjectId) return;
AntModal.confirm({ AntModal.confirm({
title: 'Delete Phase', title: t('deletePhase'),
content: 'Are you sure you want to delete this phase? This action cannot be undone.', content: t('deletePhaseConfirm'),
okText: t('delete'),
cancelText: t('cancel'),
okButtonProps: { danger: true },
onOk: async () => { onOk: async () => {
try { try {
const response = await dispatch( const response = await dispatch(
@@ -343,7 +375,7 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
} }
}, },
}); });
}, [finalProjectId, dispatch, refreshTasks]); }, [finalProjectId, dispatch, refreshTasks, t]);
const handleColorChange = useCallback(async (id: string, color: string) => { const handleColorChange = useCallback(async (id: string, color: string) => {
if (!finalProjectId) return; if (!finalProjectId) return;
@@ -393,39 +425,52 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
return ( return (
<Modal <Modal
title={ title={
<Title level={4} className={isDarkMode ? 'text-gray-200' : 'text-gray-800'}> <Title level={4} className={`m-0 font-semibold ${
isDarkMode ? 'text-gray-100' : 'text-gray-800'
}`}>
{t('configurePhases')} {t('configurePhases')}
</Title> </Title>
} }
open={open} open={open}
onCancel={handleClose} onCancel={handleClose}
width={600} width={720}
style={{ top: 20 }} style={{ top: 20 }}
bodyStyle={{ styles={{
body: {
maxHeight: 'calc(100vh - 200px)', maxHeight: 'calc(100vh - 200px)',
overflowY: 'auto', overflowY: 'auto',
padding: '24px', padding: '16px',
},
}} }}
footer={ footer={
<Flex justify="flex-end"> <div className={`flex justify-end pt-3 ${
<Button onClick={handleClose}> isDarkMode ? 'border-gray-700' : 'border-gray-200'
Close }`}>
<Button
onClick={handleClose}
className={`font-medium ${
isDarkMode
? 'text-gray-300 hover:text-gray-200 border-gray-600'
: 'text-gray-600 hover:text-gray-800 border-gray-300'
}`}
>
{t('close')}
</Button> </Button>
</Flex> </div>
} }
className={isDarkMode ? 'dark-modal' : ''} className={`${isDarkMode ? 'dark-modal' : ''} phase-manage-modal`}
loading={loadingPhases || sorting} loading={loadingPhases || sorting}
> >
<div className="space-y-4"> <div className="space-y-4">
{/* Phase Label Configuration */} {/* Phase Label Configuration */}
<div className={`p-3 rounded-md border ${ <div className={`p-3 rounded border transition-all duration-200 ${
isDarkMode isDarkMode
? 'bg-gray-800/30 border-gray-700' ? 'bg-gray-800 border-gray-700 text-gray-300'
: 'bg-blue-50/50 border-blue-200' : 'bg-blue-50 border-blue-200 text-blue-700'
}`}> }`}>
<div className="space-y-2"> <div className="space-y-2">
<Text className={`text-xs font-medium ${ <Text className={`text-xs font-medium ${
isDarkMode ? 'text-gray-300' : 'text-gray-700' isDarkMode ? 'text-gray-300' : 'text-blue-700'
}`}> }`}>
{t('phaseLabel')} {t('phaseLabel')}
</Text> </Text>
@@ -441,47 +486,93 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
</div> </div>
</div> </div>
<Divider className={isDarkMode ? 'border-gray-700' : 'border-gray-300'} /> {/* Info Banner */}
<div className={`p-3 rounded border transition-all duration-200 ${
{/* Phase Options */} isDarkMode
<div className="space-y-4"> ? 'bg-gray-800 border-gray-700 text-gray-300'
<div className={`p-2.5 rounded-md ${ : 'bg-blue-50 border-blue-200 text-blue-700'
isDarkMode ? 'bg-gray-800/50' : 'bg-purple-50'
}`}> }`}>
<Text <Text className={`text-xs font-medium ${
type="secondary" isDarkMode ? 'text-gray-300' : 'text-blue-700'
className={`text-xs ${ }`}>
isDarkMode ? 'text-gray-400' : 'text-purple-600' 🎨 Drag phases to reorder them. Click on a phase name to rename it. Each phase can have a custom color.
}`}
>
🎨 Drag phases to reorder them. Each phase can have a custom color.
</Text> </Text>
</div> </div>
{/* Add New Phase */} {/* Add New Phase Form */}
<div className={`p-3 rounded-md border-2 border-dashed transition-colors ${ {showAddForm && (
<div className={`p-2 rounded border-2 border-dashed transition-all duration-200 ${
isDarkMode
? 'border-gray-600 bg-gray-700 hover:border-gray-500'
: 'border-gray-300 bg-white hover:border-gray-400'
} shadow-sm`}>
<div className="flex gap-2">
<Input
placeholder={t('enterNewPhaseName')}
value={newPhaseName}
onChange={(e) => setNewPhaseName(e.target.value)}
onKeyDown={handleKeyDown}
className={`flex-1 ${
isDarkMode
? 'bg-gray-600 border-gray-500 text-gray-100 placeholder-gray-400'
: 'bg-white border-gray-300 text-gray-900 placeholder-gray-500'
}`}
size="small"
autoFocus
/>
<Button
type="primary"
onClick={handleCreatePhase}
disabled={!newPhaseName.trim()}
size="small"
className="text-xs"
>
{t('create')}
</Button>
<Button
onClick={() => {
setNewPhaseName('');
setShowAddForm(false);
}}
size="small"
className={`text-xs ${
isDarkMode
? 'text-gray-300 hover:text-gray-200 border-gray-600'
: 'text-gray-600 hover:text-gray-800 border-gray-300'
}`}
>
{t('cancel')}
</Button>
</div>
</div>
)}
{/* Add Phase Button */}
{!showAddForm && (
<div className={`p-3 rounded border-2 border-dashed transition-colors ${
isDarkMode isDarkMode
? 'border-gray-600 bg-gray-800/50 hover:border-gray-500' ? 'border-gray-600 bg-gray-800/50 hover:border-gray-500'
: 'border-gray-300 bg-gray-50/50 hover:border-gray-400' : 'border-gray-300 bg-gray-50/50 hover:border-gray-400'
}`}> }`}>
<div className="flex gap-2"> <div className="flex items-center justify-between">
<Text className={`text-xs font-medium flex-shrink-0 self-center ${ <Text className={`text-xs font-medium ${
isDarkMode ? 'text-gray-300' : 'text-gray-700' isDarkMode ? 'text-gray-300' : 'text-gray-700'
}`}> }`}>
{t('phaseOptions')}: {t('phaseOptions')}
</Text> </Text>
<Button <Button
type="primary" type="primary"
icon={<PlusOutlined />} icon={<PlusOutlined />}
onClick={handleAddPhase} onClick={() => setShowAddForm(true)}
disabled={loadingPhases} disabled={loadingPhases}
size="small" size="small"
className="ml-auto" className="text-xs"
> >
{t('addOption')} {t('addOption')}
</Button> </Button>
</div> </div>
</div> </div>
)}
{/* Phase List with Drag & Drop */} {/* Phase List with Drag & Drop */}
<DndContext sensors={sensors} onDragEnd={handleDragEnd}> <DndContext sensors={sensors} onDragEnd={handleDragEnd}>
@@ -489,7 +580,7 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
items={phaseList.map(phase => phase.id)} items={phaseList.map(phase => phase.id)}
strategy={verticalListSortingStrategy} strategy={verticalListSortingStrategy}
> >
<div className="space-y-2"> <div className="space-y-1">
{phaseList.map((phase) => ( {phaseList.map((phase) => (
<SortablePhaseItem <SortablePhaseItem
key={phase.id} key={phase.id}
@@ -506,12 +597,28 @@ const ManagePhaseModal: React.FC<ManagePhaseModalProps> = ({
</DndContext> </DndContext>
{phaseList.length === 0 && ( {phaseList.length === 0 && (
<div className={`text-center py-8 ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}> <div className={`text-center py-8 transition-colors ${
<Text>No phases found. Add your first phase above.</Text> isDarkMode ? 'text-gray-400' : 'text-gray-500'
}`}>
<Text className="text-sm font-medium">
{t('noPhasesFound')}
</Text>
<br />
<Button
type="link"
size="small"
onClick={() => setShowAddForm(true)}
className={`text-xs mt-1 font-medium ${
isDarkMode
? 'text-blue-400 hover:text-blue-300'
: 'text-blue-600 hover:text-blue-700'
}`}
>
{t('addOption')}
</Button>
</div> </div>
)} )}
</div> </div>
</div>
</Modal> </Modal>
); );
}; };