Refactored styled to use hybrid Scss and MUI for more dynamic styling
This commit is contained in:
parent
69fbd6d5e1
commit
f595509104
23
app/components/PageLinks/PageLinks.scss
Normal file
23
app/components/PageLinks/PageLinks.scss
Normal file
@ -0,0 +1,23 @@
|
||||
/* PageLinks.scss */
|
||||
|
||||
.link-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 1px;
|
||||
border-radius: 4px;
|
||||
color: var(--text-tertiary);
|
||||
text-decoration: none;
|
||||
transition: background 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: var(--hover-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.link-text {
|
||||
color: var(--text-tertiary);
|
||||
margin-left: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
25
app/components/PageLinks/PageLinks.tsx
Normal file
25
app/components/PageLinks/PageLinks.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
|
||||
import clsx from "clsx"; // Utility to merge class names
|
||||
import "./PageLinks.scss";
|
||||
|
||||
interface IPageLinksProps extends ISidebarLink {
|
||||
isShowIcon?: boolean;
|
||||
}
|
||||
|
||||
export default function PageLinks({
|
||||
title,
|
||||
path,
|
||||
icon: Icon,
|
||||
}: IPageLinksProps) {
|
||||
return (
|
||||
<Link href={path} passHref legacyBehavior>
|
||||
<a className={clsx("link-container")}>
|
||||
{Icon && <Icon />}
|
||||
<span className="link-text">{title}</span>
|
||||
</a>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
// This ensures this component is rendered only on the client side
|
||||
'use client';
|
||||
"use client";
|
||||
|
||||
import { Approve } from '@/app/components/Pages/Approve/Approve';
|
||||
import { Approve } from "@/app/features/Pages/Approve/Approve";
|
||||
|
||||
export default function ApprovePage() {
|
||||
return (
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
// This ensures this component is rendered only on the client side
|
||||
// 'use client';
|
||||
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React from 'react';
|
||||
import Typography from "@mui/material/Typography";
|
||||
import React from "react";
|
||||
|
||||
export default function KycPage() {
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
<div>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
KYC Overview
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
'use client';
|
||||
"use client";
|
||||
|
||||
import React from 'react';
|
||||
import { LayoutWrapper } from '../components/dashboard/layout/layoutWrapper';
|
||||
import { MainContent } from '../components/dashboard/layout/mainContent';
|
||||
import SideBar from '../components/dashboard/sidebar/Sidebar';
|
||||
import Header from '../components/dashboard/header/Header';
|
||||
import React from "react";
|
||||
import { LayoutWrapper } from "../features/dashboard/layout/layoutWrapper";
|
||||
import { MainContent } from "../features/dashboard/layout/mainContent";
|
||||
import SideBar from "../features/dashboard/sidebar/Sidebar";
|
||||
import Header from "../features/dashboard/header/Header";
|
||||
|
||||
const DashboardLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const DashboardLayout: React.FC<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<SideBar />
|
||||
<div style={{ flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
|
||||
<div style={{ flexGrow: 1, display: "flex", flexDirection: "column" }}>
|
||||
<MainContent>
|
||||
<Header />
|
||||
{children}
|
||||
|
||||
20
app/dashboard/loading.tsx
Normal file
20
app/dashboard/loading.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
'use client';
|
||||
"use client";
|
||||
|
||||
import { DashboardHomePage } from "../components/Pages/DashboardHomePage/DashboardHomePage";
|
||||
import { DashboardHomePage } from "../features/Pages/DashboardHomePage/DashboardHomePage";
|
||||
|
||||
const DashboardPage = () => {
|
||||
return (
|
||||
<DashboardHomePage />
|
||||
);
|
||||
return <DashboardHomePage />;
|
||||
};
|
||||
|
||||
export default DashboardPage;
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
// 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() {
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<div style={{ width: "100%" }}>
|
||||
{/* This page will now be rendered on the client-side */}
|
||||
<TransactionTable />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
23
app/features/AccountIQ/AccountIQ.tsx
Normal file
23
app/features/AccountIQ/AccountIQ.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { styled } from "@mui/material";
|
||||
import { SectionCard } from "../SectionCard/SectionCard";
|
||||
|
||||
const AccountIQIcon = styled("div")(() => ({
|
||||
fontWeight: "bold",
|
||||
color: "#4ecdc4",
|
||||
marginTop: "4px",
|
||||
}));
|
||||
|
||||
export const AccountIQ = () => {
|
||||
return (
|
||||
<SectionCard
|
||||
title="AccountIQ"
|
||||
icon={<AccountIQIcon>AIQ</AccountIQIcon>}
|
||||
items={[
|
||||
{ title: "Automatically reconcile your transactions" },
|
||||
{ title: "Live wallet balances from providers" },
|
||||
{ title: "Gaming provider financial overviews" },
|
||||
{ title: "Learn more" },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
84
app/features/DateRangePicker/DateRangePicker.tsx
Normal file
84
app/features/DateRangePicker/DateRangePicker.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import { useState } from "react";
|
||||
import { Box, Typography, Paper, Popover } from "@mui/material";
|
||||
import { DateRange, Range, DateRangeProps } from "react-date-range";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import "react-date-range/dist/styles.css";
|
||||
import "react-date-range/dist/theme/default.css";
|
||||
|
||||
export const DateRangePicker = () => {
|
||||
const [range, setRange] = useState<Range[]>([
|
||||
{
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
key: "selection"
|
||||
}
|
||||
]);
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
||||
|
||||
const handleSelect: DateRangeProps['onChange'] = (ranges) => {
|
||||
if (ranges.selection) {
|
||||
setRange([ranges.selection]);
|
||||
if (ranges.selection.endDate !== ranges.selection.startDate) {
|
||||
setAnchorEl(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? 'date-range-popover' : undefined;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Popover
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
>
|
||||
<Paper>
|
||||
<DateRange
|
||||
editableDateInputs={true}
|
||||
onChange={handleSelect}
|
||||
moveRangeOnFirstSelection={false}
|
||||
ranges={range}
|
||||
/>
|
||||
</Paper>
|
||||
</Popover>
|
||||
|
||||
<Box>
|
||||
<Typography
|
||||
onClick={handleClick}
|
||||
sx={{
|
||||
fontSize: '0.875rem',
|
||||
cursor: 'pointer',
|
||||
p: 1,
|
||||
borderRadius: 1,
|
||||
'&:hover': {
|
||||
backgroundColor: 'action.hover',
|
||||
}
|
||||
}}
|
||||
>
|
||||
{format(range[0].startDate ?? new Date(), "PPP")} - {format(range[0].endDate ?? new Date(), "PPP")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
18
app/features/Documentation/Documentation.tsx
Normal file
18
app/features/Documentation/Documentation.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
import DescriptionIcon from "@mui/icons-material/Description";
|
||||
import { SectionCard } from "../SectionCard/SectionCard";
|
||||
|
||||
export const Documentation = () => {
|
||||
return (
|
||||
<SectionCard
|
||||
title="Documentation"
|
||||
icon={<DescriptionIcon fontSize="small" sx={{ height: "auto" }} />}
|
||||
items={[
|
||||
{ title: "Provider Integration Overview" },
|
||||
{ title: "APIs Introduction" },
|
||||
{ title: "Documentation Overview" },
|
||||
{ title: "How-Tos" },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
173
app/features/FetchReports/FetchReports.tsx
Normal file
173
app/features/FetchReports/FetchReports.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Typography,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
Button,
|
||||
Stack,
|
||||
Box,
|
||||
Paper,
|
||||
IconButton,
|
||||
} from "@mui/material";
|
||||
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
|
||||
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import { DateRangePicker } from "../DateRangePicker/DateRangePicker";
|
||||
|
||||
export const FetchReport = () => {
|
||||
const [state, setState] = useState("");
|
||||
const [psp, setPsp] = useState("");
|
||||
const [reportType, setReportType] = useState("");
|
||||
|
||||
const handleDownload = () => {
|
||||
// Download logic goes here
|
||||
alert("Report downloaded");
|
||||
};
|
||||
|
||||
const isDownloadEnabled = state && psp && reportType;
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
padding: "23px",
|
||||
margin: 2,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 2 }}>
|
||||
<Typography variant="h6" fontWeight="bold">
|
||||
Fetch Report
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<CalendarTodayIcon fontSize="small" />
|
||||
<Typography variant="body2">
|
||||
<DateRangePicker />
|
||||
</Typography>
|
||||
<IconButton size="small">
|
||||
<MoreVertIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Stack spacing={2}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Select state (defaults to All)</InputLabel>
|
||||
<Select
|
||||
value={state}
|
||||
onChange={(e) => setState(e.target.value)}
|
||||
label="Select state (defaults to All)"
|
||||
>
|
||||
<MenuItem value="successful">Successful</MenuItem>
|
||||
<MenuItem value="failed">Failed</MenuItem>
|
||||
<MenuItem value="canceled">Canceled</MenuItem>
|
||||
|
||||
{/* Add more states */}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Select PSPs (defaults to All)</InputLabel>
|
||||
<Select
|
||||
value={psp}
|
||||
onChange={(e) => setPsp(e.target.value)}
|
||||
label="Select PSPs (defaults to All)"
|
||||
>
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
<MenuItem value="a1">A1</MenuItem>
|
||||
<MenuItem value="ahub">AHUB</MenuItem>
|
||||
<MenuItem value="aibms">AIBMS</MenuItem>
|
||||
|
||||
{/* Add more PSPs */}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Select report type</InputLabel>
|
||||
<Select
|
||||
value={reportType}
|
||||
onChange={(e) => setReportType(e.target.value)}
|
||||
label="Select report type"
|
||||
>
|
||||
<MenuItem value="allTransactionsReport">
|
||||
All Transactions Report
|
||||
</MenuItem>
|
||||
<MenuItem value="depositReport">Deposit Report</MenuItem>
|
||||
<MenuItem value="widthdrawReport">WithDraw Report</MenuItem>
|
||||
{/* Add more types */}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<Box textAlign="center" mt={2}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleDownload}
|
||||
disabled={!isDownloadEnabled}
|
||||
sx={{ minWidth: 200 }}
|
||||
>
|
||||
Download Report
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
72
app/features/GeneralHealthCard/GeneralHealthCard.tsx
Normal file
72
app/features/GeneralHealthCard/GeneralHealthCard.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { Box, Card, CardContent, Typography, IconButton } from "@mui/material";
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
|
||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
||||
import { DateRangePicker } from "../DateRangePicker/DateRangePicker";
|
||||
|
||||
const stats = [
|
||||
{ label: "TOTAL", value: 5, change: "-84.85%" },
|
||||
{ label: "SUCCESSFUL", value: 10, change: "100%" },
|
||||
{ label: "ACCEPTANCE RATE", value: "0%", change: "-100%" },
|
||||
{ label: "AMOUNT", value: "€0.00", change: "-100%" },
|
||||
{ label: "ATV", value: "€0.00", change: "-100%" },
|
||||
];
|
||||
|
||||
const StatItem = ({
|
||||
label,
|
||||
value,
|
||||
change,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number;
|
||||
change: string;
|
||||
}) => (
|
||||
<Box sx={{ textAlign: "center", px: 2 }}>
|
||||
<Typography variant="body2" fontWeight="bold" color="text.secondary">
|
||||
{label}
|
||||
</Typography>
|
||||
<Typography variant="h6" fontWeight="bold" mt={0.5}>
|
||||
{value}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "error.main",
|
||||
}}
|
||||
>
|
||||
<ArrowDropDownIcon fontSize="small" />
|
||||
{/* <ArrowDropUp fontSize='small' /> */}
|
||||
<Typography variant="caption">{change}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const GeneralHealthCard = () => {
|
||||
return (
|
||||
<Card sx={{ borderRadius: 3, p: 2 }}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 2 }}>
|
||||
<Typography variant="h5" fontWeight="bold">
|
||||
General Health
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<CalendarTodayIcon fontSize="small" />
|
||||
<Typography variant="body2">
|
||||
<DateRangePicker />
|
||||
</Typography>
|
||||
<IconButton size="small">
|
||||
<MoreVertIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-around", mt: 2 }}>
|
||||
{stats.map((item, i) => (
|
||||
<StatItem key={item.label + i} {...item} />
|
||||
))}
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
162
app/features/Pages/Approve/Approve.tsx
Normal file
162
app/features/Pages/Approve/Approve.tsx
Normal file
@ -0,0 +1,162 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
TextField,
|
||||
IconButton,
|
||||
InputAdornment,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Checkbox,
|
||||
Paper,
|
||||
MenuItem,
|
||||
InputLabel,
|
||||
Select,
|
||||
FormControl,
|
||||
SelectChangeEvent
|
||||
} from '@mui/material';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
|
||||
const rows = [
|
||||
{
|
||||
merchantId: '100987998',
|
||||
txId: '1049078821',
|
||||
userId: 17,
|
||||
userEmail: 'dhkheni1@yopmail.com',
|
||||
kycStatus: 'N/A',
|
||||
},
|
||||
{
|
||||
merchantId: '100987998',
|
||||
txId: '1049078821',
|
||||
userId: 18,
|
||||
userEmail: 'dhkheni1@yopmail.com',
|
||||
kycStatus: 'N/A',
|
||||
},
|
||||
{
|
||||
merchantId: '100987998',
|
||||
txId: '1049078821',
|
||||
userId: 19,
|
||||
userEmail: 'dhkheni1@yopmail.com',
|
||||
kycStatus: 'N/A',
|
||||
},
|
||||
];
|
||||
|
||||
export const Approve = () => {
|
||||
const [age, setAge] = useState('');
|
||||
const [selectedRows, setSelectedRows] = useState<number[]>([]);
|
||||
|
||||
|
||||
|
||||
const handleCheckboxChange = (userId: number) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const isChecked = event.target.checked;
|
||||
setSelectedRows((prevSelected: number[]) =>
|
||||
isChecked
|
||||
? [...prevSelected, userId]
|
||||
: prevSelected.filter((id) => id !== userId)
|
||||
);
|
||||
console.log('Selected IDs:', isChecked
|
||||
? [...selectedRows, userId]
|
||||
: selectedRows.filter((id) => id !== userId));
|
||||
};
|
||||
|
||||
const handleChangeAge = (event: SelectChangeEvent) => {
|
||||
setAge(event.target.value as string);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box p={2}>
|
||||
<Box mb={2} display="flex" justifyContent="space-between" alignItems="center">
|
||||
<TextField
|
||||
variant="outlined"
|
||||
placeholder="Filter by tags or search by keyword"
|
||||
size="small"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Box sx={{ width: '100px' }}>
|
||||
{/* <IconButton onClick={handleMenuOpen}> */}
|
||||
{/* <MoreVertIcon /> */}
|
||||
{/* </IconButton> */}
|
||||
{/* <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleMenuClose}> */}
|
||||
{/* <MenuItem onClick={handleMenuClose}>Action 1</MenuItem> */}
|
||||
{/* <MenuItem onClick={handleMenuClose}>Action 2</MenuItem> */}
|
||||
{/* </Menu> */}
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">Action</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={age}
|
||||
label="Age"
|
||||
onChange={handleChangeAge}
|
||||
>
|
||||
<MenuItem value={10}>Ten</MenuItem>
|
||||
<MenuItem value={20}>Twenty</MenuItem>
|
||||
<MenuItem value={30}>Thirty</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<TableContainer component={Paper}>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell padding="checkbox"><Checkbox /></TableCell>
|
||||
<TableCell>Merchant-id</TableCell>
|
||||
<TableCell>Tx-id</TableCell>
|
||||
<TableCell>User</TableCell>
|
||||
<TableCell>User email</TableCell>
|
||||
<TableCell>KYC Status</TableCell>
|
||||
<TableCell>KYC PSP</TableCell>
|
||||
<TableCell>KYC PSP status</TableCell>
|
||||
<TableCell>KYC ID status</TableCell>
|
||||
<TableCell>KYC address status</TableCell>
|
||||
<TableCell>KYC liveness status</TableCell>
|
||||
<TableCell>KYC age status</TableCell>
|
||||
<TableCell>KYC peps and sanctions</TableCell>
|
||||
<TableCell>Suspected</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{rows.map((row, idx) => (
|
||||
<TableRow key={idx}>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox checked={selectedRows.includes(row.userId)}
|
||||
onChange={handleCheckboxChange(row.userId)} /></TableCell>
|
||||
<TableCell>{row.merchantId}</TableCell>
|
||||
<TableCell>{row.txId}</TableCell>
|
||||
<TableCell>
|
||||
<a href={`/user/${row.userId}`} target="_blank" rel="noopener noreferrer">
|
||||
{row.userId}
|
||||
</a>
|
||||
</TableCell>
|
||||
<TableCell>{row.userEmail}</TableCell>
|
||||
<TableCell>{row.kycStatus}</TableCell>
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
<TableCell />
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
24
app/features/Pages/DashboardHomePage/DashboardHomePage.tsx
Normal file
24
app/features/Pages/DashboardHomePage/DashboardHomePage.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { Box } from "@mui/material"
|
||||
import { GeneralHealthCard } from "../../GeneralHealthCard/GeneralHealthCard"
|
||||
import { TransactionsOverview } from "../../TransactionsOverview/TransactionsOverview"
|
||||
import { TransactionsWaitingApproval } from "../../TransactionsWaitingApproval/TransactionsWaitingApproval"
|
||||
import { FetchReport } from "../../FetchReports/FetchReports"
|
||||
import { Documentation } from "../../Documentation/Documentation"
|
||||
import { AccountIQ } from "../../AccountIQ/AccountIQ"
|
||||
import { WhatsNew } from "../../WhatsNew/WhatsNew"
|
||||
|
||||
export const DashboardHomePage = () => {
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<GeneralHealthCard />
|
||||
</Box>
|
||||
<TransactionsOverview />
|
||||
<FetchReport />
|
||||
<TransactionsWaitingApproval />
|
||||
<Documentation />
|
||||
<AccountIQ />
|
||||
<WhatsNew />
|
||||
</>
|
||||
)
|
||||
}
|
||||
131
app/features/Pages/transactions/Transactions.tsx
Normal file
131
app/features/Pages/transactions/Transactions.tsx
Normal file
@ -0,0 +1,131 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
FormControl,
|
||||
Select,
|
||||
MenuItem,
|
||||
FormControlLabel,
|
||||
Checkbox,
|
||||
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 };
|
||||
|
||||
export default function TransactionTable() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [fileType, setFileType] = useState<"csv" | "xls" | "xlsx">("csv");
|
||||
const [onlyCurrentTable, setOnlyCurrentTable] = useState(false);
|
||||
|
||||
const handleExport = () => {
|
||||
const exportRows = onlyCurrentTable ? rows.slice(0, 5) : rows;
|
||||
const exportData = [
|
||||
columns.map((col) => col.headerName),
|
||||
// @ts-expect-error - Dynamic field access from DataGrid columns
|
||||
...exportRows.map((row) => columns.map((col) => row[col.field] ?? "")),
|
||||
];
|
||||
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(exportData);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "Transactions");
|
||||
|
||||
if (fileType === "csv") {
|
||||
const csv = XLSX.utils.sheet_to_csv(worksheet);
|
||||
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
||||
saveAs(blob, "transactions.csv");
|
||||
} else {
|
||||
XLSX.writeFile(workbook, `transactions.${fileType}`, {
|
||||
bookType: fileType,
|
||||
});
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledPaper>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
p={2}
|
||||
>
|
||||
<TextField
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
// value={'searchQuery'}
|
||||
onChange={(e) => console.log(`setSearchQuery(${e.target.value})`)}
|
||||
sx={{ width: 300 }}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<FileUploadIcon />}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
initialState={{ pagination: { paginationModel } }}
|
||||
pageSizeOptions={[50, 100]}
|
||||
sx={{ border: 0 }}
|
||||
/>
|
||||
|
||||
{/* Export Dialog */}
|
||||
<Dialog open={open} onClose={() => setOpen(false)}>
|
||||
<DialogTitle>Export Transactions</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||
<Select
|
||||
value={fileType}
|
||||
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>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={onlyCurrentTable}
|
||||
onChange={(e) => setOnlyCurrentTable(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label="Only export the results in the current table"
|
||||
sx={{ mt: 2 }}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpen(false)}>Cancel</Button>
|
||||
<Button variant="contained" onClick={handleExport}>
|
||||
Export
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</StyledPaper>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledPaper = styled(Paper)(() => ({
|
||||
height: "90vh",
|
||||
}));
|
||||
80
app/features/Pages/transactions/constants.ts
Normal file
80
app/features/Pages/transactions/constants.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { GridColDef } from "@mui/x-data-grid";
|
||||
|
||||
export const columns: GridColDef[] = [
|
||||
{ field: 'merchandId', headerName: 'Merchant ID', width: 130 },
|
||||
{ field: 'transactionID', headerName: 'Transaction ID', width: 130 },
|
||||
{ field: 'user', headerName: 'User', width: 75 },
|
||||
{ field: 'created', headerName: 'Created', type: 'number', width: 130 },
|
||||
{ field: 'state', headerName: 'State', type: 'number', width: 130 },
|
||||
{ field: 'statusDescription', headerName: 'Status Description', type: 'number', width: 130 },
|
||||
{ field: 'pspStatusCode', headerName: 'PSP Status Code', type: 'number', width: 130 },
|
||||
{ field: 'pspStatusMessage', headerName: 'PSP Status Message', type: 'number', width: 90 },
|
||||
{ field: 'psp', headerName: 'PSP', type: 'number', width: 90 },
|
||||
{ field: 'pspAccount', headerName: 'PSP Account', type: 'number', width: 90 },
|
||||
{ field: 'initPSP', headerName: 'Init PSP', type: 'number', width: 90 },
|
||||
{ field: 'initPSPAccout', headerName: 'Init PSP Account', type: 'number', width: 90 },
|
||||
{ field: 'pspService', headerName: 'PSP Service', type: 'number', width: 90 },
|
||||
{ field: 'transactionType', headerName: 'Transaction Type', type: 'number', width: 90 },
|
||||
{ field: 'paymentMethod', headerName: 'Payment Method', type: 'number', width: 90 },
|
||||
{ field: 'rules', headerName: 'Rules', type: 'number', width: 90 },
|
||||
{ field: 'amount', headerName: 'Amount', type: 'number', width: 90 },
|
||||
{ field: 'fee', headerName: 'Fee', type: 'number', width: 90 },
|
||||
{ field: 'transactionAmount', headerName: 'Transaction Amount', type: 'number', width: 90 },
|
||||
{ field: 'baseAmount', headerName: 'Base Amount', type: 'number', width: 90 },
|
||||
{ field: 'baseFee', headerName: 'Base Fee', type: 'number', width: 90 },
|
||||
{ field: 'baseTransaction', headerName: 'Base Transaction', type: 'number', width: 90 },
|
||||
{ field: 'pspFee', headerName: 'PSP Fee', type: 'number', width: 90 },
|
||||
{ field: 'basePspFee', headerName: 'Base PSP Fee', type: 'number', width: 90 },
|
||||
{ field: 'authAmount', headerName: 'Auth Amount', type: 'number', width: 90 },
|
||||
{ field: 'baseAuthAmount', headerName: 'Base Auth Amount', type: 'number', width: 90 },
|
||||
{ field: 'userBalance', headerName: 'User Balance', type: 'number', width: 90 },
|
||||
{ field: 'updated', headerName: 'Updated', type: 'number', width: 90 },
|
||||
{ field: 'userIp', headerName: 'User IP', type: 'number', width: 90 },
|
||||
{ field: 'channel', headerName: 'Channel', type: 'number', width: 90 },
|
||||
{ field: 'depositType', headerName: 'Deposit Type', type: 'number', width: 90 },
|
||||
{ field: 'userEmal', headerName: 'User Emal', type: 'number', width: 90 },
|
||||
{ field: 'userCategory', headerName: 'User Category', type: 'number', width: 90 },
|
||||
{ field: 'userCountry', headerName: 'User Country', type: 'number', width: 90 },
|
||||
{ field: 'userAccount', headerName: 'User Account', type: 'number', width: 90 },
|
||||
{ field: 'bankName', headerName: 'Bank Name', type: 'number', width: 90 },
|
||||
{ field: 'pspUserReference', headerName: 'PSP User Reference', type: 'number', width: 90 },
|
||||
{ field: 'pspFraudScore', headerName: 'PSP Fraud Score', type: 'number', width: 90 },
|
||||
{ field: 'fraudStatus', headerName: 'FraudStatus', type: 'number', width: 90 },
|
||||
{ field: 'blocked', headerName: 'Blocked', type: 'number', width: 90 },
|
||||
{ field: 'abuse', headerName: 'Abuse', type: 'number', width: 90 },
|
||||
{ field: 'kycStatus', headerName: 'KYC Status', type: 'number', width: 90 },
|
||||
{ field: 'kycPSPName', headerName: 'KYC PSP Name', type: 'number', width: 90 },
|
||||
{ field: 'kycPSPStatus', headerName: 'KYC PSP Status', type: 'number', width: 90 },
|
||||
{ field: 'kycIdStatus', headerName: 'KYC ID Status', type: 'number', width: 90 },
|
||||
{ field: 'kycAddressStatus', headerName: 'KYC Address Status', type: 'number', width: 90 },
|
||||
{ field: 'kycAgeStatus', headerName: 'KYC Age Status', type: 'number', width: 90 },
|
||||
{ field: 'kycPEPAndSanction', headerName: 'KYC PEP And Sanction', type: 'number', width: 90 },
|
||||
{ field: 'pspReferenceId', headerName: 'PSPReferenceID', type: 'number', width: 90 },
|
||||
{ field: 'siteReferenceId', headerName: 'Site Reference ID', type: 'number', width: 90 },
|
||||
{ field: 'info', headerName: 'Info', type: 'number', width: 90 },
|
||||
{ field: 'accountHolder', headerName: 'Account Holder', type: 'number', width: 90 },
|
||||
{ field: 'firstName', headerName: 'First Name', type: 'number', width: 90 },
|
||||
{ field: 'lastName', headerName: 'Last Name', type: 'number', width: 90 },
|
||||
{ field: 'street', headerName: 'Street', type: 'number', width: 90 },
|
||||
{ field: 'city', headerName: 'City', type: 'number', width: 90 },
|
||||
{ field: 'zip', headerName: 'ZIP', type: 'number', width: 90 },
|
||||
{ field: 'dob', headerName: 'DOB', type: 'number', width: 90 },
|
||||
{ field: 'mobile', headerName: 'Mobile', type: 'number', width: 90 },
|
||||
{ field: 'lastUpdatedBy', headerName: 'Last Updated By', type: 'number', width: 90 },
|
||||
{ field: 'ipCity', headerName: 'IP City', type: 'number', width: 90 },
|
||||
{ field: 'ipRegion', headerName: 'IP Region', type: 'number', width: 90 },
|
||||
{ field: 'ipCountry', headerName: 'IP Country', type: 'number', width: 90 },
|
||||
{ field: 'cardIssuerCountry', headerName: 'Card Issuer Country', type: 'number', width: 90 },
|
||||
{ field: 'cardBand', headerName: 'Card Band', type: 'number', width: 90 },
|
||||
{ field: 'cardCategory', headerName: 'Card Category', type: 'number', width: 90 },
|
||||
{ field: 'cardIssuerName', headerName: 'Card Issuer Name', type: 'number', width: 90 },
|
||||
{ field: 'inn', headerName: 'INN', type: 'number', width: 90 },
|
||||
{ field: 'cardType', headerName: 'Card Type', type: 'number', width: 90 },
|
||||
{ field: 'firstAttempt', headerName: 'First Attempt', type: 'number', width: 90 },
|
||||
{ field: 'firstSuccessful', headerName: 'First Successful', type: 'number', width: 90 },
|
||||
{ field: 'firstTransaction', headerName: 'First Transaction', type: 'number', width: 90 },
|
||||
{ field: 'firstPspAcountAttempt', headerName: 'First PSP Acount Attempt', type: 'number', width: 90 },
|
||||
{ field: 'firstPspAcountSuccessful', headerName: 'First PSP Acount Successful', type: 'number', width: 90 },
|
||||
{ field: 'originTransactionId', headerName: 'Origin Transaction ID', type: 'number', width: 90 },
|
||||
{ field: 'transactionReferenceId', headerName: 'Transaction Reference ID', type: 'number', width: 90 },
|
||||
];
|
||||
2134
app/features/Pages/transactions/mockData.ts
Normal file
2134
app/features/Pages/transactions/mockData.ts
Normal file
File diff suppressed because it is too large
Load Diff
69
app/features/PieCharts/PieCharts.tsx
Normal file
69
app/features/PieCharts/PieCharts.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Box } from "@mui/material";
|
||||
import { PieChart, Pie, Cell, ResponsiveContainer } from "recharts";
|
||||
|
||||
const data = [
|
||||
{ name: "Group A", value: 100 },
|
||||
{ name: "Group B", value: 200 },
|
||||
{ name: "Group C", value: 400 },
|
||||
{ name: "Group D", value: 300 }
|
||||
];
|
||||
|
||||
const COLORS = ["#4caf50", "#ff9800", "#f44336", "#9e9e9e"];
|
||||
|
||||
const RADIAN = Math.PI / 180;
|
||||
const renderCustomizedLabel = ({
|
||||
cx,
|
||||
cy,
|
||||
midAngle,
|
||||
innerRadius,
|
||||
outerRadius,
|
||||
percent,
|
||||
// index
|
||||
}: any) => {
|
||||
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
|
||||
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
||||
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
||||
|
||||
return (
|
||||
<text
|
||||
x={x}
|
||||
y={y}
|
||||
fill="white"
|
||||
textAnchor={x > cx ? "start" : "end"}
|
||||
dominantBaseline="central"
|
||||
>
|
||||
{`${(percent * 100).toFixed(0)}%`}
|
||||
</text>
|
||||
);
|
||||
};
|
||||
export const PieCharts = () => {
|
||||
return (
|
||||
<Box sx={{
|
||||
width: {
|
||||
xs: '100%',
|
||||
md: '60%'
|
||||
}, height: '300px'
|
||||
}}>
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={data}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
labelLine={false}
|
||||
label={renderCustomizedLabel}
|
||||
outerRadius="80%" // Percentage-based radius
|
||||
fill="#8884d8"
|
||||
dataKey="value"
|
||||
>
|
||||
{data.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</Box >
|
||||
);
|
||||
}
|
||||
|
||||
50
app/features/SectionCard/SectionCard.tsx
Normal file
50
app/features/SectionCard/SectionCard.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import {
|
||||
CardContent,
|
||||
Typography,
|
||||
Divider,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Box,
|
||||
IconButton,
|
||||
} from "@mui/material";
|
||||
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import { ISectionCardProps } from "./types";
|
||||
|
||||
export const SectionCard = ({ title, icon, items }: ISectionCardProps) => (
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{ padding: 2, margin: 2, display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<CardContent>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 2 }}>
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
{icon}
|
||||
<Typography variant="h6" fontWeight="bold">
|
||||
{title}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<IconButton size="small">
|
||||
<MoreVertIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Divider />
|
||||
<List dense disablePadding>
|
||||
{items.map((item, index) => (
|
||||
<ListItem key={item.title + index} disableGutters>
|
||||
<ListItemText
|
||||
primary={item.title}
|
||||
secondary={item.date}
|
||||
primaryTypographyProps={{ fontSize: 14 }}
|
||||
secondaryTypographyProps={{ fontSize: 12 }}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</CardContent>
|
||||
</Paper>
|
||||
);
|
||||
12
app/features/SectionCard/types.ts
Normal file
12
app/features/SectionCard/types.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export interface ISectionItem {
|
||||
title: string;
|
||||
date?: string;
|
||||
}
|
||||
|
||||
export interface ISectionCardProps {
|
||||
title: string;
|
||||
icon: ReactNode;
|
||||
items: ISectionItem[];
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Paper,
|
||||
Box,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
|
||||
const data1 = [
|
||||
{ state: "Success", count: 120, percentage: "60%", color: "green" },
|
||||
{ state: "Pending", count: 50, percentage: "25%", color: "orange" },
|
||||
{ state: "Failed", count: 20, percentage: "10%", color: "red" },
|
||||
{ state: "Other", count: 10, percentage: "5%", color: "gray" },
|
||||
];
|
||||
|
||||
export const TransactionsOverviewTable = () => {
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">State</TableCell>
|
||||
<TableCell align="center">Count</TableCell>
|
||||
<TableCell align="center">Percentage</TableCell>
|
||||
<TableCell align="center">Action</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data1.map((row, i) => (
|
||||
<TableRow key={row.state + i}>
|
||||
<TableCell align="center">
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
mx: "auto", // center the flexbox itself
|
||||
width: "73px", // consistent width for alignment
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: "50%",
|
||||
bgcolor: row.color,
|
||||
mr: 1,
|
||||
}}
|
||||
/>
|
||||
{row.state}
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell align="center">{row.count}</TableCell>
|
||||
<TableCell align="center">{row.percentage}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Button variant="outlined" size="small">
|
||||
View
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
68
app/features/TransactionsOverview/TransactionsOverview.tsx
Normal file
68
app/features/TransactionsOverview/TransactionsOverview.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Box, Button, IconButton, Paper, Typography } from "@mui/material";
|
||||
import { PieCharts } from "../PieCharts/PieCharts";
|
||||
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import { TransactionsOverviewTable } from "./TransactionsOverViewTable";
|
||||
|
||||
export const TransactionsOverview = () => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
padding: "23px",
|
||||
margin: 2,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{/* Title and All Transactions Button */}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
px: 1,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5" fontWeight="bold">
|
||||
Transactions Overview (Last 24h)
|
||||
</Typography>
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => router.push("dashboard/transactions")}
|
||||
>
|
||||
All Transactions
|
||||
</Button>
|
||||
<IconButton size="small">
|
||||
<MoreVertIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Chart and Table */}
|
||||
<Box
|
||||
sx={{
|
||||
padding: 2,
|
||||
margin: 2,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
flexWrap: {
|
||||
xs: "wrap", // Wrap on small screens
|
||||
md: "nowrap", // No wrap on medium and up
|
||||
},
|
||||
gap: {
|
||||
xs: 4, // Add spacing on small screens
|
||||
md: 0, // No spacing on larger screens
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PieCharts />
|
||||
<TransactionsOverviewTable />
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,195 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
IconButton,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
|
||||
const transactions = [
|
||||
{
|
||||
id: "1049078821",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078822",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078823",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078824",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078821",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078822",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078823",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078824",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078821",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078822",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078823",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
{
|
||||
id: "1049078824",
|
||||
user: "17",
|
||||
created: "2025-06-17 16:45",
|
||||
type: "BestPayWithdrawal",
|
||||
amount: "-787.49 TRY",
|
||||
psp: "BestPay",
|
||||
},
|
||||
];
|
||||
|
||||
export const TransactionsWaitingApproval = () => {
|
||||
return (
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{ padding: 2, margin: 2, display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 2 }}>
|
||||
<Typography variant="h5" fontWeight="bold">
|
||||
Transactions Waiting for Approval
|
||||
</Typography>
|
||||
<Box>
|
||||
<Button variant="outlined">All Pending Withdrawals</Button>
|
||||
<IconButton size="small">
|
||||
<MoreVertIcon fontSize="small" />
|
||||
</IconButton>{" "}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<TableContainer
|
||||
component={Paper}
|
||||
sx={{
|
||||
maxHeight: 400, // Set desired height
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<strong>ID</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>User</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>Created</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>Type</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>Amount</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>PSP</strong>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<strong>Action</strong>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{transactions.map((tx, i) => (
|
||||
<TableRow key={tx.id + i}>
|
||||
<TableCell>{tx.id}</TableCell>
|
||||
<TableCell>{tx.user}</TableCell>
|
||||
<TableCell>{tx.created}</TableCell>
|
||||
<TableCell>{tx.type}</TableCell>
|
||||
<TableCell>{tx.amount}</TableCell>
|
||||
<TableCell>{tx.psp}</TableCell>
|
||||
<TableCell>
|
||||
<IconButton color="success">
|
||||
<CheckCircleIcon />
|
||||
</IconButton>
|
||||
<IconButton color="error">
|
||||
<CancelIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
27
app/features/WhatsNew/WhatsNew.tsx
Normal file
27
app/features/WhatsNew/WhatsNew.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { SectionCard } from "../SectionCard/SectionCard";
|
||||
import WifiIcon from "@mui/icons-material/Wifi";
|
||||
|
||||
export const WhatsNew = () => {
|
||||
return (
|
||||
<SectionCard
|
||||
title="What’s New"
|
||||
icon={<WifiIcon fontSize="small" sx={{ height: "auto" }} />}
|
||||
items={[
|
||||
{
|
||||
title: "Sneak Peek – Discover the New Rules Hub Feature",
|
||||
date: "13 May 2025",
|
||||
},
|
||||
{
|
||||
title:
|
||||
"New security measures for anonymizing sensitive configuration values, effective December 2nd",
|
||||
date: "31 Oct 2024",
|
||||
},
|
||||
{
|
||||
title: "Introducing Our New Transactions and Rule Views",
|
||||
date: "23 Oct 2024",
|
||||
},
|
||||
{ title: "Introducing Our New Status Page", date: "09 Sept 2024" },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
17
app/features/dashboard/header/Header.scss
Normal file
17
app/features/dashboard/header/Header.scss
Normal file
@ -0,0 +1,17 @@
|
||||
.header-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.left-group {
|
||||
width: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px; // optional spacing between menu and dropdown
|
||||
}
|
||||
|
||||
.right-group {
|
||||
margin-left: auto; // pushes it to the far right
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
46
app/features/dashboard/header/Header.tsx
Normal file
46
app/features/dashboard/header/Header.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React, { useState } from "react";
|
||||
import { AppBar, Toolbar, IconButton, Menu, MenuItem } from "@mui/material";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
import Dropdown from "./dropDown/DropDown";
|
||||
import AccountMenu from "./accountMenu/AccountMenu";
|
||||
import "./Header.scss";
|
||||
|
||||
const Header = () => {
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
|
||||
// Handle menu open
|
||||
const handleMenuClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
// Handle menu close
|
||||
const handleMenuClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleChange = (e: any) => {};
|
||||
|
||||
return (
|
||||
<AppBar
|
||||
position="sticky"
|
||||
color="transparent"
|
||||
elevation={0}
|
||||
sx={{ borderBottom: "1px solid #22242626" }}
|
||||
>
|
||||
<Toolbar className="header-toolbar">
|
||||
<div className="left-group">
|
||||
<IconButton edge="start" color="inherit" aria-label="menu">
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Dropdown onChange={handleChange} />
|
||||
</div>
|
||||
|
||||
<div className="right-group">
|
||||
<AccountMenu />
|
||||
</div>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
64
app/features/dashboard/header/accountMenu/AccountMenu.tsx
Normal file
64
app/features/dashboard/header/accountMenu/AccountMenu.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
|
||||
export default function AccountMenu() {
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton onClick={handleClick} color="inherit">
|
||||
<AccountCircleIcon />
|
||||
</IconButton>
|
||||
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
onClick={handleClose}
|
||||
transformOrigin={{ horizontal: "right", vertical: "top" }}
|
||||
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
|
||||
>
|
||||
<MenuItem>
|
||||
<ListItemIcon>
|
||||
<AccountCircleIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">Account</Typography>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem>
|
||||
<ListItemIcon>
|
||||
<SettingsIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">Settings</Typography>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem>
|
||||
<ListItemIcon>
|
||||
<LogoutIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">Sign out</Typography>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
app/features/dashboard/header/dropDown/DropDown.scss
Normal file
8
app/features/dashboard/header/dropDown/DropDown.scss
Normal file
@ -0,0 +1,8 @@
|
||||
.dropdown-container {
|
||||
.link-container {
|
||||
color: var(--text-secondary);
|
||||
.link-text {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
app/features/dashboard/header/dropDown/DropDown.tsx
Normal file
52
app/features/dashboard/header/dropDown/DropDown.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
import {
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
SelectChangeEvent,
|
||||
} from "@mui/material";
|
||||
import { SIDEBAR_LINKS } from "@/app/features/dashboard/sidebar/SidebarLink.constants";
|
||||
import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
|
||||
import PageLinks from "../../../../components/PageLinks/PageLinks";
|
||||
import "./DropDown.scss";
|
||||
|
||||
interface Props {
|
||||
onChange?: (event: SelectChangeEvent<string>) => void;
|
||||
}
|
||||
|
||||
export default function SidebarDropdown({ onChange }: Props) {
|
||||
const [value, setValue] = React.useState("");
|
||||
|
||||
const handleChange = (event: SelectChangeEvent<string>) => {
|
||||
setValue(event.target.value);
|
||||
onChange?.(event);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl fullWidth variant="outlined" sx={{ minWidth: 200 }}>
|
||||
<InputLabel id="sidebar-dropdown-label">Navigate To</InputLabel>
|
||||
<Select
|
||||
labelId="sidebar-dropdown-label"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
label="Navigate To"
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
style: {
|
||||
maxHeight: 200,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<em className="em">Select a page</em>
|
||||
<MenuItem value="" disabled></MenuItem>
|
||||
<div className="dropdown-container">
|
||||
{SIDEBAR_LINKS.map((link: ISidebarLink) => (
|
||||
<PageLinks key={link.path} title={link.title} path={link.path} />
|
||||
))}
|
||||
</div>
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
7
app/features/dashboard/layout/layoutWrapper.ts
Normal file
7
app/features/dashboard/layout/layoutWrapper.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { styled } from "@mui/system";
|
||||
|
||||
export const LayoutWrapper = styled("div")({
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
height: "100vh",
|
||||
});
|
||||
8
app/features/dashboard/layout/mainContent.ts
Normal file
8
app/features/dashboard/layout/mainContent.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { styled } from '@mui/system';
|
||||
|
||||
export const MainContent = styled('div')(({ theme }) => ({
|
||||
marginLeft: '240px',
|
||||
padding: theme.spacing(3),
|
||||
minHeight: '100vh',
|
||||
width: 'calc(100% - 240px)',
|
||||
}));
|
||||
30
app/features/dashboard/sidebar/Sidebar.tsx
Normal file
30
app/features/dashboard/sidebar/Sidebar.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import DashboardIcon from "@mui/icons-material/Dashboard";
|
||||
import { SIDEBAR_LINKS } from "@/app/features/dashboard/sidebar/SidebarLink.constants";
|
||||
import PageLinks from "../../../components/PageLinks/PageLinks";
|
||||
import "./sideBar.scss";
|
||||
|
||||
const SideBar = () => {
|
||||
return (
|
||||
<aside className="sidebar-container">
|
||||
<div className="sidebar-header">
|
||||
<span>
|
||||
Betrise cashir{" "}
|
||||
<DashboardIcon fontSize="small" className="sidebar-icon-spacing" />
|
||||
</span>
|
||||
</div>
|
||||
{SIDEBAR_LINKS.map((link) => (
|
||||
<PageLinks
|
||||
key={link.path}
|
||||
title={link.title}
|
||||
path={link.path}
|
||||
icon={link.icon}
|
||||
/>
|
||||
))}
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideBar;
|
||||
32
app/features/dashboard/sidebar/SidebarLink.constants.ts
Normal file
32
app/features/dashboard/sidebar/SidebarLink.constants.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import HomeIcon from "@mui/icons-material/Home";
|
||||
import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import VerifiedUserIcon from "@mui/icons-material/VerifiedUser";
|
||||
import PeopleIcon from "@mui/icons-material/People";
|
||||
import GavelIcon from "@mui/icons-material/Gavel";
|
||||
import HubIcon from "@mui/icons-material/Hub";
|
||||
import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings";
|
||||
import InsightsIcon from "@mui/icons-material/Insights";
|
||||
import { ISidebarLink } from "@/app/features/dashboard/sidebar/SidebarLink.interfaces";
|
||||
|
||||
export const SIDEBAR_LINKS: ISidebarLink[] = [
|
||||
{ title: "Home", path: "/dashboard", icon: HomeIcon },
|
||||
{
|
||||
title: "Transaction",
|
||||
path: "/dashboard/transactions",
|
||||
icon: AccountBalanceWalletIcon,
|
||||
},
|
||||
{ title: "Approve", path: "/dashboard/approve", icon: CheckCircleIcon },
|
||||
{ title: "Investigate", path: "/dashboard/investigate", icon: SearchIcon },
|
||||
{ title: "KYC", path: "/kyc", icon: VerifiedUserIcon },
|
||||
{ title: "User Accounts", path: "/user-accounts", icon: PeopleIcon },
|
||||
// { title: 'Analytics', path: '/analytics', icon: BarChartIcon },
|
||||
{ title: "Rules", path: "/rules", icon: GavelIcon },
|
||||
{ title: "Rules Hub", path: "/rules-hub", icon: HubIcon },
|
||||
{ title: "Admin", path: "/admin", icon: AdminPanelSettingsIcon },
|
||||
{ title: "Account IQ", path: "/account-iq", icon: InsightsIcon },
|
||||
// { title: 'Documentation', path: '/documentation', icon: DescriptionIcon },
|
||||
// { title: 'Support', path: '/support', icon: SupportAgentIcon },
|
||||
// { title: 'System Status', path: '/system-status', icon: WarningAmberIcon },
|
||||
];
|
||||
7
app/features/dashboard/sidebar/SidebarLink.interfaces.ts
Normal file
7
app/features/dashboard/sidebar/SidebarLink.interfaces.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { ElementType } from "react";
|
||||
|
||||
export interface ISidebarLink {
|
||||
title: string;
|
||||
path: string;
|
||||
icon?: ElementType;
|
||||
}
|
||||
27
app/features/dashboard/sidebar/sideBar.scss
Normal file
27
app/features/dashboard/sidebar/sideBar.scss
Normal file
@ -0,0 +1,27 @@
|
||||
.sidebar-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 240px;
|
||||
height: 100vh;
|
||||
background-color: var(--background-primary);
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
z-index: 1100;
|
||||
border-right: 1px solid #333;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar-icon-spacing {
|
||||
margin-left: 8px;
|
||||
}
|
||||
@ -1,12 +1,17 @@
|
||||
import ThemeRegistry from '@/config/ThemeRegistry';
|
||||
import type { Metadata } from 'next';
|
||||
import ThemeRegistry from "@/config/ThemeRegistry";
|
||||
import type { Metadata } from "next";
|
||||
import "../styles/globals.scss";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Your App',
|
||||
description: 'Generated by Next.js',
|
||||
title: "Your App",
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
|
||||
11
app/utils/defineStyles.ts
Normal file
11
app/utils/defineStyles.ts
Normal 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;
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
"use client";
|
||||
|
||||
'use client';
|
||||
import { ThemeProvider, CssBaseline } from "@mui/material";
|
||||
import theme from "./theme";
|
||||
|
||||
import { ThemeProvider, CssBaseline } from '@mui/material';
|
||||
import theme from './theme';
|
||||
|
||||
export default function ThemeRegistry({ children }: { children: React.ReactNode }) {
|
||||
export default function ThemeRegistry({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
|
||||
1460
package-lock.json
generated
1460
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,13 +12,19 @@
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^7.1.1",
|
||||
"@mui/material": "^7.1.1",
|
||||
"@mui/material": "^7.1.2",
|
||||
"@mui/x-data-grid": "^8.5.2",
|
||||
"@mui/x-date-pickers": "^8.5.3",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"file-saver": "^2.0.5",
|
||||
"next": "15.3.3",
|
||||
"react": "^19.0.0",
|
||||
"react-date-range": "^2.0.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"recharts": "^2.15.3",
|
||||
"sass": "^1.89.2",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -26,6 +32,7 @@
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-date-range": "^1.4.10",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.3.3",
|
||||
|
||||
52
styles/globals.scss
Normal file
52
styles/globals.scss
Normal file
@ -0,0 +1,52 @@
|
||||
@use "./variables" as *;
|
||||
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
--primary-color: #{$primary-color};
|
||||
--secondary-color: #{$secondary-color};
|
||||
--background-primary: #{$background-primary};
|
||||
--text-primary: #{$text-primary};
|
||||
--text-secondary: #{$text-secondary};
|
||||
--text-tertiary: #{$text-tertiary};
|
||||
--hover-color: #{$hover-color};
|
||||
--font-family-base: #{$font-family-base};
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
10
styles/variables.scss
Normal file
10
styles/variables.scss
Normal file
@ -0,0 +1,10 @@
|
||||
// These Variable match thee MUI theme variables. For now they have to be updated manually. But can be done automatically also
|
||||
$primary-color: #1976d2;
|
||||
$secondary-color: #d32f2f;
|
||||
$background-primary: rgb(69, 190, 171);
|
||||
$text-primary: #000000;
|
||||
$text-secondary: #555555;
|
||||
$text-tertiary: #ffffff;
|
||||
$hover-color: rgba(0, 0, 0, 0.08);
|
||||
|
||||
$font-family-base: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||
Loading…
x
Reference in New Issue
Block a user