Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const App = () => {
path="/clientlist"
element={<ProtectedRoute element={<ClientList/>} allowedRoles={['admin', 'user']} />}
/>

<Route
path="/clientdata"
element={<ProtectedRoute element={<ClientData />} allowedRoles={['admin', 'user']} />}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/clientlist/AddClientForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export const AddClientForm = ({ onClientAdded, setShowUnfinishedAlert}: AddClien
<>
<Button ref={btnRef} colorScheme='blue' onClick={onOpen}>
{!formInProgress && <Text>Add</Text>}
{formInProgress && <Text>Edit New Client</Text>}
{formInProgress && <Text>Edit</Text>}
</Button>
<Drawer
isOpen={isOpen}
Expand Down
312 changes: 160 additions & 152 deletions client/src/components/clientlist/ClientList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Table,
TableContainer,
Tbody,
Flex,
Td,
Text,
Th,
Expand All @@ -28,7 +29,9 @@ import {
SortingState,
useReactTable,
} from "@tanstack/react-table";
import { FiUpload } from "react-icons/fi";
import { MdFileUpload } from "react-icons/md";
import { MdOutlineManageSearch } from "react-icons/md";

import { useNavigate } from "react-router-dom";

import { useAuthContext } from "../../contexts/hooks/useAuthContext";
Expand Down Expand Up @@ -78,11 +81,13 @@ export const ClientList = ({ admin }: ClientListProps) => {
const [filterQuery, setFilterQuery] = useState<string[]>([]);
const [sorting, setSorting] = useState<SortingState>([]);
const [loading, setLoading] = useState(true);
// const [displayName, setDisplayName] = useState("");
const navigate = useNavigate();


const [showUnfinishedAlert, setShowUnfinishedAlert] = useState(false)

const [showSearch, setShowSearch] = useState(false);

const columns = useMemo<ColumnDef<Client>[]>(
() => [
{
Expand Down Expand Up @@ -350,13 +355,12 @@ export const ClientList = ({ admin }: ClientListProps) => {
clientsRequest = backend.get(`/clients?page=&filter=${encodeURIComponent(filterQuery.join(" "))}&search=`);
} else {
clientsRequest = backend.get("/clients");
const [lastUpdatedResponse, clientsResponse] = await Promise.all([lastUpdatedRequest, clientsRequest]);

const date = new Date(lastUpdatedResponse.data[0]?.lastUpdatedAt);
setLastUpdated(date.toLocaleString());
setClients(clientsResponse.data);

}
const [lastUpdatedResponse, clientsResponse] = await Promise.all([lastUpdatedRequest, clientsRequest]);

const date = new Date(lastUpdatedResponse.data[0]?.lastUpdatedAt);
setLastUpdated(date.toLocaleString());
setClients(clientsResponse.data);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
Expand All @@ -368,162 +372,166 @@ export const ClientList = ({ admin }: ClientListProps) => {
fetchData();
}, [backend, searchKey, filterQuery]);


return (
<VStack
spacing={2}
spacing={6}
align="start"
sx={{ maxWidth: "100%", marginX: "auto", padding: "4%" }}
>
{showUnfinishedAlert && <UnfinishedClientAlert/>}
<Heading paddingBottom="4%">Welcome, {currentUser?.displayName}</Heading>
<HStack width="100%">
<Heading size="md">My Complete Client Table</Heading>
<Heading
size="sm"
paddingLeft="10%"
<VStack width='100%'>
{showUnfinishedAlert && <UnfinishedClientAlert/>}
<Flex width="100%" flexDirection="column" justifyContent="flex-start">
<Heading fontWeight="none" fontSize="24px" color={"#3182CE"} mb="25px">Welcome, {currentUser?.displayName}</Heading>
<Heading fontSize="30px" mb="10px">Complete Client Table</Heading>
<Text
fontSize="14px"
>
Last Updated: {lastUpdated}
</Text>
</Flex>
{admin && <UpdateClients />}

<Flex
width="100%"
justifyContent="flex-end"
>
Last Updated: {lastUpdated}
</Heading>
</HStack>
{admin && <UpdateClients />}
<VStack></VStack>
<HStack
width="100%"
justifyContent="space-between"
>
<Input
fontSize="12px"
width="20%"
height="30px"
placeholder="search"
onChange={(e) => setSearchKey(e.target.value)}
/>
<ClientListFilter setFilterQuery={setFilterQuery} />
<HStack
width="55%"
justifyContent="space-between"
>
{/* <Text fontSize="12px">
showing {clients.length} results on this page
</Text> */}
<HStack>
{/* <Button></Button> */}
{/* <Text fontSize="12px">
page {} of {Math.ceil(clients.length / 20)}
</Text> */}
{/* <Button></Button> */}
</HStack>
<HStack>
<Button
fontSize="12px"
onClick={() => setDeleteModalOpen(true)}
isDisabled={selectedRowIds.length === 0}
>
delete
</Button>
{/* <Button fontSize="12px">add</Button> */}
<AddClientForm onClientAdded={fetchData} setShowUnfinishedAlert={setShowUnfinishedAlert} />
<IconButton
aria-label="Download CSV"
onClick={() => onPressCSVButton()}
>
<FiUpload />
</IconButton>
</HStack>
</HStack>
</HStack>
{/* If you want to have a fixed bottom height I'd prob have to change the css of this whole thing no? */}

<HStack>
<Button
onClick={() => setDeleteModalOpen(true)}
isDisabled={selectedRowIds.length === 0}
>
Delete
</Button>

<AddClientForm onClientAdded={fetchData} setShowUnfinishedAlert={setShowUnfinishedAlert} />
</HStack>

</Flex>
</VStack>
<Box
width = {'100%'}
justifyContent={"center"}
>
{loading ?
<LoadingWheel/> :
<TableContainer
maxHeight="calc(100vh - 20px)"
sx={{
overflowX: "auto",
overflowY: "auto",
maxWidth: "100%",
border: "1px solid gray",
}}
>
<Table variant="striped">
<Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<Th
key={header.id}
cursor={header.column.getCanSort() ? "pointer" : "default"}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{header.column.getCanSort() && (
<Box
display="inline-block"
ml={1}
>
{header.column.getIsSorted() === "asc" ? (
<TriangleUpIcon />
) : header.column.getIsSorted() === "desc" ? (
<TriangleDownIcon />
) : null}
</Box>
)}
</Th>
))}
</Tr>
))}
</Thead>
<Tbody>
{table.getRowModel().rows.map((row, index) => (
<Tr
key={row.id}
cursor="pointer"
onClick={
() => navigate(`/ViewClient/2`)
}
>
{row.getVisibleCells().map((cell) => (
<Td
key={cell.id}
fontSize="14px"
fontWeight="500px"
onClick={(e) => {
if (cell.column.id === "rowNumber") {
e.stopPropagation();
}
}}
>
{cell.column.id === "rowNumber" ? (
<HoverCheckbox
id={row.original.id}
isSelected={selectedRowIds.includes(row.original.id)}
onSelectionChange={handleRowSelect}
index={index}
/>
) : (
flexRender(cell.column.columnDef.cell, cell.getContext())
)}
</Td>
))}
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
}
</Box>
<DeleteRowModal
isOpen={isDeleteModalOpen}
onClose={() => setDeleteModalOpen(false)}
onConfirm={handleDelete}
/>
<Box border="1px solid" padding = "10px" borderColor="gray.300" borderRadius="md" overflow="hidden" width="100%" maxHeight="80%">
<HStack padding="5px">
<ClientListFilter setFilterQuery={setFilterQuery} />
<HStack width="100%" justifyContent={"right"} gap={"0"}>
<Input maxWidth="20%" placeholder="search" value={searchKey} onChange={(e) => setSearchKey(e.target.value)} display={showSearch ? 'block' : 'none'}></Input>
<Box
display="flex"
alignItems="center"
paddingX="8px"
paddingY="8px"
cursor="pointer"
onClick={() => {setShowSearch(!showSearch); setSearchKey("")}}
>
<Button background={"white"}>
<MdOutlineManageSearch size="24px" />
</Button>
</Box>
<Box
display="flex"
alignItems="center"
paddingX="8px"
paddingY="8px"
cursor="pointer"
onClick={() => onPressCSVButton()}
>
<Button background={"white"}>
<MdFileUpload size="16px" />
<Text ml="8px">Export</Text>
</Button>
</Box>
</HStack>
</HStack>
<TableContainer
maxHeight="calc(100vh - 20px)"
borderRadius="lg"
boxShadow="sm"
sx={{
overflowX: "auto",
overflowY: "auto",
maxWidth: "100%",
border: "1px solid gray",
}}
>
<Table variant="striped">
<Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<Th
key={header.id}
cursor={header.column.getCanSort() ? "pointer" : "default"}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{header.column.getCanSort() && (
<Box
display="inline-block"
ml={1}
>
{header.column.getIsSorted() === "asc" ? (
<TriangleUpIcon />
) : header.column.getIsSorted() === "desc" ? (
<TriangleDownIcon />
) : null}
</Box>
)}
</Th>
))}
</Tr>
))}
</Thead>
<Tbody>
{table.getRowModel().rows.map((row, index) => (
<Tr
key={row.id}
cursor="pointer"
onClick={() => {navigate(`/ViewClient/${row.original.id}`)}}
>
{row.getVisibleCells().map((cell) => (
<Td
key={cell.id}
fontSize="14px"
fontWeight="500px"
onClick={(e) => {
if (cell.column.id === "rowNumber") {
e.stopPropagation();
}
}}
>
{cell.column.id === "rowNumber" ? (
<HoverCheckbox
id={row.original.id}
isSelected={selectedRowIds.includes(row.original.id)}
onSelectionChange={handleRowSelect}
index={index}
/>
) : (
flexRender(cell.column.columnDef.cell, cell.getContext())
)}
</Td>
))}
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Box>
}
</Box>
<DeleteRowModal
isOpen={isDeleteModalOpen}
onClose={() => setDeleteModalOpen(false)}
onConfirm={handleDelete}
/>
</VStack>
);
};
2 changes: 1 addition & 1 deletion client/src/components/clientlist/ClientListFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const ClientListFilter = ({setFilterQuery}: ClientListFilterProps) => {
return (
<Popover placement="bottom-start">
<PopoverTrigger>
<Button>
<Button background={"white"}>
<HStack>
<Icon as={MdOutlineFilterAlt} />
<h1>Filter</h1>
Expand Down
Loading