diff --git a/compass/components/Table/ResourceTable.tsx b/compass/components/Table/ResourceTable.tsx new file mode 100644 index 0000000..a416273 --- /dev/null +++ b/compass/components/Table/ResourceTable.tsx @@ -0,0 +1,152 @@ +import { PageLayout } from "@/components/PageLayout"; +import { RowOpenAction } from "@/components/Table/RowOpenAction"; +import { RowOptionMenu } from "@/components/Table/RowOptionMenu"; +import { Table } from "@/components/Table/Table"; +import TagsInput from "@/components/TagsInput/Index"; +import Resource from "@/utils/models/Resource"; +import { createClient } from "@/utils/supabase/client"; + +import { Bars2Icon, BookmarkIcon } from "@heroicons/react/24/solid"; +import { ColumnDef, createColumnHelper } from "@tanstack/react-table"; +import { useEffect, useState } from "react"; + +export function ResourceTable({ resources }: { resources: Resource[] }) { + const columnHelper = createColumnHelper<Resource>(); + + const [data, setData] = useState<Resource[]>([...resources]); + + // TODO: Connect data manipulation methods to the database (deleteResource, hideResource, addResource) + const deleteUser = (userId: number) => { + console.log(data); + setData((currentData) => + currentData.filter((user) => user.id !== userId) + ); + }; + + const hideUser = (userId: number) => { + console.log(`Toggling visibility for user with ID: ${userId}`); + setData((currentData) => { + const newData = currentData + .map((user) => { + if (user.id === userId) { + return { ...user, visible: !user.visible }; + } + return user; + }) + .sort((a, b) => + a.visible === b.visible ? 0 : a.visible ? -1 : 1 + ); + + console.log(newData); + return newData; + }); + }; + + const addUser = () => { + setData([...data]); + }; + + const [presetOptions, setPresetOptions] = useState([ + "administrator", + "volunteer", + "employee", + ]); + const [tagColors, setTagColors] = useState(new Map()); + + const getTagColor = (tag: string) => { + if (!tagColors.has(tag)) { + const colors = [ + "bg-cyan-100", + "bg-blue-100", + "bg-green-100", + "bg-yellow-100", + "bg-purple-100", + ]; + const randomColor = + colors[Math.floor(Math.random() * colors.length)]; + setTagColors(new Map(tagColors).set(tag, randomColor)); + } + return tagColors.get(tag); + }; + + const handleRowUpdate = (updatedRow: Resource) => { + const dataIndex = data.findIndex((row) => row.id === updatedRow.id); + if (dataIndex !== -1) { + const updatedData = [...data]; + updatedData[dataIndex] = updatedRow; + setData(updatedData); + } + }; + + const columns: ColumnDef<Resource, any>[] = [ + columnHelper.display({ + id: "options", + cell: (props) => ( + <RowOptionMenu + onDelete={() => {}} + onHide={() => hideUser(props.row.original.id)} + /> + ), + }), + columnHelper.accessor("name", { + header: () => ( + <> + <Bars2Icon className="inline align-top h-4" /> Name + </> + ), + cell: (info) => ( + <RowOpenAction + title={info.getValue()} + rowData={info.row.original} + onRowUpdate={handleRowUpdate} + /> + ), + }), + columnHelper.accessor("link", { + header: () => ( + <> + <Bars2Icon className="inline align-top h-4" /> Link + </> + ), + cell: (info) => ( + <a + href={info.getValue()} + target={"_blank"} + className="ml-2 text-gray-500 underline hover:text-gray-400" + > + {info.getValue()} + </a> + ), + }), + columnHelper.accessor("program", { + header: () => ( + <> + <Bars2Icon className="inline align-top h-4" /> Program + </> + ), + cell: (info) => ( + <TagsInput presetValue={info.getValue()} /> + ), + }), + + columnHelper.accessor("summary", { + header: () => ( + <> + <Bars2Icon className="inline align-top h-4" /> Summary + </> + ), + cell: (info) => ( + <span className="ml-2 text-gray-500">{info.getValue()}</span> + ), + }), + ]; + + return ( + <div className="min-h-screen flex flex-col"> + {/* icon + title */} + <PageLayout title="Resources" icon={<BookmarkIcon />}> + <Table initialData={resources} columns={columns}/> + </PageLayout> + </div> + ); +} diff --git a/compass/components/Table/Table.tsx b/compass/components/Table/Table.tsx index ee11cbe..fb843fe 100644 --- a/compass/components/Table/Table.tsx +++ b/compass/components/Table/Table.tsx @@ -11,6 +11,8 @@ import { } from "@heroicons/react/24/solid"; import { rankItem } from "@tanstack/match-sorter-utils"; import Resource from "@/utils/models/Resource"; +import Service from "@/utils/models/Service"; +import User from "@/utils/models/User" // For search const fuzzyFilter = ( @@ -37,7 +39,39 @@ export const Table = ({ initialData, columns }: { initialData: Resource[], colum setData(sortedData); }, [initialData]); - const [data, setData] = useState<Resource[]>([...initialData]); + const [data, setData] = useState<(Resource | User | Service)[]>([...initialData]); + + // Data manipulation + // TODO: Connect data manipulation methods to the database (deleteResource, hideResource, addResource) + const deleteData = (dataId: number) => { + console.log(data); + setData((currentData) => + currentData.filter((data) => data.id !== dataId) + ); + }; + + const hideData = (dataId: number) => { + console.log(`Toggling visibility for data with ID: ${dataId}`); + setData((currentData) => { + const newData = currentData + .map((data) => { + if (data.id === dataId) { + return { ...data, visible: !data.visible }; + } + return data; + }) + .sort((a, b) => + a.visible === b.visible ? 0 : a.visible ? -1 : 1 + ); + + console.log(newData); + return newData; + }); + }; + + const addData = () => { + setData([...data]); + }; // Searching const [query, setQuery] = useState(""); @@ -54,7 +88,7 @@ export const Table = ({ initialData, columns }: { initialData: Resource[], colum // TODO: Filtering // TODO: Sorting - + const table = useReactTable({ columns, data, @@ -113,9 +147,9 @@ export const Table = ({ initialData, columns }: { initialData: Resource[], colum <tbody> {table.getRowModel().rows.map((row) => { // Individual row - const isUserVisible = row.original.visible; + const isDataVisible = row.original.visible; const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${ - !isUserVisible ? "bg-gray-200 text-gray-500" : "" + !isDataVisible ? "bg-gray-200 text-gray-500" : "" }`; return ( <tr className={rowClassNames} key={row.id}> @@ -141,7 +175,7 @@ export const Table = ({ initialData, columns }: { initialData: Resource[], colum <td className="p-3 border-y border-gray-200 text-gray-600 hover:bg-gray-50" colSpan={100} - onClick={addUser} + onClick={addData} > <span className="flex ml-1 text-gray-500"> <PlusIcon className="inline h-4 mr-1" />