diff --git a/src/app/_components/table-instance-provider.tsx b/src/app/_components/table-instance-provider.tsx new file mode 100644 index 0000000..663c9f1 --- /dev/null +++ b/src/app/_components/table-instance-provider.tsx @@ -0,0 +1,42 @@ +"use client" + +import { createContext, useContext, useState } from "react" +import type { Table } from "@tanstack/react-table" + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +interface TableInstanceContextProps { + tableInstance: Table + setTableInstance: React.Dispatch>> +} + +const TableInstanceContext = createContext({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + tableInstance: {} as Table, + setTableInstance: () => {}, +}) + +export function useTableInstanceContext() { + const context = useContext(TableInstanceContext) + if (!context) { + throw new Error( + "useTableInstanceContext must be used within a TableInstanceProvider" + ) + } + return context +} + +export function TableInstanceProvider({ + table, + children, +}: { + table: Table + children: React.ReactNode +}) { + const [tableInstance, setTableInstance] = useState>(table) + + return ( + + {children} + + ) +} diff --git a/src/app/_components/tasks-table.tsx b/src/app/_components/tasks-table.tsx index 5de26aa..49c2459 100644 --- a/src/app/_components/tasks-table.tsx +++ b/src/app/_components/tasks-table.tsx @@ -10,6 +10,7 @@ import { DataTable } from "@/components/data-table/data-table" import type { getTasks, getViews } from "../_lib/queries" import { getPriorityIcon, getStatusIcon } from "../_lib/utils" +import { TableInstanceProvider } from "./table-instance-provider" import { getColumns } from "./tasks-table-columns" import { TasksTableFloatingBar } from "./tasks-table-floating-bar" import { TasksTableToolbarActions } from "./tasks-table-toolbar-actions" @@ -76,17 +77,19 @@ export function TasksTable({ tasksPromise, viewsPromise }: TasksTableProps) { }) return ( - } - > - + } > - - - + + + + + ) } diff --git a/src/components/data-table/advanced/data-table-advanced-toolbar.tsx b/src/components/data-table/advanced/data-table-advanced-toolbar.tsx index 5cc8edb..479c5e9 100644 --- a/src/components/data-table/advanced/data-table-advanced-toolbar.tsx +++ b/src/components/data-table/advanced/data-table-advanced-toolbar.tsx @@ -22,6 +22,7 @@ import UpdateViewForm from "./views/update-view-form" import { calcFilterParams, calcViewSearchParamsURL, + COLUMNS, getIsFiltered, } from "./views/utils" @@ -99,13 +100,26 @@ export function DataTableAdvancedToolbar({ const isFiltered = getIsFiltered(searchParams) - const currentView = views.find( - (view) => view.id === searchParams.get("viewId") - ) + const viewId = searchParams.get("viewId") + const currentView = views.find((view) => view.id === viewId) + const columns = table + .getVisibleFlatColumns() + .filter( + (column) => + typeof column.accessorFn !== "undefined" && column.getCanHide() + ) + .map((column) => column.id) const filterParams = calcFilterParams(selectedOptions, searchParams) - const isUpdated = !isEqual(currentView?.filterParams, filterParams) + const isColumnsUpdated = currentView + ? !isEqual(currentView?.columns, columns) + : !isEqual(COLUMNS, columns) + + const isDefaultViewUpdated = isFiltered || isColumnsUpdated + + const isUpdated = + !isEqual(currentView?.filterParams, filterParams) || isColumnsUpdated function resetToCurrentView() { if (!currentView) return @@ -114,6 +128,34 @@ export function DataTableAdvancedToolbar({ router.push(`${pathname}?${searchParamsURL}`) } + React.useEffect(() => { + if (isColumnsUpdated) { + setOpenFilterBuilder(true) + } + }, [isColumnsUpdated]) + + // Update visible columns when viewId is changed + React.useEffect(() => { + if (!currentView) { + return table.setColumnVisibility({}) + } + + table.setColumnVisibility(() => { + const invisibleColumns = COLUMNS.filter( + (column) => !currentView.columns?.includes(column) + ) + const newVisibilityState = invisibleColumns.reduce( + (acc, item) => { + acc[item] = false + return acc + }, + {} as Partial> + ) + return newVisibilityState + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [viewId]) + // Update table state when search params are changed React.useEffect(() => { const searchParamsObj = Object.fromEntries(searchParams) @@ -232,7 +274,7 @@ export function DataTableAdvancedToolbar({ )} - {isFiltered && !currentView && ( + {isDefaultViewUpdated && !currentView && ( )} diff --git a/src/components/data-table/advanced/views/create-view-form.tsx b/src/components/data-table/advanced/views/create-view-form.tsx index 516e5ea..0574164 100644 --- a/src/components/data-table/advanced/views/create-view-form.tsx +++ b/src/components/data-table/advanced/views/create-view-form.tsx @@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Separator } from "@/components/ui/separator" import { LoaderIcon } from "@/components/loader-icon" +import { useTableInstanceContext } from "@/app/_components/table-instance-provider" import { createView } from "@/app/_lib/actions" import type { FilterParams } from "@/app/_lib/validations" @@ -31,10 +32,20 @@ export function CreateViewForm({ const nameInputRef = useRef(null) + const { tableInstance } = useTableInstanceContext() + const [state, formAction] = useFormState(createView, { message: "", }) + const visibleColumns = tableInstance + .getVisibleFlatColumns() + .filter( + (column) => + typeof column.accessorFn !== "undefined" && column.getCanHide() + ) + .map((column) => column.id) + useEffect(() => { nameInputRef.current?.focus() }, []) @@ -76,6 +87,11 @@ export function CreateViewForm({ )}
+ + typeof column.accessorFn !== "undefined" && column.getCanHide() + ) + .map((column) => column.id) + useEffect(() => { if (state.status === "success") { toast.success(state.message) @@ -32,6 +43,11 @@ export default function UpdateViewForm({ + ( selectedOptions: DataTableFilterOption[], searchParams: ReadonlyURLSearchParams