Skip to content

Commit

Permalink
FEAT: Apex Charts
Browse files Browse the repository at this point in the history
- dynamicParams set to true for faster page reload
- FEAT: Apex Charts for displaying Enquiries trend
  • Loading branch information
rohit1901 authored Apr 6, 2024
1 parent 7124927 commit 526230f
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 19 deletions.
116 changes: 116 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.525.0",
"apexcharts": "^3.48.0",
"aws-sdk": "^2.1569.0",
"flowbite": "^2.3.0",
"flowbite-react": "^0.7.2",
Expand All @@ -24,6 +25,7 @@
"next-auth": "^4.24.6",
"partysocket": "^1.0.1",
"react": "^18",
"react-apexcharts": "^1.4.1",
"react-dom": "^18",
"react-select": "^5.8.0",
"react-switch": "^7.0.0",
Expand Down
10 changes: 6 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {PageHeader} from "@admin/components/PageHeader";
import {IoReload} from "react-icons/io5";
import {useSession} from "next-auth/react";
import {ScreenLoader} from "@admin/components/Loaders";
// TODO: Show a chart of the number of emails sent via the website
import {isEmailAuthorized} from "@admin/lib";
import {EmailStatistics} from "@admin/components/Dashboard/EmailStatistics";
export default function Dashboard() {
const {data: session, status} = useSession()
const {mode} = useThemeMode()
Expand Down Expand Up @@ -68,6 +69,7 @@ export default function Dashboard() {
return (
<main className='p-8 mx-auto md:ml-64 h-auto bg-white-50 dark:bg-gray-800'>
<PageHeader title="Dashboard"/>
<EmailStatistics/>
<div className='flex flex-row gap-4 mt-4 justify-between'>
<Card className="max-w-sm dark:border-primary-50">
<h5 className="text-2xl font-bold tracking-tight text-cyan-800 dark:text-cyan-50">
Expand All @@ -85,7 +87,7 @@ export default function Dashboard() {
<div className="flex flex-wrap gap-2">
<Button
outline
disabled={checkingS3Status} onClick={async () => checkS3Status()}>
disabled={checkingS3Status || !isEmailAuthorized(session)} onClick={async () => checkS3Status()}>
{checkingS3Status ? <Spinner/> : <div className='flex flex-row gap-2 items-center'>
<IoReload className="h-5 w-5"/>
<span>Check S3 Status</span>
Expand All @@ -109,7 +111,7 @@ export default function Dashboard() {
<div className="flex flex-wrap gap-2">
<Button
outline
disabled={checkingHerokuStatus} onClick={async () => checkHerokuStatus()}>
disabled={checkingHerokuStatus || !isEmailAuthorized(session)} onClick={async () => checkHerokuStatus()}>
{checkingHerokuStatus ? <Spinner/> : <div className='flex flex-row gap-2 items-center'>
<IoReload className="h-5 w-5"/>
<span>Check Heroku Status</span>
Expand All @@ -133,7 +135,7 @@ export default function Dashboard() {
<div className="flex flex-wrap gap-2">
<Button
outline
disabled={checkingMongoDBStatus} onClick={async () => checkMongoDBStatus()}>
disabled={checkingMongoDBStatus || !isEmailAuthorized(session)} onClick={async () => checkMongoDBStatus()}>
{checkingMongoDBStatus ? <Spinner/> : <div className='flex flex-row gap-2 items-center'>
<IoReload className="h-5 w-5"/>
<span>Check MongoDB Status</span>
Expand Down
2 changes: 1 addition & 1 deletion src/app/programs/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ export default async function ProgramPage({params: {slug}}: {
)
}

export const dynamicParams = false
export const dynamicParams = true
3 changes: 1 addition & 2 deletions src/app/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import {useSession} from "next-auth/react";
import {ScreenLoader} from "@admin/components/Loaders";
import {GoogleReviewsCard} from "@admin/components/SettingsPage/GoogleReviewsCard";
import {ImagePreviewCard} from "@admin/components/SettingsPage/ImagePreviewCard";
// TODO: Add feature to toggle image previews
export default function Settings() {
const {status} = useSession();
if (status === "unauthenticated") return null;
if (status === "loading") return <ScreenLoader/>;
return (
<main className='p-8 mx-auto md:ml-64 h-auto bg-white-50 dark:bg-gray-800'>
<PageHeader title={'Settings'}/>
<div className='flex flex-row gap-4 mt-4'>
<div className='flex lg:flex-row md:flex-row flex-col justify-between gap-4'>
<DeleteCard/>
<GoogleReviewsCard/>
<ImagePreviewCard/>
Expand Down
94 changes: 94 additions & 0 deletions src/components/Dashboard/EmailStatistics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {ApexOptions} from "apexcharts";
import {useNotificationsStore} from "@admin/store/useNotificationsStore";
import {MONTHS, MonthsType} from "@admin/lib/constants";
import {getDataForMonth, getDataTrend} from "@admin/lib";
import {useEffect, useState} from "react";
import dynamic from 'next/dynamic'
import {Card} from "flowbite-react";
import {TrendIcon} from "@admin/components/Dashboard/TrendIcon";

//NOTE: Fix for ApexCharts not working with SSR
const Chart = dynamic(() => import('react-apexcharts'), {ssr: false});
/**
* The ApexCharts options for the email statistics
*/
const chartData: ApexOptions = {
chart: {
height: "100%",
type: "area",
dropShadow: {
enabled: false,
},
toolbar: {
show: false,
},
},
tooltip: {
enabled: true,
x: {
show: false,
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 6,
},
grid: {
show: false,
strokeDashArray: 4,
},
xaxis: {
categories: MONTHS,
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
show: false,
},
};
export const EmailStatistics = () => {
const {notificationPageData} = useNotificationsStore()
const [data, setData] =
useState<number[]>(MONTHS.map((month: MonthsType) => getDataForMonth(month, notificationPageData?.notifications ?? [])))
const [trend, setTrend] = useState(getDataTrend(data))
useEffect(() => {
setData(MONTHS.map((month: MonthsType) => getDataForMonth(month, notificationPageData?.notifications ?? [])))
setTrend(getDataTrend(data))
}, [notificationPageData])
if (!notificationPageData || notificationPageData.notifications.length === 0) return null
return (
<Card className="w-full dark:bg-gray-800 dark:border-primary-50 px-4 md:px-6">
<div className="text-cyan-800 dark:text-cyan-50 text-3xl">
<h4 className="font-bold">Statistics</h4>
<div
className="h-1 w-10 bg-cyan-800 rounded dark:bg-cyan-50"></div>
</div>
<div className="flex justify-between">
<div>
<h5 className="leading-none text-3xl font-bold text-cyan-800 dark:text-cyan-50 pb-2">
<span>{notificationPageData?.notifications?.length ?? 0}</span>
</h5>
<p className="text-base font-normal text-gray-500 dark:text-gray-400">Enquiries this year</p>
</div>
<TrendIcon {...trend}/>
</div>
{<Chart options={chartData} series={[
{
name: "Enquiries",
data: data,
color: "#155E75",
},
]} type="area" width="100%" height={350}/>}
</Card>

);
}
25 changes: 25 additions & 0 deletions src/components/Dashboard/TrendIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {TrendType} from "@admin/types";
import {getAbsoluteValue} from "@admin/lib";
import {FaArrowDown, FaArrowUp} from "react-icons/fa";

export const TrendIcon = ({trend, value}: TrendType) => {
switch (trend) {
case "up":
return (<div
className="flex items-center px-2.5 py-0.5 text-base font-semibold text-green-500 dark:text-green-500 text-center">
{getAbsoluteValue(value)}%
<FaArrowUp className="ml-1 text-green-500"/>
</div>)
case "down":
return <div
className="flex items-center px-2.5 py-0.5 text-base font-semibold text-red-500 dark:text-red-500 text-center">
{getAbsoluteValue(value)}%
<FaArrowDown className="ml-1 text-red-500"/>
</div>
case "same":
return <div
className="flex items-center px-2.5 py-0.5 text-base font-semibold text-gray-500 dark:text-gray-500 text-center">
{getAbsoluteValue(value)}%
</div>
}
}
2 changes: 1 addition & 1 deletion src/components/LFNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const LFNavbar = () => {
<span className="block truncate text-sm font-medium text-cyan-800 dark:text-cyan-50">{session?.user?.email}</span>
</DropdownHeader>
<Link href="/">
<DropdownItem icon={MdInsertChart} href="/" className="text-cyan-800 dark:text-cyan-50">Dashboard</DropdownItem>
<DropdownItem as="div" icon={MdInsertChart} href="/" className="text-cyan-800 dark:text-cyan-50">Dashboard</DropdownItem>
</Link>
<DropdownItem as='a' href="http://email.littlefern.in" target='_blank' icon={HiInbox}
className="text-cyan-800 dark:text-cyan-50">
Expand Down
Loading

0 comments on commit 526230f

Please sign in to comment.