Commit 275d26fd by Arjun Jhukal

updated the dashboard static version and starting working on notification or…

updated the dashboard static version and starting working on notification or simply push notification
parent 41097315
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
"lint": "eslint" "lint": "eslint"
}, },
"dependencies": { "dependencies": {
"@ckeditor/ckeditor5-build-classic": "^41.4.2",
"@ckeditor/ckeditor5-react": "^11.0.0",
"@ckeditor/ckeditor5-source-editing": "^47.0.0",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
"@mui/material": "^7.3.2", "@mui/material": "^7.3.2",
......
import { IconButton } from '@mui/material'
import { ArrowLeft, More } from '@wandersonalwes/iconsax-react'
import { ApexOptions } from 'apexcharts';
import React from 'react'
import Chart from "react-apexcharts";
export default function AdminAnalytics() {
const charts = [
{
title: 'Total Revenue',
subtitle: 'Jul 23 - Jul 30 (2025)',
value: '$2.689M',
change: 16,
isIncrease: true,
chartOptions: {
chart: { type: 'area', sparkline: { enabled: true } },
stroke: { curve: 'smooth', width: 2 },
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'vertical',
shadeIntensity: 1,
gradientToColors: ['#E14A5E'],
opacityFrom: 1,
opacityTo: 0,
stops: [0, 100],
},
},
colors: ['#E14A5E'],
tooltip: { enabled: true },
} as ApexOptions,
chartSeries: [{ name: 'Revenue', data: [400, 600, 700, 1200, 1400, 1800, 2500] }],
},
{
title: 'New Users',
subtitle: 'Jul 23 - Jul 30 (2025)',
value: '3.2K',
change: 8,
isIncrease: true,
chartOptions: {
chart: { type: 'area', sparkline: { enabled: true } },
stroke: { curve: 'straight', width: 2 },
fill: {
type: 'gradient',
gradient: {
shade: 'dark',
type: 'vertical',
shadeIntensity: 0.8,
gradientToColors: ['#22C55E'],
opacityFrom: 0.8,
opacityTo: 0,
stops: [0, 100],
},
},
colors: ['#22C55E'],
tooltip: { enabled: true },
} as ApexOptions,
chartSeries: [{ name: 'Users', data: [200, 400, 600, 700, 900, 1200, 1500] }],
},
{
title: 'Churn Rate',
subtitle: 'Jul 23 - Jul 30 (2025)',
value: '5.4%',
change: -4,
isIncrease: false,
chartOptions: {
chart: { type: 'area', sparkline: { enabled: true } },
stroke: { curve: 'smooth', width: 2 },
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'vertical',
shadeIntensity: 1,
gradientToColors: ['#F59E0B'],
opacityFrom: 1,
opacityTo: 0,
stops: [0, 100],
},
},
colors: ['#F59E0B'],
tooltip: { enabled: true },
} as ApexOptions,
chartSeries: [{ name: 'Churn', data: [8, 7, 6, 5, 5, 4, 3] }],
},
{
title: 'Support Tickets',
subtitle: 'Jul 23 - Jul 30 (2025)',
value: '1.2K',
change: -12,
isIncrease: false,
chartOptions: {
chart: { type: 'area', sparkline: { enabled: true } },
stroke: { curve: 'stepline', width: 2 },
fill: {
type: 'gradient',
gradient: {
shade: 'dark',
type: 'vertical',
shadeIntensity: 0.8,
gradientToColors: ['#3B82F6'],
opacityFrom: 0.7,
opacityTo: 0,
stops: [0, 100],
},
},
colors: ['#3B82F6'],
tooltip: { enabled: true },
} as ApexOptions,
chartSeries: [{ name: 'Tickets', data: [50, 45, 40, 38, 35, 30, 25] }],
},
];
// const chartSeries = [
// {
// name: "Revenue",
// data: [400, 600, 700, 1200, 1400, 1800, 2500],
// },
// ];
return (
<div className="grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 analytics__wrapper mb-5">
{charts.map((chart, index) => (
<div className="col-span-1" key={index} >
<div className="analytics__card p-4 rounded-[8px]">
<div className="card__title flex justify-between items-center mb-2">
<div className="title">
<strong className='text-[12px] leading-[120%] text-title font-[500] mb-1 block'>Total Revenue</strong>
<span className="text-[10px] text-para-light leading-[120%] font-[500]">Jul 23 - Jul 30 (2025)</span>
</div>
<div className="card__action">
<IconButton>
<More className='rotate-90' variant='TwoTone' />
</IconButton>
</div>
</div>
<div className="card__content">
<div className="flex gap-2 items-end justify-between mb-2">
<div className="content flex gap-2 items-center">
<strong className='text-[16px] leading-[120%] font-[600] text-title'>$2.689M</strong>
<p className={`flex gap-1 items-center ${chart.isIncrease ? "increase" : "decrease"}`}>
<span className="arrow w-[18px] h-[18px] rounded-full flex justify-center items-center "><ArrowLeft size={12} /></span>16%</p>
</div>
<div className="relative aspect-[72/68] w-full max-w-[144px] h-[100px] text-right">
<Chart
options={chart.chartOptions}
series={chart.chartSeries}
type="area"
width="100%"
height="100%"
/>
</div>
</div>
<p className='text-[12px] font-[500] text-para-light'>compared to previous week</p>
</div>
</div>
</div>
))}
</div>
)
}
"use client";
import PlayerListing from '@/components/pages/dashboard/adminDashboard/players';
import LatestRegisteredPlayer from '@/components/pages/dashboard/adminDashboard/players/LatestRegisteredPlayer';
import TransactionTable from '@/components/pages/dashboard/adminDashboard/transaction/TransactionTable'
import { PATH } from '@/routes/PATH';
import Link from 'next/link';
import React from 'react'
import AdminAnalytics from './AdminAnalytics';
import CreditCard from '@/components/organism/Charts/CreditCard';
import { percent } from 'framer-motion';
import AdminTransactionChart from './AdminTransactionChart';
const AdminDashboardTableWrapper = ({ title, cta, children }: { title?: string; cta?: { label: string; url: string }, children: React.ReactNode }) => {
return (
<div className="dashboard__table__wrapper border broder-solid border-gray rounded-2xl mb-5">
<div className="section__title flex justify-between items-center px-6 pt-6 pb-4">
{title ? <h2>{title}</h2> : ""}
{cta ? <Link href={cta.url} className='text-primary text-[10px] leading-[120%] font-[500]'>{cta.label}</Link> : ""}
</div>
<div className="table__wrapper">
{children}
</div>
</div>
)
}
export default function AdminDashboardRoot() {
const [search, setSearch] = React.useState("");
const games = [
{
name: "Firekirin",
amount: 50,
percentage: 10
},
{
name: "Ultrapanda",
amount: "168k",
percentage: 10
},
{
name: "Panda Master",
amount: "268k",
percentage: 10
},
{
name: "Fish Master",
amount: "136k",
percentage: 10
},
]
return (
<>
<h1 className="text-[24px] leading-[120%] mb-6">Dashboard</h1>
<AdminAnalytics />
<AdminDashboardTableWrapper title='My Available Credit'>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-2 px-6 pb-6">
{games.map((game) => (
<div className="col-span-1" key={game.name}>
<CreditCard key={game.name} game={game} />
</div>
))}
</div>
</AdminDashboardTableWrapper>
<div className="grid gap-5 lg:grid-cols-12 items-stretch">
<div className="lg:col-span-6 xl:col-span-7">
<AdminDashboardTableWrapper title='Latest Registered Players' cta={{
label: "View All",
url: PATH.ADMIN.PLAYERS.ROOT
}}>
<LatestRegisteredPlayer />
</AdminDashboardTableWrapper>
</div>
<div className="lg:col-span-6 xl:col-span-5 ">
<AdminDashboardTableWrapper title='Admin Transaction' >
<AdminTransactionChart />
</AdminDashboardTableWrapper>
</div>
</div>
<AdminDashboardTableWrapper title='Recent Transaction' cta={{
label: "View All",
url: PATH.ADMIN.TRANSACTIONS.ROOT
}}>
<TransactionTable search={search} />
</AdminDashboardTableWrapper>
</>
)
}
import React from "react";
import Chart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
export default function AdminTransactionChart() {
const chartOptions: ApexOptions = {
chart: {
type: "donut",
},
labels: ["User Transaction", "My Settled", "My Unsettled"],
colors: ["#8B5CF6", "#FACC15", "#22C55E"], // purple, yellow, green
legend: { show: false }, // hide default legend
dataLabels: { enabled: false },
stroke: {
width: 2,
colors: ["#fff"],
},
plotOptions: {
pie: {
donut: {
size: "65%",
},
},
},
};
const chartSeries = [483569, 26894, 13894]; // sample values for 3 segments
return (
<div className="px-6 pb-6">
{/* Donut Chart */}
<Chart options={chartOptions} series={chartSeries} type="donut" height={280} />
{/* Custom Legend */}
<div className="grid grid-cols-3 gap-4 mt-4 text-sm">
<div className="flex flex-col items-center">
<span className="flex items-center gap-1">
<span className="w-3 h-3 rounded-full inline-block bg-purple-500"></span>
User Transaction
</span>
<strong className="text-gray-800">$483,569</strong>
</div>
<div className="flex flex-col items-center">
<span className="flex items-center gap-1">
<span className="w-3 h-3 rounded-full inline-block bg-yellow-400"></span>
My Settled
</span>
<strong className="text-gray-800">$26,894</strong>
</div>
<div className="flex flex-col items-center">
<span className="flex items-center gap-1">
<span className="w-3 h-3 rounded-full inline-block bg-green-500"></span>
My Unsettled
</span>
<strong className="text-gray-800">$13,894</strong>
</div>
</div>
</div>
);
}
import AddNotificationForm from '@/components/pages/dashboard/adminDashboard/notifications/addNotification'
import React from 'react'
export default function AddNotifications() {
return (
<AddNotificationForm />
)
}
import AddNotificationForm from '@/components/pages/dashboard/adminDashboard/notifications/addNotification'
import React from 'react'
export default async function EditNotification(props: { params: Promise<{ id: string }> }) {
const { id } = await props.params;
return (
<AddNotificationForm id={id} />
)
}
import NotificationPageRoot from '@/components/pages/dashboard/adminDashboard/notifications'
import React from 'react'
export default function NotificationPage() {
return (
<NotificationPageRoot />
)
}
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
import TransactionTable from '@/components/pages/dashboard/adminDashboard/transaction/TransactionTable'; import TransactionTable from '@/components/pages/dashboard/adminDashboard/transaction/TransactionTable';
import { useAppSelector } from '@/hooks/hook' import { useAppSelector } from '@/hooks/hook'
import React from 'react' import React from 'react'
import AdminDashboardRoot from '../../(admin)/AdminDashboard';
export default function DashboardProvider({ children }: { children: React.ReactNode }) { export default function DashboardProvider({ children }: { children: React.ReactNode }) {
const [search, setSearch] = React.useState("");
const user = useAppSelector(state => state?.auth.user); const user = useAppSelector(state => state?.auth.user);
if (user?.role && user.role.toUpperCase() === "ADMIN") { if (user?.role && user.role.toUpperCase() === "ADMIN") {
return <> return <AdminDashboardRoot />
<h1 className="text-[24px] leading-[120%] mb-6">Dashboard</h1>
<TransactionTable search={search} />
</>
} }
return ( return (
<div>{children}</div> <div>{children}</div>
......
...@@ -95,15 +95,13 @@ export default async function Home() { ...@@ -95,15 +95,13 @@ export default async function Home() {
</ProtectedLink> </ProtectedLink>
))} ))}
</div> </div>
) : ( ) : ""}
<p className="text-gray-500">No games found.</p>
)}
{/* Trending Games */} {/* Trending Games */}
<section className="trending__games"> <section className="trending__games">
<h2 className="text-[14px] mb-4">Top 10 Trending Games</h2> <h2 className="text-[14px] mb-4">Top 10 Trending Games</h2>
{subGamesError ? ( {subGamesError ? (
<p className="text-red-500">{subGamesError}</p> ""
) : ( ) : (
<div className="grid gap-4 grid-cols-2 md:grid-cols-3 lg:grid-cols-5 2xl:grid-cols-6 mb-8"> <div className="grid gap-4 grid-cols-2 md:grid-cols-3 lg:grid-cols-5 2xl:grid-cols-6 mb-8">
{subGames?.data?.map((game: any) => ( {subGames?.data?.map((game: any) => (
...@@ -126,7 +124,7 @@ export default async function Home() { ...@@ -126,7 +124,7 @@ export default async function Home() {
{/* Sub Banners */} {/* Sub Banners */}
{subBannersError ? ( {subBannersError ? (
<p className="text-red-500">{subBannersError}</p> ""
) : subBanners?.data?.length ? ( ) : subBanners?.data?.length ? (
<div className="dashboard-card-wrapper grid grid-cols-2 gap-5 justify-center"> <div className="dashboard-card-wrapper grid grid-cols-2 gap-5 justify-center">
{subBanners.data.map((subBanner, index) => ( {subBanners.data.map((subBanner, index) => (
...@@ -195,7 +193,7 @@ export default async function Home() { ...@@ -195,7 +193,7 @@ export default async function Home() {
{/* USP Slider */} {/* USP Slider */}
{uspError ? ( {uspError ? (
<p className="text-red-500">{uspError}</p> ""
) : ( ) : (
<UspSlider uspData={usps?.data || []} /> <UspSlider uspData={usps?.data || []} />
)} )}
......
...@@ -214,3 +214,47 @@ ...@@ -214,3 +214,47 @@
.banner-desc span { .banner-desc span {
@apply text-[47px] leading-[50%] text-secondary font-[700]; @apply text-[47px] leading-[50%] text-secondary font-[700];
} }
.admin__table tr:not(:last-child) td {
border-bottom: 1px solid #e0e0e0;
}
.increase svg {
transform: rotate(90deg);
}
.decrease svg {
transform: rotate(-90deg);
}
.increase {
color: #008000;
}
.decrease {
color: #FF0000;
}
.increase span {
background: rgba(0, 128, 0, 0.10);
}
.decrease span {
background: rgba(255, 0, 0, 0.10);
}
.analytics__wrapper>div:nth-child(4n+1) .analytics__card {
background: rgba(225, 74, 94, 0.10);
}
.analytics__wrapper>div:nth-child(4n+2) .analytics__card {
background: rgba(74, 225, 125, 0.10);
}
.analytics__wrapper>div:nth-child(4n+3) .analytics__card {
background: rgba(74, 142, 225, 0.10);
}
.analytics__wrapper>div:nth-child(4n+4) .analytics__card {
background: rgba(192, 74, 225, 0.10);
}
\ No newline at end of file
...@@ -52,20 +52,20 @@ export default function ActionGroup({ ...@@ -52,20 +52,20 @@ export default function ActionGroup({
> >
<ClickAwayListener onClickAway={handleClose}> <ClickAwayListener onClickAway={handleClose}>
<List> <List>
<ListItem> {onView ? <ListItem>
<Link href={onView || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>View Profile</Link> <Link href={onView || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>View Profile</Link>
</ListItem> </ListItem> : ""}
<ListItem> {onEdit ? <ListItem>
<Link href={onEdit || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>Edit</Link> <Link href={onEdit || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>Edit</Link>
</ListItem> </ListItem> : ""}
<ListItem> {onDelete ? <ListItem>
<Link href={"#"} className='block py-3 px-4 hover:bg-[#FBF4FB]' <Link href={"#"} className='block py-3 px-4 hover:bg-[#FBF4FB]'
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
setConfirmOpen(true); setConfirmOpen(true);
}} }}
>Delete</Link> >Delete</Link>
</ListItem> </ListItem> : ""}
</List> </List>
</ClickAwayListener> </ClickAwayListener>
</Paper> </Paper>
......
import { Box, Button, ClickAwayListener, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Fade, IconButton, List, ListItem, Paper, Popper } from '@mui/material'
import { More } from '@wandersonalwes/iconsax-react'
import Link from 'next/link';
import React, { useRef, useState } from 'react'
export default function AnalyticsAction({
onView, onEdit, onDelete
}: { onView?: string; onEdit?: string; onDelete?: () => void }) {
const anchorRef = useRef<HTMLButtonElement | null>(null)
const [open, setOpen] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false);
const handleToggle = () => setOpen((prev) => !prev);
const handleClose = (event: MouseEvent | TouchEvent) => {
if (anchorRef.current?.contains(event.target as Node)) return;
setOpen(false);
};
const handleConfirmDelete = async () => {
setConfirmOpen(false);
if (onDelete) await onDelete();
};
const id = open ? 'action' : undefined;
return (
<Box>
<IconButton
aria-describedby={id}
ref={anchorRef}
onClick={handleToggle}
>
<More className='rotate-90' variant="TwoTone" />
</IconButton>
<Popper
open={open}
anchorEl={anchorRef.current}
placement="bottom-end"
transition
style={{ zIndex: 1300 }}
id={id}
>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={300}>
<Paper
elevation={3}
sx={{
width: 215,
borderRadius: 2,
mt: 1,
}}
>
<ClickAwayListener onClickAway={handleClose}>
<List>
{onView ? <ListItem>
<Link href={onView || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>View Profile</Link>
</ListItem> : ""}
{onEdit ? <ListItem>
<Link href={onEdit || ""} className='block py-3 px-4 hover:bg-[#FBF4FB]'>Edit</Link>
</ListItem> : ""}
{onDelete ? <ListItem>
<Link href={"#"} className='block py-3 px-4 hover:bg-[#FBF4FB]'
onClick={(e) => {
e.preventDefault();
setConfirmOpen(true);
}}
>Delete</Link>
</ListItem> : ""}
</List>
</ClickAwayListener>
</Paper>
</Fade>
)}
</Popper>
<Dialog
open={confirmOpen}
onClose={() => setConfirmOpen(false)}
>
<DialogTitle>Confirm Delete</DialogTitle>
<DialogContent>
<p className='text-para-light'>
Are you sure you want to delete this record? This action cannot be undone.
</p>
</DialogContent>
<DialogActions>
<Button color="error"
variant="contained" onClick={() => setConfirmOpen(false)}>Cancel</Button>
<Button
onClick={handleConfirmDelete}
color="success"
variant="contained"
>
Delete
</Button>
</DialogActions>
</Dialog>
</Box>
)
}
'use client'; // 'use client';
// next // // next
import dynamic from 'next/dynamic'; // import dynamic from 'next/dynamic';
// material-ui // // material-ui
import Box from '@mui/material/Box'; // import Box from '@mui/material/Box';
// // third-party
// import 'react-quill-new/dist/quill.snow.css';
// // project imports
// third-party // const ReactQuill = dynamic(() => import('react-quill-new'), { ssr: false });
import 'react-quill-new/dist/quill.snow.css';
// project imports // interface Props {
// value?: string;
// editorMinHeight?: number;
// onChange?: (value: string) => void;
// }
const ReactQuill = dynamic(() => import('react-quill-new'), { ssr: false });
// export default function ReactQuillEditor({ value, editorMinHeight = 135, onChange }: Props) {
// return (
// <Box
// sx={(theme) => ({
// '& .quill': {
// // bgcolor: 'background.paper',
// // ...theme.applyStyles('dark', { bgcolor: 'secondary.main' }),
// borderRadius: '4px',
// '& .ql-toolbar': {
// // bgcolor: 'secondary.100',
// // ...theme.applyStyles('dark', { bgcolor: 'secondary.light' }),
// borderColor: 'divider',
// borderTopLeftRadius: '8px',
// borderTopRightRadius: '8px'
// },
// // '& .ql-snow .ql-picker': {
// // ...theme.applyStyles('dark', { color: 'secondary.500' })
// // },
// // '& .ql-snow .ql-stroke': {
// // ...theme.applyStyles('dark', { stroke: theme.palette.secondary.main })
// // },
// '& .ql-container': {
// // bgcolor: 'transparent',
// // ...theme.applyStyles('dark', { bgcolor: 'background.default' }),
// // borderColor: `${theme.palette.secondary.light} !important`,
// borderBottomLeftRadius: '8px',
// borderBottomRightRadius: '8px',
// '& .ql-editor': { minHeight: editorMinHeight }
// },
// // ...(theme.direction === ThemeDirection.RTL && {
// // '& .ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg': {
// // right: '0%',
// // left: 'inherit'
// // }
// // })
// }
// })}
// >
// <ReactQuill {...(value && { value })} {...(onChange && { onChange })} />
// </Box>
// );
// }
'use client';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import Box from '@mui/material/Box';
interface Props { interface Props {
value?: string; value?: string;
...@@ -20,46 +77,50 @@ interface Props { ...@@ -20,46 +77,50 @@ interface Props {
} }
export default function ReactQuillEditor({ value, editorMinHeight = 135, onChange }: Props) { export default function CKEditorEditor({
value = '',
editorMinHeight = 135,
onChange
}: Props) {
return ( return (
<Box <Box
sx={(theme) => ({ sx={{
'& .quill': { '& .ck.ck-editor__editable_inline': {
// bgcolor: 'background.paper', minHeight: editorMinHeight,
// ...theme.applyStyles('dark', { bgcolor: 'secondary.main' }), borderRadius: '8px',
borderRadius: '4px',
'& .ql-toolbar': {
// bgcolor: 'secondary.100',
// ...theme.applyStyles('dark', { bgcolor: 'secondary.light' }),
borderColor: 'divider',
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px'
}, },
// '& .ql-snow .ql-picker': { '& .ck.ck-toolbar': {
// ...theme.applyStyles('dark', { color: 'secondary.500' }) borderTopLeftRadius: '8px',
// }, borderTopRightRadius: '8px',
// '& .ql-snow .ql-stroke': {
// ...theme.applyStyles('dark', { stroke: theme.palette.secondary.main })
// },
'& .ql-container': {
// bgcolor: 'transparent',
// ...theme.applyStyles('dark', { bgcolor: 'background.default' }),
// borderColor: `${theme.palette.secondary.light} !important`,
borderBottomLeftRadius: '8px',
borderBottomRightRadius: '8px',
'& .ql-editor': { minHeight: editorMinHeight }
}, },
// ...(theme.direction === ThemeDirection.RTL && { }}
// '& .ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg': {
// right: '0%',
// left: 'inherit'
// }
// })
}
})}
> >
<ReactQuill {...(value && { value })} {...(onChange && { onChange })} /> <CKEditor
disableWatchdog={true}
// editor={ClassicEditor}
editor={ClassicEditor as any}
data={value}
config={{
toolbar: [
'heading',
'|',
'bold',
'italic',
'link',
'bulletedList',
'numberedList',
// '|',
// 'undo',
// 'redo',
],
}}
onChange={(_, editor) => {
const data = editor.getData();
onChange?.(data);
}}
/>
</Box> </Box>
); );
} }
...@@ -34,7 +34,7 @@ const CreditCard = ({ game }: { game: any }) => { ...@@ -34,7 +34,7 @@ const CreditCard = ({ game }: { game: any }) => {
return ( return (
<div className=" rounded-lg p-3 border border-gray"> <div className=" rounded-lg p-3 border border-gray">
<Image src={"/assets/images/auth-image.png"} alt='' width={32} height={32} className='aspect-square rounded-sm' /> <Image src={"/assets/images/auth-image.png"} alt='' width={32} height={32} className='aspect-square rounded-sm' />
<strong className="block text-[16px] leading-[120%] font-[600] tet-title mt-2 mb-3">Firekirin</strong> <strong className="block text-[16px] leading-[120%] font-[600] tet-title mt-2 mb-3">{game?.name}</strong>
<div className="chart__wrapper mt-2 px-2 py-3" style={{ <div className="chart__wrapper mt-2 px-2 py-3" style={{
background: "rgba(184, 1, 192, 0.10)", background: "rgba(184, 1, 192, 0.10)",
borderRadius: "4px" borderRadius: "4px"
......
...@@ -19,7 +19,7 @@ export default function CustomTable<TData>({ table, loading = false, ...@@ -19,7 +19,7 @@ export default function CustomTable<TData>({ table, loading = false,
if (user?.role && user?.role.toUpperCase() !== "USER") { if (user?.role && user?.role.toUpperCase() !== "USER") {
return ( return (
<table className="min-w-full border-collapse border border-gray-200 text-left"> <table className="min-w-full border-collapse border border-gray-200 text-left admin__table">
<thead> <thead>
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}> <tr key={headerGroup.id}>
...@@ -61,7 +61,7 @@ export default function CustomTable<TData>({ table, loading = false, ...@@ -61,7 +61,7 @@ export default function CustomTable<TData>({ table, loading = false,
table.getRowModel().rows.map((row) => ( table.getRowModel().rows.map((row) => (
<tr key={row.id} className=""> <tr key={row.id} className="">
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map((cell) => (
<td key={cell.id} className="px-4 py-4 text-[12px] text-title"> <td key={cell.id} className="px-4 py-4 text-[12px] text-title ">
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext() cell.getContext()
......
import React from 'react'
export default function AddNotificationForm() {
return (
<div>AddNotificationForm</div>
)
}
import PageHeader from '@/components/molecules/PageHeader'
import React from 'react'
import AddNotificationForm from './AddNotificationForm'
export default function NotificationFormRoot({ id }: { id?: string }) {
return (
<>
<PageHeader
title='Notifications'
/>
<AddNotificationForm />
</>
)
}
import PageHeader from '@/components/molecules/PageHeader'
import { PATH } from '@/routes/PATH'
import React from 'react'
export default function NotificationPageRoot() {
return (
<>
<PageHeader
title='Notifications'
cta={{
label: "Add New Notifications",
url: PATH.ADMIN.NOTIFICATIONS.ADD_NOTIFICATIONS.ROOT
}}
/>
</>
)
}
...@@ -184,7 +184,7 @@ export default function AddPageForm({ id }: { id?: string }) { ...@@ -184,7 +184,7 @@ export default function AddPageForm({ id }: { id?: string }) {
{/* Dynamic Content */} {/* Dynamic Content */}
<InputLabel className="mb-2">Page Content</InputLabel> <InputLabel className="mb-2">Page Content</InputLabel>
{formik.values.content.map((item, i) => ( {formik.values.content.map((item, i) => (
<div className="space-y-6" key={i}> <div className="space-y-6" key={`content-${i}`}>
<div <div
className="grid grid-cols-1 lg:grid-cols-12 gap-4 items-start border border-gray-200 p-4 rounded-lg relative" className="grid grid-cols-1 lg:grid-cols-12 gap-4 items-start border border-gray-200 p-4 rounded-lg relative"
...@@ -216,6 +216,7 @@ export default function AddPageForm({ id }: { id?: string }) { ...@@ -216,6 +216,7 @@ export default function AddPageForm({ id }: { id?: string }) {
{/* Description */} {/* Description */}
<div className="lg:col-span-8"> <div className="lg:col-span-8">
<ReactQuillEditor <ReactQuillEditor
key={`${i}-${formik.values.content.length}`}
value={item.description} value={item.description}
onChange={(val: string) => onChange={(val: string) =>
formik.setFieldValue(`content[${i}].description`, val) formik.setFieldValue(`content[${i}].description`, val)
......
import CustomTable from '@/components/organism/Table';
import { useGetAllPlayerQuery } from '@/services/playerApi';
import { PlayerItem } from '@/types/player';
import { formatDateTime } from '@/utils/formatDateTime';
import { getInitials } from '@/utils/getInitials';
import { Box } from '@mui/material';
import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table';
import React, { useMemo, useState } from 'react'
export default function LatestRegisteredPlayer() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(6);
const { data, isLoading: loadingPlayer } = useGetAllPlayerQuery({
page,
per_page: pageSize,
});
const columns = useMemo<ColumnDef<PlayerItem>[]>(() => [
{
accessorKey: 'id',
header: '#ID',
cell: ({ row }) => row.original.id
},
{
accessorKey: "name",
header: "Name",
cell: ({ row }) => {
const { first_name, last_name, name } = row.original;
const initials = getInitials(first_name, last_name);
return (
<Box className="flex justify-start items-center gap-2">
<small className="text-[10px] w-[24px] h-[24px] flex items-center justify-center uppercase rounded-[4px] bg-[#1EB41B]/10 font-[500] text-[#1EB41B]">
{initials}
</small>
<div className="name-detail">
<strong className="text-primary block text-[12px] leading-[120%] font-[500] capitalize">
{first_name} {last_name}
</strong>
<small className="text-[10px] text-para-light font-[500]">{name}</small>
</div>
</Box>
);
},
},
{
accessorKey: 'email',
header: 'Email',
cell: ({ row }) => (
<span className="text-[12px] font-[500]">{row.original.email}</span>
)
},
{
accessorKey: 'registeredDate',
header: 'Registered Date',
cell: ({ row }) => {
const { date, time } = formatDateTime(row.original.registered_date as string);
return (
<Box>
<span className="text-[12px] font-[500] block">{date}</span>
<small className="text-[10px] text-para-light font-[500]">[{time}]</small>
</Box>
)
}
},
], []);
const filteredData = useMemo(() => data?.data?.data || [], [data]);
const table = useReactTable({
data: filteredData || [],
columns,
getCoreRowModel: getCoreRowModel(),
})
return (
<CustomTable
table={table}
loading={loadingPlayer}
/>
)
}
...@@ -52,8 +52,8 @@ export const PATH = { ...@@ -52,8 +52,8 @@ export const PATH = {
}, },
NOTIFICATIONS: { NOTIFICATIONS: {
ROOT: "/notifications", ROOT: "/notifications",
ADD_PAGE: { ADD_NOTIFICATIONS: {
ROOT: "/notifications/add-notification" ROOT: "/notifications/add-notifications"
} }
} }
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment