This commit is contained in:
chamikaJ
2025-04-17 18:28:54 +05:30
parent f583291d8a
commit 8825b0410a
2837 changed files with 241385 additions and 127578 deletions

View File

@@ -0,0 +1,63 @@
import { projectsApiService } from '@/api/projects/projects.api.service';
import { IProjectViewModel } from '@/types/project/projectViewModel.types';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
interface IProjectDrawerState {
isProjectDrawerOpen: boolean;
projectId: string | null;
projectLoading: boolean;
project: IProjectViewModel | null;
}
const initialState: IProjectDrawerState = {
isProjectDrawerOpen: false,
projectId: null,
projectLoading: false,
project: null,
};
export const fetchProjectData = createAsyncThunk(
'project/fetchProjectData',
async (projectId: string, { rejectWithValue, dispatch }) => {
try {
const response = await projectsApiService.getProject(projectId);
return response.body;
} catch (error) {
return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch project');
}
}
);
const projectDrawerSlice = createSlice({
name: 'projectDrawer',
initialState,
reducers: {
toggleProjectDrawer: state => {
state.isProjectDrawerOpen = !state.isProjectDrawerOpen;
},
setProjectId: (state, action) => {
state.projectId = action.payload;
},
setProjectData: (state, action) => {
state.project = action.payload;
},
},
extraReducers: builder => {
builder
.addCase(fetchProjectData.pending, state => {
state.projectLoading = true;
})
.addCase(fetchProjectData.fulfilled, (state, action) => {
state.project = action.payload;
state.projectLoading = false;
})
.addCase(fetchProjectData.rejected, state => {
state.projectLoading = false;
});
},
});
export const { toggleProjectDrawer, setProjectId, setProjectData } = projectDrawerSlice.actions;
export default projectDrawerSlice.reducer;

View File

@@ -0,0 +1,221 @@
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
import { ITaskListColumn, ITaskListGroup } from '@/types/tasks/taskList.types';
import { ITeamMemberViewModel } from '@/types/teamMembers/teamMembersGetResponse.types';
import { ITaskLabel } from '@/types/tasks/taskLabel.types';
import { ITaskPrioritiesGetResponse } from '@/types/apiModels/taskPrioritiesGetResponse.types';
import { ITaskStatusViewModel } from '@/types/tasks/taskStatusGetResponse.types';
import { ITaskPhase } from '@/types/tasks/taskPhase.types';
import { IProjectViewModel } from '@/types/project/projectViewModel.types';
import { projectsApiService } from '@/api/projects/projects.api.service';
interface TaskListState {
projectId: string | null;
project: IProjectViewModel | null;
projectLoading: boolean;
columns: ITaskListColumn[];
members: ITeamMemberViewModel[];
activeMembers: [];
labels: ITaskLabel[];
statuses: ITaskStatusViewModel[];
priorities: ITaskPrioritiesGetResponse[];
phases: ITaskPhase[];
groups: ITaskListGroup[];
isSubtasksIncluded: boolean;
selectedTasks: IProjectTask[];
isLoading: boolean;
error: string | null;
importTaskTemplateDrawerOpen: boolean;
createTaskTemplateDrawerOpen: boolean;
projectView: 'list' | 'kanban';
refreshTimestamp: string | null;
}
const initialState: TaskListState = {
projectId: null,
project: null,
projectLoading: false,
activeMembers: [],
columns: [],
members: [],
labels: [],
statuses: [],
priorities: [],
phases: [],
groups: [],
isSubtasksIncluded: false,
selectedTasks: [],
isLoading: false,
error: null,
importTaskTemplateDrawerOpen: false,
createTaskTemplateDrawerOpen: false,
projectView: 'list',
refreshTimestamp: null,
};
export const getProject = createAsyncThunk(
'project/getProject',
async (projectId: string, { rejectWithValue, dispatch }) => {
try {
const response = await projectsApiService.getProject(projectId);
dispatch(setProject(response.body));
return response.body;
} catch (error) {
return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch project');
}
}
);
const projectSlice = createSlice({
name: 'project',
initialState,
reducers: {
setProjectId: (state, action: PayloadAction<string | null>) => {
state.projectId = action.payload;
},
setProject: (state, action: PayloadAction<IProjectViewModel>) => {
state.project = action.payload;
},
setColumns: (state, action: PayloadAction<ITaskListColumn[]>) => {
state.columns = action.payload;
},
setMembers: (state, action: PayloadAction<ITeamMemberViewModel[]>) => {
state.members = action.payload;
},
setLabels: (state, action: PayloadAction<ITaskLabel[]>) => {
state.labels = action.payload;
},
setStatuses: (state, action: PayloadAction<ITaskStatusViewModel[]>) => {
state.statuses = action.payload;
},
setPriorities: (state, action: PayloadAction<ITaskPrioritiesGetResponse[]>) => {
state.priorities = action.payload;
},
setPhases: (state, action: PayloadAction<ITaskPhase[]>) => {
state.phases = action.payload;
},
setGroups: (state, action: PayloadAction<ITaskListGroup[]>) => {
state.groups = action.payload;
},
setSubtasksIncluded: (state, action: PayloadAction<boolean>) => {
state.isSubtasksIncluded = action.payload;
},
setSelectedTasks: (state, action: PayloadAction<IProjectTask[]>) => {
state.selectedTasks = action.payload;
},
setActiveMembers: (state, action: PayloadAction<[]>) => {
state.activeMembers = action.payload;
},
setImportTaskTemplateDrawerOpen: (state, action: PayloadAction<boolean>) => {
state.importTaskTemplateDrawerOpen = action.payload;
},
setCreateTaskTemplateDrawerOpen: (state, action: PayloadAction<boolean>) => {
state.createTaskTemplateDrawerOpen = action.payload;
},
updatePhaseLabel: (state, action: PayloadAction<string>) => {
if (state.project) {
state.project.phase_label = action.payload;
}
},
addTask: (
state,
action: PayloadAction<{ task: IProjectTask; groupId: string; insert?: boolean }>
) => {
const { task, groupId, insert = false } = action.payload;
const group = state.groups.find(g => g.id === groupId);
if (!group || !task.id) return;
if (task.parent_task_id) {
const parentTask = group.tasks.find(t => t.id === task.parent_task_id);
if (parentTask) {
parentTask.sub_tasks_count = (parentTask.sub_tasks_count || 0) + 1;
if (!parentTask.sub_tasks) parentTask.sub_tasks = [];
parentTask.sub_tasks.push(task);
// Add subtask to the main tasks array if subtasks are included
if (state.isSubtasksIncluded) {
const parentIndex = group.tasks.indexOf(parentTask);
if (parentIndex !== -1) {
group.tasks.splice(parentIndex + 1, 0, task);
}
}
}
} else {
insert ? group.tasks.unshift(task) : group.tasks.push(task);
}
console.log('addTask', group.tasks);
},
deleteTask: (state, action: PayloadAction<{ taskId: string; index?: number }>) => {
const { taskId, index } = action.payload;
for (const group of state.groups) {
const taskIndex = index ?? group.tasks.findIndex(t => t.id === taskId);
if (taskIndex === -1) continue;
const task = group.tasks[taskIndex];
if (task.is_sub_task) {
const parentTask = group.tasks.find(t => t.id === task.parent_task_id);
if (parentTask?.sub_tasks) {
const subTaskIndex = parentTask.sub_tasks.findIndex(t => t.id === task.id);
if (subTaskIndex !== -1) {
parentTask.sub_tasks_count = Math.max((parentTask.sub_tasks_count || 0) - 1, 0);
parentTask.sub_tasks.splice(subTaskIndex, 1);
}
}
} else {
group.tasks.splice(taskIndex, 1);
}
break;
}
},
reset: () => initialState,
setRefreshTimestamp: (state) => {
state.refreshTimestamp = new Date().getTime().toString();
},
setProjectView: (state, action: PayloadAction<'list' | 'kanban'>) => {
state.projectView = action.payload;
},
},
extraReducers: builder => {
builder
.addCase(getProject.pending, state => {
state.projectLoading = true;
state.error = null;
})
.addCase(getProject.fulfilled, (state, action) => {
state.projectLoading = false;
state.project = action.payload;
})
.addCase(getProject.rejected, (state, action) => {
state.projectLoading = false;
state.error = action.payload as string;
});
},
});
export const {
setProjectId,
setProject,
setColumns,
setMembers,
setLabels,
setStatuses,
setPriorities,
setPhases,
setGroups,
setSubtasksIncluded,
setSelectedTasks,
setActiveMembers,
addTask,
deleteTask,
reset,
setImportTaskTemplateDrawerOpen,
setCreateTaskTemplateDrawerOpen,
setProjectView,
updatePhaseLabel,
setRefreshTimestamp
} = projectSlice.actions;
export default projectSlice.reducer;