mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
AdjusteD
This commit is contained in:
@@ -54,6 +54,7 @@ export default function DataTable({
|
|||||||
onRefsReady?.({
|
onRefsReady?.({
|
||||||
getFilters: () => filtersRef.current,
|
getFilters: () => filtersRef.current,
|
||||||
getSort: () => sortRef.current,
|
getSort: () => sortRef.current,
|
||||||
|
resetSelection: () => table.resetRowSelection(), // ← expose this
|
||||||
});
|
});
|
||||||
|
|
||||||
onFetch({ page: 1, limit: pagination.limit, filters: [], sort: [] });
|
onFetch({ page: 1, limit: pagination.limit, filters: [], sort: [] });
|
||||||
|
|||||||
@@ -97,21 +97,6 @@ export const UserProvider = ({ children }) => {
|
|||||||
[request]
|
[request]
|
||||||
);
|
);
|
||||||
|
|
||||||
// ─── DELETE /api/admin/users/:id (soft delete) ────────────────────────────
|
|
||||||
const deactivateUser = useCallback(
|
|
||||||
(userId) =>
|
|
||||||
request(async () => {
|
|
||||||
const res = await api.delete(`${BASE}/users/${userId}`);
|
|
||||||
|
|
||||||
setUsers((prev) =>
|
|
||||||
prev.map((u) => (u.user_id === userId ? { ...u, is_active: false } : u))
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
}),
|
|
||||||
[request]
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── GET /api/admin/users/archived ────────────────────────────────────────────
|
// ─── GET /api/admin/users/archived ────────────────────────────────────────────
|
||||||
const fetchArchivedUsers = useCallback(
|
const fetchArchivedUsers = useCallback(
|
||||||
({ page = 1, limit = 10, filters = [], sort = [] } = {}) =>
|
({ page = 1, limit = 10, filters = [], sort = [] } = {}) =>
|
||||||
@@ -135,6 +120,44 @@ export const UserProvider = ({ children }) => {
|
|||||||
[request]
|
[request]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ─── DELETE /api/admin/users/:id (soft delete) ────────────────────────────
|
||||||
|
const deactivateUser = useCallback(
|
||||||
|
(userId) =>
|
||||||
|
request(async () => {
|
||||||
|
const res = await api.delete(`${BASE}/users/${userId}`);
|
||||||
|
|
||||||
|
setUsers((prev) =>
|
||||||
|
prev.map((u) => (u.user_id === userId ? { ...u, is_active: false } : u))
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
}),
|
||||||
|
[request]
|
||||||
|
);
|
||||||
|
|
||||||
|
// ─── DELETE /api/admin/users/bulk ─────────────────────────────────────────────
|
||||||
|
const deactivateUsers = useCallback(
|
||||||
|
({ ids }) =>
|
||||||
|
request(async () => {
|
||||||
|
const res = await api.delete(`${BASE}/users/bulk`, { data: { ids } });
|
||||||
|
|
||||||
|
const { deactivated_ids } = res.data?.data ?? {}; // ← unwrap nested data
|
||||||
|
|
||||||
|
if (deactivated_ids?.length) {
|
||||||
|
setUsers((prev) =>
|
||||||
|
prev.map((u) =>
|
||||||
|
deactivated_ids.includes(u.user_id)
|
||||||
|
? { ...u, is_active: false }
|
||||||
|
: u
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
}),
|
||||||
|
[request]
|
||||||
|
);
|
||||||
|
|
||||||
// ─── POST /api/admin/users/:id/restore ────────────────────────────────────
|
// ─── POST /api/admin/users/:id/restore ────────────────────────────────────
|
||||||
const restoreUser = useCallback(
|
const restoreUser = useCallback(
|
||||||
(userId) =>
|
(userId) =>
|
||||||
@@ -150,6 +173,28 @@ export const UserProvider = ({ children }) => {
|
|||||||
[request]
|
[request]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const restoreUsers = useCallback(
|
||||||
|
({ ids }) =>
|
||||||
|
request(async () => {
|
||||||
|
const res = await api.post(`${BASE}/users/bulk/restore`, { ids });
|
||||||
|
|
||||||
|
const { restored_ids } = res.data?.data ?? {}; // ← same unwrap
|
||||||
|
|
||||||
|
if (restored_ids?.length) {
|
||||||
|
setUsers((prev) =>
|
||||||
|
prev.map((u) =>
|
||||||
|
restored_ids.includes(u.user_id)
|
||||||
|
? { ...u, is_active: true }
|
||||||
|
: u
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
}),
|
||||||
|
[request]
|
||||||
|
);
|
||||||
|
|
||||||
// ─── GET /api/admin/users/:id/sessions ────────────────────────────────────
|
// ─── GET /api/admin/users/:id/sessions ────────────────────────────────────
|
||||||
const fetchUserSessions = useCallback(
|
const fetchUserSessions = useCallback(
|
||||||
(userId) =>
|
(userId) =>
|
||||||
@@ -209,7 +254,9 @@ export const UserProvider = ({ children }) => {
|
|||||||
fetchUser,
|
fetchUser,
|
||||||
updateUser,
|
updateUser,
|
||||||
deactivateUser,
|
deactivateUser,
|
||||||
|
deactivateUsers,
|
||||||
restoreUser,
|
restoreUser,
|
||||||
|
restoreUsers,
|
||||||
fetchUserSessions,
|
fetchUserSessions,
|
||||||
terminateSession,
|
terminateSession,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// ─── components/ArchiveUserDialog.jsx ────────────────────────────────────────
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogAction,
|
AlertDialogAction,
|
||||||
@@ -12,11 +11,23 @@ import {
|
|||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { useUsers } from "@/contexts/AdminUserContext";
|
import { useUsers } from "@/contexts/AdminUserContext";
|
||||||
|
|
||||||
export function ArchiveUserDialog({ open, onOpenChange, user, onSuccess }) {
|
/**
|
||||||
const { deactivateUser, loading } = useUsers();
|
* Unified archive dialog — works for both single and bulk.
|
||||||
|
*
|
||||||
|
* Single: <ArchiveUserDialog user={rowObject} ... />
|
||||||
|
* Bulk: <ArchiveUserDialog ids={[1, 2, 3]} ... />
|
||||||
|
*/
|
||||||
|
export function ArchiveUserDialog({ open, onOpenChange, user, ids, onSuccess }) {
|
||||||
|
const { deactivateUser, deactivateUsers, loading } = useUsers();
|
||||||
|
|
||||||
|
const isBulk = Array.isArray(ids) && ids.length > 0;
|
||||||
|
const count = isBulk ? ids.length : 1;
|
||||||
|
|
||||||
const handleArchive = async () => {
|
const handleArchive = async () => {
|
||||||
const res = await deactivateUser(user?.user_id);
|
const res = isBulk
|
||||||
|
? await deactivateUsers({ ids })
|
||||||
|
: await deactivateUser(user?.user_id);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
@@ -27,11 +38,15 @@ export function ArchiveUserDialog({ open, onOpenChange, user, onSuccess }) {
|
|||||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>Archive User</AlertDialogTitle>
|
<AlertDialogTitle>
|
||||||
|
Archive {isBulk ? `${count} Users` : "User"}
|
||||||
|
</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
Are you sure you want to archive{" "}
|
Are you sure you want to archive{" "}
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
{user?.personal_info?.name?.full_name ?? user?.email}
|
{isBulk
|
||||||
|
? `${count} selected user${count !== 1 ? "s" : ""}`
|
||||||
|
: (user?.personal_info?.name?.full_name ?? user?.email)}
|
||||||
</span>
|
</span>
|
||||||
? They will be deactivated and lose access immediately.
|
? They will be deactivated and lose access immediately.
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
@@ -44,7 +59,7 @@ export function ArchiveUserDialog({ open, onOpenChange, user, onSuccess }) {
|
|||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
{loading ? <Spinner className="size-4 mr-2" /> : null}
|
{loading ? <Spinner className="size-4 mr-2" /> : null}
|
||||||
Archive
|
Archive{isBulk ? ` ${count} User${count !== 1 ? "s" : ""}` : ""}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ import { buildRowActions } from "../config/archive/rowActions.config";
|
|||||||
|
|
||||||
import { getTimestamp } from "@/utils/timestamp.util";
|
import { getTimestamp } from "@/utils/timestamp.util";
|
||||||
|
|
||||||
export default function UsersTable() {
|
export default function ArchiveUsersTable() {
|
||||||
const [restoreTarget, setRestoreTarget] = useState(null);
|
const [restoreTarget, setRestoreTarget] = useState(null); // single: row object
|
||||||
const tableRefsRef = useRef({ getFilters: () => [], getSort: () => [] });
|
const [restoreIds, setRestoreIds] = useState(null); // bulk: array of ids
|
||||||
|
const tableRefsRef = useRef({ getFilters: () => [], getSort: () => [], resetSelection: () => {} });
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -26,9 +27,8 @@ export default function UsersTable() {
|
|||||||
loading,
|
loading,
|
||||||
fetchUserFieldValues,
|
fetchUserFieldValues,
|
||||||
fetchArchivedUsers,
|
fetchArchivedUsers,
|
||||||
restoreUser
|
|
||||||
} = useUsers();
|
} = useUsers();
|
||||||
|
|
||||||
// Shared export config — passed into toolbar + selection configs
|
// Shared export config — passed into toolbar + selection configs
|
||||||
const exportConfig = {
|
const exportConfig = {
|
||||||
allData: users,
|
allData: users,
|
||||||
@@ -37,17 +37,26 @@ export default function UsersTable() {
|
|||||||
sheetName: "ArchivedUsers",
|
sheetName: "ArchivedUsers",
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(users)
|
|
||||||
|
|
||||||
const rowActions = buildRowActions({ navigate, onRestore: (row) => setRestoreTarget(row), });
|
const rowActions = buildRowActions({ navigate, onRestore: (row) => setRestoreTarget(row), });
|
||||||
const toolbarActions = buildToolbarActions({
|
const toolbarActions = buildToolbarActions({
|
||||||
fetchArchivedUsers, pagination, exportConfig, navigate,
|
fetchArchivedUsers, pagination, exportConfig, navigate,
|
||||||
getFilters: () => tableRefsRef.current.getFilters(),
|
getFilters: () => tableRefsRef.current.getFilters(),
|
||||||
getSort: () => tableRefsRef.current.getSort(),
|
getSort: () => tableRefsRef.current.getSort(),
|
||||||
});
|
});
|
||||||
const selectionActions = buildSelectionActions({ exportConfig, restoreUser });
|
const selectionActions = buildSelectionActions({
|
||||||
|
exportConfig,
|
||||||
|
restoreUser: (row) => setRestoreTarget(row), // single — open dialog with row
|
||||||
|
restoreUsers: (ids) => setRestoreIds(ids), // bulk — open dialog with ids
|
||||||
|
});
|
||||||
const columns = useMemo(() => buildUserColumns(attributes, rowActions), [attributes]);
|
const columns = useMemo(() => buildUserColumns(attributes, rowActions), [attributes]);
|
||||||
|
|
||||||
|
const handleRestoreSuccess = () => {
|
||||||
|
setRestoreTarget(null);
|
||||||
|
setRestoreIds(null);
|
||||||
|
tableRefsRef.current.resetSelection?.(); // ← clear selection
|
||||||
|
fetchArchivedUsers({ page: 1, limit: pagination.limit });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTable
|
<DataTable
|
||||||
@@ -77,14 +86,20 @@ export default function UsersTable() {
|
|||||||
recordLabel="user"
|
recordLabel="user"
|
||||||
emptyMessage="No users match the current filters."
|
emptyMessage="No users match the current filters."
|
||||||
/>
|
/>
|
||||||
|
{/* Single restore */}
|
||||||
<RestoreUserDialog
|
<RestoreUserDialog
|
||||||
open={!!restoreTarget}
|
open={!!restoreTarget}
|
||||||
onOpenChange={(v) => !v && setRestoreTarget(null)}
|
onOpenChange={(v) => !v && setRestoreTarget(null)}
|
||||||
user={restoreTarget}
|
user={restoreTarget}
|
||||||
onSuccess={() => {
|
onSuccess={handleRestoreSuccess}
|
||||||
setRestoreTarget(null);
|
/>
|
||||||
fetchArchivedUsers({ page: 1, limit: pagination.limit });
|
|
||||||
}}
|
{/* Bulk restore */}
|
||||||
|
<RestoreUserDialog
|
||||||
|
open={!!restoreIds}
|
||||||
|
onOpenChange={(v) => !v && setRestoreIds(null)}
|
||||||
|
ids={restoreIds ?? []}
|
||||||
|
onSuccess={handleRestoreSuccess}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,11 +12,23 @@ import {
|
|||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { useUsers } from "@/contexts/AdminUserContext";
|
import { useUsers } from "@/contexts/AdminUserContext";
|
||||||
|
|
||||||
export function RestoreUserDialog({ open, onOpenChange, user, onSuccess }) {
|
/**
|
||||||
const { restoreUser, loading } = useUsers();
|
* Unified restore dialog — works for both single and bulk.
|
||||||
|
*
|
||||||
|
* Single: <RestoreUserDialog user={rowObject} ... />
|
||||||
|
* Bulk: <RestoreUserDialog ids={[1, 2, 3]} ... />
|
||||||
|
*/
|
||||||
|
export function RestoreUserDialog({ open, onOpenChange, user, ids, onSuccess }) {
|
||||||
|
const { restoreUser, restoreUsers, loading } = useUsers();
|
||||||
|
|
||||||
|
const isBulk = Array.isArray(ids) && ids.length > 0;
|
||||||
|
const count = isBulk ? ids.length : 1;
|
||||||
|
|
||||||
const handleRestore = async () => {
|
const handleRestore = async () => {
|
||||||
const res = await restoreUser(user?.user_id);
|
const res = isBulk
|
||||||
|
? await restoreUsers({ ids })
|
||||||
|
: await restoreUser(user?.user_id);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
@@ -27,13 +39,15 @@ export function RestoreUserDialog({ open, onOpenChange, user, onSuccess }) {
|
|||||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>Restore User</AlertDialogTitle>
|
<AlertDialogTitle>Restore {isBulk ? `${count} Users` : "User"}</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
Are you sure you want to restore{" "}
|
Are you sure you want to restore{" "}
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
{user?.personal_info?.name?.full_name ?? user?.email}
|
{isBulk
|
||||||
|
? `${count} selected user${count !== 1 ? "s" : ""}`
|
||||||
|
: (user?.personal_info?.name?.full_name ?? user?.email)}
|
||||||
</span>
|
</span>
|
||||||
? They will regain access to their account immediately.
|
? They will regain access to their account{isBulk && count !== 1 ? "s" : ""} immediately.
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
@@ -44,7 +58,7 @@ export function RestoreUserDialog({ open, onOpenChange, user, onSuccess }) {
|
|||||||
className="bg-emerald-600 text-white hover:bg-emerald-700"
|
className="bg-emerald-600 text-white hover:bg-emerald-700"
|
||||||
>
|
>
|
||||||
{loading ? <Spinner className="size-4 mr-2" /> : null}
|
{loading ? <Spinner className="size-4 mr-2" /> : null}
|
||||||
Restore
|
Restore{isBulk ? ` ${count} User${count !== 1 ? "s" : ""}` : ""}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import { buildRowActions } from "../config/rowActions.config";
|
|||||||
import { getTimestamp } from "@/utils/timestamp.util";
|
import { getTimestamp } from "@/utils/timestamp.util";
|
||||||
|
|
||||||
export default function UsersTable() {
|
export default function UsersTable() {
|
||||||
const [archiveTarget, setArchiveTarget] = useState(null);
|
const [archiveTarget, setArchiveTarget] = useState(null); // single: row object
|
||||||
const tableRefsRef = useRef({ getFilters: () => [], getSort: () => [] });
|
const [archiveIds, setArchiveIds] = useState(null); // bulk: array of ids
|
||||||
|
const tableRefsRef = useRef({ getFilters: () => [], getSort: () => [], resetSelection: () => {} });
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
users,
|
users,
|
||||||
attributes,
|
attributes,
|
||||||
@@ -26,7 +27,6 @@ export default function UsersTable() {
|
|||||||
loading,
|
loading,
|
||||||
fetchUsers,
|
fetchUsers,
|
||||||
fetchUserFieldValues,
|
fetchUserFieldValues,
|
||||||
deactivateUser
|
|
||||||
} = useUsers();
|
} = useUsers();
|
||||||
|
|
||||||
// Shared export config — passed into toolbar + selection configs
|
// Shared export config — passed into toolbar + selection configs
|
||||||
@@ -43,9 +43,20 @@ export default function UsersTable() {
|
|||||||
getFilters: () => tableRefsRef.current.getFilters(),
|
getFilters: () => tableRefsRef.current.getFilters(),
|
||||||
getSort: () => tableRefsRef.current.getSort(),
|
getSort: () => tableRefsRef.current.getSort(),
|
||||||
});
|
});
|
||||||
const selectionActions = buildSelectionActions({ exportConfig, deactivateUser });
|
const selectionActions = buildSelectionActions({
|
||||||
|
exportConfig,
|
||||||
|
archiveUser: (row) => setArchiveTarget(row), // single
|
||||||
|
archiveUsers: (ids) => setArchiveIds(ids), // bulk
|
||||||
|
});
|
||||||
const columns = useMemo(() => buildUserColumns(attributes, rowActions), [attributes]);
|
const columns = useMemo(() => buildUserColumns(attributes, rowActions), [attributes]);
|
||||||
|
|
||||||
|
const handleArchiveSuccess = () => {
|
||||||
|
setArchiveTarget(null);
|
||||||
|
setArchiveIds(null);
|
||||||
|
tableRefsRef.current.resetSelection?.(); // ← clear selection
|
||||||
|
fetchUsers({ page: 1, limit: pagination.limit });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTable
|
<DataTable
|
||||||
@@ -75,14 +86,20 @@ export default function UsersTable() {
|
|||||||
recordLabel="user"
|
recordLabel="user"
|
||||||
emptyMessage="No users match the current filters."
|
emptyMessage="No users match the current filters."
|
||||||
/>
|
/>
|
||||||
|
{/* Single archive */}
|
||||||
<ArchiveUserDialog
|
<ArchiveUserDialog
|
||||||
open={!!archiveTarget}
|
open={!!archiveTarget}
|
||||||
onOpenChange={(v) => !v && setArchiveTarget(null)}
|
onOpenChange={(v) => !v && setArchiveTarget(null)}
|
||||||
user={archiveTarget}
|
user={archiveTarget}
|
||||||
onSuccess={() => {
|
onSuccess={handleArchiveSuccess}
|
||||||
setArchiveTarget(null);
|
/>
|
||||||
fetchUsers({ page: 1, limit: pagination.limit });
|
|
||||||
}}
|
{/* Bulk archive */}
|
||||||
|
<ArchiveUserDialog
|
||||||
|
open={!!archiveIds}
|
||||||
|
onOpenChange={(v) => !v && setArchiveIds(null)}
|
||||||
|
ids={archiveIds ?? []}
|
||||||
|
onSuccess={handleArchiveSuccess}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// config/selection.config.jsx
|
// config/selection.config.jsx
|
||||||
import { Download, Archive, Trash2 } from "lucide-react";
|
import { Download, ArchiveRestore } from "lucide-react";
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,7 +8,27 @@ import { exportTableToExcel } from "@/utils/excel.util";
|
|||||||
* @param {Function} deps.archiveUser Archive handler from useManagement
|
* @param {Function} deps.archiveUser Archive handler from useManagement
|
||||||
* @param {Function} deps.deleteUser Delete handler from useManagement
|
* @param {Function} deps.deleteUser Delete handler from useManagement
|
||||||
*/
|
*/
|
||||||
export function buildSelectionActions({ exportConfig, archiveUser, deleteUser }) {
|
export function buildSelectionActions({ exportConfig, restoreUser, restoreUsers }) {
|
||||||
return [
|
return [
|
||||||
|
{
|
||||||
|
key: "export-selected",
|
||||||
|
label: "Export",
|
||||||
|
icon: <Download className="h-3.5 w-3.5" />,
|
||||||
|
onClick: (rows, table) =>
|
||||||
|
exportTableToExcel({ ...exportConfig, selectedRows: rows, tableInstance: table }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "restore-selected",
|
||||||
|
label: "Restore",
|
||||||
|
icon: <ArchiveRestore className="h-3.5 w-3.5" />,
|
||||||
|
className:
|
||||||
|
"text-emerald-600 border-emerald-600/40 hover:bg-emerald-600/10 hover:text-emerald-700",
|
||||||
|
onClick: (rows) => {
|
||||||
|
const ids = rows.map((r) => r.user_id);
|
||||||
|
ids.length === 1
|
||||||
|
? restoreUser(rows[0]) // opens single dialog
|
||||||
|
: restoreUsers(ids); // opens bulk dialog
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ import { exportTableToExcel } from "@/utils/excel.util";
|
|||||||
* @param {Function} deps.archiveUser Archive handler from useManagement
|
* @param {Function} deps.archiveUser Archive handler from useManagement
|
||||||
* @param {Function} deps.deleteUser Delete handler from useManagement
|
* @param {Function} deps.deleteUser Delete handler from useManagement
|
||||||
*/
|
*/
|
||||||
export function buildSelectionActions({ exportConfig, archiveUser }) {
|
export function buildSelectionActions({ exportConfig, archiveUser, archiveUsers }) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "export-selected",
|
key: "export-selected",
|
||||||
@@ -22,7 +22,12 @@ export function buildSelectionActions({ exportConfig, archiveUser }) {
|
|||||||
label: "Archive",
|
label: "Archive",
|
||||||
icon: <Archive className="h-3.5 w-3.5" />,
|
icon: <Archive className="h-3.5 w-3.5" />,
|
||||||
className: "text-destructive border-destructive/40 hover:bg-destructive/10 hover:text-destructive",
|
className: "text-destructive border-destructive/40 hover:bg-destructive/10 hover:text-destructive",
|
||||||
onClick: (rows) => archiveUser({ ids: rows.map((r) => r.id) }),
|
onClick: (rows) => {
|
||||||
|
const ids = rows.map((r) => r.user_id);
|
||||||
|
ids.length === 1
|
||||||
|
? archiveUser(rows[0]) // opens single dialog
|
||||||
|
: archiveUsers(ids); // opens bulk dialog
|
||||||
|
},
|
||||||
hidden: (rows) => rows.every((r) => r.status === "archived"),
|
hidden: (rows) => rows.every((r) => r.status === "archived"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user