Fixed a bunch of stuff

This commit is contained in:
Mitchell Magro 2025-06-29 08:49:58 +02:00
parent 26e97a0c44
commit c4692e2222
18 changed files with 177 additions and 236 deletions

View File

@ -2,7 +2,7 @@
import Link from "next/link"; import Link from "next/link";
import { styled } from "@mui/system"; import { styled } from "@mui/system";
import { ISidebarLink } from "@/interfaces/SidebarLink.interfaces"; import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
const LinkContainer = styled("div")(({ theme }) => ({ const LinkContainer = styled("div")(({ theme }) => ({
display: "flex", display: "flex",

View File

@ -0,0 +1,20 @@
// app/dashboard/loading.tsx
"use client";
import CircularProgress from "@mui/material/CircularProgress";
import { styled } from "@mui/system";
const LoaderWrapper = styled("div")({
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center",
});
export default function Loading() {
return (
<LoaderWrapper>
<CircularProgress />
</LoaderWrapper>
);
}

View File

@ -1,13 +1,13 @@
// This ensures this component is rendered only on the client side // This ensures this component is rendered only on the client side
'use client'; "use client";
import TransactionTable from '@/app/components/Pages/Transactions/Transactions'; import TransactionTable from "@/app/features/Pages/transactions/Transactions";
export default function TransactionPage() { export default function TransactionPage() {
return ( return (
<div style={{ width: '100%' }}> <div style={{ width: "100%" }}>
{/* This page will now be rendered on the client-side */} {/* This page will now be rendered on the client-side */}
<TransactionTable /> <TransactionTable />
</div> </div>
); );
} }

View File

@ -3,7 +3,6 @@ import MoreVertIcon from "@mui/icons-material/MoreVert";
import CalendarTodayIcon from "@mui/icons-material/CalendarToday"; import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import { DateRangePicker } from "../DateRangePicker/DateRangePicker"; import { DateRangePicker } from "../DateRangePicker/DateRangePicker";
// import { ArrowDropUp } from '@mui/icons-material';
const stats = [ const stats = [
{ label: "TOTAL", value: 5, change: "-84.85%" }, { label: "TOTAL", value: 5, change: "-84.85%" },
@ -63,8 +62,8 @@ export const GeneralHealthCard = () => {
</Box> </Box>
</Box> </Box>
<Box sx={{ display: "flex", justifyContent: "space-around", mt: 2 }}> <Box sx={{ display: "flex", justifyContent: "space-around", mt: 2 }}>
{stats.map((item) => ( {stats.map((item, i) => (
<StatItem key={item.label} {...item} /> <StatItem key={item.label + i} {...item} />
))} ))}
</Box> </Box>
</CardContent> </CardContent>

View File

@ -1,110 +1,131 @@
'use client'; "use client";
import { useState } from 'react'; import { useState } from "react";
import { import {
Button, Dialog, DialogTitle, DialogContent, DialogActions, Button,
FormControl, Select, MenuItem, FormControlLabel, Checkbox, Dialog,
Stack, Paper, styled, DialogTitle,
TextField DialogContent,
} from '@mui/material'; DialogActions,
import FileUploadIcon from '@mui/icons-material/FileUpload'; FormControl,
import * as XLSX from 'xlsx'; Select,
import { saveAs } from 'file-saver'; MenuItem,
import { DataGrid } from '@mui/x-data-grid'; FormControlLabel,
import { columns } from './constants'; Checkbox,
import { rows } from './mockData'; Stack,
Paper,
styled,
TextField,
} from "@mui/material";
import FileUploadIcon from "@mui/icons-material/FileUpload";
import * as XLSX from "xlsx";
import { saveAs } from "file-saver";
import { DataGrid } from "@mui/x-data-grid";
import { columns } from "./constants";
import { rows } from "./mockData";
const paginationModel = { page: 0, pageSize: 50 }; const paginationModel = { page: 0, pageSize: 50 };
export default function TransactionTable() { export default function TransactionTable() {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [fileType, setFileType] = useState<'csv' | 'xls' | 'xlsx'>('csv'); const [fileType, setFileType] = useState<"csv" | "xls" | "xlsx">("csv");
const [onlyCurrentTable, setOnlyCurrentTable] = useState(false); const [onlyCurrentTable, setOnlyCurrentTable] = useState(false);
const handleExport = () => { const handleExport = () => {
const exportRows = onlyCurrentTable ? rows.slice(0, 5) : rows; const exportRows = onlyCurrentTable ? rows.slice(0, 5) : rows;
const exportData = [ const exportData = [
columns.map(col => col.headerName), columns.map((col) => col.headerName),
// @ts-expect-error - Dynamic field access from DataGrid columns // @ts-expect-error - Dynamic field access from DataGrid columns
...exportRows.map(row => columns.map(col => row[col.field] ?? '')), ...exportRows.map((row) => columns.map((col) => row[col.field] ?? "")),
]; ];
const worksheet = XLSX.utils.aoa_to_sheet(exportData); const worksheet = XLSX.utils.aoa_to_sheet(exportData);
const workbook = XLSX.utils.book_new(); const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Transactions'); XLSX.utils.book_append_sheet(workbook, worksheet, "Transactions");
if (fileType === 'csv') { if (fileType === "csv") {
const csv = XLSX.utils.sheet_to_csv(worksheet); const csv = XLSX.utils.sheet_to_csv(worksheet);
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
saveAs(blob, 'transactions.csv'); saveAs(blob, "transactions.csv");
} else { } else {
XLSX.writeFile(workbook, `transactions.${fileType}`, { bookType: fileType }); XLSX.writeFile(workbook, `transactions.${fileType}`, {
} bookType: fileType,
});
}
setOpen(false); setOpen(false);
}; };
return ( return (
<StyledPaper> <StyledPaper>
<Stack direction="row" justifyContent="space-between" alignItems="center" p={2}> <Stack
<TextField direction="row"
label="Search" justifyContent="space-between"
variant="outlined" alignItems="center"
size="small" p={2}
// value={'searchQuery'} >
onChange={(e) => console.log(`setSearchQuery(${e.target.value})`)} <TextField
sx={{ width: 300 }} label="Search"
/> variant="outlined"
<Button size="small"
variant="outlined" // value={'searchQuery'}
startIcon={<FileUploadIcon />} onChange={(e) => console.log(`setSearchQuery(${e.target.value})`)}
onClick={() => setOpen(true)} sx={{ width: 300 }}
> />
Export <Button
</Button> variant="outlined"
</Stack> startIcon={<FileUploadIcon />}
onClick={() => setOpen(true)}
>
Export
</Button>
</Stack>
<DataGrid <DataGrid
rows={rows} rows={rows}
columns={columns} columns={columns}
initialState={{ pagination: { paginationModel } }} initialState={{ pagination: { paginationModel } }}
pageSizeOptions={[50 , 100]} pageSizeOptions={[50, 100]}
sx={{ border: 0 }} sx={{ border: 0 }}
/> />
{/* Export Dialog */} {/* Export Dialog */}
<Dialog open={open} onClose={() => setOpen(false)}> <Dialog open={open} onClose={() => setOpen(false)}>
<DialogTitle>Export Transactions</DialogTitle> <DialogTitle>Export Transactions</DialogTitle>
<DialogContent> <DialogContent>
<FormControl fullWidth sx={{ mt: 2 }}> <FormControl fullWidth sx={{ mt: 2 }}>
<Select <Select
value={fileType} value={fileType}
onChange={(e) => setFileType(e.target.value as 'csv' | 'xls' | 'xlsx')} onChange={(e) =>
> setFileType(e.target.value as "csv" | "xls" | "xlsx")
<MenuItem value="csv">CSV</MenuItem> }
<MenuItem value="xls">XLS</MenuItem> >
<MenuItem value="xlsx">XLSX</MenuItem> <MenuItem value="csv">CSV</MenuItem>
</Select> <MenuItem value="xls">XLS</MenuItem>
</FormControl> <MenuItem value="xlsx">XLSX</MenuItem>
<FormControlLabel </Select>
control={ </FormControl>
<Checkbox <FormControlLabel
checked={onlyCurrentTable} control={
onChange={(e) => setOnlyCurrentTable(e.target.checked)} <Checkbox
/> checked={onlyCurrentTable}
} onChange={(e) => setOnlyCurrentTable(e.target.checked)}
label="Only export the results in the current table" />
sx={{ mt: 2 }} }
/> label="Only export the results in the current table"
</DialogContent> sx={{ mt: 2 }}
<DialogActions> />
<Button onClick={() => setOpen(false)}>Cancel</Button> </DialogContent>
<Button variant="contained" onClick={handleExport}>Export</Button> <DialogActions>
</DialogActions> <Button onClick={() => setOpen(false)}>Cancel</Button>
</Dialog> <Button variant="contained" onClick={handleExport}>
</StyledPaper> Export
); </Button>
</DialogActions>
</Dialog>
</StyledPaper>
);
} }
const StyledPaper = styled(Paper)(() => ({ const StyledPaper = styled(Paper)(() => ({
height: '90vh', height: "90vh",
})); }));

View File

@ -35,7 +35,7 @@ export const SectionCard = ({ title, icon, items }: ISectionCardProps) => (
<Divider /> <Divider />
<List dense disablePadding> <List dense disablePadding>
{items.map((item, index) => ( {items.map((item, index) => (
<ListItem key={index} disableGutters> <ListItem key={item.title + index} disableGutters>
<ListItemText <ListItemText
primary={item.title} primary={item.title}
secondary={item.date} secondary={item.date}

View File

@ -30,8 +30,8 @@ export const TransactionsOverviewTable = () => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{data1.map((row) => ( {data1.map((row, i) => (
<TableRow key={row.state}> <TableRow key={row.state + i}>
<TableCell align="center"> <TableCell align="center">
<Box <Box
sx={{ sx={{

View File

@ -168,8 +168,8 @@ export const TransactionsWaitingApproval = () => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{transactions.map((tx) => ( {transactions.map((tx, i) => (
<TableRow key={tx.id}> <TableRow key={tx.id + i}>
<TableCell>{tx.id}</TableCell> <TableCell>{tx.id}</TableCell>
<TableCell>{tx.user}</TableCell> <TableCell>{tx.user}</TableCell>
<TableCell>{tx.created}</TableCell> <TableCell>{tx.created}</TableCell>

View File

@ -5,4 +5,5 @@ export const Em = styled("em")(() => ({
alignItems: "center", alignItems: "center",
opacity: 0.7, opacity: 0.7,
fontStyle: "normal", fontStyle: "normal",
color: "white",
})); }));

View File

@ -7,8 +7,8 @@ import {
SelectChangeEvent, SelectChangeEvent,
} from "@mui/material"; } from "@mui/material";
import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import { SIDEBAR_LINKS } from "@/constants/SidebarLink.constants"; import { SIDEBAR_LINKS } from "@/app/features/dashboard/sidebar/SidebarLink.constants";
import { ISidebarLink } from "@/interfaces/SidebarLink.interfaces"; import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
import { Em } from "./DropDown.styled"; import { Em } from "./DropDown.styled";
import PageLinks from "../../../../components/PageLinks/PageLinks"; import PageLinks from "../../../../components/PageLinks/PageLinks";
@ -35,6 +35,7 @@ export default function SidebarDropdown({ onChange }: Props) {
MenuProps={{ MenuProps={{
PaperProps: { PaperProps: {
style: { style: {
backgroundColor: "rgba(30, 30, 30, 0.7)", // 0.9 opacity
maxHeight: 200, maxHeight: 200,
}, },
}, },

View File

@ -1,8 +1,7 @@
import { styled } from '@mui/system'; import { styled } from "@mui/system";
export const LayoutWrapper = styled('div')({ export const LayoutWrapper = styled("div")({
display: 'flex', display: "flex",
width: '100%', width: "100%",
height: '100vh', height: "100vh",
// overflow: 'hidden',
}); });

View File

@ -3,7 +3,7 @@
import React from "react"; import React from "react";
import DashboardIcon from "@mui/icons-material/Dashboard"; import DashboardIcon from "@mui/icons-material/Dashboard";
import { styled } from "@mui/system"; import { styled } from "@mui/system";
import { SIDEBAR_LINKS } from "@/constants/SidebarLink.constants"; import { SIDEBAR_LINKS } from "@/app/features/dashboard/sidebar/SidebarLink.constants";
import PageLinks from "../../../components/PageLinks/PageLinks"; import PageLinks from "../../../components/PageLinks/PageLinks";
const SideBarContainer = styled("aside")(({ theme }) => ({ const SideBarContainer = styled("aside")(({ theme }) => ({

View File

@ -8,7 +8,7 @@ import GavelIcon from "@mui/icons-material/Gavel";
import HubIcon from "@mui/icons-material/Hub"; import HubIcon from "@mui/icons-material/Hub";
import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings"; import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings";
import InsightsIcon from "@mui/icons-material/Insights"; import InsightsIcon from "@mui/icons-material/Insights";
import { ISidebarLink } from "@/interfaces/SidebarLink.interfaces"; import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
export const SIDEBAR_LINKS: ISidebarLink[] = [ export const SIDEBAR_LINKS: ISidebarLink[] = [
{ title: "Home", path: "/dashboard", icon: HomeIcon }, { title: "Home", path: "/dashboard", icon: HomeIcon },

View File

@ -1,41 +0,0 @@
'use client';
import Link from 'next/link';
import { styled } from '@mui/system';
import { ISidebarLink } from '@/interfaces/SidebarLink.interfaces';
const LinkContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
padding: '12px 1px',
borderRadius: '4px',
color: theme.palette.text.tertiary,
textDecoration: 'none',
transition: 'background 0.2s ease-in-out',
'&:hover': {
color: 'rgb(255, 255, 255)',
background: 'rgba(255, 255, 255, 0.08)',
backgroundColor: theme.palette.action.hover,
cursor: 'pointer',
},
}));
const LinkText = styled('span')(({ theme }) => ({
color: theme.palette.text.tertiary,
marginLeft: '12px',
fontWeight: 500,
}));
export default function SidebarLink({ title, path, icon: Icon }: ISidebarLink) {
return (
<Link href={path} passHref legacyBehavior>
<a style={{ textDecoration: 'none' }}>
<LinkContainer>
{Icon && <Icon />}
<LinkText>{title}</LinkText>
</LinkContainer>
</a>
</Link>
);
}

View File

@ -1,73 +0,0 @@
'use client';
import React from 'react';
import { styled } from '@mui/system';
import DashboardIcon from '@mui/icons-material/Dashboard';
import { SIDEBAR_LINKS } from '@/constants/SidebarLink.constants';
import SideBarLink from './SideBarLink';
// SideBar Container (styled using MUI System)
export const SideBar = styled('div')(({ theme }) => ({
width: '240px',
backgroundColor: theme.palette.background.primary,
color: 'white',
padding: theme.spacing(2),
height: '100vh',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
transition: 'width 0.3s ease', // Transition for resizing
}));
// Main Content Area
export const MainContent = styled('div')(({ theme }) => ({
flexGrow: 1,
padding: theme.spacing(4),
backgroundColor: theme.palette.background.default,
minHeight: '100vh',
overflowY: 'auto',
}));
// SideBar Header
export const SideBarHeader = styled('div')(({ theme }) => ({
marginBottom: theme.spacing(2),
fontSize: '20px',
fontWeight: 600,
display: 'flex',
alignItems: 'center',
}));
// Page Wrapper that holds SideBar and Content
export const LayoutWrapper = styled('div')({
display: 'flex',
flexDirection: 'row',
height: '100vh',
});
interface SideBarLayoutProps {
children: React.ReactNode; // Add children to accept passed content
}
const SideBarLayout: React.FC<SideBarLayoutProps> = ({ children }) => {
return (
<LayoutWrapper>
<SideBar>
<SideBarHeader>
PaymentIQ
<DashboardIcon sx={{ marginLeft: 0.5 }} />
</SideBarHeader>
{SIDEBAR_LINKS.map((link) => (
<SideBarLink
key={link.path}
title={link.title}
path={link.path}
icon={link.icon}
/>
))}
</SideBar>
<MainContent>{children}</MainContent> {/* Render children here */}
</LayoutWrapper>
);
};
export default SideBarLayout;

View File

@ -0,0 +1,11 @@
// utils/defineStyles.ts
import type { SxProps, Theme } from "@mui/material/styles";
/**
* Helper to define style objects with full key/type inference as SxProps<Theme>
*/
export function defineStyles<T extends Record<string, SxProps<Theme>>>(
styles: T
): T {
return styles;
}

View File

@ -1,10 +1,13 @@
"use client";
'use client'; import { ThemeProvider, CssBaseline } from "@mui/material";
import theme from "./theme";
import { ThemeProvider, CssBaseline } from '@mui/material'; export default function ThemeRegistry({
import theme from './theme'; children,
}: {
export default function ThemeRegistry({ children }: { children: React.ReactNode }) { children: React.ReactNode;
}) {
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<CssBaseline /> <CssBaseline />