feat(components): introduce new UI components and enhance Vite configuration
- Added AssigneeSelector, Avatar, AvatarGroup, Button, Checkbox, CustomColordLabel, CustomNumberLabel, LabelsSelector, Progress, Tag, and Tooltip components for improved UI functionality. - Updated Vite configuration to change the development server port to 5173 and removed unnecessary interop settings for module compatibility. - Enhanced task management components to utilize new task structure and improve performance.
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { createSlice, createEntityAdapter, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice, createEntityAdapter, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { Task, TaskManagementState } from '@/types/task-management.types';
|
||||
import { RootState } from '@/app/store';
|
||||
import { tasksApiService, ITaskListConfigV2 } from '@/api/tasks/tasks.api.service';
|
||||
import logger from '@/utils/errorLogger';
|
||||
|
||||
// Entity adapter for normalized state
|
||||
const tasksAdapter = createEntityAdapter<Task>({
|
||||
selectId: (task) => task.id,
|
||||
sortComparer: (a, b) => a.order - b.order,
|
||||
});
|
||||
|
||||
@@ -15,6 +16,91 @@ const initialState: TaskManagementState = {
|
||||
error: null,
|
||||
};
|
||||
|
||||
// Async thunk to fetch tasks from API
|
||||
export const fetchTasks = createAsyncThunk(
|
||||
'taskManagement/fetchTasks',
|
||||
async (projectId: string, { rejectWithValue, getState }) => {
|
||||
try {
|
||||
const state = getState() as RootState;
|
||||
const currentGrouping = state.grouping.currentGrouping;
|
||||
|
||||
const config: ITaskListConfigV2 = {
|
||||
id: projectId,
|
||||
archived: false,
|
||||
group: currentGrouping,
|
||||
field: '',
|
||||
order: '',
|
||||
search: '',
|
||||
statuses: '',
|
||||
members: '',
|
||||
projects: '',
|
||||
isSubtasksInclude: false,
|
||||
labels: '',
|
||||
priorities: '',
|
||||
};
|
||||
|
||||
const response = await tasksApiService.getTaskList(config);
|
||||
|
||||
// Helper function to safely convert time values
|
||||
const convertTimeValue = (value: any): number => {
|
||||
if (typeof value === 'number') return value;
|
||||
if (typeof value === 'string') {
|
||||
const parsed = parseFloat(value);
|
||||
return isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
// Handle time objects like {hours: 2, minutes: 30}
|
||||
if ('hours' in value || 'minutes' in value) {
|
||||
const hours = Number(value.hours || 0);
|
||||
const minutes = Number(value.minutes || 0);
|
||||
return hours + (minutes / 60);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Transform the API response to our Task type
|
||||
const tasks: Task[] = response.body.flatMap((group: any) =>
|
||||
group.tasks.map((task: any) => ({
|
||||
id: task.id,
|
||||
task_key: task.task_key || '',
|
||||
title: task.name || '',
|
||||
description: task.description || '',
|
||||
status: task.status_name?.toLowerCase() || 'todo',
|
||||
priority: task.priority_name?.toLowerCase() || 'medium',
|
||||
phase: task.phase_name || 'Development',
|
||||
progress: typeof task.complete_ratio === 'number' ? task.complete_ratio : 0,
|
||||
assignees: task.assignees?.map((a: any) => a.team_member_id) || [],
|
||||
labels: task.labels?.map((l: any) => ({
|
||||
id: l.id || l.label_id,
|
||||
name: l.name,
|
||||
color: l.color_code || '#1890ff',
|
||||
end: l.end,
|
||||
names: l.names
|
||||
})) || [],
|
||||
dueDate: task.end_date,
|
||||
timeTracking: {
|
||||
estimated: convertTimeValue(task.total_time),
|
||||
logged: convertTimeValue(task.time_spent),
|
||||
},
|
||||
customFields: {},
|
||||
createdAt: task.created_at || new Date().toISOString(),
|
||||
updatedAt: task.updated_at || new Date().toISOString(),
|
||||
order: typeof task.sort_order === 'number' ? task.sort_order : 0,
|
||||
}))
|
||||
);
|
||||
|
||||
return tasks;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Tasks', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch tasks');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const taskManagementSlice = createSlice({
|
||||
name: 'taskManagement',
|
||||
initialState: tasksAdapter.getInitialState(initialState),
|
||||
@@ -99,6 +185,22 @@ const taskManagementSlice = createSlice({
|
||||
state.loading = false;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(fetchTasks.pending, (state) => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchTasks.fulfilled, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = null;
|
||||
tasksAdapter.setAll(state, action.payload);
|
||||
})
|
||||
.addCase(fetchTasks.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
|
||||
Reference in New Issue
Block a user