init
This commit is contained in:
113
worklenz-frontend/src/features/taskAttributes/taskLabelSlice.ts
Normal file
113
worklenz-frontend/src/features/taskAttributes/taskLabelSlice.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { ITaskLabel } from '@/types/tasks/taskLabel.types';
|
||||
import logger from '@utils/errorLogger';
|
||||
import { labelsApiService } from '@/api/taskAttributes/labels/labels.api.service';
|
||||
|
||||
interface ILabelState {
|
||||
labels: ITaskLabel[];
|
||||
selectedLabel: ITaskLabel | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
initialized: boolean;
|
||||
}
|
||||
|
||||
const initialState: ILabelState = {
|
||||
labels: [],
|
||||
selectedLabel: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
initialized: false,
|
||||
};
|
||||
|
||||
// Create async thunk for fetching labels
|
||||
export const fetchLabels = createAsyncThunk(
|
||||
'taskLabel/fetchLabels',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await labelsApiService.getLabels();
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Labels', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch labels');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Create async thunk for fetching labels by task
|
||||
export const fetchLabelsByTask = createAsyncThunk(
|
||||
'taskLabel/fetchLabelsByTask',
|
||||
async (taskId: string, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await labelsApiService.getPriorityByTask(taskId);
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Labels By Task', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch task labels');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Initialization thunk
|
||||
export const initializeLabels = createAsyncThunk(
|
||||
'taskLabel/initialize',
|
||||
async (_, { dispatch, getState }) => {
|
||||
const state = getState() as { taskLabelReducer: ILabelState };
|
||||
if (!state.taskLabelReducer.initialized) {
|
||||
await dispatch(fetchLabels());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const taskLabelSlice = createSlice({
|
||||
name: 'taskLabelReducer',
|
||||
initialState,
|
||||
reducers: {
|
||||
updateLabelColor: (state, action: PayloadAction<{ id: string; color: string }>) => {
|
||||
const label = state.labels.find(l => l.id === action.payload.id);
|
||||
if (label) {
|
||||
label.color_code = action.payload.color;
|
||||
}
|
||||
},
|
||||
deleteLabel: (state, action: PayloadAction<string>) => {
|
||||
state.labels = state.labels.filter(label => label.id !== action.payload);
|
||||
},
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(fetchLabels.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchLabels.fulfilled, (state, action: PayloadAction<ITaskLabel[]>) => {
|
||||
state.loading = false;
|
||||
state.labels = action.payload;
|
||||
state.initialized = true;
|
||||
})
|
||||
.addCase(fetchLabels.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
})
|
||||
// Fetch Labels By Task
|
||||
.addCase(fetchLabelsByTask.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchLabelsByTask.fulfilled, (state, action: PayloadAction<ITaskLabel[]>) => {
|
||||
state.loading = false;
|
||||
state.labels = action.payload;
|
||||
})
|
||||
.addCase(fetchLabelsByTask.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { updateLabelColor, deleteLabel } = taskLabelSlice.actions;
|
||||
export default taskLabelSlice.reducer;
|
||||
@@ -0,0 +1,85 @@
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
export interface ITeamMember {
|
||||
id?: string;
|
||||
name?: string;
|
||||
job_title_id?: string;
|
||||
is_owner?: boolean;
|
||||
user_id?: string;
|
||||
team_id?: string;
|
||||
pending_invitation?: boolean;
|
||||
role_id?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
export interface ITeamMemberViewModel extends ITeamMember {
|
||||
id?: string;
|
||||
active?: boolean;
|
||||
name?: string;
|
||||
taskCount?: number;
|
||||
job_title?: string;
|
||||
email?: string;
|
||||
task_count?: number;
|
||||
projects_count?: number;
|
||||
role_name?: string;
|
||||
tasks?: any[]; // ITask[] type would need to be imported
|
||||
is_admin?: boolean;
|
||||
show_handles?: boolean;
|
||||
is_online?: boolean;
|
||||
avatar_url?: string;
|
||||
selected?: boolean;
|
||||
color_code?: string;
|
||||
usage?: number;
|
||||
projects?: any;
|
||||
total_logged_time?: string;
|
||||
member_teams?: string[];
|
||||
is_pending?: boolean;
|
||||
}
|
||||
|
||||
interface TaskMemberState {
|
||||
assignees: ITeamMemberViewModel[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
const initialState: TaskMemberState = {
|
||||
assignees: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
export const fetchTaskAssignees = createAsyncThunk(
|
||||
'taskMember/fetchTaskAssignees',
|
||||
async (projectId: string) => {
|
||||
const response = await fetch(`/api/tasks/assignees/${projectId}`);
|
||||
const data = await response.json();
|
||||
return data.data;
|
||||
}
|
||||
);
|
||||
|
||||
const taskMemberSlice = createSlice({
|
||||
name: 'taskMember',
|
||||
initialState,
|
||||
reducers: {},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(fetchTaskAssignees.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(
|
||||
fetchTaskAssignees.fulfilled,
|
||||
(state, action: PayloadAction<ITeamMemberViewModel[]>) => {
|
||||
state.loading = false;
|
||||
state.assignees = action.payload;
|
||||
}
|
||||
)
|
||||
.addCase(fetchTaskAssignees.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.error.message || 'Failed to fetch assignees';
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default taskMemberSlice.reducer;
|
||||
@@ -0,0 +1,105 @@
|
||||
import { priorityApiService } from '@/api/taskAttributes/priority/priority.api.service';
|
||||
import { ITaskPrioritiesGetResponse, ITaskPriority } from '@/types/tasks/taskPriority.types';
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
|
||||
import logger from '@utils/errorLogger';
|
||||
|
||||
interface ITaskPriorityState {
|
||||
priorities: ITaskPrioritiesGetResponse[];
|
||||
selectedPriority: ITaskPriority | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
initialized: boolean;
|
||||
}
|
||||
|
||||
const initialState: ITaskPriorityState = {
|
||||
priorities: [],
|
||||
selectedPriority: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
initialized: false,
|
||||
};
|
||||
|
||||
// Create async thunk for fetching priorities
|
||||
export const fetchPriorities = createAsyncThunk(
|
||||
'taskPriority/fetchPriorities',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await priorityApiService.getPriorities();
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Priorities', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch priorities');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Create async thunk for fetching priority by ID
|
||||
export const fetchPriorityById = createAsyncThunk(
|
||||
'taskPriority/fetchPriorityById',
|
||||
async (priorityId: string, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await priorityApiService.getPriorityById(priorityId);
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Priority By Id', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch priority');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Initialization thunk
|
||||
export const initializePriorities = createAsyncThunk(
|
||||
'taskPriority/initialize',
|
||||
async (_, { dispatch, getState }) => {
|
||||
const state = getState() as { taskPriorityReducer: ITaskPriorityState };
|
||||
if (!state.taskPriorityReducer.initialized) {
|
||||
await dispatch(fetchPriorities());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const taskPrioritySlice = createSlice({
|
||||
name: 'taskPriorityReducer',
|
||||
initialState,
|
||||
reducers: {},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(fetchPriorities.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(
|
||||
fetchPriorities.fulfilled,
|
||||
(state, action: PayloadAction<ITaskPrioritiesGetResponse[]>) => {
|
||||
state.loading = false;
|
||||
state.priorities = action.payload;
|
||||
state.initialized = true;
|
||||
}
|
||||
)
|
||||
.addCase(fetchPriorities.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
})
|
||||
// Fetch Priority By Id
|
||||
.addCase(fetchPriorityById.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchPriorityById.fulfilled, (state, action: PayloadAction<ITaskPriority>) => {
|
||||
state.loading = false;
|
||||
state.selectedPriority = action.payload;
|
||||
})
|
||||
.addCase(fetchPriorityById.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default taskPrioritySlice.reducer;
|
||||
130
worklenz-frontend/src/features/taskAttributes/taskStatusSlice.ts
Normal file
130
worklenz-frontend/src/features/taskAttributes/taskStatusSlice.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { ICategorizedStatus, ITaskStatus } from '@/types/tasks/taskStatus.types';
|
||||
import logger from '@utils/errorLogger';
|
||||
import { statusApiService } from '@/api/taskAttributes/status/status.api.service';
|
||||
import { ITaskStatusCategory } from '@/types/status.types';
|
||||
import { ITaskStatusCreateRequest } from '@/types/tasks/task-status-create-request';
|
||||
|
||||
interface IStatusState {
|
||||
status: ITaskStatus[];
|
||||
statusCategories: ITaskStatusCategory[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
initialized: boolean;
|
||||
}
|
||||
|
||||
const initialState: IStatusState = {
|
||||
status: [],
|
||||
statusCategories: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
initialized: false,
|
||||
};
|
||||
|
||||
// Create async thunk for fetching statuses
|
||||
export const fetchStatuses = createAsyncThunk(
|
||||
'status/fetchStatuses',
|
||||
async (projectId: string, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await statusApiService.getStatuses(projectId);
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Statuses', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch statuses');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchStatusesCategories = createAsyncThunk(
|
||||
'status/fetchStatusesCategories',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await statusApiService.getStatusCategories();
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
logger.error('Fetch Statuses Categories', error);
|
||||
if (error instanceof Error) {
|
||||
return rejectWithValue(error.message);
|
||||
}
|
||||
return rejectWithValue('Failed to fetch statuses categories');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const createStatus = createAsyncThunk(
|
||||
'status/createStatus',
|
||||
async (
|
||||
{ body, currentProjectId }: { body: ITaskStatusCreateRequest; currentProjectId: string },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
return await statusApiService.createStatus(body, currentProjectId);
|
||||
}
|
||||
);
|
||||
|
||||
const taskStatusSlice = createSlice({
|
||||
name: 'taskStatusReducer',
|
||||
initialState,
|
||||
reducers: {
|
||||
addStatus: (state, action: PayloadAction<ITaskStatus>) => {
|
||||
state.status.push(action.payload);
|
||||
},
|
||||
updateStatus: (state, action: PayloadAction<ITaskStatus>) => {
|
||||
const index = state.status.findIndex(status => status.id === action.payload.id);
|
||||
if (index !== -1) {
|
||||
state.status[index] = action.payload;
|
||||
}
|
||||
},
|
||||
deleteStatus: (state, action: PayloadAction<string>) => {
|
||||
state.status = state.status.filter(status => status.id !== action.payload);
|
||||
},
|
||||
setCategorizedStatuses: (state, action: PayloadAction<ITaskStatusCategory[]>) => {
|
||||
state.statusCategories = action.payload;
|
||||
},
|
||||
resetStatuses: state => {
|
||||
state.status = [];
|
||||
state.loading = false;
|
||||
state.error = null;
|
||||
state.initialized = false;
|
||||
},
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(fetchStatuses.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchStatuses.fulfilled, (state, action: PayloadAction<ITaskStatus[]>) => {
|
||||
state.loading = false;
|
||||
state.status = action.payload;
|
||||
state.initialized = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(fetchStatuses.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
})
|
||||
.addCase(fetchStatusesCategories.pending, state => {
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(
|
||||
fetchStatusesCategories.fulfilled,
|
||||
(state, action: PayloadAction<ITaskStatusCategory[]>) => {
|
||||
state.loading = false;
|
||||
state.statusCategories = action.payload;
|
||||
state.error = null;
|
||||
}
|
||||
)
|
||||
.addCase(fetchStatusesCategories.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload as string;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { addStatus, updateStatus, deleteStatus, setCategorizedStatuses, resetStatuses } =
|
||||
taskStatusSlice.actions;
|
||||
export default taskStatusSlice.reducer;
|
||||
Reference in New Issue
Block a user