mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-07 05:00:16 -04:00
Edited the UI
This commit is contained in:
parent
38d640edc9
commit
f9a6e71484
|
@ -9,7 +9,7 @@ type ButtonProps = {
|
||||||
|
|
||||||
|
|
||||||
const Button: FunctionComponent<ButtonProps> = ({ children, type, disabled, onClick}) => {
|
const Button: FunctionComponent<ButtonProps> = ({ children, type, disabled, onClick}) => {
|
||||||
const buttonClassName = `inline-block rounded border ${disabled ? 'bg-gray-400 text-gray-600 cursor-not-allowed' : 'border-purple-600 bg-purple-600 text-white hover:bg-transparent hover:text-purple-600 focus:outline-none focus:ring active:text-purple-500'} px-4 py-1 text-md font-semibold w-20 h-10 text-center`;
|
const buttonClassName = ` inline-block rounded border ${disabled ? 'bg-gray-400 text-gray-600 cursor-not-allowed' : 'border-purple-600 bg-purple-600 text-white hover:bg-transparent hover:text-purple-600 focus:outline-none focus:ring active:text-purple-500'} px-4 py-1 text-md font-semibold w-20 h-10 text-center`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const FilterBox = () => {
|
||||||
selectedTags.map((tag) => (
|
selectedTags.map((tag) => (
|
||||||
<div
|
<div
|
||||||
key={tag}
|
key={tag}
|
||||||
className="bg-blue-100 text-blue-800 px-2 py-1 rounded-md flex items-center mr-2"
|
className="bg-purple-100 text-purple-800 px-2 py-1 rounded-md flex items-center mr-2"
|
||||||
>
|
>
|
||||||
<span>{tag}</span>
|
<span>{tag}</span>
|
||||||
<span
|
<span
|
||||||
|
@ -74,7 +74,7 @@ export const FilterBox = () => {
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={selectedTags.includes(tag)}
|
checked={selectedTags.includes(tag)}
|
||||||
onChange={() => handleTagChange(tag)}
|
onChange={() => handleTagChange(tag)}
|
||||||
className="mr-2"
|
className="mr-2 accent-purple-500"
|
||||||
/>
|
/>
|
||||||
<label>{tag}</label>
|
<label>{tag}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,11 +12,24 @@ import {
|
||||||
sortingFns,
|
sortingFns,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
import { ChangeEvent, useState, useEffect, FunctionComponent, useRef, ChangeEventHandler, Key } from "react";
|
import {
|
||||||
|
ChangeEvent,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
FunctionComponent,
|
||||||
|
useRef,
|
||||||
|
ChangeEventHandler,
|
||||||
|
Key,
|
||||||
|
} from "react";
|
||||||
import { RowOptionMenu } from "./RowOptionMenu";
|
import { RowOptionMenu } from "./RowOptionMenu";
|
||||||
import { RowOpenAction } from "./RowOpenAction";
|
import { RowOpenAction } from "./RowOpenAction";
|
||||||
import { TableAction } from "./TableAction";
|
import { TableAction } from "./TableAction";
|
||||||
import { AtSymbolIcon, Bars2Icon, ArrowDownCircleIcon, PlusIcon } from "@heroicons/react/24/solid";
|
import {
|
||||||
|
AtSymbolIcon,
|
||||||
|
Bars2Icon,
|
||||||
|
ArrowDownCircleIcon,
|
||||||
|
PlusIcon,
|
||||||
|
} from "@heroicons/react/24/solid";
|
||||||
import TagsInput from "../TagsInput/Index";
|
import TagsInput from "../TagsInput/Index";
|
||||||
import { rankItem } from "@tanstack/match-sorter-utils";
|
import { rankItem } from "@tanstack/match-sorter-utils";
|
||||||
import { TableCell } from "./TableCell";
|
import { TableCell } from "./TableCell";
|
||||||
|
@ -36,52 +49,70 @@ type User = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// For search
|
// For search
|
||||||
const fuzzyFilter = (row: Row<any>, columnId: string, value: any, addMeta: (meta: any) => void) => {
|
const fuzzyFilter = (
|
||||||
|
row: Row<any>,
|
||||||
|
columnId: string,
|
||||||
|
value: any,
|
||||||
|
addMeta: (meta: any) => void
|
||||||
|
) => {
|
||||||
// Rank the item
|
// Rank the item
|
||||||
const itemRank = rankItem(row.getValue(columnId), value)
|
const itemRank = rankItem(row.getValue(columnId), value);
|
||||||
|
|
||||||
// Store the ranking info
|
// Store the ranking info
|
||||||
addMeta(itemRank)
|
addMeta(itemRank);
|
||||||
|
|
||||||
// Return if the item should be filtered in/out
|
// Return if the item should be filtered in/out
|
||||||
return itemRank.passed
|
return itemRank.passed;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Table = () => {
|
export const Table = () => {
|
||||||
const columnHelper = createColumnHelper<User>();
|
const columnHelper = createColumnHelper<User>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const sortedUsers = [...usersExample].sort((a, b) => (a.visible === b.visible ? 0 : a.visible ? -1 : 1));
|
const sortedUsers = [...usersExample].sort((a, b) =>
|
||||||
|
a.visible === b.visible ? 0 : a.visible ? -1 : 1
|
||||||
|
);
|
||||||
setData(sortedUsers);
|
setData(sortedUsers);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const deleteUser = (userId) => {
|
const deleteUser = (userId) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
setData(currentData => currentData.filter(user => user.id !== userId));
|
setData((currentData) => currentData.filter((user) => user.id !== userId));
|
||||||
};
|
};
|
||||||
|
|
||||||
const hideUser = (userId: number) => {
|
const hideUser = (userId: number) => {
|
||||||
console.log(`Toggling visibility for user with ID: ${userId}`);
|
console.log(`Toggling visibility for user with ID: ${userId}`);
|
||||||
setData(currentData => {
|
setData((currentData) => {
|
||||||
const newData = currentData.map(user => {
|
const newData = currentData
|
||||||
if (user.id === userId) {
|
.map((user) => {
|
||||||
return { ...user, visible: !user.visible };
|
if (user.id === userId) {
|
||||||
}
|
return { ...user, visible: !user.visible };
|
||||||
return user;
|
}
|
||||||
}).sort((a, b) => a.visible === b.visible ? 0 : a.visible ? -1 : 1);
|
return user;
|
||||||
|
})
|
||||||
|
.sort((a, b) => (a.visible === b.visible ? 0 : a.visible ? -1 : 1));
|
||||||
|
|
||||||
console.log(newData);
|
console.log(newData);
|
||||||
return newData;
|
return newData;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const [presetOptions, setPresetOptions] = useState(["administrator", "volunteer", "employee"]);
|
const [presetOptions, setPresetOptions] = useState([
|
||||||
|
"administrator",
|
||||||
|
"volunteer",
|
||||||
|
"employee",
|
||||||
|
]);
|
||||||
const [tagColors, setTagColors] = useState(new Map());
|
const [tagColors, setTagColors] = useState(new Map());
|
||||||
|
|
||||||
const getTagColor = (tag: string) => {
|
const getTagColor = (tag: string) => {
|
||||||
if (!tagColors.has(tag)) {
|
if (!tagColors.has(tag)) {
|
||||||
const colors = ["bg-cyan-100", "bg-blue-100", "bg-green-100", "bg-yellow-100", "bg-purple-100"];
|
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)];
|
const randomColor = colors[Math.floor(Math.random() * colors.length)];
|
||||||
setTagColors(new Map(tagColors).set(tag, randomColor));
|
setTagColors(new Map(tagColors).set(tag, randomColor));
|
||||||
}
|
}
|
||||||
|
@ -91,28 +122,62 @@ export const Table = () => {
|
||||||
const columns = [
|
const columns = [
|
||||||
columnHelper.display({
|
columnHelper.display({
|
||||||
id: "options",
|
id: "options",
|
||||||
cell: props => <RowOptionMenu onDelete={() => deleteUser(props.row.original.id)} onHide={() => hideUser(props.row.original.id)} />
|
cell: (props) => (
|
||||||
|
<RowOptionMenu
|
||||||
|
onDelete={() => deleteUser(props.row.original.id)}
|
||||||
|
onHide={() => hideUser(props.row.original.id)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("username", {
|
columnHelper.accessor("username", {
|
||||||
header: () => <><Bars2Icon className="inline align-top h-4" /> Username</>,
|
header: () => (
|
||||||
cell: (info) => <RowOpenAction title={info.getValue()} rowData={info.row.original} onRowUpdate={handleRowUpdate} />,
|
<>
|
||||||
|
<Bars2Icon className="inline align-top h-4" /> Username
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<RowOpenAction
|
||||||
|
title={info.getValue()}
|
||||||
|
rowData={info.row.original}
|
||||||
|
onRowUpdate={handleRowUpdate}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("role", {
|
columnHelper.accessor("role", {
|
||||||
header: () => <><ArrowDownCircleIcon className="inline align-top h-4" /> Role</>,
|
header: () => (
|
||||||
cell: (info) => <TagsInput presetValue={info.getValue() }
|
<>
|
||||||
presetOptions={presetOptions}
|
<ArrowDownCircleIcon className="inline align-top h-4" /> Role
|
||||||
setPresetOptions={setPresetOptions}
|
</>
|
||||||
getTagColor={getTagColor}
|
),
|
||||||
setTagColors={setTagColors}
|
cell: (info) => (
|
||||||
/>,
|
<TagsInput
|
||||||
|
presetValue={info.getValue()}
|
||||||
|
presetOptions={presetOptions}
|
||||||
|
setPresetOptions={setPresetOptions}
|
||||||
|
getTagColor={getTagColor}
|
||||||
|
setTagColors={setTagColors}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("email", {
|
columnHelper.accessor("email", {
|
||||||
header: () => <><AtSymbolIcon className="inline align-top h-4" /> Email</>,
|
header: () => (
|
||||||
cell: TableCell,
|
<>
|
||||||
|
<AtSymbolIcon className="inline align-top h-4" /> Email
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => (
|
||||||
|
<span className="ml-2 text-gray-500 underline hover:text-gray-400">
|
||||||
|
{info.getValue()}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("program", {
|
columnHelper.accessor("program", {
|
||||||
header: () => <><ArrowDownCircleIcon className="inline align-top h-4" /> Program</>,
|
header: () => (
|
||||||
cell: (info) => info.renderValue(),
|
<>
|
||||||
|
<ArrowDownCircleIcon className="inline align-top h-4" /> Program
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
cell: (info) => <TagsInput presetValue={info.getValue()} />,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -120,22 +185,22 @@ export const Table = () => {
|
||||||
|
|
||||||
const addUser = () => {
|
const addUser = () => {
|
||||||
setData([...data, {}]);
|
setData([...data, {}]);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Searching
|
// Searching
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const handleSearchChange = (e: ChangeEvent) => {
|
const handleSearchChange = (e: ChangeEvent) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
setQuery(String(target.value));
|
setQuery(String(target.value));
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCellChange = (e: ChangeEvent, key: Key) => {
|
const handleCellChange = (e: ChangeEvent, key: Key) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
console.log(key);
|
console.log(key);
|
||||||
}
|
};
|
||||||
|
|
||||||
// TODO: Filtering
|
// TODO: Filtering
|
||||||
|
|
||||||
// TODO: Sorting
|
// TODO: Sorting
|
||||||
|
|
||||||
// added this fn for editing rows
|
// added this fn for editing rows
|
||||||
|
@ -152,7 +217,7 @@ export const Table = () => {
|
||||||
columns,
|
columns,
|
||||||
data,
|
data,
|
||||||
filterFns: {
|
filterFns: {
|
||||||
fuzzy: fuzzyFilter
|
fuzzy: fuzzyFilter,
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
globalFilter: query,
|
globalFilter: query,
|
||||||
|
@ -185,17 +250,17 @@ export const Table = () => {
|
||||||
<th
|
<th
|
||||||
scope="col"
|
scope="col"
|
||||||
className={
|
className={
|
||||||
"p-2 border-gray-200 border-y font-medium "
|
"p-2 border-gray-200 border-y font-medium " +
|
||||||
+ ((1 < i && i < columns.length - 1) ? "border-x" : "")
|
(1 < i && i < columns.length - 1 ? "border-x" : "")
|
||||||
}
|
}
|
||||||
key={header.id}
|
key={header.id}
|
||||||
>
|
>
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder
|
||||||
? null
|
? null
|
||||||
: flexRender(
|
: flexRender(
|
||||||
header.column.columnDef.header,
|
header.column.columnDef.header,
|
||||||
header.getContext()
|
header.getContext()
|
||||||
)}
|
)}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -205,15 +270,17 @@ export const Table = () => {
|
||||||
{table.getRowModel().rows.map((row) => {
|
{table.getRowModel().rows.map((row) => {
|
||||||
// Individual row
|
// Individual row
|
||||||
const isUserVisible = row.original.visible;
|
const isUserVisible = row.original.visible;
|
||||||
const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${!isUserVisible ? "bg-gray-200 text-gray-500" : ""}`;
|
const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${
|
||||||
|
!isUserVisible ? "bg-gray-200 text-gray-500" : ""
|
||||||
|
}`;
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr className={rowClassNames} key={row.id}>
|
||||||
className={rowClassNames}
|
|
||||||
key={row.id}
|
|
||||||
>
|
|
||||||
{row.getVisibleCells().map((cell, i) => (
|
{row.getVisibleCells().map((cell, i) => (
|
||||||
<td key={cell.id}
|
<td
|
||||||
className={"[&:nth-child(n+3)]:border-x relative first:text-left first:px-0 last:border-none"}
|
key={cell.id}
|
||||||
|
className={
|
||||||
|
"[&:nth-child(n+3)]:border-x relative first:text-left first:px-0 last:border-none"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
</td>
|
</td>
|
||||||
|
@ -223,9 +290,12 @@ export const Table = () => {
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td className="p-3 border-y border-gray-200 text-gray-600 hover:bg-gray-50" colSpan={100} onClick={addUser}>
|
<td
|
||||||
|
className="p-3 border-y border-gray-200 text-gray-600 hover:bg-gray-50"
|
||||||
|
colSpan={100}
|
||||||
|
onClick={addUser}
|
||||||
|
>
|
||||||
<span className="flex ml-1 text-gray-500">
|
<span className="flex ml-1 text-gray-500">
|
||||||
<PlusIcon className="inline h-4 mr-1" />
|
<PlusIcon className="inline h-4 mr-1" />
|
||||||
New
|
New
|
||||||
|
@ -235,6 +305,5 @@ export const Table = () => {
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,43 @@
|
||||||
//delete, duplicate, open
|
//delete, duplicate, open
|
||||||
import { TrashIcon, DocumentDuplicateIcon, ArrowUpRightIcon, EllipsisVerticalIcon, EyeSlashIcon } from "@heroicons/react/24/solid";
|
import {
|
||||||
|
TrashIcon,
|
||||||
|
DocumentDuplicateIcon,
|
||||||
|
ArrowUpRightIcon,
|
||||||
|
EllipsisVerticalIcon,
|
||||||
|
EyeSlashIcon,
|
||||||
|
} from "@heroicons/react/24/solid";
|
||||||
import Button from "../Button";
|
import Button from "../Button";
|
||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { RowOption } from "./RowOption";
|
import { RowOption } from "./RowOption";
|
||||||
|
|
||||||
export const RowOptionMenu = ( { onDelete, onHide } ) => {
|
export const RowOptionMenu = ({ onDelete, onHide }) => {
|
||||||
const [menuOpen, setMenuOpen] = useState(false);
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
const openMenu = () => setMenuOpen(true);
|
const openMenu = () => setMenuOpen(true);
|
||||||
const closeMenu = () => setMenuOpen(false);
|
const closeMenu = () => setMenuOpen(false);
|
||||||
|
|
||||||
|
|
||||||
// TODO: Hide menu if clicked elsewhere
|
// TODO: Hide menu if clicked elsewhere
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button className="align-center" onClick={() => setMenuOpen(!menuOpen)}><EllipsisVerticalIcon className="h-4"/></button>
|
<button className="align-center" onClick={() => setMenuOpen(!menuOpen)}>
|
||||||
<div
|
<EllipsisVerticalIcon className="h-4" />
|
||||||
className={"justify-start border border-gray-200 shadow-lg flex flex-col absolute bg-white w-auto p-2 rounded [&>*]:rounded z-10" + (!menuOpen ? " invisible" : "")}
|
</button>
|
||||||
>
|
<div
|
||||||
<RowOption icon={TrashIcon} label="Delete" onClick={onDelete} />
|
className={
|
||||||
<RowOption icon={ArrowUpRightIcon} label="Open" onClick={() => { /* handle open */ }} />
|
"justify-start border border-gray-200 shadow-lg flex flex-col absolute bg-white w-auto p-2 rounded [&>*]:rounded z-10" +
|
||||||
<RowOption icon={EyeSlashIcon} label="Hide" onClick={ onHide } />
|
(!menuOpen ? " invisible" : "")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<RowOption icon={TrashIcon} label="Delete" onClick={onDelete} />
|
||||||
|
<RowOption
|
||||||
|
icon={ArrowUpRightIcon}
|
||||||
|
label="Open"
|
||||||
|
onClick={() => {
|
||||||
|
/* handle open */
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<RowOption icon={EyeSlashIcon} label="Hide" onClick={onHide} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
@ -43,8 +43,8 @@ export const TableAction: FunctionComponent<TableActionProps> = ({
|
||||||
Filter
|
Filter
|
||||||
</span>
|
</span>
|
||||||
{showFilterBox && <FilterBox />}
|
{showFilterBox && <FilterBox />}
|
||||||
<span className="p-1 rounded hover:bg-gray-100">Sort</span>
|
<span className="p-1 rounded hover:text-purple-700 focus:bg-purple-50 hover:bg-purple-50 hover:bg-gray-100">Sort</span>
|
||||||
<span className="p-1 rounded hover:bg-gray-100" onClick={activateSearch}>
|
<span className="p-1 rounded hover:text-purple-700 focus:bg-purple-50 hover:bg-purple-50 hover:bg-gray-100" onClick={activateSearch}>
|
||||||
<MagnifyingGlassIcon className="w-4 h-4 inline" />
|
<MagnifyingGlassIcon className="w-4 h-4 inline" />
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -3,16 +3,16 @@ import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
export const Tag = ({ children, handleDelete, active = false }) => {
|
export const Tag = ({ children, handleDelete, active = false }) => {
|
||||||
|
|
||||||
const [tagColor, setTagColor] = useState('');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`font-normal bg-cyan-100 text-gray-800 flex flex-row p-1 px-2 rounded-lg`}>
|
<span
|
||||||
|
className={`font-normal bg-purple-100 text-gray-800 flex flex-row p-1 px-2 rounded-lg`}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
{active && handleDelete && (
|
{active && handleDelete && (
|
||||||
<button onClick={() => handleDelete(children)}>
|
<button onClick={() => handleDelete(children)}>
|
||||||
<XMarkIcon className={`ml-1 w-3 text-cyan-500`} />
|
<XMarkIcon className={`ml-1 w-3 text-purple-500`} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Tag } from "./Tag"
|
||||||
export const TagsArray = ({ tags, handleDelete, active = false }) => {
|
export const TagsArray = ({ tags, handleDelete, active = false }) => {
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="flex flex-wrap gap-2 items-center">
|
<div className="flex ml-2 flex-wrap gap-2 items-center">
|
||||||
{
|
{
|
||||||
Array.from(tags).map((tag) => {
|
Array.from(tags).map((tag) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,184 +1,246 @@
|
||||||
import { FunctionComponent, ReactElement, ReactNode } from 'react';
|
import { FunctionComponent, ReactNode } from "react";
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from "react";
|
||||||
import { ChevronDoubleLeftIcon } from '@heroicons/react/24/solid';
|
import { ChevronDoubleLeftIcon } from "@heroicons/react/24/solid";
|
||||||
import { BookmarkIcon, XMarkIcon, StarIcon as SolidStarIcon, EnvelopeIcon, UserIcon } from "@heroicons/react/24/solid";
|
import {
|
||||||
import { ArrowsPointingOutIcon, ArrowsPointingInIcon, StarIcon as OutlineStarIcon, ListBulletIcon } from '@heroicons/react/24/outline';
|
StarIcon as SolidStarIcon,
|
||||||
import Card from '@/components/page/Card'
|
EnvelopeIcon,
|
||||||
import TagsInput from '../TagsInput/Index';
|
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 = {
|
type DrawerProps = {
|
||||||
title: string;
|
title: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
type?: "button" | "submit" | "reset"; // specify possible values for type
|
type?: "button" | "submit" | "reset"; // specify possible values for type
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
editableContent?: any;
|
editableContent?: any;
|
||||||
onSave?: (content: any) => void;
|
onSave?: (content: any) => void;
|
||||||
rowContent?: any;
|
rowContent?: any;
|
||||||
onRowUpdate?: (content: any) => void;
|
onRowUpdate?: (content: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface EditContent {
|
interface EditContent {
|
||||||
content: string;
|
content: string;
|
||||||
isEditing: boolean;
|
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 Drawer: FunctionComponent<DrawerProps> = ({ title, children, onSave, editableContent, rowContent, onRowUpdate }) => {
|
const handleTempRowContentChange = (e) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const { name, value } = e.target;
|
||||||
const [isFull, setIsFull] = useState(false);
|
console.log(name);
|
||||||
const [currentCardIcon, setCurrentCardIcon] = useState<string>('');
|
console.log(value);
|
||||||
const [isFavorite, setIsFavorite] = useState(false);
|
setTempRowContent((prevContent) => ({
|
||||||
const [tempRowContent, setTempRowContent] = useState(rowContent);
|
...prevContent,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const handleTempRowContentChange = (e) => {
|
const handleEnterPress = (e) => {
|
||||||
const { name, value } = e.target;
|
if (e.key === "Enter") {
|
||||||
console.log(name);
|
e.preventDefault();
|
||||||
console.log(value);
|
// Update the rowContent with the temporaryRowContent
|
||||||
setTempRowContent((prevContent) => ({
|
if (onRowUpdate) {
|
||||||
...prevContent,
|
onRowUpdate(tempRowContent);
|
||||||
[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 toggleDrawer = () => {
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
if (isFull) {
|
||||||
|
setIsFull(!isFull);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const toggleFavorite = () => setIsFavorite(!isFavorite);
|
const toggleDrawerFullScreen = () => setIsFull(!isFull);
|
||||||
|
|
||||||
const drawerClassName = `fixed top-0 right-0 w-1/2 h-full bg-white transform ease-in-out duration-300 z-20 ${
|
const toggleFavorite = () => setIsFavorite(!isFavorite);
|
||||||
isOpen ? "translate-x-0 shadow-xl" : "translate-x-full"
|
|
||||||
|
|
||||||
} ${isFull ? "w-full" : "w-1/2"}`;
|
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 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 favoriteIcon = isFavorite ? (
|
||||||
|
<SolidStarIcon className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<OutlineStarIcon className="h-5 w-5" />
|
||||||
|
);
|
||||||
|
|
||||||
const [presetOptions, setPresetOptions] = useState(["administrator", "volunteer", "employee"]);
|
const [presetOptions, setPresetOptions] = useState([
|
||||||
const [rolePresetOptions, setRolePresetOptions] = useState(["domestic", "community", "economic"]);
|
"administrator",
|
||||||
const [tagColors, setTagColors] = useState(new Map());
|
"volunteer",
|
||||||
|
"employee",
|
||||||
|
]);
|
||||||
|
const [rolePresetOptions, setRolePresetOptions] = useState([
|
||||||
|
"domestic",
|
||||||
|
"community",
|
||||||
|
"economic",
|
||||||
|
]);
|
||||||
|
const [tagColors, setTagColors] = useState(new Map());
|
||||||
|
|
||||||
const getTagColor = (tag: string) => {
|
const getTagColor = (tag: string) => {
|
||||||
if (!tagColors.has(tag)) {
|
if (!tagColors.has(tag)) {
|
||||||
const colors = ["bg-cyan-100", "bg-blue-100", "bg-green-100", "bg-yellow-100", "bg-purple-100"];
|
const colors = [
|
||||||
const randomColor = colors[Math.floor(Math.random() * colors.length)];
|
"bg-cyan-100",
|
||||||
setTagColors(new Map(tagColors).set(tag, randomColor));
|
"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"
|
||||||
}
|
}
|
||||||
return tagColors.get(tag);
|
onClick={toggleDrawer}
|
||||||
};
|
>
|
||||||
|
Open
|
||||||
|
</button>
|
||||||
return (
|
<div className={drawerClassName}></div>
|
||||||
<div>
|
<div className={drawerClassName}>
|
||||||
<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="flex items-center justify-between p-4">
|
||||||
<div className={drawerClassName}></div>
|
<div className="flex flex-row items-center justify-between space-x-2">
|
||||||
<div className={drawerClassName}>
|
<span className="h-5 text-purple-200 w-5">
|
||||||
<div className="flex items-center justify-between p-4 border-b">
|
<UserIcon />
|
||||||
<div className="flex flex-row items-center justify-between space-x-2">
|
</span>
|
||||||
<span className="h-5 text-purple-700 w-5">{currentCardIcon}</span>
|
<h2 className="text-lg text-gray-800 font-semibold">
|
||||||
<h2 style={{ fontSize: '20px' }} className = "text-sm text-gray-800 font-semibold">{rowContent.username}</h2>
|
{rowContent.username}
|
||||||
</div>
|
</h2>
|
||||||
<div>
|
</div>
|
||||||
<button onClick={toggleFavorite} className="py-2 text-gray-500 hover:text-gray-800 mr-2">
|
<div>
|
||||||
{favoriteIcon}
|
<button
|
||||||
</button>
|
onClick={toggleFavorite}
|
||||||
<button onClick={toggleDrawerFullScreen} className="py-2 text-gray-500 hover:text-gray-800 mr-2">
|
className="py-2 text-gray-500 hover:text-gray-800 mr-2"
|
||||||
{iconComponent}
|
>
|
||||||
</button>
|
{favoriteIcon}
|
||||||
<button onClick={toggleDrawer} className="py-2 text-gray-500 hover:text-gray-800">
|
</button>
|
||||||
<ChevronDoubleLeftIcon className="h-5 w-5" />
|
<button
|
||||||
</button>
|
onClick={toggleDrawerFullScreen}
|
||||||
</div>
|
className="py-2 text-gray-500 hover:text-gray-800 mr-2"
|
||||||
</div>
|
>
|
||||||
<div className="p-4">
|
{iconComponent}
|
||||||
<table className="p-4">
|
</button>
|
||||||
<tbody className="items-center">
|
<button
|
||||||
<tr className="w-full text-sm items-center flex flex-row justify-between">
|
onClick={toggleDrawer}
|
||||||
<div className="flex flex-row space-x-2 text-gray-500 items-center">
|
className="py-2 text-gray-500 hover:text-gray-800"
|
||||||
<td><UserIcon className="h-4 w-4" /></td>
|
>
|
||||||
<td className="w-32">Username</td>
|
<ChevronDoubleLeftIcon className="h-5 w-5" />
|
||||||
</div>
|
</button>
|
||||||
<td className="w-3/4 w-3/4 p-2 pl-0">
|
</div>
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="username"
|
|
||||||
value={tempRowContent.username}
|
|
||||||
onChange={handleTempRowContentChange}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
className="w-full p-1 focus:outline-gray-200 hover:bg-gray-50"
|
|
||||||
/></td>
|
|
||||||
</tr>
|
|
||||||
<tr className="w-full text-sm 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-sm 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="w-80 p-1 focus:outline-gray-200 hover:bg-gray-50 underline text-gray-500"
|
|
||||||
/></td>
|
|
||||||
</tr>
|
|
||||||
<tr className="w-full text-sm 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>
|
</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;
|
export default Drawer;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user