mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-06 20:50:17 -04:00
Added drawer
This commit is contained in:
parent
80760c1f14
commit
6f18419a74
37
compass/app/admin/layout.tsx
Normal file
37
compass/app/admin/layout.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
"use client"
|
||||
|
||||
import Sidebar from '@/components/resource/Sidebar';
|
||||
import React, { useState } from 'react';
|
||||
import { ChevronDoubleRightIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex-row">
|
||||
{/* 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} />
|
||||
</div>
|
||||
{/* page ui */}
|
||||
<div className={`flex-1 transition duration-300 ease-in-out ${isSidebarOpen ? 'ml-64' : 'ml-0'}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,90 +1,21 @@
|
|||
"use client";
|
||||
// import Table from "@/components/Table";
|
||||
import {
|
||||
ColumnDef,
|
||||
createColumnHelper,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useState } from "react";
|
||||
import usersImport from "./users.json";
|
||||
|
||||
const usersExample = usersImport as unknown as User[];
|
||||
|
||||
type User = {
|
||||
id: number;
|
||||
created_at: any;
|
||||
username: string;
|
||||
role: "ADMIN" | "EMPLOYEE" | "VOLUNTEER";
|
||||
email: string;
|
||||
program: "DOMESTIC" | "ECONOMIC" | "COMMUNITY";
|
||||
experience: number;
|
||||
group?: string;
|
||||
};
|
||||
|
||||
import { PageLayout } from "@/components/admin/PageLayout";
|
||||
import { Table } from "@/components/admin/Table/Index";
|
||||
|
||||
import { UsersIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
|
||||
|
||||
|
||||
import { BookmarkIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
export default function Page() {
|
||||
const columnHelper = createColumnHelper<User>();
|
||||
|
||||
const columns = [
|
||||
columnHelper.accessor("username", {
|
||||
cell: (info) => info.getValue(),
|
||||
}),
|
||||
columnHelper.accessor("role", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
columnHelper.accessor("email", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
columnHelper.accessor("program", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
];
|
||||
|
||||
const [data, setData] = useState<User[]>([...usersExample]);
|
||||
|
||||
const table = useReactTable({
|
||||
columns,
|
||||
data,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
{/* icon + title */}
|
||||
<PageLayout title="Resources" icon={<BookmarkIcon />}>
|
||||
<table>
|
||||
<thead>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<th key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
<tr key={row.id}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<PageLayout title="Users" icon={<UsersIcon />}>
|
||||
<Table />
|
||||
</PageLayout>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
// pages/index.tsx
|
||||
"use client";
|
||||
|
||||
import Button from '@/components/Button';
|
||||
import Input from '@/components/Input'
|
||||
import InlineLink from '@/components/InlineLink';
|
||||
import Paper from '@/components/auth/Paper';
|
||||
// import { Metadata } from 'next'
|
||||
import Image from 'next/image';
|
||||
import {ChangeEvent, useState} from "react";
|
||||
|
||||
// export const metadata: Metadata = {
|
||||
// title: 'Login',
|
||||
// }
|
||||
|
||||
export default function Page() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEmail(event.currentTarget.value);
|
||||
console.log("email " + email);
|
||||
}
|
||||
|
||||
const handlePasswordChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(event.currentTarget.value);
|
||||
console.log("password " + password)
|
||||
}
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
// Priority: Incorrect combo > Missing email > Missing password
|
||||
|
||||
if (password.trim().length === 0) {
|
||||
setError("Please enter your password.")
|
||||
}
|
||||
// This shouldn't happen, <input type="email"> already provides validation, but just in case.
|
||||
if (email.trim().length === 0) {
|
||||
setError("Please enter your email.")
|
||||
}
|
||||
// Placeholder for incorrect email + password combo.
|
||||
if (email === "incorrect@gmail.com" && password) {
|
||||
setError("Incorrect password.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Paper>
|
||||
<form className="mb-0 m-auto mt-6 space-y-4 rounded-lg p-4 shadow-lg sm:p-6 lg:p-8 bg-white max-w-xl">
|
||||
<Image
|
||||
src="/logo.png"
|
||||
alt='Compass Center logo.'
|
||||
width={100}
|
||||
height={91}
|
||||
/>
|
||||
<h1 className='font-bold text-xl text-purple-800'>Login</h1>
|
||||
<div className="mb-4">
|
||||
<Input type='email' title="Email" placeholder="janedoe@gmail.com" onChange={handleEmailChange} />
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<Input type='password' title="Password" onChange={handlePasswordChange} />
|
||||
</div>
|
||||
<div className="flex flex-col items-left space-y-4">
|
||||
<InlineLink href="/forgot_password">
|
||||
Forgot password?
|
||||
</InlineLink>
|
||||
<Button onClick={handleClick}>
|
||||
Login
|
||||
</Button>
|
||||
<div className="text-center text-red-600" hidden={!error}>
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<p className="text-center mt-6 text-gray-500 text-xs">
|
||||
© 2024 Compass Center
|
||||
</p>
|
||||
</Paper>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
// pages/index.tsx
|
||||
"use client";
|
||||
|
||||
|
||||
import Drawer from '@/components/page/Drawer';
|
||||
// import { Metadata } from 'next'
|
||||
import {ChangeEvent, useState} from "react";
|
||||
|
||||
// export const metadata: Metadata = {
|
||||
// title: 'Login',
|
||||
// }
|
||||
|
||||
export default function Page() {
|
||||
const [pageContent, setPageContent] = useState("")
|
||||
|
||||
const handleDrawerContentChange = (newContent) => {
|
||||
setPageContent(newContent);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="text-2xl font-bold text-gray-700 sm:text-3xl">Resources</h1>
|
||||
<Drawer title="My Drawer Title" editableContent={pageContent} onSave={handleDrawerContentChange}>{pageContent}</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -15,7 +15,7 @@ export const PageLayout: React.FC<PageLayoutProps> = ({ icon, title, children })
|
|||
</div>
|
||||
</div>
|
||||
{/* data */}
|
||||
<div>
|
||||
<div className="px-8 py-8">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
91
compass/components/admin/Table/Index.tsx
Normal file
91
compass/components/admin/Table/Index.tsx
Normal file
|
@ -0,0 +1,91 @@
|
|||
// for showcasing to compass
|
||||
|
||||
import usersImport from "./users.json";
|
||||
import {
|
||||
ColumnDef,
|
||||
createColumnHelper,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useState } from "react";
|
||||
import { RowAction } from "./RowAction";
|
||||
import { TableAction } from "./TableAction";
|
||||
|
||||
const usersExample = usersImport as unknown as User[];
|
||||
|
||||
type User = {
|
||||
id: number;
|
||||
created_at: any;
|
||||
username: string;
|
||||
role: "ADMIN" | "EMPLOYEE" | "VOLUNTEER";
|
||||
email: string;
|
||||
program: "DOMESTIC" | "ECONOMIC" | "COMMUNITY";
|
||||
experience: number;
|
||||
group?: string;
|
||||
};
|
||||
|
||||
|
||||
export const Table = () => {
|
||||
const columnHelper = createColumnHelper<User>();
|
||||
|
||||
const columns = [
|
||||
columnHelper.accessor("username", {
|
||||
cell: (info) => <RowAction title={info.getValue()} />,
|
||||
}),
|
||||
columnHelper.accessor("role", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
columnHelper.accessor("email", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
columnHelper.accessor("program", {
|
||||
cell: (info) => info.renderValue(),
|
||||
}),
|
||||
];
|
||||
|
||||
const [data, setData] = useState<User[]>([...usersExample]);
|
||||
|
||||
const table = useReactTable({
|
||||
columns,
|
||||
data,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
});
|
||||
|
||||
return(
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row justify-end">
|
||||
<TableAction />
|
||||
</div>
|
||||
<table className="w-full text-xs text-left rtl:text-right">
|
||||
<thead className="text-xs text-gray-500 capitalize">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<th scope="col" className="p-3 border-gray-200 border-y font-medium" key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody className="">
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
<tr className="text-gray-800 border-y lowercase hover:bg-gray-50" key={row.id}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td className="py-2 px-2" key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
21
compass/components/admin/Table/RowAction.tsx
Normal file
21
compass/components/admin/Table/RowAction.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import Drawer from "@/components/page/Drawer";
|
||||
import {ChangeEvent, useState} from "react";
|
||||
|
||||
export const RowAction = ({ title }) => {
|
||||
const [pageContent, setPageContent] = useState("")
|
||||
|
||||
const handleDrawerContentChange = (newContent) => {
|
||||
setPageContent(newContent);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="font-semibold group flex flex-row items-center justify-between pr-2">
|
||||
{title}
|
||||
<span >
|
||||
<Drawer title="My Drawer Title" editableContent={pageContent} onSave={handleDrawerContentChange}>{pageContent}</Drawer>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
12
compass/components/admin/Table/TableAction.tsx
Normal file
12
compass/components/admin/Table/TableAction.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { MagnifyingGlassIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
export const TableAction = () => {
|
||||
return (
|
||||
<div className="w-40 flex flex-row items-center justify-between text-xs font-medium text-gray-500 p-2">
|
||||
<span>Filter</span>
|
||||
<span>Sort</span>
|
||||
<span className="w-4 h-4"><MagnifyingGlassIcon /></span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -44,7 +44,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({ title, children, onSave, edita
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={toggleDrawer}>{isOpen ? "Close" : "Open"} Drawer</Button>
|
||||
<button className="ml-2 uppercase opacity-0 group-hover:opacity-100 text-gray-500 font-medium border border-gray-200 bg-white shadow hover:bg-gray-50 p-2 rounded-md" onClick={toggleDrawer}>Open</button>
|
||||
<div className={drawerClassName}>
|
||||
<div className="flex items-center justify-between p-4 border-b">
|
||||
<h2>{title}</h2>
|
||||
|
|
Loading…
Reference in New Issue
Block a user