feat(localization): add new translation keys for task management

- Updated localization JSON files for Albanian, German, English, Spanish, Portuguese, and Chinese to include new keys for managing statuses and phases.
- Enhanced existing translations for clarity and consistency across multiple languages.
- Ensured that new keys align with recent UI changes to improve user experience in task management features.
This commit is contained in:
chamiakJ
2025-07-10 16:25:13 +05:30
parent f846230d59
commit 857b48e225
13 changed files with 78 additions and 21 deletions

View File

@@ -68,5 +68,7 @@
"clearing": "Duke pastruar...",
"cancel": "Anulo",
"search": "Kërko",
"groupedBy": "Grupuar sipas"
"groupedBy": "Grupuar sipas",
"manageStatuses": "Menaxho Statuset",
"managePhases": "Menaxho Fazat"
}

View File

@@ -65,8 +65,10 @@
"filtersActive": "Filter aktiv",
"filterActive": "Filter aktiv",
"clearAll": "Alle löschen",
"clearing": "Löschen...",
"cancel": "Abbrechen",
"clearing": "Wird gelöscht...",
"cancel": "Stornieren",
"search": "Suchen",
"groupedBy": "Gruppiert nach"
"groupedBy": "Gruppiert nach",
"manageStatuses": "Status verwalten",
"managePhases": "Phasen verwalten"
}

View File

@@ -68,5 +68,7 @@
"clearing": "Clearing...",
"cancel": "Cancel",
"search": "Search",
"groupedBy": "Grouped by"
"groupedBy": "Grouped by",
"manageStatuses": "Manage Statuses",
"managePhases": "Manage Phases"
}

View File

@@ -64,5 +64,7 @@
"clearing": "Limpiando...",
"cancel": "Cancelar",
"search": "Buscar",
"groupedBy": "Agrupado por"
"groupedBy": "Agrupado por",
"manageStatuses": "Gestionar Estados",
"managePhases": "Gestionar Fases"
}

View File

@@ -65,5 +65,7 @@
"clearing": "Limpando...",
"cancel": "Cancelar",
"search": "Pesquisar",
"groupedBy": "Agrupado por"
"groupedBy": "Agrupado por",
"manageStatuses": "Gerenciar Status",
"managePhases": "Gerenciar Fases"
}

View File

@@ -62,5 +62,7 @@
"clearing": "清除中...",
"cancel": "取消",
"search": "搜索",
"groupedBy": "分组依据"
"groupedBy": "分组依据",
"manageStatuses": "管理状态",
"managePhases": "管理阶段"
}

View File

@@ -14,7 +14,7 @@ import { toggleDrawer } from '@/features/projects/status/StatusSlice';
import './create-status-drawer.css';
import { createStatus, fetchStatusesCategories } from '@/features/taskAttributes/taskStatusSlice';
import { createStatus, fetchStatusesCategories, fetchStatuses } from '@/features/taskAttributes/taskStatusSlice';
import { ITaskStatusCategory } from '@/types/status.types';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
import useTabSearchParam from '@/hooks/useTabSearchParam';
@@ -56,6 +56,8 @@ const StatusDrawer: React.FC = () => {
dispatch(toggleDrawer());
refreshTasks();
dispatch(fetchStatusesCategories());
// Refetch task statuses to ensure UI reflects the new status
dispatch(fetchStatuses(projectId));
}
};

View File

@@ -476,8 +476,8 @@ const TaskListV2Section: React.FC = () => {
);
})}
</div>
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-sm italic text-gray-400 dark:text-gray-500 bg-white dark:bg-gray-900 px-4 py-1 rounded-md border border-gray-200 dark:border-gray-700">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2 flex items-center">
<div className="text-sm text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-900 px-3 py-1.5 rounded-md border border-gray-200 dark:border-gray-700 shadow-sm">
{t('noTasksInGroup')}
</div>
</div>

View File

@@ -18,16 +18,16 @@ export const BASE_COLUMNS = [
{ id: 'taskKey', label: 'keyColumn', width: '100px', key: COLUMN_KEYS.KEY, minWidth: '100px', maxWidth: '150px' },
{ id: 'title', label: 'taskColumn', width: '470px', isSticky: true, key: COLUMN_KEYS.NAME },
{ id: 'description', label: 'descriptionColumn', width: '260px', key: COLUMN_KEYS.DESCRIPTION },
{ id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS },
{ id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES },
{ id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY },
{ id: 'dueDate', label: 'dueDateColumn', width: '140px', key: COLUMN_KEYS.DUE_DATE },
{ id: 'progress', label: 'progressColumn', width: '120px', key: COLUMN_KEYS.PROGRESS },
{ id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES },
{ id: 'labels', label: 'labelsColumn', width: 'auto', key: COLUMN_KEYS.LABELS },
{ id: 'phase', label: 'phaseColumn', width: '120px', key: COLUMN_KEYS.PHASE },
{ id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS },
{ id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY },
{ id: 'timeTracking', label: 'timeTrackingColumn', width: '120px', key: COLUMN_KEYS.TIME_TRACKING },
{ id: 'estimation', label: 'estimationColumn', width: '120px', key: COLUMN_KEYS.ESTIMATION },
{ id: 'startDate', label: 'startDateColumn', width: '140px', key: COLUMN_KEYS.START_DATE },
{ id: 'dueDate', label: 'dueDateColumn', width: '140px', key: COLUMN_KEYS.DUE_DATE },
{ id: 'dueTime', label: 'dueTimeColumn', width: '120px', key: COLUMN_KEYS.DUE_TIME },
{ id: 'completedDate', label: 'completedDateColumn', width: '140px', key: COLUMN_KEYS.COMPLETED_DATE },
{ id: 'createdDate', label: 'createdDateColumn', width: '140px', key: COLUMN_KEYS.CREATED_DATE },

View File

@@ -82,7 +82,9 @@ import useIsProjectManager from '@/hooks/useIsProjectManager';
// Performance constants
const FILTER_DEBOUNCE_DELAY = 300; // ms
const SEARCH_DEBOUNCE_DELAY = 500; // ms
const MAX_FILTER_OPTIONS = 100; // Limit options to prevent UI lag
const MAX_FILTER_OPTIONS = 100;
// Limit options to prevent UI lag
// Optimized selectors with proper transformation logic
const selectFilterData = createSelector(
@@ -364,6 +366,7 @@ const FilterDropdown: React.FC<{
themeClasses: any;
isDarkMode: boolean;
className?: string;
dispatch?: any;
}> = ({
section,
onSelectionChange,
@@ -372,6 +375,7 @@ const FilterDropdown: React.FC<{
themeClasses,
isDarkMode,
className = '',
dispatch,
}) => {
const { t } = useTranslation('task-list-filters');
// Add permission checks for groupBy section
@@ -480,8 +484,34 @@ const FilterDropdown: React.FC<{
{/* Configuration Buttons for GroupBy section */}
{section.id === 'groupBy' && canConfigure && (
<div className="inline-flex items-center gap-1 ml-2">
{section.selectedValues[0] === 'phase' && <ConfigPhaseButton />}
{section.selectedValues[0] === 'status' && <CreateStatusButton />}
{section.selectedValues[0] === 'phase' && (
<button
onClick={() => {
import('@/features/projects/singleProject/phase/phases.slice').then(({ toggleDrawer }) => {
dispatch(toggleDrawer());
});
}}
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 ease-in-out hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${
isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'
}`}
>
{t('managePhases')}
</button>
)}
{section.selectedValues[0] === 'status' && (
<button
onClick={() => {
import('@/features/projects/status/StatusSlice').then(({ toggleDrawer }) => {
dispatch(toggleDrawer());
});
}}
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 ease-in-out hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${
isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'
}`}
>
{t('manageStatuses')}
</button>
)}
</div>
)}
@@ -1265,6 +1295,7 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
onToggle={() => handleDropdownToggle(section.id)}
themeClasses={themeClasses}
isDarkMode={isDarkMode}
dispatch={dispatch}
/>
))
) : (

View File

@@ -23,6 +23,7 @@ import { fetchBoardTaskGroups } from '@/features/board/board-slice';
import { setImportTaskTemplateDrawerOpen } from '@/features/project/project.slice';
import useTabSearchParam from '@/hooks/useTabSearchParam';
import { fetchTaskGroups } from '@/features/tasks/tasks.slice';
import { fetchTasksV3 } from '@/features/task-management/task-management.slice';
const ImportTaskTemplate = () => {
const dispatch = useAppDispatch();
@@ -90,7 +91,8 @@ const ImportTaskTemplate = () => {
const res = await taskTemplatesApiService.importTemplate(projectId, tasks);
if (res.done) {
if (tab === 'board') dispatch(fetchBoardTaskGroups(projectId));
if (tab === 'tasks-list') dispatch(fetchTaskGroups(projectId));
if (tab === 'tasks-list') dispatch(fetchTasksV3(projectId));
dispatch(setImportTaskTemplateDrawerOpen(false));
}
} catch (error) {

View File

@@ -4,6 +4,7 @@ import { useAppSelector } from '@/hooks/useAppSelector';
import { fetchPriorities } from '@/features/taskAttributes/taskPrioritySlice';
import { fetchLabelsByProject, fetchTaskAssignees } from '@/features/tasks/tasks.slice';
import { getTeamMembers } from '@/features/team-members/team-members.slice';
import { fetchStatuses } from '@/features/taskAttributes/taskStatusSlice';
/**
* Hook to manage filter data loading independently of main task list loading
@@ -15,6 +16,9 @@ export const useFilterDataLoader = () => {
// Memoize the priorities selector to prevent unnecessary re-renders
const priorities = useAppSelector(state => state.priorityReducer.priorities);
// Memoize the statuses selector to prevent unnecessary re-renders
const statuses = useAppSelector(state => state.taskStatusReducer.status);
// Memoize the projectId selector to prevent unnecessary re-renders
const projectId = useAppSelector(state => state.projectReducer.projectId);
@@ -32,6 +36,11 @@ export const useFilterDataLoader = () => {
// They will update the UI when ready, but won't block initial render
dispatch(fetchLabelsByProject(projectId));
dispatch(fetchTaskAssignees(projectId));
// Load statuses if not already loaded
if (!statuses.length) {
dispatch(fetchStatuses(projectId));
}
}
// Load team members for member filters
@@ -49,7 +58,7 @@ export const useFilterDataLoader = () => {
console.error('Error loading filter data:', error);
// Don't throw - filter loading errors shouldn't break the main UI
}
}, [dispatch, priorities.length, projectId]);
}, [dispatch, priorities.length, statuses.length, projectId]);
// Load filter data on mount and when dependencies change
useEffect(() => {

View File

@@ -66,6 +66,7 @@ import { fetchPhasesByProjectId } from '@/features/projects/singleProject/phase/
import { fetchEnhancedKanbanGroups } from '@/features/enhanced-kanban/enhanced-kanban.slice';
import { fetchTasksV3 } from '@/features/task-management/task-management.slice';
import { ShareAltOutlined } from '@ant-design/icons';
import { fetchStatuses } from '@/features/taskAttributes/taskStatusSlice';
const ProjectViewHeader = memo(() => {
const navigate = useNavigate();
@@ -101,9 +102,9 @@ const ProjectViewHeader = memo(() => {
switch (tab) {
case 'tasks-list':
dispatch(fetchStatuses(projectId));
dispatch(fetchTaskListColumns(projectId));
dispatch(fetchPhasesByProjectId(projectId));
dispatch(fetchTaskGroups(projectId));
dispatch(fetchTasksV3(projectId));
break;
case 'board':