mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -73,7 +73,7 @@ export default function ArchiveTaskListTable() {
|
|||||||
|
|
||||||
const selectionActions = buildSelectionActions({
|
const selectionActions = buildSelectionActions({
|
||||||
exportConfig,
|
exportConfig,
|
||||||
onRestoreMany: (ids) => setRestoreIds(ids),
|
onBulkRestore: (ids) => setRestoreIds(ids),
|
||||||
getTableInstance: () => tableRefsRef.current.tableInstance,
|
getTableInstance: () => tableRefsRef.current.tableInstance,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ export default function ArchiveTaskListTable() {
|
|||||||
onOpenChange={(v) => !v && setRestoreIds(null)}
|
onOpenChange={(v) => !v && setRestoreIds(null)}
|
||||||
ids={restoreIds ?? []}
|
ids={restoreIds ?? []}
|
||||||
entityLabel="Task List"
|
entityLabel="Task List"
|
||||||
onRestore={(ids) => bulkRestoreTaskLists(ids)}
|
onRestore={({ ids }) => bulkRestoreTaskLists(ids)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useRef, useState, useCallback } from "react";
|
import { useMemo, useRef, useState, useCallback, useEffect } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import { useAdminTask } from "@/contexts/AdminTaskContext";
|
import { useAdminTask } from "@/contexts/AdminTaskContext";
|
||||||
@@ -31,7 +31,7 @@ export default function ArchivedTaskTable() {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
taskList, tasks, attributes, pagination, loading,
|
taskList, tasks, attributes, pagination, loading,
|
||||||
fetchArchivedTasks,
|
fetchTaskList, fetchArchivedTasks, fetchTaskFieldValues,
|
||||||
restoreTask,
|
restoreTask,
|
||||||
bulkRestoreTasks,
|
bulkRestoreTasks,
|
||||||
} = useAdminTask();
|
} = useAdminTask();
|
||||||
@@ -47,6 +47,11 @@ export default function ArchivedTaskTable() {
|
|||||||
tableInstance: null,
|
tableInstance: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchTaskList(taskListId);
|
||||||
|
fetchArchivedTasks(taskListId, { page: 1, limit: 10 });
|
||||||
|
}, [taskListId]);
|
||||||
|
|
||||||
const handleRefsReady = (refs) => {
|
const handleRefsReady = (refs) => {
|
||||||
tableRefsRef.current = refs;
|
tableRefsRef.current = refs;
|
||||||
};
|
};
|
||||||
@@ -82,19 +87,16 @@ export default function ArchivedTaskTable() {
|
|||||||
}), [navigate]);
|
}), [navigate]);
|
||||||
|
|
||||||
const toolbarActions = useMemo(() => buildToolbarActions({
|
const toolbarActions = useMemo(() => buildToolbarActions({
|
||||||
taskListId,
|
fetchArchivedTasks: handleFetch, taskListId,
|
||||||
navigate,
|
navigate, pagination, exportConfig,
|
||||||
getSort: () => tableRefsRef.current.getSort(),
|
|
||||||
fetchArchivedTasks: handleFetch,
|
|
||||||
pagination,
|
|
||||||
exportConfig,
|
|
||||||
getFilters: () => tableRefsRef.current.getFilters(),
|
getFilters: () => tableRefsRef.current.getFilters(),
|
||||||
|
getSort: () => tableRefsRef.current.getSort(),
|
||||||
getTableInstance: () => tableRefsRef.current.tableInstance,
|
getTableInstance: () => tableRefsRef.current.tableInstance,
|
||||||
}), [taskListId, navigate, handleFetch, pagination, exportConfig]);
|
}), [taskListId, navigate, handleFetch, pagination, exportConfig]);
|
||||||
|
|
||||||
const selectionActions = useMemo(() => buildSelectionActions({
|
const selectionActions = useMemo(() => buildSelectionActions({
|
||||||
exportConfig,
|
exportConfig,
|
||||||
onRestoreMany: (ids) => setRestoreIds(ids),
|
onBulkRestore: (ids) => setRestoreIds(ids), // ← was onRestoreMany
|
||||||
getTableInstance: () => tableRefsRef.current.tableInstance,
|
getTableInstance: () => tableRefsRef.current.tableInstance,
|
||||||
}), [exportConfig]);
|
}), [exportConfig]);
|
||||||
|
|
||||||
@@ -182,7 +184,7 @@ export default function ArchivedTaskTable() {
|
|||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onFetch={handleFetch}
|
onFetch={handleFetch}
|
||||||
onFetchFilterData={() => []}
|
onFetchFilterData={(field) => fetchTaskFieldValues(taskListId, field)}
|
||||||
onRefsReady={handleRefsReady}
|
onRefsReady={handleRefsReady}
|
||||||
renderFilterSheet={({ open, onOpenChange, column, attr, data, loading }) => (
|
renderFilterSheet={({ open, onOpenChange, column, attr, data, loading }) => (
|
||||||
<FilterSheet
|
<FilterSheet
|
||||||
@@ -219,7 +221,7 @@ export default function ArchivedTaskTable() {
|
|||||||
onOpenChange={(v) => !v && setRestoreIds(null)}
|
onOpenChange={(v) => !v && setRestoreIds(null)}
|
||||||
ids={restoreIds ?? []}
|
ids={restoreIds ?? []}
|
||||||
entityLabel="Task"
|
entityLabel="Task"
|
||||||
onRestore={(ids) => bulkRestoreTasks(taskListId, ids)}
|
onRestore={({ ids }) => bulkRestoreTasks(taskListId, ids)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ export default function TaskListTable() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ── Export config ─────────────────────────────────────────────────────────
|
// ── Export config ─────────────────────────────────────────────────────────
|
||||||
const exportConfig = {
|
const exportConfig = useMemo(() => ({
|
||||||
allData: taskLists,
|
allData: taskLists,
|
||||||
attributes,
|
attributes,
|
||||||
filename: `${getTimestamp()}_TaskLists`,
|
filename: `${getTimestamp()}_TaskLists`,
|
||||||
sheetName: "Task Lists",
|
sheetName: "Task Lists",
|
||||||
};
|
}), [taskLists, attributes]);
|
||||||
|
|
||||||
// ── Row actions ───────────────────────────────────────────────────────────
|
// ── Row actions ───────────────────────────────────────────────────────────
|
||||||
const rowActions = buildRowActions({
|
const rowActions = buildRowActions({
|
||||||
@@ -90,6 +90,7 @@ export default function TaskListTable() {
|
|||||||
// ── Toolbar ───────────────────────────────────────────────────────────────
|
// ── Toolbar ───────────────────────────────────────────────────────────────
|
||||||
const toolbarActions = buildToolbarActions({
|
const toolbarActions = buildToolbarActions({
|
||||||
fetchTaskLists, fetchArchivedTaskLists, pagination, navigate,
|
fetchTaskLists, fetchArchivedTaskLists, pagination, navigate,
|
||||||
|
exportConfig,
|
||||||
showArchived,
|
showArchived,
|
||||||
onToggleArchived: handleToggleArchived,
|
onToggleArchived: handleToggleArchived,
|
||||||
getFilters: () => tableRefsRef.current.getFilters(),
|
getFilters: () => tableRefsRef.current.getFilters(),
|
||||||
@@ -101,10 +102,8 @@ export default function TaskListTable() {
|
|||||||
const selectionActions = buildSelectionActions({
|
const selectionActions = buildSelectionActions({
|
||||||
exportConfig,
|
exportConfig,
|
||||||
showArchived,
|
showArchived,
|
||||||
onArchive: (row) => setArchiveTarget(row),
|
onBulkArchive: (ids) => setArchiveIds(ids),
|
||||||
onArchiveMany: (ids) => setArchiveIds(ids),
|
onBulkRestore: (ids) => setRestoreIds(ids),
|
||||||
onRestore: (row) => setRestoreTarget(row),
|
|
||||||
onRestoreMany: (ids) => setRestoreIds(ids),
|
|
||||||
getTableInstance: () => tableRefsRef.current.tableInstance,
|
getTableInstance: () => tableRefsRef.current.tableInstance,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ export default function TaskListTable() {
|
|||||||
entity={archiveTarget}
|
entity={archiveTarget}
|
||||||
entityLabel="Task List"
|
entityLabel="Task List"
|
||||||
getName={(r) => r?.name}
|
getName={(r) => r?.name}
|
||||||
onArchive={(r) => archiveTaskList(r?.task_list_id)}
|
onArchive={(entity) => archiveTaskList(entity?.task_list_id)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
@@ -162,7 +161,7 @@ export default function TaskListTable() {
|
|||||||
entity={restoreTarget}
|
entity={restoreTarget}
|
||||||
entityLabel="Task List"
|
entityLabel="Task List"
|
||||||
getName={(r) => r?.name}
|
getName={(r) => r?.name}
|
||||||
onRestore={(r) => restoreTaskList(r?.task_list_id)}
|
onRestore={(entity) => restoreTaskList(entity?.task_list_id)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
@@ -173,7 +172,7 @@ export default function TaskListTable() {
|
|||||||
onOpenChange={(v) => !v && setArchiveIds(null)}
|
onOpenChange={(v) => !v && setArchiveIds(null)}
|
||||||
ids={archiveIds ?? []}
|
ids={archiveIds ?? []}
|
||||||
entityLabel="Task List"
|
entityLabel="Task List"
|
||||||
onArchive={(ids) => bulkArchiveTaskLists(ids)}
|
onArchive={({ ids }) => bulkArchiveTaskLists(ids)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
@@ -184,7 +183,7 @@ export default function TaskListTable() {
|
|||||||
onOpenChange={(v) => !v && setRestoreIds(null)}
|
onOpenChange={(v) => !v && setRestoreIds(null)}
|
||||||
ids={restoreIds ?? []}
|
ids={restoreIds ?? []}
|
||||||
entityLabel="Task List"
|
entityLabel="Task List"
|
||||||
onRestore={(ids) => bulkRestoreTaskLists(ids)}
|
onRestore={({ ids }) => bulkRestoreTaskLists(ids)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
import { RotateCcw } from "lucide-react";
|
import { Download, RotateCcw } from "lucide-react";
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
import { Download } from "lucide-react";
|
|
||||||
|
|
||||||
export function buildSelectionActions({
|
export function buildSelectionActions({
|
||||||
exportConfig,
|
exportConfig,
|
||||||
onRestoreMany,
|
onBulkRestore,
|
||||||
getTableInstance,
|
getTableInstance,
|
||||||
}) {
|
}) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "export-selected",
|
key: "export-selected",
|
||||||
label: "Export Selected",
|
label: "Export",
|
||||||
icon: <Download className="size-4" />,
|
icon: <Download className="h-3.5 w-3.5" />,
|
||||||
onClick: () =>
|
onClick: (rows, table) =>
|
||||||
exportTableToExcel({
|
exportTableToExcel({
|
||||||
...exportConfig,
|
...exportConfig,
|
||||||
tableInstance: getTableInstance?.(),
|
selectedRows: rows,
|
||||||
selectedOnly: true,
|
tableInstance: table ?? getTableInstance?.(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "bulk-restore",
|
key: "restore-selected",
|
||||||
label: "Restore Selected",
|
label: "Restore Selected",
|
||||||
icon: <RotateCcw className="size-4" />,
|
icon: <RotateCcw className="h-3.5 w-3.5" />,
|
||||||
variant: "outline",
|
onClick: (rows) => {
|
||||||
onClick: (selectedRows) =>
|
const ids = rows.map((r) => r.task_list_id).filter(Boolean);
|
||||||
onRestoreMany(selectedRows.map((r) => r.task_list_id)),
|
if (!ids.length) return;
|
||||||
|
onBulkRestore?.(ids);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ export function buildSelectionActions({
|
|||||||
),
|
),
|
||||||
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) => {
|
onClick: (rows) => {
|
||||||
const ids = rows.map((r) => r.task_id).filter(Boolean);
|
const ids = rows.map((r) => r.task_list_id).filter(Boolean);
|
||||||
if (!ids.length) return;
|
if (!ids.length) return;
|
||||||
showArchived ? onBulkRestore?.(ids) : onBulkArchive?.(ids);
|
showArchived ? onBulkRestore?.(ids) : onBulkArchive?.(ids);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,34 +1,32 @@
|
|||||||
// config/selection.config.jsx
|
import { Download, RotateCcw } from "lucide-react";
|
||||||
import { Download, Archive, Trash2 } from "lucide-react";
|
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
export function buildSelectionActions({
|
||||||
* @param {Object} deps
|
exportConfig,
|
||||||
* @param {Object} deps.exportConfig { allData, attributes, filename, sheetName }
|
onBulkRestore,
|
||||||
* @param {Function} deps.archiveUser Archive handler from useManagement
|
getTableInstance,
|
||||||
* @param {Function} deps.deleteUser Delete handler from useManagement
|
}) {
|
||||||
*/
|
return [
|
||||||
export function buildSelectionActions({ exportConfig, archiveUser, archiveUsers, getTableInstance }) {
|
{
|
||||||
return [
|
key: "export-selected",
|
||||||
{
|
label: "Export",
|
||||||
key: "export-selected",
|
icon: <Download className="h-3.5 w-3.5" />,
|
||||||
label: "Export",
|
onClick: (rows, table) =>
|
||||||
icon: <Download className="h-3.5 w-3.5" />,
|
exportTableToExcel({
|
||||||
onClick: (rows, table) =>
|
...exportConfig,
|
||||||
exportTableToExcel({ ...exportConfig, selectedRows: rows, tableInstance: table ?? getTableInstance() }),
|
selectedRows: rows,
|
||||||
},
|
tableInstance: table ?? getTableInstance?.(),
|
||||||
{
|
}),
|
||||||
key: "archive-selected",
|
},
|
||||||
label: "Archive",
|
{
|
||||||
icon: <Archive className="h-3.5 w-3.5" />,
|
key: "restore-selected",
|
||||||
className: "text-destructive border-destructive/40 hover:bg-destructive/10 hover:text-destructive",
|
label: "Restore Selected",
|
||||||
onClick: (rows) => {
|
icon: <RotateCcw className="h-3.5 w-3.5" />,
|
||||||
const ids = rows.map((r) => r.user_id);
|
onClick: (rows) => {
|
||||||
ids.length === 1
|
const ids = rows.map((r) => r.task_id).filter(Boolean);
|
||||||
? archiveUser(rows[0]) // opens single dialog
|
if (!ids.length) return;
|
||||||
: archiveUsers(ids); // opens bulk dialog
|
onBulkRestore?.(ids);
|
||||||
},
|
},
|
||||||
hidden: (rows) => rows.every((r) => r.status === "archived"),
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
}
|
}
|
||||||
@@ -1,57 +1,39 @@
|
|||||||
// ─── config/toolbar.config.jsx ────────────────────────────────────────────────
|
import { RefreshCw, Download } from "lucide-react";
|
||||||
import { RefreshCw, Download, Plus, Archive } from "lucide-react";
|
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} deps
|
|
||||||
* @param {Function} deps.fetchTasks
|
|
||||||
* @param {string} deps.taskId
|
|
||||||
* @param {Object} deps.pagination
|
|
||||||
* @param {Object} deps.exportConfig
|
|
||||||
* @param {Function} deps.navigate
|
|
||||||
* @param {boolean} deps.showArchived
|
|
||||||
* @param {Function} deps.onToggleArchived
|
|
||||||
* @param {Function} deps.getFilters
|
|
||||||
* @param {Function} deps.getSort
|
|
||||||
* @param {Function} deps.getTableInstance
|
|
||||||
*/
|
|
||||||
export function buildToolbarActions({
|
export function buildToolbarActions({
|
||||||
fetchTasks,
|
fetchArchivedTasks,
|
||||||
taskId,
|
taskListId,
|
||||||
pagination,
|
pagination,
|
||||||
exportConfig,
|
exportConfig,
|
||||||
navigate,
|
getFilters,
|
||||||
showArchived,
|
getSort,
|
||||||
onToggleArchived,
|
getTableInstance,
|
||||||
getFilters,
|
|
||||||
getSort,
|
|
||||||
getTableInstance,
|
|
||||||
}) {
|
}) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "refresh",
|
key: "refresh",
|
||||||
type: "button",
|
type: "button",
|
||||||
icon: <RefreshCw className="size-4" />,
|
icon: <RefreshCw className="size-4" />,
|
||||||
label: "Refresh",
|
label: "Refresh",
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
fetchTasks(taskId, {
|
fetchArchivedTasks(taskListId, {
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: pagination?.limit ?? 10,
|
limit: pagination?.limit ?? 10,
|
||||||
filters: getFilters?.() ?? [],
|
filters: getFilters?.() ?? [],
|
||||||
sort: getSort?.() ?? [],
|
sort: getSort?.() ?? [],
|
||||||
archived: showArchived,
|
}),
|
||||||
}),
|
},
|
||||||
},
|
{
|
||||||
{
|
key: "export",
|
||||||
key: "export",
|
type: "button",
|
||||||
type: "button",
|
icon: <Download className="size-4" />,
|
||||||
icon: <Download className="size-4" />,
|
label: "Export",
|
||||||
label: "Export",
|
onClick: (table) =>
|
||||||
onClick: (table) =>
|
exportTableToExcel({
|
||||||
exportTableToExcel({
|
...exportConfig,
|
||||||
...exportConfig,
|
tableInstance: table ?? getTableInstance?.(),
|
||||||
tableInstance: table ?? getTableInstance?.(),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,39 @@
|
|||||||
// config/selection.config.jsx
|
import { Download, Archive, RotateCcw } from "lucide-react";
|
||||||
import { Download, Archive, Trash2 } from "lucide-react";
|
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
export function buildSelectionActions({
|
||||||
* @param {Object} deps
|
exportConfig,
|
||||||
* @param {Object} deps.exportConfig { allData, attributes, filename, sheetName }
|
showArchived,
|
||||||
* @param {Function} deps.archiveUser Archive handler from useManagement
|
onBulkArchive,
|
||||||
* @param {Function} deps.deleteUser Delete handler from useManagement
|
onBulkRestore,
|
||||||
*/
|
getTableInstance,
|
||||||
export function buildSelectionActions({ exportConfig, archiveUser, archiveUsers, getTableInstance }) {
|
}) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "export-selected",
|
key: "export-selected",
|
||||||
label: "Export",
|
label: "Export",
|
||||||
icon: <Download className="h-3.5 w-3.5" />,
|
icon: <Download className="h-3.5 w-3.5" />,
|
||||||
onClick: (rows, table) =>
|
onClick: (rows, table) =>
|
||||||
exportTableToExcel({ ...exportConfig, selectedRows: rows, tableInstance: table ?? getTableInstance() }),
|
exportTableToExcel({
|
||||||
},
|
...exportConfig,
|
||||||
{
|
selectedRows: rows,
|
||||||
key: "archive-selected",
|
tableInstance: table ?? getTableInstance?.(),
|
||||||
label: "Archive",
|
}),
|
||||||
icon: <Archive className="h-3.5 w-3.5" />,
|
},
|
||||||
className: "text-destructive border-destructive/40 hover:bg-destructive/10 hover:text-destructive",
|
{
|
||||||
onClick: (rows) => {
|
key: showArchived ? "restore-selected" : "archive-selected",
|
||||||
const ids = rows.map((r) => r.user_id);
|
label: showArchived ? "Restore" : "Archive",
|
||||||
ids.length === 1
|
icon: showArchived ? (
|
||||||
? archiveUser(rows[0]) // opens single dialog
|
<RotateCcw className="h-3.5 w-3.5" />
|
||||||
: archiveUsers(ids); // opens bulk dialog
|
) : (
|
||||||
},
|
<Archive className="h-3.5 w-3.5" />
|
||||||
hidden: (rows) => rows.every((r) => r.status === "archived"),
|
),
|
||||||
},
|
className: "text-destructive border-destructive/40 hover:bg-destructive/10 hover:text-destructive",
|
||||||
];
|
onClick: (rows) => {
|
||||||
|
const ids = rows.map((r) => r.task_id).filter(Boolean);
|
||||||
|
if (!ids.length) return;
|
||||||
|
showArchived ? onBulkRestore?.(ids) : onBulkArchive?.(ids);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
@@ -1,76 +1,63 @@
|
|||||||
// ─── config/toolbar.config.jsx ────────────────────────────────────────────────
|
|
||||||
import { RefreshCw, Download, Plus, Archive } from "lucide-react";
|
import { RefreshCw, Download, Plus, Archive } from "lucide-react";
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} deps
|
|
||||||
* @param {Function} deps.fetchTasks
|
|
||||||
* @param {string} deps.taskListId
|
|
||||||
* @param {Object} deps.pagination
|
|
||||||
* @param {Object} deps.exportConfig
|
|
||||||
* @param {Function} deps.navigate
|
|
||||||
* @param {boolean} deps.showArchived
|
|
||||||
* @param {Function} deps.onToggleArchived
|
|
||||||
* @param {Function} deps.getFilters
|
|
||||||
* @param {Function} deps.getSort
|
|
||||||
* @param {Function} deps.getTableInstance
|
|
||||||
*/
|
|
||||||
export function buildToolbarActions({
|
export function buildToolbarActions({
|
||||||
fetchTasks,
|
fetchTasks,
|
||||||
taskListId,
|
fetchArchivedTasks,
|
||||||
pagination,
|
taskListId,
|
||||||
exportConfig,
|
pagination,
|
||||||
navigate,
|
exportConfig,
|
||||||
showArchived,
|
navigate,
|
||||||
onToggleArchived,
|
showArchived,
|
||||||
getFilters,
|
onToggleArchived,
|
||||||
getSort,
|
getFilters,
|
||||||
getTableInstance,
|
getSort,
|
||||||
|
getTableInstance,
|
||||||
}) {
|
}) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "refresh",
|
key: "refresh",
|
||||||
type: "button",
|
type: "button",
|
||||||
icon: <RefreshCw className="size-4" />,
|
icon: <RefreshCw className="size-4" />,
|
||||||
label: "Refresh",
|
label: "Refresh",
|
||||||
onClick: () =>
|
onClick: () => {
|
||||||
fetchTasks(taskId, {
|
const fetcher = showArchived ? fetchArchivedTasks : fetchTasks;
|
||||||
page: 1,
|
fetcher(taskListId, {
|
||||||
limit: pagination?.limit ?? 10,
|
page: 1,
|
||||||
filters: getFilters?.() ?? [],
|
limit: pagination?.limit ?? 10,
|
||||||
sort: getSort?.() ?? [],
|
filters: getFilters?.() ?? [],
|
||||||
archived: showArchived,
|
sort: getSort?.() ?? [],
|
||||||
}),
|
});
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
key: "export",
|
{
|
||||||
type: "button",
|
key: "export",
|
||||||
icon: <Download className="size-4" />,
|
type: "button",
|
||||||
label: "Export",
|
icon: <Download className="size-4" />,
|
||||||
onClick: (table) =>
|
label: "Export",
|
||||||
exportTableToExcel({
|
onClick: (table) =>
|
||||||
...exportConfig,
|
exportTableToExcel({
|
||||||
tableInstance: table ?? getTableInstance?.(),
|
...exportConfig,
|
||||||
}),
|
tableInstance: table ?? getTableInstance?.(),
|
||||||
},
|
}),
|
||||||
{
|
},
|
||||||
key: "add-task",
|
{
|
||||||
type: "button",
|
key: "add-task",
|
||||||
icon: <Plus className="size-4" />,
|
type: "button",
|
||||||
label: "Create Task",
|
icon: <Plus className="size-4" />,
|
||||||
variant: "default",
|
label: "Create Task",
|
||||||
className: "text-primary-foreground",
|
variant: "default",
|
||||||
onClick: () => navigate(`/admin/taskList/${taskListId}/tasks/create`),
|
className: "text-primary-foreground",
|
||||||
},
|
onClick: () => navigate(`/admin/taskList/${taskListId}/tasks/create`),
|
||||||
{
|
},
|
||||||
key: "toggle-archived-task",
|
{
|
||||||
type: "button",
|
key: "toggle-archived-task",
|
||||||
icon: <Archive className="size-4" />,
|
type: "button",
|
||||||
label: showArchived ? "Active Tasks" : "Archived Tasks",
|
icon: <Archive className="size-4" />,
|
||||||
variant: "secondary",
|
label: showArchived ? "Active Tasks" : "Archived Tasks",
|
||||||
className: "border border-border",
|
variant: "secondary",
|
||||||
// onClick: onToggleArchived,
|
className: "border border-border",
|
||||||
onClick: () => navigate(`/admin/taskList/${taskListId}/tasks/archived`),
|
onClick: () => navigate(`/admin/taskList/${taskListId}/tasks/archived`),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,10 @@
|
|||||||
// ─── config/toolbar.config.jsx ────────────────────────────────────────────────
|
// ─── config/task_list/toolbar.config.jsx ─────────────────────────────────────
|
||||||
import { RefreshCw, Download, Plus, Archive } from "lucide-react";
|
import { RefreshCw, Download, Plus, Archive } from "lucide-react";
|
||||||
import { exportTableToExcel } from "@/utils/excel.util";
|
import { exportTableToExcel } from "@/utils/excel.util";
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} deps
|
|
||||||
* @param {Function} deps.fetchTasks
|
|
||||||
* @param {string} deps.taskListId
|
|
||||||
* @param {Object} deps.pagination
|
|
||||||
* @param {Object} deps.exportConfig
|
|
||||||
* @param {Function} deps.navigate
|
|
||||||
* @param {boolean} deps.showArchived
|
|
||||||
* @param {Function} deps.onToggleArchived
|
|
||||||
* @param {Function} deps.getFilters
|
|
||||||
* @param {Function} deps.getSort
|
|
||||||
* @param {Function} deps.getTableInstance
|
|
||||||
*/
|
|
||||||
export function buildToolbarActions({
|
export function buildToolbarActions({
|
||||||
fetchTasks,
|
fetchTaskLists,
|
||||||
fetchArchivedTaskLists,
|
fetchArchivedTaskLists,
|
||||||
taskListId,
|
|
||||||
pagination,
|
pagination,
|
||||||
exportConfig,
|
exportConfig,
|
||||||
navigate,
|
navigate,
|
||||||
@@ -34,14 +20,15 @@ export function buildToolbarActions({
|
|||||||
type: "button",
|
type: "button",
|
||||||
icon: <RefreshCw className="size-4" />,
|
icon: <RefreshCw className="size-4" />,
|
||||||
label: "Refresh",
|
label: "Refresh",
|
||||||
onClick: () =>
|
onClick: () => {
|
||||||
fetchTasks(taskListId, {
|
const fetcher = showArchived ? fetchArchivedTaskLists : fetchTaskLists;
|
||||||
|
fetcher({
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: pagination?.limit ?? 10,
|
limit: pagination?.limit ?? 10,
|
||||||
filters: getFilters?.() ?? [],
|
filters: getFilters?.() ?? [],
|
||||||
sort: getSort?.() ?? [],
|
sort: getSort?.() ?? [],
|
||||||
archived: showArchived,
|
});
|
||||||
}),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "export",
|
key: "export",
|
||||||
@@ -55,7 +42,7 @@ export function buildToolbarActions({
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "add-task",
|
key: "add-task-list",
|
||||||
type: "button",
|
type: "button",
|
||||||
icon: <Plus className="size-4" />,
|
icon: <Plus className="size-4" />,
|
||||||
label: "Create Task List",
|
label: "Create Task List",
|
||||||
@@ -64,10 +51,10 @@ export function buildToolbarActions({
|
|||||||
onClick: () => navigate(`/admin/taskList/create`),
|
onClick: () => navigate(`/admin/taskList/create`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "toggle-archived-task",
|
key: "toggle-archived",
|
||||||
type: "button",
|
type: "button",
|
||||||
icon: <Archive className="size-4" />,
|
icon: <Archive className="size-4" />,
|
||||||
label: showArchived ? "Active Task Lists" : "Archived Task List",
|
label: showArchived ? "Active Task Lists" : "Archived Task Lists",
|
||||||
variant: "secondary",
|
variant: "secondary",
|
||||||
className: "border border-border",
|
className: "border border-border",
|
||||||
onClick: () => navigate("/admin/taskList/archived"),
|
onClick: () => navigate("/admin/taskList/archived"),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||||||
import { useAdminTask } from '@/contexts/AdminTaskContext';
|
import { useAdminTask } from '@/contexts/AdminTaskContext';
|
||||||
|
|
||||||
import DataTable from '@/components/generic/Table/DataTable';
|
import DataTable from '@/components/generic/Table/DataTable';
|
||||||
|
import { FilterSheet } from "@/components/generic/Sheet/FilterSheet";
|
||||||
import { ArchiveDialog } from '@/components/generic/Dialogs/ArchiveDialog';
|
import { ArchiveDialog } from '@/components/generic/Dialogs/ArchiveDialog';
|
||||||
import { RestoreDialog } from '@/components/generic/Dialogs/RestoreDialog';
|
import { RestoreDialog } from '@/components/generic/Dialogs/RestoreDialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -23,6 +24,7 @@ import { buildDataColumns, columnPinning } from '@/modules/admin/config/task_lis
|
|||||||
import { buildToolbarActions } from '@/modules/admin/config/task_list/task/toolbar.config';
|
import { buildToolbarActions } from '@/modules/admin/config/task_list/task/toolbar.config';
|
||||||
import { buildSelectionActions } from '@/modules/admin/config/task_list/task/selection.config';
|
import { buildSelectionActions } from '@/modules/admin/config/task_list/task/selection.config';
|
||||||
import { buildRowActions } from '@/modules/admin/config/task_list/task/rowActions.config';
|
import { buildRowActions } from '@/modules/admin/config/task_list/task/rowActions.config';
|
||||||
|
import { getTimestamp } from '@/utils/timestamp.util';
|
||||||
|
|
||||||
export default function Tasks() {
|
export default function Tasks() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -81,20 +83,30 @@ export default function Tasks() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowActions = useMemo(() => buildRowActions({
|
const exportConfig = useMemo(() => ({
|
||||||
|
allData: tasks,
|
||||||
|
attributes,
|
||||||
|
filename: `${getTimestamp()}_Tasks`,
|
||||||
|
sheetName: "Tasks",
|
||||||
|
}), [tasks, attributes]);
|
||||||
|
|
||||||
|
const rowActions = buildRowActions({
|
||||||
navigate,
|
navigate,
|
||||||
onArchive: (row) => setArchiveTarget(row),
|
onArchive: (row) => setArchiveTarget(row),
|
||||||
onRestore: (row) => setRestoreTarget(row),
|
onRestore: (row) => setRestoreTarget(row),
|
||||||
showArchived,
|
showArchived,
|
||||||
}), [navigate, showArchived]);
|
});
|
||||||
|
|
||||||
const toolbarActions = buildToolbarActions({
|
const toolbarActions = buildToolbarActions({
|
||||||
fetchTasks, fetchArchivedTasks, taskListId, pagination, navigate,
|
fetchTasks, fetchArchivedTasks, taskListId,
|
||||||
|
pagination, navigate, exportConfig,
|
||||||
showArchived, onToggleArchived: handleToggleArchived,
|
showArchived, onToggleArchived: handleToggleArchived,
|
||||||
getFilters: () => tableRefsRef.current.getFilters(),
|
getFilters: () => tableRefsRef.current.getFilters(),
|
||||||
getSort: () => tableRefsRef.current.getSort(),
|
getSort: () => tableRefsRef.current.getSort(),
|
||||||
|
getTableInstance: () => tableRefsRef.current.tableInstance,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Selection ─────────────────────────────────────────────────────────────
|
||||||
const selectionActions = buildSelectionActions({
|
const selectionActions = buildSelectionActions({
|
||||||
showArchived,
|
showArchived,
|
||||||
onBulkArchive: (ids) => setBulkArchiveIds(ids),
|
onBulkArchive: (ids) => setBulkArchiveIds(ids),
|
||||||
@@ -214,11 +226,21 @@ export default function Tasks() {
|
|||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onFetch={handleFetch}
|
onFetch={handleFetch}
|
||||||
onFetchFilterData={fetchTaskFieldValues}
|
onFetchFilterData={(field) => fetchTaskFieldValues(taskListId, field)}
|
||||||
toolbarActions={toolbarActions}
|
toolbarActions={toolbarActions}
|
||||||
selectionActions={selectionActions}
|
selectionActions={selectionActions}
|
||||||
columnPinning={columnPinning}
|
columnPinning={columnPinning}
|
||||||
onRefsReady={handleRefsReady}
|
onRefsReady={handleRefsReady}
|
||||||
|
renderFilterSheet={({ open, onOpenChange, column, attr, data, loading }) => (
|
||||||
|
<FilterSheet
|
||||||
|
open={open}
|
||||||
|
onOpenChange={onOpenChange}
|
||||||
|
column={column}
|
||||||
|
attr={attr}
|
||||||
|
data={data}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* ── All Groups Dialog ─────────────────────────────────────────── */}
|
{/* ── All Groups Dialog ─────────────────────────────────────────── */}
|
||||||
@@ -251,11 +273,9 @@ export default function Tasks() {
|
|||||||
entity={archiveTarget}
|
entity={archiveTarget}
|
||||||
entityLabel="Task"
|
entityLabel="Task"
|
||||||
getName={(r) => r?.name}
|
getName={(r) => r?.name}
|
||||||
onArchive={async (r) => {
|
onArchive={(entity) => archiveTask(taskListId, entity?.task_id)}
|
||||||
const ok = await archiveTask(taskListId, r?.task_id);
|
|
||||||
if (ok) { setArchiveTarget(null); afterMutation(); }
|
|
||||||
}}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onSuccess={afterMutation}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* ── Single restore ────────────────────────────────────────────── */}
|
{/* ── Single restore ────────────────────────────────────────────── */}
|
||||||
@@ -265,39 +285,31 @@ export default function Tasks() {
|
|||||||
entity={restoreTarget}
|
entity={restoreTarget}
|
||||||
entityLabel="Task"
|
entityLabel="Task"
|
||||||
getName={(r) => r?.name}
|
getName={(r) => r?.name}
|
||||||
onRestore={async (r) => {
|
onRestore={(entity) => restoreTask(taskListId, entity?.task_id)}
|
||||||
const ok = await restoreTask(taskListId, r?.task_id);
|
|
||||||
if (ok) { setRestoreTarget(null); afterMutation(); }
|
|
||||||
}}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onSuccess={afterMutation}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* ── Bulk archive ──────────────────────────────────────────────── */}
|
{/* ── Bulk archive ──────────────────────────────────────────────── */}
|
||||||
<ArchiveDialog
|
<ArchiveDialog
|
||||||
open={!!bulkArchiveIds}
|
open={!!bulkArchiveIds}
|
||||||
onOpenChange={(v) => !v && setBulkArchiveIds(null)}
|
onOpenChange={(v) => !v && setBulkArchiveIds(null)}
|
||||||
entity={bulkArchiveIds}
|
ids={bulkArchiveIds ?? []}
|
||||||
entityLabel={`${bulkArchiveIds?.length ?? 0} Task(s)`}
|
entityLabel="Task"
|
||||||
getName={() => `${bulkArchiveIds?.length ?? 0} task(s)`}
|
onArchive={({ ids }) => bulkArchiveTasks(taskListId, ids)}
|
||||||
onArchive={async () => {
|
|
||||||
const ok = await bulkArchiveTasks(taskListId, bulkArchiveIds);
|
|
||||||
if (ok) { setBulkArchiveIds(null); afterMutation(); }
|
|
||||||
}}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onSuccess={afterMutation}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* ── Bulk restore ──────────────────────────────────────────────── */}
|
{/* ── Bulk restore ──────────────────────────────────────────────── */}
|
||||||
<RestoreDialog
|
<RestoreDialog
|
||||||
open={!!bulkRestoreIds}
|
open={!!bulkRestoreIds}
|
||||||
onOpenChange={(v) => !v && setBulkRestoreIds(null)}
|
onOpenChange={(v) => !v && setBulkRestoreIds(null)}
|
||||||
entity={bulkRestoreIds}
|
ids={bulkRestoreIds ?? []}
|
||||||
entityLabel={`${bulkRestoreIds?.length ?? 0} Task(s)`}
|
entityLabel="Task"
|
||||||
getName={() => `${bulkRestoreIds?.length ?? 0} task(s)`}
|
onRestore={({ ids }) => bulkRestoreTasks(taskListId, ids)}
|
||||||
onRestore={async () => {
|
|
||||||
const ok = await bulkRestoreTasks(taskListId, bulkRestoreIds);
|
|
||||||
if (ok) { setBulkRestoreIds(null); afterMutation(); }
|
|
||||||
}}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onSuccess={afterMutation}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user