mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-17 17:30:17 -04:00
Restructure data
This commit is contained in:
commit
150dde1b0a
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Sidebar from "@/components/resource/Sidebar";
|
import Sidebar from "@/components/Sidebar/Sidebar";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
@ -80,7 +80,7 @@ export default function RootLayout({
|
||||||
setIsSidebarOpen={setIsSidebarOpen}
|
setIsSidebarOpen={setIsSidebarOpen}
|
||||||
name={user.username}
|
name={user.username}
|
||||||
email={user.email}
|
email={user.email}
|
||||||
admin={user.role === Role.ADMIN}
|
isAdmin={user.role === Role.ADMIN}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* page ui */}
|
{/* page ui */}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import User from "@/utils/models/User";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
|
@ -10,5 +11,14 @@ export async function GET(request: Request) {
|
||||||
|
|
||||||
const data = await fetch(`${apiEndpoint}?user_id=${uuid}`);
|
const data = await fetch(`${apiEndpoint}?user_id=${uuid}`);
|
||||||
|
|
||||||
return NextResponse.json(await data.json(), { status: data.status });
|
const userData: User[] = await data.json();
|
||||||
|
// TODO: Remove make every user visible
|
||||||
|
|
||||||
|
const users = userData.map((user: User) => {
|
||||||
|
user.visible = true;
|
||||||
|
|
||||||
|
return user;
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(users, { status: data.status });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
import Sidebar from "@/components/resource/Sidebar";
|
import Sidebar from "@/components/Sidebar/Sidebar";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
@ -69,7 +69,7 @@ export default function RootLayout({
|
||||||
name={user.username}
|
name={user.username}
|
||||||
email={user.email}
|
email={user.email}
|
||||||
setIsSidebarOpen={setIsSidebarOpen}
|
setIsSidebarOpen={setIsSidebarOpen}
|
||||||
admin={user.role === Role.ADMIN}
|
isAdmin={user.role === Role.ADMIN}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* page ui */}
|
{/* page ui */}
|
||||||
|
|
247
compass/components/Drawer/Drawer.tsx
Normal file
247
compass/components/Drawer/Drawer.tsx
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
import { FunctionComponent, ReactNode } from "react";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { ChevronDoubleLeftIcon } from "@heroicons/react/24/solid";
|
||||||
|
import {
|
||||||
|
StarIcon as SolidStarIcon,
|
||||||
|
EnvelopeIcon,
|
||||||
|
UserIcon,
|
||||||
|
} from "@heroicons/react/24/solid";
|
||||||
|
import {
|
||||||
|
ArrowsPointingOutIcon,
|
||||||
|
ArrowsPointingInIcon,
|
||||||
|
StarIcon as OutlineStarIcon,
|
||||||
|
ListBulletIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
|
import TagsInput from "../TagsInput/Index";
|
||||||
|
|
||||||
|
type DrawerProps = {
|
||||||
|
title: string;
|
||||||
|
children: ReactNode;
|
||||||
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
|
type?: "button" | "submit" | "reset"; // specify possible values for type
|
||||||
|
disabled?: boolean;
|
||||||
|
editableContent?: any;
|
||||||
|
onSave?: (content: any) => void;
|
||||||
|
rowContent?: any;
|
||||||
|
onRowUpdate?: (content: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface EditContent {
|
||||||
|
content: string;
|
||||||
|
isEditing: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Drawer: FunctionComponent<DrawerProps> = ({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
onSave,
|
||||||
|
editableContent,
|
||||||
|
rowContent,
|
||||||
|
onRowUpdate,
|
||||||
|
}) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isFull, setIsFull] = useState(false);
|
||||||
|
const [isFavorite, setIsFavorite] = useState(false);
|
||||||
|
const [tempRowContent, setTempRowContent] = useState(rowContent);
|
||||||
|
|
||||||
|
const handleTempRowContentChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
console.log(name);
|
||||||
|
console.log(value);
|
||||||
|
setTempRowContent((prevContent) => ({
|
||||||
|
...prevContent,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEnterPress = (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
// Update the rowContent with the temporaryRowContent
|
||||||
|
if (onRowUpdate) {
|
||||||
|
onRowUpdate(tempRowContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleDrawer = () => {
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
if (isFull) {
|
||||||
|
setIsFull(!isFull);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleDrawerFullScreen = () => setIsFull(!isFull);
|
||||||
|
|
||||||
|
const toggleFavorite = () => setIsFavorite(!isFavorite);
|
||||||
|
|
||||||
|
const drawerClassName = `fixed top-0 right-0 w-1/2 h-full bg-white transform ease-in-out duration-300 z-20 ${
|
||||||
|
isOpen ? "translate-x-0 shadow-xl" : "translate-x-full"
|
||||||
|
} ${isFull ? "w-full" : "w-1/2"}`;
|
||||||
|
|
||||||
|
const iconComponent = isFull ? (
|
||||||
|
<ArrowsPointingInIcon className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<ArrowsPointingOutIcon className="h-5 w-5" />
|
||||||
|
);
|
||||||
|
|
||||||
|
const favoriteIcon = isFavorite ? (
|
||||||
|
<SolidStarIcon className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<OutlineStarIcon className="h-5 w-5" />
|
||||||
|
);
|
||||||
|
|
||||||
|
const [presetOptions, setPresetOptions] = useState([
|
||||||
|
"administrator",
|
||||||
|
"volunteer",
|
||||||
|
"employee",
|
||||||
|
]);
|
||||||
|
const [rolePresetOptions, setRolePresetOptions] = useState([
|
||||||
|
"domestic",
|
||||||
|
"community",
|
||||||
|
"economic",
|
||||||
|
]);
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
className={
|
||||||
|
"ml-2 text-xs 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>
|
||||||
|
<div className={drawerClassName}>
|
||||||
|
<div className="flex items-center justify-between p-4">
|
||||||
|
<div className="flex flex-row items-center justify-between space-x-2">
|
||||||
|
<span className="h-5 text-purple-200 w-5">
|
||||||
|
<UserIcon />
|
||||||
|
</span>
|
||||||
|
<h2 className="text-lg text-gray-800 font-semibold">
|
||||||
|
{rowContent.username}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={toggleFavorite}
|
||||||
|
className="py-2 text-gray-500 hover:text-gray-800 mr-2"
|
||||||
|
>
|
||||||
|
{favoriteIcon}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={toggleDrawerFullScreen}
|
||||||
|
className="py-2 text-gray-500 hover:text-gray-800 mr-2"
|
||||||
|
>
|
||||||
|
{iconComponent}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={toggleDrawer}
|
||||||
|
className="py-2 text-gray-500 hover:text-gray-800"
|
||||||
|
>
|
||||||
|
<ChevronDoubleLeftIcon className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<table className="p-4">
|
||||||
|
<tbody className="items-center">
|
||||||
|
<tr className="w-full text-xs items-center flex flex-row justify-between">
|
||||||
|
<div className="flex flex-row space-x-2 text-gray-500 items-center">
|
||||||
|
<td>
|
||||||
|
<UserIcon className="h-4 w-4" />
|
||||||
|
</td>
|
||||||
|
<td className="w-32">Username</td>
|
||||||
|
</div>
|
||||||
|
<td className="w-3/4 w-3/4 p-2 pl-0">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
value={tempRowContent.username}
|
||||||
|
onChange={handleTempRowContentChange}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
|
className="ml-2 w-full p-1 focus:outline-gray-200 hover:bg-gray-50"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="w-full text-xs items-center flex flex-row justify-between">
|
||||||
|
<div className="flex flex-row space-x-2 text-gray-500 items-center">
|
||||||
|
<td>
|
||||||
|
<ListBulletIcon className="h-4 w-4" />
|
||||||
|
</td>
|
||||||
|
<td className="w-32">Role</td>
|
||||||
|
</div>
|
||||||
|
<td className="w-3/4 hover:bg-gray-50">
|
||||||
|
<TagsInput
|
||||||
|
presetValue={tempRowContent.role}
|
||||||
|
presetOptions={presetOptions}
|
||||||
|
setPresetOptions={setPresetOptions}
|
||||||
|
getTagColor={getTagColor}
|
||||||
|
setTagColors={setTagColors}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="w-full text-xs items-center flex flex-row justify-between">
|
||||||
|
<div className="flex flex-row space-x-2 text-gray-500 items-center">
|
||||||
|
<td>
|
||||||
|
<EnvelopeIcon className="h-4 w-4" />
|
||||||
|
</td>
|
||||||
|
<td className="w-32">Email</td>
|
||||||
|
</div>
|
||||||
|
<td className="w-3/4 p-2 pl-0">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="email"
|
||||||
|
value={tempRowContent.email}
|
||||||
|
onChange={handleTempRowContentChange}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
|
className="ml-2 w-80 p-1 font-normal hover:text-gray-400 focus:outline-gray-200 hover:bg-gray-50 underline text-gray-500"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="w-full text-xs items-center flex flex-row justify-between">
|
||||||
|
<div className="flex flex-row space-x-2 text-gray-500 items-center">
|
||||||
|
<td>
|
||||||
|
<ListBulletIcon className="h-4 w-4" />
|
||||||
|
</td>
|
||||||
|
<td className="w-32">Type of Program</td>
|
||||||
|
</div>
|
||||||
|
<td className="w-3/4 hover:bg-gray-50">
|
||||||
|
{/* {rowContent.program} */}
|
||||||
|
<TagsInput
|
||||||
|
presetValue={tempRowContent.program}
|
||||||
|
presetOptions={rolePresetOptions}
|
||||||
|
setPresetOptions={setRolePresetOptions}
|
||||||
|
getTagColor={getTagColor}
|
||||||
|
setTagColors={setTagColors}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Drawer;
|
|
@ -7,20 +7,20 @@ import {
|
||||||
BookOpenIcon,
|
BookOpenIcon,
|
||||||
} from "@heroicons/react/24/solid";
|
} from "@heroicons/react/24/solid";
|
||||||
import { SidebarItem } from "./SidebarItem";
|
import { SidebarItem } from "./SidebarItem";
|
||||||
import { UserProfile } from "./UserProfile";
|
import { UserProfile } from "../resource/UserProfile";
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
setIsSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
admin: boolean;
|
isAdmin: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Sidebar: React.FC<SidebarProps> = ({
|
const Sidebar: React.FC<SidebarProps> = ({
|
||||||
setIsSidebarOpen,
|
setIsSidebarOpen,
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
admin,
|
isAdmin: admin,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-64 h-full border border-gray-200 bg-gray-50 px-4">
|
<div className="w-64 h-full border border-gray-200 bg-gray-50 px-4">
|
|
@ -1,42 +0,0 @@
|
||||||
import { Component } from "react";
|
|
||||||
|
|
||||||
// interface TableHeader {
|
|
||||||
// title: string,
|
|
||||||
// type: string
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface TableRow {
|
|
||||||
// [key: string]: any,
|
|
||||||
// }
|
|
||||||
interface TableProps {
|
|
||||||
headersData: string[];
|
|
||||||
data: { [key: string]: any }[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const Table: React.FC<TableProps> = ({ headersData, data }) => {
|
|
||||||
const headers = headersData.map((header, i) => {
|
|
||||||
return <th key={"header-" + i}>{header}</th>;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
const rows = data.map((item) => {
|
|
||||||
const row = headersData.map((key) => {
|
|
||||||
return <td key={"item-" + item.id + key}>{item[key]}</td>;
|
|
||||||
});
|
|
||||||
return <tr key={"item-" + item.id}>{row}</tr>;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>{headers}</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>{rows}</tbody>
|
|
||||||
</table>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Table;
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* An extension of TableCell.tsx that includes an "open" button and the drawer.
|
/* An extension of TableCell.tsx that includes an "open" button and the drawer.
|
||||||
For cells in the "primary" (or first) column of the table. */
|
For cells in the "primary" (or first) column of the table. */
|
||||||
import Drawer from "@/components/page/Drawer";
|
import Drawer from "@/components/Drawer/Drawer";
|
||||||
import { TableCell } from "./TableCell";
|
import { TableCell } from "./TableCell";
|
||||||
import { SetStateAction, useState } from "react";
|
import { SetStateAction, useState } from "react";
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Drawer from "@/components/page/Drawer";
|
import Drawer from "@/components/Drawer/Drawer";
|
||||||
import { ChangeEvent, useState } from "react";
|
import { ChangeEvent, useState } from "react";
|
||||||
|
|
||||||
export const RowOpenAction = ({ title, rowData, onRowUpdate }) => {
|
export const RowOpenAction = ({ title, rowData, onRowUpdate }) => {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const RowOptionMenu = ({ onDelete, onHide }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
className="align-center"
|
className="items-end"
|
||||||
onClick={() => setMenuOpen(!menuOpen)}
|
onClick={() => setMenuOpen(!menuOpen)}
|
||||||
>
|
>
|
||||||
<EllipsisVerticalIcon className="h-4" />
|
<EllipsisVerticalIcon className="h-4" />
|
||||||
|
|
|
@ -118,7 +118,7 @@ const TagsInput: React.FC<TagsInputProps> = ({
|
||||||
<TagsArray handleDelete={handleDeleteTag} tags={tags} />
|
<TagsArray handleDelete={handleDeleteTag} tags={tags} />
|
||||||
) : (
|
) : (
|
||||||
<div ref={dropdown}>
|
<div ref={dropdown}>
|
||||||
<div className="absolute w-64 z-50 -ml-3 -mt-7">
|
<div className="absolute w-64 z-50 ml-1 mt-5">
|
||||||
<div className="rounded-md border border-gray-200 shadow">
|
<div className="rounded-md border border-gray-200 shadow">
|
||||||
<div className="flex flex-wrap rounded-t-md items-center gap-2 bg-gray-50 p-2">
|
<div className="flex flex-wrap rounded-t-md items-center gap-2 bg-gray-50 p-2">
|
||||||
<TagsArray
|
<TagsArray
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import React, { ReactNode, useState } from "react";
|
|
||||||
|
|
||||||
interface TagProps {
|
|
||||||
text: string;
|
|
||||||
icon: React.ReactNode;
|
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Card: React.FC<TagProps> = ({ children, text, icon, onClick }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
onClick={onClick}
|
|
||||||
className="flex flex-row space-x-2 items-start justify-start border border-gray-200 bg-white hover:bg-gray-50 shadow rounded-md p-4 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 w-1/4"
|
|
||||||
>
|
|
||||||
<span className="h-5 text-purple-700 w-5">{icon}</span>
|
|
||||||
<span className="text-sm text-gray-800 font-semibold">{text}</span>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Card;
|
|
|
@ -1,40 +0,0 @@
|
||||||
import React, { ChangeEvent, FunctionComponent } from "react";
|
|
||||||
|
|
||||||
// Define the shape of a single option
|
|
||||||
interface DropdownOption {
|
|
||||||
label: string;
|
|
||||||
value: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the props for the Dropdown component
|
|
||||||
interface DropdownProps {
|
|
||||||
options: DropdownOption[];
|
|
||||||
onChange: (event: ChangeEvent<HTMLSelectElement>) => void; // Type for change event on <select>
|
|
||||||
defaultValue?: string | number;
|
|
||||||
id?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dropdown Component
|
|
||||||
const Dropdown: FunctionComponent<DropdownProps> = ({
|
|
||||||
options,
|
|
||||||
onChange,
|
|
||||||
defaultValue,
|
|
||||||
id,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<select
|
|
||||||
id={id}
|
|
||||||
defaultValue={defaultValue}
|
|
||||||
onChange={onChange}
|
|
||||||
className="form-select form-select-lg mb-3"
|
|
||||||
>
|
|
||||||
{options.map((option, index) => (
|
|
||||||
<option key={index} value={option.value}>
|
|
||||||
{option.label}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Dropdown;
|
|
Loading…
Reference in New Issue
Block a user