Files
starr-philproperties/src/contexts/AdminUserGroupContext.jsx
T
kennethobsequio 244aa607f7 add: more things
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
2026-07-06 15:21:36 +08:00

333 lines
12 KiB
React

import { createContext, useCallback, useContext, useState } from "react";
import api from "@/utils/api.util";
import { toast } from "sonner";
const BASE = "/admin";
const UserGroupContext = createContext(null);
export function useUserGroups() {
const ctx = useContext(UserGroupContext);
if (!ctx) throw new Error("useUserGroups must be used within a UserGroupProvider");
return ctx;
}
export function UserGroupProvider({ children }) {
const [groups, setGroups] = useState([]);
const [group, setGroup] = useState(null);
const [members, setMembers] = useState([]);
const [usersIn, setUsersIn] = useState([]);
const [usersNotIn, setUsersNotIn] = useState([]);
const [attributes, setAttributes] = useState([]);
const [pagination, setPagination] = useState({ page: 1, limit: 10, total: 0, totalPages: 1 });
const [loading, setLoading] = useState(false);
const request = useCallback(async (fn) => {
setLoading(true);
try {
return await fn();
} catch (err) {
const message = err?.response?.data?.message ?? "Something went wrong.";
toast(message, {
action: {
label: "Close",
onClick: () => {}
}
});
return null;
} finally {
setLoading(false);
}
}, []);
// ─── GET /api/admin/groups ─────────────────────────────────────────────────
const fetchGroups = useCallback(
({ page = 1, limit = 10, filters = [], sort = [] } = {}) =>
request(async () => {
const res = await api.get(`${BASE}/groups`, {
params: { page, limit, filters: JSON.stringify(filters), sort: JSON.stringify(sort) },
});
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
setGroups(data ?? []);
setAttributes(attrs ?? []);
setPagination(pg ?? { page, limit, total: 0, totalPages: 1 });
return res.data;
}),
[request]
);
// ─── GET /api/admin/groups/archived ───────────────────────────────────────
const fetchArchivedGroups = useCallback(
({ page = 1, limit = 10, filters = [], sort = [] } = {}) =>
request(async () => {
const res = await api.get(`${BASE}/groups/archived`, {
params: { page, limit, filters: JSON.stringify(filters), sort: JSON.stringify(sort) },
});
const { data, attributes: attrs, pagination: pg } = res.data?.data ?? {};
setGroups(data ?? []);
setAttributes(attrs ?? []);
setPagination(pg ?? { page, limit, total: 0, totalPages: 1 });
return res.data;
}),
[request]
);
// ─── GET /api/admin/groups/:gid ───────────────────────────────────────────
const fetchGroup = useCallback(
(gid, paginationParams = {}) =>
request(async () => {
const { page = 1, limit = 10, filters = [], sort = [] } = paginationParams;
const res = await api.get(`${BASE}/groups/${gid}`, {
params: { page, limit, filters: JSON.stringify(filters), sort: JSON.stringify(sort) },
});
const { group: g, members: m } = res.data?.data ?? {};
setGroup(g ?? null);
setMembers(m?.data ?? []);
setPagination(m?.pagination ?? { page, limit, total: 0, totalPages: 1 });
return res.data;
}),
[request]
);
// ─── GET /api/admin/groups/:gid/users ─────────────────────────────────────
const fetchUsersInGroup = useCallback(
(gid) =>
request(async () => {
const res = await api.get(`${BASE}/groups/${gid}/users`);
setUsersIn(res.data?.data ?? []);
return res.data;
}),
[request]
);
// ─── GET /api/admin/groups/:gid/users/add ─────────────────────────────────
const fetchUsersNotInGroup = useCallback(
(gid) =>
request(async () => {
const res = await api.get(`${BASE}/groups/${gid}/users/add`);
setUsersNotIn(res.data?.data ?? []);
return res.data;
}),
[request]
);
// ─── GET /api/admin/groups/field-values ───────────────────────────────────
const fetchGroupFieldValues = useCallback(
(field) =>
request(async () => {
const res = await api.get(`${BASE}/groups/field-values`, { params: { field } });
return res.data;
}),
[request]
);
// ─── POST /api/admin/groups ────────────────────────────────────────────────
const createGroup = useCallback(
({ name, description, group_code }) =>
request(async () => {
const res = await api.post(`${BASE}/groups`, { name, description, group_code });
setGroups((prev) => [res.data?.data, ...prev]);
toast("Group created successfully.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── PUT /api/admin/groups/:gid ───────────────────────────────────────────
const updateGroup = useCallback(
(gid, { name, description, group_code }) =>
request(async () => {
const res = await api.put(`${BASE}/groups/${gid}`, { name, description, group_code });
setGroups((prev) =>
prev.map((g) => (g.group_id === gid ? { ...g, ...res.data?.data } : g))
);
setGroup((prev) => (prev?.group_id === gid ? { ...prev, ...res.data?.data } : prev));
toast("Group updated successfully.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── PATCH /api/admin/groups/:gid/deactivate ──────────────────────────────
const deactivateGroup = useCallback(
(gid) =>
request(async () => {
const res = await api.patch(`${BASE}/groups/${gid}/deactivate`);
setGroups((prev) =>
prev.map((g) => (g.group_id === gid ? { ...g, is_active: false } : g))
);
toast("Group deactivated.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/groups/bulk ────────────────────────────────────────
const deactivateGroups = useCallback(
({ ids }) =>
request(async () => {
const res = await api.delete(`${BASE}/groups/bulk`, { data: { ids } });
const { deactivated_ids } = res.data?.data ?? {};
if (deactivated_ids?.length) {
setGroups((prev) =>
prev.map((g) =>
deactivated_ids.includes(g.group_id) ? { ...g, is_active: false } : g
)
);
toast(`${deactivated_ids.length} group(s) deactivated.`, {
action: {
label: "Close",
onClick: () => {}
}
});
}
return res.data;
}),
[request]
);
// ─── PATCH /api/admin/groups/:gid/restore ─────────────────────────────────
const restoreGroup = useCallback(
(gid) =>
request(async () => {
const res = await api.patch(`${BASE}/groups/${gid}/restore`);
setGroups((prev) =>
prev.map((g) => (g.group_id === gid ? { ...g, is_active: true } : g))
);
toast("Group restored.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── POST /api/admin/groups/bulk/restore ──────────────────────────────────
const restoreGroups = useCallback(
({ ids }) =>
request(async () => {
const res = await api.post(`${BASE}/groups/bulk/restore`, { ids });
const { restored_ids } = res.data?.data ?? {};
if (restored_ids?.length) {
setGroups((prev) =>
prev.map((g) =>
restored_ids.includes(g.group_id) ? { ...g, is_active: true } : g
)
);
toast(`${restored_ids.length} group(s) restored.`, {
action: {
label: "Close",
onClick: () => {}
}
});
}
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/groups/:gid/permanent ──────────────────────────────
const permanentlyDeleteGroup = useCallback(
(gid) =>
request(async () => {
const res = await api.delete(`${BASE}/groups/${gid}/permanent`);
setGroups((prev) => prev.filter((g) => g.group_id !== gid));
toast("Group permanently deleted.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/groups/bulk/permanent ──────────────────────────────
const permanentlyDeleteGroups = useCallback(
({ ids }) =>
request(async () => {
const res = await api.delete(`${BASE}/groups/bulk/permanent`, { data: { ids } });
const { deleted_ids } = res.data?.data ?? {};
if (deleted_ids?.length) {
setGroups((prev) => prev.filter((g) => !deleted_ids.includes(g.group_id)));
toast(`${deleted_ids.length} group(s) permanently deleted.`, {
action: {
label: "Close",
onClick: () => {}
}
});
}
return res.data;
}),
[request]
);
// ─── POST /api/admin/groups/:gid/users ────────────────────────────────────
const addUsersToGroup = useCallback(
(gid, user_ids) =>
request(async () => {
const res = await api.post(`${BASE}/groups/${gid}/users`, { user_ids });
setUsersNotIn((prev) => prev.filter((u) => !user_ids.includes(u.user_id)));
toast("Users added to group.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/groups/:gid/users ──────────────────────────────────
const removeUsersFromGroup = useCallback(
(gid, user_ids) =>
request(async () => {
const res = await api.delete(`${BASE}/groups/${gid}/users`, { data: { user_ids } });
setMembers((prev) => prev.filter((u) => !user_ids.includes(u.user_id)));
setUsersIn((prev) => prev.filter((u) => !user_ids.includes(u.user_id)));
toast("Users removed from group.", {
action: {
label: "Close",
onClick: () => {}
}
});
return res.data;
}),
[request]
);
return (
<UserGroupContext.Provider value={{
groups, group, members, usersIn, usersNotIn, attributes, pagination, loading,
setPagination,
fetchGroups, fetchArchivedGroups, fetchGroup,
fetchUsersInGroup, fetchUsersNotInGroup, fetchGroupFieldValues,
createGroup, updateGroup,
deactivateGroup, deactivateGroups,
restoreGroup, restoreGroups,
permanentlyDeleteGroup, permanentlyDeleteGroups,
addUsersToGroup, removeUsersFromGroup,
}}>
{children}
</UserGroupContext.Provider>
);
}