mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
add: tasks func()
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
@@ -0,0 +1,403 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : AdminTaskContext.jsx
|
||||
* Type : Context / Provider
|
||||
* Description : Admin task management context.
|
||||
* Covers: task lists (list, get, create, update, archive, restore, bulk archive, bulk restore)
|
||||
* tasks (list, get, create, update, archive, restore, bulk archive, bulk restore)
|
||||
* task list groups (list assigned, assign, unassign)
|
||||
***********************************************************************************************************************************************************************/
|
||||
import { createContext, useCallback, useContext, useState } from 'react';
|
||||
import api from '@/utils/api.util';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const BASE = '/admin/task-lists';
|
||||
|
||||
// ─── Context ──────────────────────────────────────────────────────────────────
|
||||
const AdminTaskContext = createContext(null);
|
||||
|
||||
export function useAdminTask() {
|
||||
const ctx = useContext(AdminTaskContext);
|
||||
if (!ctx) throw new Error('useAdminTask must be used within an AdminTaskProvider');
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// ─── Provider ─────────────────────────────────────────────────────────────────
|
||||
export function AdminTaskProvider({ children }) {
|
||||
// ── Task List state ───────────────────────────────────────────────────────
|
||||
const [taskLists, setTaskLists] = useState([]);
|
||||
const [taskList, setTaskList] = useState(null);
|
||||
|
||||
// ── Task state ────────────────────────────────────────────────────────────
|
||||
const [tasks, setTasks] = useState([]);
|
||||
const [task, setTask] = useState(null);
|
||||
|
||||
// ── Task List Groups state ────────────────────────────────────────────────
|
||||
const [taskListGroups, setTaskListGroups] = useState([]);
|
||||
|
||||
// ── Shared ────────────────────────────────────────────────────────────────
|
||||
const [attributes, setAttributes] = useState([]);
|
||||
const [pagination, setPagination] = useState({ page: 1, limit: 10, totalRecords: 0, totalPages: 1 });
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// ─── Generic request wrapper ──────────────────────────────────────────────
|
||||
const request = useCallback(async (fn) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
return await fn();
|
||||
} catch (err) {
|
||||
const message = err?.response?.data?.message ?? 'Something went wrong.';
|
||||
toast.error(message);
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
// TASK LISTS
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// ─── GET ALL ──────────────────────────────────────────────────────────────
|
||||
const fetchTaskLists = useCallback(
|
||||
({ page = 1, limit = 10, filters = [], sort = [], archived = false } = {}) =>
|
||||
request(async () => {
|
||||
const res = await api.get(BASE, {
|
||||
params: {
|
||||
page,
|
||||
limit,
|
||||
filters: JSON.stringify(filters),
|
||||
sort: JSON.stringify(sort),
|
||||
archived: archived ? 'true' : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
|
||||
|
||||
setTaskLists(data ?? []);
|
||||
setAttributes(attrs ?? []);
|
||||
setPagination(pg ?? { page: 1, limit: 10, totalRecords: 0, totalPages: 1 });
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── GET ONE ──────────────────────────────────────────────────────────────
|
||||
// Response now includes a `groups` array on the task list object.
|
||||
const fetchTaskList = useCallback(
|
||||
(taskListId) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/${taskListId}`);
|
||||
const taskListData = res.data?.data ?? null;
|
||||
setTaskList(taskListData);
|
||||
// Sync the groups slice from the embedded payload so consumers
|
||||
// don't have to call fetchTaskListGroups separately after a getOne.
|
||||
if (taskListData?.groups) setTaskListGroups(taskListData.groups);
|
||||
return taskListData;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── GET ARCHIVED TASK LISTS ──────────────────────────────────────────────
|
||||
const fetchArchivedTaskLists = useCallback(
|
||||
({ page = 1, limit = 10, filters = [], sort = [] } = {}) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/archived`, {
|
||||
params: {
|
||||
page,
|
||||
limit,
|
||||
filters: JSON.stringify(filters),
|
||||
sort: JSON.stringify(sort),
|
||||
},
|
||||
});
|
||||
|
||||
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
|
||||
|
||||
setTaskLists(data ?? []);
|
||||
setAttributes(attrs ?? []);
|
||||
setPagination(pg ?? { page: 1, limit: 10, totalRecords: 0, totalPages: 1 });
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── GET ARCHIVED TASKS ───────────────────────────────────────────────────
|
||||
const fetchArchivedTasks = useCallback(
|
||||
(taskListId, { page = 1, limit = 10, filters = [], sort = [] } = {}) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/${taskListId}/tasks/archived`, {
|
||||
params: {
|
||||
page,
|
||||
limit,
|
||||
filters: JSON.stringify(filters),
|
||||
sort: JSON.stringify(sort),
|
||||
},
|
||||
});
|
||||
|
||||
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
|
||||
|
||||
setTasks(data ?? []);
|
||||
setAttributes(attrs ?? []);
|
||||
setPagination(pg ?? { page: 1, limit: 10, totalRecords: 0, totalPages: 1 });
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── CREATE ───────────────────────────────────────────────────────────────
|
||||
const createTaskList = useCallback(
|
||||
(payload) =>
|
||||
request(async () => {
|
||||
const res = await api.post(BASE, payload);
|
||||
toast.success('Task list created.');
|
||||
return res.data?.data ?? null;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── UPDATE ───────────────────────────────────────────────────────────────
|
||||
const updateTaskList = useCallback(
|
||||
(taskListId, payload) =>
|
||||
request(async () => {
|
||||
const res = await api.patch(`${BASE}/${taskListId}`, payload);
|
||||
toast.success('Task list updated.');
|
||||
return res.data?.data?.data ?? null;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── ARCHIVE ──────────────────────────────────────────────────────────────
|
||||
const archiveTaskList = useCallback(
|
||||
(taskListId) =>
|
||||
request(async () => {
|
||||
await api.delete(`${BASE}/${taskListId}`);
|
||||
toast.success('Task list archived.');
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── RESTORE ──────────────────────────────────────────────────────────────
|
||||
const restoreTaskList = useCallback(
|
||||
(taskListId) =>
|
||||
request(async () => {
|
||||
await api.patch(`${BASE}/${taskListId}/restore`);
|
||||
toast.success('Task list restored.');
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── BULK ARCHIVE ─────────────────────────────────────────────────────────
|
||||
const bulkArchiveTaskLists = useCallback(
|
||||
(ids) =>
|
||||
request(async () => {
|
||||
await api.post(`${BASE}/bulk-archive`, { ids });
|
||||
toast.success(`${ids.length} task list(s) archived.`);
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── BULK RESTORE ─────────────────────────────────────────────────────────
|
||||
const bulkRestoreTaskLists = useCallback(
|
||||
(ids) =>
|
||||
request(async () => {
|
||||
await api.post(`${BASE}/bulk-restore`, { ids });
|
||||
toast.success(`${ids.length} task list(s) restored.`);
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
// TASK LIST GROUPS
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// ─── GET ASSIGNED GROUPS ──────────────────────────────────────────────────
|
||||
// GET /admin/task-lists/:taskListId/groups
|
||||
const fetchTaskListGroups = useCallback(
|
||||
(taskListId) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/${taskListId}/groups`);
|
||||
const groups = res.data?.data ?? [];
|
||||
setTaskListGroups(groups);
|
||||
return groups;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── ASSIGN GROUPS ────────────────────────────────────────────────────────
|
||||
// POST /admin/task-lists/:taskListId/groups/assign
|
||||
// payload: { group_ids: number[] }
|
||||
//
|
||||
// Returns summary: { assigned_ids, already_assigned_ids, invalid_ids }
|
||||
const assignGroups = useCallback(
|
||||
(taskListId, groupIds) =>
|
||||
request(async () => {
|
||||
const res = await api.post(`${BASE}/${taskListId}/groups/assign`, {
|
||||
group_ids: groupIds,
|
||||
});
|
||||
const result = res.data?.data ?? {};
|
||||
if (result.assigned_ids?.length) {
|
||||
toast.success(`${result.assigned_ids.length} group(s) assigned.`);
|
||||
} else {
|
||||
toast.info('All selected groups were already assigned.');
|
||||
}
|
||||
return result;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── UNASSIGN GROUPS ──────────────────────────────────────────────────────
|
||||
// POST /admin/task-lists/:taskListId/groups/unassign
|
||||
// payload: { group_ids: number[] }
|
||||
//
|
||||
// Returns summary: { unassigned_ids, skipped_ids }
|
||||
const unassignGroups = useCallback(
|
||||
(taskListId, groupIds) =>
|
||||
request(async () => {
|
||||
const res = await api.post(`${BASE}/${taskListId}/groups/unassign`, {
|
||||
group_ids: groupIds,
|
||||
});
|
||||
const result = res.data?.data ?? {};
|
||||
toast.success(`${result.unassigned_ids?.length ?? 0} group(s) unassigned.`);
|
||||
return result;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
// TASKS
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// ─── GET ALL ──────────────────────────────────────────────────────────────
|
||||
const fetchTasks = useCallback(
|
||||
(taskListId, { page = 1, limit = 10, filters = [], sort = [], archived = false } = {}) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/${taskListId}/tasks`, {
|
||||
params: {
|
||||
page,
|
||||
limit,
|
||||
filters: JSON.stringify(filters),
|
||||
sort: JSON.stringify(sort),
|
||||
archived: archived ? 'true' : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
|
||||
|
||||
setTasks(data ?? []);
|
||||
setAttributes(attrs ?? []);
|
||||
setPagination(pg ?? { page: 1, limit: 10, totalRecords: 0, totalPages: 1 });
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── GET ONE ──────────────────────────────────────────────────────────────
|
||||
const fetchTask = useCallback(
|
||||
(taskListId, taskId) =>
|
||||
request(async () => {
|
||||
const res = await api.get(`${BASE}/${taskListId}/tasks/${taskId}`);
|
||||
const taskData = res.data?.data ?? null;
|
||||
|
||||
setTask(taskData);
|
||||
return taskData;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── CREATE ───────────────────────────────────────────────────────────────
|
||||
const createTask = useCallback(
|
||||
(taskListId, payload) =>
|
||||
request(async () => {
|
||||
const res = await api.post(`${BASE}/${taskListId}/tasks`, payload);
|
||||
toast.success('Task created.');
|
||||
return res.data?.data?.data ?? null;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── UPDATE ───────────────────────────────────────────────────────────────
|
||||
const updateTask = useCallback(
|
||||
(taskListId, taskId, payload) =>
|
||||
request(async () => {
|
||||
const res = await api.patch(`${BASE}/${taskListId}/tasks/${taskId}`, payload);
|
||||
toast.success('Task updated.');
|
||||
return res.data?.data?.data ?? null;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── ARCHIVE ──────────────────────────────────────────────────────────────
|
||||
const archiveTask = useCallback(
|
||||
(taskListId, taskId) =>
|
||||
request(async () => {
|
||||
await api.delete(`${BASE}/${taskListId}/tasks/${taskId}`);
|
||||
toast.success('Task archived.');
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── RESTORE ──────────────────────────────────────────────────────────────
|
||||
const restoreTask = useCallback(
|
||||
(taskListId, taskId) =>
|
||||
request(async () => {
|
||||
await api.patch(`${BASE}/${taskListId}/tasks/${taskId}/restore`);
|
||||
toast.success('Task restored.');
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── BULK ARCHIVE ─────────────────────────────────────────────────────────
|
||||
const bulkArchiveTasks = useCallback(
|
||||
(taskListId, ids) =>
|
||||
request(async () => {
|
||||
await api.post(`${BASE}/${taskListId}/tasks/bulk-archive`, { ids });
|
||||
toast.success(`${ids.length} task(s) archived.`);
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─── BULK RESTORE ─────────────────────────────────────────────────────────
|
||||
const bulkRestoreTasks = useCallback(
|
||||
(taskListId, ids) =>
|
||||
request(async () => {
|
||||
await api.post(`${BASE}/${taskListId}/tasks/bulk-restore`, { ids });
|
||||
toast.success(`${ids.length} task(s) restored.`);
|
||||
return true;
|
||||
}),
|
||||
[request]
|
||||
);
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
return (
|
||||
<AdminTaskContext.Provider value={{
|
||||
// state
|
||||
taskLists, taskList,
|
||||
tasks, task,
|
||||
taskListGroups, setTaskListGroups,
|
||||
attributes, setAttributes,
|
||||
pagination, setPagination,
|
||||
loading,
|
||||
|
||||
// task list actions
|
||||
fetchTaskLists, fetchTaskList, fetchArchivedTaskLists,
|
||||
createTaskList, updateTaskList,
|
||||
archiveTaskList, restoreTaskList,
|
||||
bulkArchiveTaskLists, bulkRestoreTaskLists,
|
||||
|
||||
// task list group actions
|
||||
fetchTaskListGroups,
|
||||
assignGroups,
|
||||
unassignGroups,
|
||||
|
||||
// task actions
|
||||
fetchTasks, fetchTask, fetchArchivedTasks,
|
||||
createTask, updateTask,
|
||||
archiveTask, restoreTask,
|
||||
bulkArchiveTasks, bulkRestoreTasks,
|
||||
}}>
|
||||
{children}
|
||||
</AdminTaskContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { AdminDashboardProvider } from "../AdminDashboardContext"
|
||||
import { UserProvider } from "../AdminUserContext";
|
||||
import { UserGroupProvider } from "../AdminUserGroupContext";
|
||||
import { CoursesProvider } from "../AdminCoursesContext";
|
||||
import { AdminTaskProvider } from "../AdminTaskContext";
|
||||
|
||||
export const AdminProvider = ({ children }) => {
|
||||
return (
|
||||
@@ -12,7 +13,9 @@ export const AdminProvider = ({ children }) => {
|
||||
<UserProvider>
|
||||
<UserGroupProvider>
|
||||
<CoursesProvider>
|
||||
{children}
|
||||
<AdminTaskProvider>
|
||||
{children}
|
||||
</AdminTaskProvider>
|
||||
</CoursesProvider>
|
||||
</UserGroupProvider>
|
||||
</UserProvider>
|
||||
|
||||
Reference in New Issue
Block a user