mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-20 18:40:17 -04:00
refactored typing for tables. More work needs to be done to ensure tables are overall working properly
This commit is contained in:
parent
a57ee4963d
commit
7c8aa2d377
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import { Table } from "@/components/Table/Index"
|
import UserTable from "@/components/Table/UserTable";
|
||||||
import User from "@/utils/models/User";
|
import User from "@/utils/models/User";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ export default function Page() {
|
||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
{/* icon + title */}
|
{/* icon + title */}
|
||||||
<PageLayout title="Users" icon={<UsersIcon />}>
|
<PageLayout title="Users" icon={<UsersIcon />}>
|
||||||
<Table users={users} />
|
<UserTable data={users} setData={setUsers} />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import Sidebar from "@/components/Sidebar/Sidebar";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
|
||||||
import { createClient } from "@/utils/supabase/client";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import User, { Role } from "@/utils/models/User";
|
|
||||||
import Loading from "@/components/auth/Loading";
|
|
||||||
|
|
||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
|
||||||
const router = useRouter();
|
|
||||||
const [user, setUser] = useState<User>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getUser() {
|
|
||||||
const supabase = createClient();
|
|
||||||
|
|
||||||
const { data, error } = await supabase.auth.getUser();
|
|
||||||
|
|
||||||
console.log(data, error);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log("Accessed admin page but not logged in");
|
|
||||||
router.push("/auth/login");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userData = await fetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_HOST}/api/user?uuid=${data.user.id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const user: User = await userData.json();
|
|
||||||
|
|
||||||
if (user.role !== Role.ADMIN) {
|
|
||||||
console.log(
|
|
||||||
`Accessed admin page but incorrect permissions: ${user.username} ${user.role}`
|
|
||||||
);
|
|
||||||
router.push("/home");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser();
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex-row">
|
|
||||||
{user ? (
|
|
||||||
<div>
|
|
||||||
{/* button to open sidebar */}
|
|
||||||
<button
|
|
||||||
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
|
|
||||||
className={`fixed z-20 p-2 text-gray-500 hover:text-gray-800 left-0`}
|
|
||||||
aria-label={"Open sidebar"}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
!isSidebarOpen && (
|
|
||||||
<ChevronDoubleRightIcon className="h-5 w-5" />
|
|
||||||
) // Icon for closing the sidebar
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
{/* sidebar */}
|
|
||||||
<div
|
|
||||||
className={`absolute inset-y-0 left-0 transform ${
|
|
||||||
isSidebarOpen
|
|
||||||
? "translate-x-0"
|
|
||||||
: "-translate-x-full"
|
|
||||||
} w-64 transition duration-300 ease-in-out`}
|
|
||||||
>
|
|
||||||
<Sidebar
|
|
||||||
setIsSidebarOpen={setIsSidebarOpen}
|
|
||||||
name={user.username}
|
|
||||||
email={user.email}
|
|
||||||
isAdmin={user.role === Role.ADMIN}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* page ui */}
|
|
||||||
<div
|
|
||||||
className={`flex-1 transition duration-300 ease-in-out ${
|
|
||||||
isSidebarOpen ? "ml-64" : "ml-0"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Loading />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
|
||||||
import { Table } from "@/components/Table/Index"
|
|
||||||
import UserTable from "@/components/Table/UserIndex";
|
|
||||||
import User from "@/utils/models/User";
|
|
||||||
import { createClient } from "@/utils/supabase/client";
|
|
||||||
|
|
||||||
import { UsersIcon } from "@heroicons/react/24/solid";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getUser() {
|
|
||||||
const supabase = createClient();
|
|
||||||
|
|
||||||
const { data, error } = await supabase.auth.getUser();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log("Accessed admin page but not logged in");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userListData = await fetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_HOST}/api/user/all?uuid=${data.user.id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const users: User[] = await userListData.json();
|
|
||||||
|
|
||||||
setUsers(users);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen flex flex-col">
|
|
||||||
{/* icon + title */}
|
|
||||||
<PageLayout title="Users" icon={<UsersIcon />}>
|
|
||||||
<UserTable users={users} />
|
|
||||||
</PageLayout>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import Resource from "@/utils/models/Resource";
|
import Resource from "@/utils/models/Resource";
|
||||||
import ResourceTable from "@/components/Table/ResourceIndex";
|
import ResourceTable from "@/components/Table/ResourceTable";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
|
||||||
import { BookmarkIcon } from "@heroicons/react/24/solid";
|
import { BookmarkIcon } from "@heroicons/react/24/solid";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import ServiceTable from "@/components/Table/ServiceIndex";
|
import ServiceTable from "@/components/Table/ServiceTable";
|
||||||
import Service from "@/utils/models/Service";
|
import Service from "@/utils/models/Service";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
import { Bars2Icon } from "@heroicons/react/24/solid";
|
import { Bars2Icon } from "@heroicons/react/24/solid";
|
||||||
import { useState } from "react";
|
import { Dispatch, SetStateAction, useState } from "react";
|
||||||
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
||||||
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
||||||
import { Table } from "@/components/Table/Table";
|
|
||||||
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
||||||
|
import Table from "@/components/Table/Table";
|
||||||
import TagsInput from "@/components/TagsInput/Index";
|
import TagsInput from "@/components/TagsInput/Index";
|
||||||
import Resource from "@/utils/models/Resource";
|
import Resource from "@/utils/models/Resource";
|
||||||
import { DataPoint } from "@/components/Table/Table";
|
|
||||||
|
type ResourceTableProps = {
|
||||||
|
data: Resource[],
|
||||||
|
setData: Dispatch<SetStateAction<Resource[]>>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table componenet used for displaying resources
|
* Table componenet used for displaying resources
|
||||||
* @param props.resources List of resources to be displayed by the table
|
* @param props.resources List of resources to be displayed by the table
|
||||||
*/
|
*/
|
||||||
export default function ResourceTable({ resources }: { resources: Resource[] }) {
|
export default function ResourceTable({ data, setData }: ResourceTableProps ) {
|
||||||
const columnHelper = createColumnHelper<Resource>();
|
const columnHelper = createColumnHelper<Resource>();
|
||||||
const [data, setData] = useState<DataPoint[]>([...resources]);
|
|
||||||
|
|
||||||
// TODO: Update preset options for resources
|
// TODO: Update preset options for resources
|
||||||
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
||||||
|
@ -23,7 +26,7 @@ export default function ResourceTable({ resources }: { resources: Resource[] })
|
||||||
"employee",
|
"employee",
|
||||||
])
|
])
|
||||||
|
|
||||||
const handleRowUpdate = (updatedRow: DataPoint) => {
|
const handleRowUpdate = (updatedRow: Resource) => {
|
||||||
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
||||||
if (dataIndex !== -1) {
|
if (dataIndex !== -1) {
|
||||||
const updatedData = [...data];
|
const updatedData = [...data];
|
|
@ -1,20 +1,24 @@
|
||||||
import { Bars2Icon } from "@heroicons/react/24/solid";
|
import { Bars2Icon } from "@heroicons/react/24/solid";
|
||||||
import { useState } from "react";
|
import { Dispatch, SetStateAction } from "react";
|
||||||
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
||||||
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
||||||
import { Table } from "@/components/Table/Table";
|
import Table from "@/components/Table/Table";
|
||||||
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
||||||
import TagsInput from "@/components/TagsInput/Index";
|
import TagsInput from "@/components/TagsInput/Index";
|
||||||
import Service from "@/utils/models/Service";
|
import Service from "@/utils/models/Service";
|
||||||
import { DataPoint } from "@/components/Table/Table";
|
import DataPoint from "@/utils/models/DataPoint";
|
||||||
|
|
||||||
|
type ServiceTableProps = {
|
||||||
|
data: Service[],
|
||||||
|
setData: Dispatch<SetStateAction<Service[]>>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table componenet used for displaying services
|
* Table componenet used for displaying services
|
||||||
* @param props.services List of services to be displayed by the table
|
* @param props.services List of services to be displayed by the table
|
||||||
*/
|
*/
|
||||||
export default function ServiceTable({ services }: { services: Service[] }) {
|
export default function ServiceTable({ data, setData }: ServiceTableProps ) {
|
||||||
const columnHelper = createColumnHelper<Service>();
|
const columnHelper = createColumnHelper<Service>();
|
||||||
const [data, setData] = useState<DataPoint[]>([...services]);
|
|
||||||
|
|
||||||
// TODO: Update preset options for services
|
// TODO: Update preset options for services
|
||||||
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
||||||
|
@ -23,7 +27,7 @@ export default function ServiceTable({ services }: { services: Service[] }) {
|
||||||
"employee",
|
"employee",
|
||||||
])
|
])
|
||||||
|
|
||||||
const handleRowUpdate = (updatedRow: DataPoint) => {
|
const handleRowUpdate = (updatedRow: Service) => {
|
||||||
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
||||||
if (dataIndex !== -1) {
|
if (dataIndex !== -1) {
|
||||||
const updatedData = [...data];
|
const updatedData = [...data];
|
||||||
|
@ -101,5 +105,5 @@ export default function ServiceTable({ services }: { services: Service[] }) {
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
return <Table data={data} setData={setData} columns={columns} />
|
return <Table<Service> data={data} setData={setData} columns={columns} />
|
||||||
};
|
};
|
|
@ -17,17 +17,13 @@ import {
|
||||||
import { TableAction } from "./TableAction";
|
import { TableAction } from "./TableAction";
|
||||||
import { PlusIcon } from "@heroicons/react/24/solid";
|
import { PlusIcon } from "@heroicons/react/24/solid";
|
||||||
import { rankItem } from "@tanstack/match-sorter-utils";
|
import { rankItem } from "@tanstack/match-sorter-utils";
|
||||||
import Resource from "@/utils/models/Resource";
|
import DataPoint from "@/utils/models/DataPoint";
|
||||||
import Service from "@/utils/models/Service";
|
|
||||||
import User from "@/utils/models/User";
|
|
||||||
import { RowOptionMenu } from "./RowOptionMenu";
|
import { RowOptionMenu } from "./RowOptionMenu";
|
||||||
|
|
||||||
export type DataPoint = Resource | User | Service;
|
type TableProps<T extends DataPoint> = {
|
||||||
|
data: T[],
|
||||||
type TableProps = {
|
setData: Dispatch<SetStateAction<T[]>>,
|
||||||
data: DataPoint[],
|
columns: ColumnDef<T, any>[]
|
||||||
setData: Dispatch<SetStateAction<DataPoint[]>>
|
|
||||||
columns: ColumnDef<any, any>[]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For search
|
// For search
|
||||||
|
@ -53,15 +49,14 @@ const fuzzyFilter = (
|
||||||
* @param props.setData State setter to be used for data manipulation methods
|
* @param props.setData State setter to be used for data manipulation methods
|
||||||
* @param props.columns Column definitions made with Tanstack columnHelper
|
* @param props.columns Column definitions made with Tanstack columnHelper
|
||||||
*/
|
*/
|
||||||
export const Table = ({ data, setData, columns }: TableProps) => {
|
export default function Table<T extends DataPoint>({ data, setData, columns }: TableProps<T>) {
|
||||||
const columnHelper = createColumnHelper<DataPoint>();
|
const columnHelper = createColumnHelper<T>();
|
||||||
useEffect(() => {
|
|
||||||
const sortedData = [...data].sort((a, b) =>
|
|
||||||
a.visible === b.visible ? 0 : a.visible ? -1 : 1
|
|
||||||
);
|
|
||||||
setData(sortedData);
|
|
||||||
}, [data, setData]);
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setData(prevData => prevData.sort((a, b) =>
|
||||||
|
a.visible === b.visible ? 0 : a.visible ? -1 : 1
|
||||||
|
))
|
||||||
|
}, [setData]);
|
||||||
|
|
||||||
// Data manipulation
|
// Data manipulation
|
||||||
// TODO: Connect data manipulation methods to the database (deleteData, hideData, addData)
|
// TODO: Connect data manipulation methods to the database (deleteData, hideData, addData)
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
import { ArrowDownCircleIcon, AtSymbolIcon, Bars2Icon } from "@heroicons/react/24/solid";
|
import { ArrowDownCircleIcon, AtSymbolIcon, Bars2Icon } from "@heroicons/react/24/solid";
|
||||||
import { useState } from "react";
|
import { Dispatch, SetStateAction } from "react";
|
||||||
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
import useTagsHandler from "@/components/TagsInput/TagsHandler";
|
||||||
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
|
||||||
import { Table } from "@/components/Table/Table";
|
import Table from "@/components/Table/Table";
|
||||||
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
import { RowOpenAction } from "@/components/Table/RowOpenAction";
|
||||||
import TagsInput from "@/components/TagsInput/Index";
|
import TagsInput from "@/components/TagsInput/Index";
|
||||||
import User from "@/utils/models/User";
|
import User from "@/utils/models/User";
|
||||||
import { DataPoint } from "@/components/Table/Table";
|
|
||||||
|
type UserTableProps = {
|
||||||
|
data: User[],
|
||||||
|
setData: Dispatch<SetStateAction<User[]>>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table componenet used for displaying users
|
* Table componenet used for displaying users
|
||||||
* @param props.users List of users to be displayed by the table
|
* @param props.users List of users to be displayed by the table
|
||||||
*/
|
*/
|
||||||
export default function UserTable({ users }: { users: User[] }) {
|
export default function UserTable({ data, setData }: UserTableProps ) {
|
||||||
const columnHelper = createColumnHelper<User>();
|
const columnHelper = createColumnHelper<User>();
|
||||||
const [data, setData] = useState<DataPoint[]>([...users]);
|
|
||||||
|
|
||||||
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
const { presetOptions, setPresetOptions, getTagColor } = useTagsHandler([
|
||||||
"administrator",
|
"administrator",
|
||||||
|
@ -22,7 +25,7 @@ export default function UserTable({ users }: { users: User[] }) {
|
||||||
"employee",
|
"employee",
|
||||||
])
|
])
|
||||||
|
|
||||||
const handleRowUpdate = (updatedRow: DataPoint) => {
|
const handleRowUpdate = (updatedRow: User) => {
|
||||||
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
const dataIndex = data.findIndex((row) => row.id === updatedRow.id);
|
||||||
if (dataIndex !== -1) {
|
if (dataIndex !== -1) {
|
||||||
const updatedData = [...data];
|
const updatedData = [...data];
|
||||||
|
@ -93,5 +96,5 @@ export default function UserTable({ users }: { users: User[] }) {
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
return <Table data={data} setData={setData} columns={columns}/>
|
return <Table<User> data={data} setData={setData} columns={columns}/>
|
||||||
}
|
}
|
6
compass/utils/models/DataPoint.ts
Normal file
6
compass/utils/models/DataPoint.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
interface DataPoint {
|
||||||
|
id: number;
|
||||||
|
visible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DataPoint;
|
|
@ -1,6 +1,7 @@
|
||||||
import { Program } from "./User";
|
import { Program } from "./User";
|
||||||
|
import DataPoint from "./DataPoint";
|
||||||
|
|
||||||
export default interface Resource {
|
export default interface Resource extends DataPoint {
|
||||||
id: number;
|
id: number;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Program } from "./User";
|
import { Program } from "./User";
|
||||||
|
import DataPoint from "./DataPoint";
|
||||||
|
|
||||||
export default interface Service {
|
export default interface Service extends DataPoint {
|
||||||
id: number;
|
id: number;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import DataPoint from "./DataPoint";
|
||||||
|
|
||||||
export enum Program {
|
export enum Program {
|
||||||
ECONOMIC = "ECONOMIC",
|
ECONOMIC = "ECONOMIC",
|
||||||
DOMESTIC = "DOMESTIC",
|
DOMESTIC = "DOMESTIC",
|
||||||
|
@ -10,7 +12,7 @@ export enum Role {
|
||||||
VOLUNTEER = "VOLUNTEER",
|
VOLUNTEER = "VOLUNTEER",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default interface User {
|
export default interface User extends DataPoint {
|
||||||
id: number;
|
id: number;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user