From b0abbd9144bb3b1ea3269ebe9174a35cf2d42a7f Mon Sep 17 00:00:00 2001 From: prateek-pareek <97360950+prateek-pareek@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:23:57 +0530 Subject: [PATCH 1/5] report page added --- app/dashboard/layout.tsx | 2 +- app/dashboard/page.tsx | 12 +- app/reports/layout.tsx | 17 + app/reports/page.tsx | 17 + .../ui/{dashboard => charts}/barChart.tsx | 0 .../ui/{dashboard => charts}/barList.tsx | 0 .../ui/{dashboard => charts}/lineChart.tsx | 2 +- .../dashboard/{charts.tsx => dashboard.tsx} | 58 +- components/ui/dashboard/dummyData.tsx | 375 --------- components/ui/dummyData.tsx | 740 ++++++++++++++++++ components/ui/{dashboard => layout}/index.tsx | 106 ++- components/ui/report/report.tsx | 267 +++++++ dev.next.config.js.sample | 24 - package.json | 8 +- public/logo/logo.jpg | Bin 0 -> 6426 bytes 15 files changed, 1157 insertions(+), 471 deletions(-) create mode 100644 app/reports/layout.tsx create mode 100644 app/reports/page.tsx rename components/ui/{dashboard => charts}/barChart.tsx (100%) rename components/ui/{dashboard => charts}/barList.tsx (100%) rename components/ui/{dashboard => charts}/lineChart.tsx (98%) rename components/ui/dashboard/{charts.tsx => dashboard.tsx} (79%) delete mode 100644 components/ui/dashboard/dummyData.tsx create mode 100644 components/ui/dummyData.tsx rename components/ui/{dashboard => layout}/index.tsx (52%) create mode 100644 components/ui/report/report.tsx delete mode 100644 dev.next.config.js.sample create mode 100644 public/logo/logo.jpg diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index 25567fe..8ff29c4 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -11,7 +11,7 @@ export default function RootLayout({ }) { return ( - {children} + {children} ) } diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index f570fa8..7481c2b 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,16 +1,14 @@ "use client"; import React from "react"; -import DashBoard from "@/components/ui/dashboard/index"; -import DashboardChart from "@/components/ui/dashboard/charts"; +import Layout from "@/components/ui/layout/index"; +import Dashboard from "@/components/ui/dashboard/dashboard"; const Page: React.FC = () => { return ( - - - - - + + + ); }; diff --git a/app/reports/layout.tsx b/app/reports/layout.tsx new file mode 100644 index 0000000..25567fe --- /dev/null +++ b/app/reports/layout.tsx @@ -0,0 +1,17 @@ +import '../(root)/globals.css'; +export const metadata = { + title: 'Next.js', + description: 'Generated by Next.js', +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/app/reports/page.tsx b/app/reports/page.tsx new file mode 100644 index 0000000..c799f1e --- /dev/null +++ b/app/reports/page.tsx @@ -0,0 +1,17 @@ +"use client"; + +import React from "react"; +import Layout from "@/components/ui/layout/index"; +import Report from "@/components/ui/report/report"; + +const Page: React.FC = () => { + return ( + + + + ); +}; + + + +export default Page \ No newline at end of file diff --git a/components/ui/dashboard/barChart.tsx b/components/ui/charts/barChart.tsx similarity index 100% rename from components/ui/dashboard/barChart.tsx rename to components/ui/charts/barChart.tsx diff --git a/components/ui/dashboard/barList.tsx b/components/ui/charts/barList.tsx similarity index 100% rename from components/ui/dashboard/barList.tsx rename to components/ui/charts/barList.tsx diff --git a/components/ui/dashboard/lineChart.tsx b/components/ui/charts/lineChart.tsx similarity index 98% rename from components/ui/dashboard/lineChart.tsx rename to components/ui/charts/lineChart.tsx index 8d6431e..cf1075b 100644 --- a/components/ui/dashboard/lineChart.tsx +++ b/components/ui/charts/lineChart.tsx @@ -9,7 +9,7 @@ interface DataPoint { interface LineChartsProps { title?: string; subTitle?: string; - data: DataPoint[]; + data: any[]; categories?: string[]; colors?: string[]; valueFormatter?: (number: number | bigint) => string; diff --git a/components/ui/dashboard/charts.tsx b/components/ui/dashboard/dashboard.tsx similarity index 79% rename from components/ui/dashboard/charts.tsx rename to components/ui/dashboard/dashboard.tsx index dc4ee1c..0f28e29 100644 --- a/components/ui/dashboard/charts.tsx +++ b/components/ui/dashboard/dashboard.tsx @@ -1,22 +1,19 @@ "use client" -import Link from "next/link"; import { useState } from "react"; -import { CircleAlertIcon, SearchIcon, BellIcon, Question } from "./icons"; -import { Avatar } from '@nextui-org/react'; -import BarListChart from "./barList"; -import BarChartComponent from "./barChart"; -import LineCharts from "./lineChart"; -import { data, pages, keyWords, campaignsData, BarData } from "./dummyData"; +import BarListChart from "../charts/barList"; +import BarChartComponent from "../charts/barChart"; +import LineCharts from "../charts/lineChart"; +import { data, pages, keyWords, campaignsData, BarData } from "../dummyData"; import CampaignTable from './table' import { format } from 'date-fns'; - -const DashboardChart = () => { +import {Slider } from "@nextui-org/react"; +const Dashboard = () => { const [value, setValue] = useState(0); const [startDate, setStartDate] = useState(new Date('2023-01-01').getTime()); const [endDate, setEndDate] = useState(new Date('2023-12-31').getTime()); const [filteredData, setFilteredData] = useState([]); const handleChange = (event: React.ChangeEvent, isStart: boolean) => { - const newValue = +event.target.value; + const newValue = +event; if (isStart) { setValue(newValue); } else { @@ -41,25 +38,6 @@ const DashboardChart = () => { return (
-
-
- -
- There are 30 days left in your trial. - - Upgrade Account - -
-
-
- - - - - XD - -
-

Dashboard

@@ -67,17 +45,21 @@ const DashboardChart = () => {

Welcome, Xue!

- - {formatDate(value)} + handleChange(event, true)} - title={formatDate(value)} + defaultValue={[startDate, endDate]} + onChange={(event: any) => handleChange(event, true)} + aria-label={formatDate(value)} + classNames={{ + base: "max-w-md", + filler: "bg-orange-500" + }} + />
@@ -207,4 +189,4 @@ const DashboardChart = () => { ); }; -export default DashboardChart; +export default Dashboard; diff --git a/components/ui/dashboard/dummyData.tsx b/components/ui/dashboard/dummyData.tsx deleted file mode 100644 index 3d6bb65..0000000 --- a/components/ui/dashboard/dummyData.tsx +++ /dev/null @@ -1,375 +0,0 @@ -export const data = [ - { - date: 'Jan 23', - Google: 232, - Sponsored: 0, - Affiliate: 49, - filterDate:'23/01/2023' - }, - { - date: 'Feb 23', - Google: 241, - Sponsored: 0, - Affiliate: 61, - filterDate:'23/02/2023' - }, - { - date: 'Mar 23', - Google: 291, - Sponsored: 0, - Affiliate: 55, - filterDate:'23/03/2023' - }, - { - date: 'Apr 23', - Google: 101, - Sponsored: 0, - Affiliate: 21, - filterDate:'23/04/2023' - }, - { - date: 'May 23', - Google: 318, - Sponsored: 0, - Affiliate: 66, - filterDate:'23/05/2023' - }, - { - date: 'Jun 23', - Google: 205, - Sponsored: 0, - Affiliate: 69, - filterDate:'23/06/2023' - }, - { - date: 'Jul 23', - Google: 372, - Sponsored: 0, - Affiliate: 55, - filterDate:'23/07/2023' - }, - { - date: 'Aug 23', - Google: 341, - Sponsored: 0, - Affiliate: 74, - filterDate:'23/08/2023' - }, - { - date: 'Sep 23', - Google: 387, - Sponsored: 120, - Affiliate: 190, - filterDate:'23/09/2023' - }, - { - date: 'Oct 23', - Google: 220, - Sponsored: 0, - Affiliate: 89, - filterDate:'23/10/2023' - }, - { - date: 'Nov 23', - Google: 372, - Sponsored: 0, - Affiliate: 144, - filterDate:'23/11/2023' - }, - { - date: 'Dec 23', - Google: 421, - Sponsored: 0, - Affiliate: 93, - filterDate:'23/12/2023' - }, -]; - - -interface DashboardData { - filter(arg0: (entry: any) => boolean): unknown; - impressions: { - date: Date; - impressions: number; - }[]; - clicks: { - date: Date; - clicks: number; - }[]; - amountSpent: { - date: Date; - amountSpent: number; - }[]; - conversions: { - month: string; - conversions: number; - }[]; - topChannels: { - campaign: string; - impressions: number; - clicks: number; - conversions: number; - }[]; - topKeywords: { - category: string; - items: { - name: string; - value: number; - }[]; - }[]; - topDestinationUrl: { - url: string; - clicks: number; - }[]; - clicksByDate: { - date: Date; - clicks: number; - }[]; -} - -export const demoData: DashboardData = { - impressions: [ - { - date: new Date("2023-01-01"), - impressions: 100000, - }, - { - date: new Date("2023-02-07"), - impressions: 200000, - }, - { - date: new Date("2023-02-14"), - impressions: 150000, - }, - { - date: new Date("2023-02-21"), - impressions: 180000, - }, - { - date: new Date("2023-02-28"), - impressions: 220000, - }, - ], - clicks: [ - { - date: new Date("2023-01-01"), - clicks: 1000, - }, - { - date: new Date("2023-02-07"), - clicks: 2000, - }, - { - date: new Date("2023-02-14"), - clicks: 1500, - }, - { - date: new Date("2023-02-21"), - clicks: 1800, - }, - { - date: new Date("2023-02-28"), - clicks: 2200, - }, - ], - amountSpent: [ - { - date: new Date("2023-01-01"), - amountSpent: 100, - }, - { - date: new Date("2023-02-07"), - amountSpent: 200, - }, - { - date: new Date("2023-02-14"), - amountSpent: 150, - }, - { - date: new Date("2023-02-21"), - amountSpent: 180, - }, - { - date: new Date("2023-02-28"), - amountSpent: 220, - }, - ], - conversions: [ - { - month: "January", - conversions: 50, - }, - { - month: "February", - conversions: 50, - }, - ], - topChannels: [ - { - campaign: "Campaign 1", - impressions: 1000, - clicks: 1000, - conversions: 100, - }, - { - campaign: "Campaign 2", - impressions: 800, - clicks: 800, - conversions: 800, - }, - { - campaign: "Campaign 3", - impressions: 600, - clicks: 600, - conversions: 600, - }, - ], - topKeywords: [ - { - category: "Category 1", - items: [ - { - name: "Keyword 1", - value: 1000, - }, - { - name: "Keyword 2", - value: 800, - }, - { - name: "Keyword 3", - value: 600, - }, - ], - }, - { - category: "Category 2", - items: [ - { - name: "Keyword 4", - value: 500, - }, - { - name: "Keyword 5", - value: 400, - }, - { - name: "Keyword 6", - value: 300, - }, - ], - }, - ], - topDestinationUrl: [ - { - url: "/packaging-machines/", - clicks: 300, - }, - { - url: "/packaging-machines/amax-series-traysealers/", - clicks: 200, - }, - { - url: "/distributors/", - clicks: 100, - }, - ], - clicksByDate: [ - { - date: new Date("2023-01-11"), - clicks: 250, - }, - { - date: new Date("2023-01-12"), - clicks: 230, - }, - { - date: new Date("2023-01-13"), - clicks: 210, - }, - { - date: new Date("2023-01-14"), - clicks: 200, - }, - { - date: new Date("2023-01-15"), - clicks: 220, - }, - ], - filter: function (arg0: (entry: any) => boolean): unknown { - throw new Error("Function not implemented."); - } -}; - -export const pages = [ - { - name: 'https://www.tesla.com', - value: 2019, - }, - { - name: 'https://mi-tech.ca', - value: 1053, - }, - { - name: 'https://abhaitech.com', - value: 997, - } -]; - - -export const keyWords = [ - { - name: 'Open AI', - value: 2019, - }, - { - name: 'Live Bots', - value: 1053, - }, - { - name: 'web3', - value: 997, - } -]; - -export const campaignsData = [ - { - id: 1, - name: "Google Shopping", - impressions: 12345, - clicks: 1234, - connections: 123, - }, - { - id: 2, - name: "Google Ads", - impressions: 23456, - clicks: 2345, - connections: 234, - }, - { - id: 3, - name: "Holiday Promo", - impressions: 34567, - clicks: 3456, - connections: 345, - } -]; -export const BarData = [ - { - age: '22-24', - 'This Year': 68560, - }, - { - age: '24-25', - 'This Year': 80233, - }, - { - age: '25-26', - 'This Year': 55123, - }, - { - age: '26-27', - 'This Year': 56000, - } -]; \ No newline at end of file diff --git a/components/ui/dummyData.tsx b/components/ui/dummyData.tsx new file mode 100644 index 0000000..08d5b1f --- /dev/null +++ b/components/ui/dummyData.tsx @@ -0,0 +1,740 @@ +export const data = [ + { + date: 'Jan 23', + Google: 232, + Sponsored: 0, + Affiliate: 49, + filterDate: '23/01/2023' + }, + { + date: 'Feb 23', + Google: 241, + Sponsored: 0, + Affiliate: 61, + filterDate: '23/02/2023' + }, + { + date: 'Mar 23', + Google: 291, + Sponsored: 0, + Affiliate: 55, + filterDate: '23/03/2023' + }, + { + date: 'Apr 23', + Google: 101, + Sponsored: 0, + Affiliate: 21, + filterDate: '23/04/2023' + }, + { + date: 'May 23', + Google: 318, + Sponsored: 0, + Affiliate: 66, + filterDate: '23/05/2023' + }, + { + date: 'Jun 23', + Google: 205, + Sponsored: 0, + Affiliate: 69, + filterDate: '23/06/2023' + }, + { + date: 'Jul 23', + Google: 372, + Sponsored: 0, + Affiliate: 55, + filterDate: '23/07/2023' + }, + { + date: 'Aug 23', + Google: 341, + Sponsored: 0, + Affiliate: 74, + filterDate: '23/08/2023' + }, + { + date: 'Sep 23', + Google: 387, + Sponsored: 120, + Affiliate: 190, + filterDate: '23/09/2023' + }, + { + date: 'Oct 23', + Google: 220, + Sponsored: 0, + Affiliate: 89, + filterDate: '23/10/2023' + }, + { + date: 'Nov 23', + Google: 372, + Sponsored: 0, + Affiliate: 144, + filterDate: '23/11/2023' + }, + { + date: 'Dec 23', + Google: 421, + Sponsored: 0, + Affiliate: 93, + filterDate: '23/12/2023' + }, +]; + + +interface DashboardData { + filter(arg0: (entry: any) => boolean): unknown; + impressions: { + date: Date; + impressions: number; + }[]; + clicks: { + date: Date; + clicks: number; + }[]; + amountSpent: { + date: Date; + amountSpent: number; + }[]; + conversions: { + month: string; + conversions: number; + }[]; + topChannels: { + campaign: string; + impressions: number; + clicks: number; + conversions: number; + }[]; + topKeywords: { + category: string; + items: { + name: string; + value: number; + }[]; + }[]; + topDestinationUrl: { + url: string; + clicks: number; + }[]; + clicksByDate: { + date: Date; + clicks: number; + }[]; +} + +export const demoData: DashboardData = { + impressions: [ + { + date: new Date("2023-01-01"), + impressions: 100000, + }, + { + date: new Date("2023-02-07"), + impressions: 200000, + }, + { + date: new Date("2023-02-14"), + impressions: 150000, + }, + { + date: new Date("2023-02-21"), + impressions: 180000, + }, + { + date: new Date("2023-02-28"), + impressions: 220000, + }, + ], + clicks: [ + { + date: new Date("2023-01-01"), + clicks: 1000, + }, + { + date: new Date("2023-02-07"), + clicks: 2000, + }, + { + date: new Date("2023-02-14"), + clicks: 1500, + }, + { + date: new Date("2023-02-21"), + clicks: 1800, + }, + { + date: new Date("2023-02-28"), + clicks: 2200, + }, + ], + amountSpent: [ + { + date: new Date("2023-01-01"), + amountSpent: 100, + }, + { + date: new Date("2023-02-07"), + amountSpent: 200, + }, + { + date: new Date("2023-02-14"), + amountSpent: 150, + }, + { + date: new Date("2023-02-21"), + amountSpent: 180, + }, + { + date: new Date("2023-02-28"), + amountSpent: 220, + }, + ], + conversions: [ + { + month: "January", + conversions: 50, + }, + { + month: "February", + conversions: 50, + }, + ], + topChannels: [ + { + campaign: "Campaign 1", + impressions: 1000, + clicks: 1000, + conversions: 100, + }, + { + campaign: "Campaign 2", + impressions: 800, + clicks: 800, + conversions: 800, + }, + { + campaign: "Campaign 3", + impressions: 600, + clicks: 600, + conversions: 600, + }, + ], + topKeywords: [ + { + category: "Category 1", + items: [ + { + name: "Keyword 1", + value: 1000, + }, + { + name: "Keyword 2", + value: 800, + }, + { + name: "Keyword 3", + value: 600, + }, + ], + }, + { + category: "Category 2", + items: [ + { + name: "Keyword 4", + value: 500, + }, + { + name: "Keyword 5", + value: 400, + }, + { + name: "Keyword 6", + value: 300, + }, + ], + }, + ], + topDestinationUrl: [ + { + url: "/packaging-machines/", + clicks: 300, + }, + { + url: "/packaging-machines/amax-series-traysealers/", + clicks: 200, + }, + { + url: "/distributors/", + clicks: 100, + }, + ], + clicksByDate: [ + { + date: new Date("2023-01-11"), + clicks: 250, + }, + { + date: new Date("2023-01-12"), + clicks: 230, + }, + { + date: new Date("2023-01-13"), + clicks: 210, + }, + { + date: new Date("2023-01-14"), + clicks: 200, + }, + { + date: new Date("2023-01-15"), + clicks: 220, + }, + ], + filter: function (arg0: (entry: any) => boolean): unknown { + throw new Error("Function not implemented."); + } +}; + +export const pages = [ + { + name: 'https://www.tesla.com', + value: 2019, + }, + { + name: 'https://mi-tech.ca', + value: 1053, + }, + { + name: 'https://abhaitech.com', + value: 997, + } +]; + + +export const keyWords = [ + { + name: 'Open AI', + value: 2019, + }, + { + name: 'Live Bots', + value: 1053, + }, + { + name: 'web3', + value: 997, + } +]; + +export const campaignsData = [ + { + id: 1, + name: "Google Shopping", + impressions: 12345, + clicks: 1234, + connections: 123, + }, + { + id: 2, + name: "Google Ads", + impressions: 23456, + clicks: 2345, + connections: 234, + }, + { + id: 3, + name: "Holiday Promo", + impressions: 34567, + clicks: 3456, + connections: 345, + } +]; +export const BarData = [ + { + age: '22-24', + 'This Year': 68560, + }, + { + age: '24-25', + 'This Year': 80233, + }, + { + age: '25-26', + 'This Year': 55123, + }, + { + age: '26-27', + 'This Year': 56000, + } +]; + +export const animals = [ + { key: "cat", label: "Cat" }, + { key: "dog", label: "Dog" }, + { key: "elephant", label: "Elephant" }, + { key: "lion", label: "Lion" }, + { key: "tiger", label: "Tiger" }, + { key: "giraffe", label: "Giraffe" }, + { key: "dolphin", label: "Dolphin" }, + { key: "penguin", label: "Penguin" }, + { key: "zebra", label: "Zebra" }, + { key: "shark", label: "Shark" }, + { key: "whale", label: "Whale" }, + { key: "otter", label: "Otter" }, + { key: "crocodile", label: "Crocodile" } +]; + +export const Reports = [ + { key: "view_through_rates", label: "View Through Rates" }, + { key: "avg_cpc", label: "Avg CPC" }, + { key: "clicks", label: "Clicks" }, + { key: "conversion_rate", label: "Conversion Rate" }, + { key: "connection", label: "Connection" }, + { key: "cost", label: "Cost" }, + { key: "cost_conversion", label: "Cost/Conversion" }, + { key: "impression", label: "Impression" } +]; + +export const Channels = [ + { key: "google_ads", label: "Google Ads" }, + { key: "facebook", label: "Facebook" }, + { key: "instagram", label: "Instgram" }, + { key: "linkedin", label: "Linkedin" } +]; +export const Campaigns = [{ key: "summer_sale", label: "Summer Sale" }, +{ key: "holiday_sale", label: "Holiday Sale" }, +{ key: "instagram_sale", label: "Instgram Sale" }, +{ key: "linkedin_sale", label: "Linkedin Sale" }] + + + + +export const ChartData=[ + { + channel: "linkedin", + campaign: "instagram_sale", + filterDate: "14/08/2023", + date: "Aug 14", + view_through_rates: 0.82, + avg_cpc: 8.44, + clicks: 618, + conversion_rate: 36.84, + connection: 321, + cost: 534.25, + cost_conversion: 45.77, + impression: 7495 + }, + { + channel: "google_ads", + campaign: "summer_sale", + filterDate: "23/03/2023", + date: "Mar 23", + view_through_rates: 0.37, + avg_cpc: 5.81, + clicks: 276, + conversion_rate: 53.18, + connection: 888, + cost: 896.43, + cost_conversion: 35.97, + impression: 5917 + }, + { + channel: "facebook", + campaign: "holiday_sale", + filterDate: "05/11/2023", + date: "Nov 5", + view_through_rates: 0.91, + avg_cpc: 2.75, + clicks: 124, + conversion_rate: 73.85, + connection: 997, + cost: 683.67, + cost_conversion: 11.24, + impression: 3095 + }, + { + channel: "instagram", + campaign: "linkedin_sale", + filterDate: "30/06/2023", + date: "Jun 30", + view_through_rates: 0.34, + avg_cpc: 9.12, + clicks: 946, + conversion_rate: 26.57, + connection: 361, + cost: 429.55, + cost_conversion: 52.73, + impression: 8645 + }, + { + channel: "linkedin", + campaign: "holiday_sale", + filterDate: "12/12/2023", + date: "Dec 12", + view_through_rates: 0.78, + avg_cpc: 7.63, + clicks: 471, + conversion_rate: 15.82, + connection: 648, + cost: 354.62, + cost_conversion: 76.82, + impression: 2690 + }, + { + channel: "google_ads", + campaign: "instagram_sale", + filterDate: "19/09/2023", + date: "Sep 19", + view_through_rates: 0.29, + avg_cpc: 1.44, + clicks: 513, + conversion_rate: 66.19, + connection: 267, + cost: 943.12, + cost_conversion: 14.75, + impression: 3991 + }, + { + channel: "facebook", + campaign: "linkedin_sale", + filterDate: "08/04/2023", + date: "Apr 8", + view_through_rates: 0.67, + avg_cpc: 4.26, + clicks: 705, + conversion_rate: 21.54, + connection: 146, + cost: 532.88, + cost_conversion: 68.77, + impression: 1653 + }, + { + channel: "instagram", + campaign: "summer_sale", + filterDate: "15/07/2023", + date: "Jul 15", + view_through_rates: 0.56, + avg_cpc: 6.75, + clicks: 487, + conversion_rate: 10.93, + connection: 523, + cost: 629.47, + cost_conversion: 37.92, + impression: 7325 + }, + { + channel: "linkedin", + campaign: "holiday_sale", + filterDate: "27/10/2023", + date: "Oct 27", + view_through_rates: 0.23, + avg_cpc: 8.11, + clicks: 352, + conversion_rate: 94.73, + connection: 819, + cost: 913.82, + cost_conversion: 88.24, + impression: 5861 + }, + { + channel: "google_ads", + campaign: "summer_sale", + filterDate: "22/02/2023", + date: "Feb 22", + view_through_rates: 0.85, + avg_cpc: 3.17, + clicks: 283, + conversion_rate: 50.82, + connection: 964, + cost: 876.26, + cost_conversion: 43.57, + impression: 7952 + }, + { + channel: "facebook", + campaign: "holiday_sale", + filterDate: "03/10/2023", + date: "Oct 3", + view_through_rates: 0.42, + avg_cpc: 1.68, + clicks: 235, + conversion_rate: 35.19, + connection: 372, + cost: 142.85, + cost_conversion: 92.51, + impression: 3612 + }, + { + channel: "instagram", + campaign: "linkedin_sale", + filterDate: "28/11/2023", + date: "Nov 28", + view_through_rates: 0.51, + avg_cpc: 2.74, + clicks: 592, + conversion_rate: 48.17, + connection: 516, + cost: 982.35, + cost_conversion: 36.89, + impression: 6801 + }, + { + channel: "linkedin", + campaign: "summer_sale", + filterDate: "07/06/2023", + date: "Jun 7", + view_through_rates: 0.38, + avg_cpc: 5.13, + clicks: 158, + conversion_rate: 12.85, + connection: 407, + cost: 645.25, + cost_conversion: 23.87, + impression: 5127 + }, + { + channel: "google_ads", + campaign: "instagram_sale", + filterDate: "18/01/2023", + date: "Jan 18", + view_through_rates: 0.16, + avg_cpc: 7.94, + clicks: 634, + conversion_rate: 82.49, + connection: 701, + cost: 364.25, + cost_conversion: 87.12, + impression: 9192 + }, + { + channel: "facebook", + campaign: "linkedin_sale", + filterDate: "25/05/2023", + date: "May 25", + view_through_rates: 0.62, + avg_cpc: 9.51, + clicks: 512, + conversion_rate: 29.58, + connection: 169, + cost: 278.36, + cost_conversion: 32.45, + impression: 7410 + }, + { + channel: "instagram", + campaign: "holiday_sale", + filterDate: "13/09/2023", + date: "Sep 13", + view_through_rates: 0.58, + avg_cpc: 1.95, + clicks: 475, + conversion_rate: 93.12, + connection: 549, + cost: 782.14, + cost_conversion: 94.52, + impression: 8365 + }, + { + channel: "linkedin", + campaign: "summer_sale", + filterDate: "21/03/2023", + date: "Mar 21", + view_through_rates: 0.77, + avg_cpc: 6.28, + clicks: 591, + conversion_rate: 79.13, + connection: 333, + cost: 217.48, + cost_conversion: 63.98, + impression: 4731 + }, + { + channel: "google_ads", + campaign: "holiday_sale", + filterDate: "04/08/2023", + date: "Aug 4", + view_through_rates: 0.59, + avg_cpc: 4.19, + clicks: 683, + conversion_rate: 42.51, + connection: 938, + cost: 157.93, + cost_conversion: 79.45, + impression: 2895 + }, + { + channel: "facebook", + campaign: "instagram_sale", + filterDate: "29/07/2023", + date: "Jul 29", + view_through_rates: 0.43, + avg_cpc: 3.11, + clicks: 256, + conversion_rate: 54.32, + connection: 788, + cost: 973.61, + cost_conversion: 22.91, + impression: 6571 + }] + + + + export const chartsMetaData = [ + { + title: "View Through Rates", + subTitle: "$231", + categories: ["view_through_rates"], + colors: ["blue"], + }, + { + title: "Avg CPC", + subTitle: "$231", + categories: ["avg_cpc"], + colors: ["blue"], + }, + { + title: "Clicks", + subTitle: "231", + categories: ["clicks"], + colors: ["blue"], + }, + { + title: "Conversion Rate", + subTitle: "99%", + categories: ["conversion_rate"], + colors: ["blue"], + }, + ]; + + export const chartsSet1 = [ + { + title: "Connection", + subTitle: "1,231", + categories: ["connection"], + colors: ["blue"], + }, + { + title: "Cost", + subTitle: "$300.15", + categories: ["cost"], + colors: ["blue"], + }, + { + title: "Cost/Conversion", + subTitle: "$231", + categories: ["cost_conversion"], + colors: ["blue"], + }, + { + title: "Impression", + subTitle: "923", + categories: ["impression"], + colors: ["blue"], + }, + ]; \ No newline at end of file diff --git a/components/ui/dashboard/index.tsx b/components/ui/layout/index.tsx similarity index 52% rename from components/ui/dashboard/index.tsx rename to components/ui/layout/index.tsx index 50557a1..e6404ad 100644 --- a/components/ui/dashboard/index.tsx +++ b/components/ui/layout/index.tsx @@ -1,6 +1,8 @@ "use client" import Link from "next/link" import { usePathname } from 'next/navigation' +import Image from 'next/image'; +import logo from '@/public/logo/logo.jpg' import { LayoutDashboardIcon, UsersIcon, @@ -11,38 +13,92 @@ import { UserIcon, ChevronDownIcon, ChevronUpIcon, -} from './icons'; +} from '../dashboard/icons'; +import { CircleAlertIcon, SearchIcon, BellIcon, Question } from "../dashboard/icons"; import { useState } from "react"; +import { Avatar } from '@nextui-org/react'; -export default function DashBoard(props: any) { +export default function Layout(props: any) { + const [isOpen, setIsOpen] = useState(false); + + const toggleSubMenu = () => { + setIsOpen(!isOpen); + }; return (
+
+
+ +
+ There are 30 days left in your trial. + + Upgrade Account + +
+
+
+ + + + + XD + +
+
{props.children}
@@ -67,18 +123,20 @@ const NavLink: React.FC = ({ href, icon: Icon, label, submenu }) = }; return ( -
-
+ +
+
{label} - {submenu && isOpen && } - {submenu && !isOpen && } + {submenu && isOpen && } + {submenu && !isOpen && }
-
+ {isOpen && submenu && (
    {submenu.map((submenuItem, index) => ( @@ -91,6 +149,8 @@ const NavLink: React.FC = ({ href, icon: Icon, label, submenu }) =
)}
+ + ); }; interface SubNavLinkData { @@ -118,14 +178,16 @@ const navLinks: NavLinkData[] = [ { href: '#', label: 'Private' }, ], }, - { href: '#', icon: FileIcon, label: 'Campagins',submenu: [ - { href: '#', label: 'Campaigns' }, - { href: '#', label: 'Ad Gap' }, - { href: '#', label: 'Ads' } - ], }, + { + href: '#', icon: FileIcon, label: 'Campagins', submenu: [ + { href: '#', label: 'Campaigns' }, + { href: '#', label: 'Ad Gap' }, + { href: '#', label: 'Ads' } + ], + }, { href: '#', icon: FileIcon, label: 'Analytics' }, { - href: '#', + href: '/reports', icon: CreditCardIcon, label: 'Reports', submenu: [ diff --git a/components/ui/report/report.tsx b/components/ui/report/report.tsx new file mode 100644 index 0000000..9d7562a --- /dev/null +++ b/components/ui/report/report.tsx @@ -0,0 +1,267 @@ +"use client" +import { useState } from "react"; +import BarListChart from "../charts/barList"; +import BarChartComponent from "../charts/barChart"; +import LineCharts from "../charts/lineChart"; +import { data, ChartData, Reports, Channels, Campaigns, chartsMetaData, chartsSet1 } from "../dummyData"; +import { format } from 'date-fns'; +import { Select, SelectItem, Button, Slider } from "@nextui-org/react"; +import html2canvas from "html2canvas"; +import { jsPDF } from "jspdf"; + + +const Report = () => { + const [value, setValue] = useState(0); + const [selectedChannels, setSelectedChannels] = useState([]); + const [selectedCampaigns, setSelectedCampaigns] = useState([]); + const [selectedReports, setSelectedReports] = useState([]); + const [startDate, setStartDate] = useState(new Date('2023-01-01').getTime()); + const [endDate, setEndDate] = useState(new Date('2023-12-31').getTime()); + const [filteredData, setFilteredData] = useState(); + + const handleChange = (event: any, isStart: boolean) => { + const newValue = +event; + if (isStart) { + setValue(newValue); + } else { + setValue(newValue); + } + applyFilters() + }; + + + const formatDate = (timestamp: number) => { + return format(new Date(timestamp), 'MM/dd/yyyy'); + }; + const monthMilliseconds = 30.44 * 24 * 60 * 60 * 1000; + + + type DataEntry = { + channel: string; + campaign: string; + filterDate: any; + date: any; + view_through_rates: number; + avg_cpc: number; + clicks: number; + conversion_rate: number; + connection: number; + cost: number; + cost_conversion: number; + impression: number; + }; + + + type FilterCriteria = { + channels: string[]; + campaigns: string[]; + startDate?: any; + endDate?: any; + }; + const filterData = (DataResource: any[], filters: FilterCriteria): DataEntry[] => { + return DataResource.filter((entry) => { + if (filters.channels.length > 0 && !filters.channels.includes(entry.channel)) { + return false; + } + if (filters.campaigns.length > 0 && !filters.campaigns.includes(entry.campaign)) { + return false; + } + + if (filters.startDate && filters.endDate) { + const filterDate = new Date(entry.filterDate); + const startDate = new Date(filters.startDate); + const endDate = new Date(filters.endDate); + + if (filterDate < startDate || filterDate > endDate) { + return false; + } + } + return true; + }); + }; + const applyFilters = () => { + const filters: FilterCriteria = { + channels: selectedChannels, + campaigns: selectedCampaigns, + startDate: value, + endDate: endDate + }; + + const filteredData = filterData(ChartData, filters); + setFilteredData(filteredData) + }; + + const handleSelect = (e: any) => { + const array = e?.target?.value.split(","); + if (e?.target?.name === "channels") { + setSelectedChannels(array) + } else if (e.target.name === "campaigns") { + setSelectedCampaigns(array) + } else if (e.target.name === "reports") { + setSelectedReports(array) + } + applyFilters() + } + + const downloadPDF = async () => { + const pdf = new jsPDF(); + try { + for (let i = 0; i < selectedReports.length; i++) { + const data = selectedReports[i]; + let element = document.getElementById(data); + if (!element || !isVisible(element)) { + throw new Error(`Element with id "${data}" not found or not visible.`); + } + const canvas = await html2canvas(element); + const imgData = canvas.toDataURL("image/png"); + + const imgWidth = canvas.width; + const imgHeight = canvas.height; + const aspectRatio = imgWidth / imgHeight; + const pdfWidth = pdf.internal.pageSize.getWidth() - 20; + const pdfHeight = pdfWidth / aspectRatio; + if (i > 0) { + pdf.addPage(); + } + const x = (pdf.internal.pageSize.getWidth() - pdfWidth) / 2; + const y = (pdf.internal.pageSize.getHeight() - pdfHeight) / 2; + pdf.addImage(imgData, "PNG", x, y, pdfWidth, pdfHeight); + } + pdf.save("chart.pdf"); + } catch (error) { + console.error("Error generating PDF:", error); + } + }; + function isVisible(elem: any) { + return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); + } + + + return ( +
+
+
+

Reports

+
+

Welcome, Xue!

+
+
+ + handleChange(event, true)} + aria-label={formatDate(value)} + classNames={{ + base: "max-w-md", + filler: "bg-orange-500" + }} + + /> + + +
+ +
+
+
+
+
+ + + +
+
+
+
+ +
+
+
+
+ {chartsMetaData.map((chart, index) => ( +
+ + + +
+ ))} +
+
+ {chartsSet1.map((chart, index) => ( +
+ + +
+ ))} +
+
+ ); +}; + +export default Report; diff --git a/dev.next.config.js.sample b/dev.next.config.js.sample deleted file mode 100644 index 7c82183..0000000 --- a/dev.next.config.js.sample +++ /dev/null @@ -1,24 +0,0 @@ - - - -const config = { - async rewrites() { - return { - fallback: [ - { - 'source': '/', - 'destination': 'https://dev.mitech.ai/', - 'basePath': false - }, - { - 'source': '/:path*', - 'destination': 'https://dev.mitech.ai/:path*', - 'basePath': false - }, - ] - }; - } -} - - -module.exports = config; \ No newline at end of file diff --git a/package.json b/package.json index d1cd7c7..1994feb 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "@vercel/analytics": "^1.1.1", "@vercel/speed-insights": "^1.0.5", "axios": "^1.6.5", + "html2canvas": "^1.4.1", "js-cookie": "^3.0.5", + "jspdf": "^2.5.1", "react-toastify": "^10.0.5", "zod": "^3.23.7" }, @@ -31,15 +33,15 @@ "@types/node": ">=20.13.0", "@types/react": ">=18.3.3", "@types/react-dom": ">=18.3.0", + "autoprefixer": ">=10.4.19", "eslint": ">=8.52.0", "eslint-config-next": ">=14.2.3", "next": ">=14.2.4", + "postcss": ">=8.4.38", "prettier": ">=3.0.3", "sharp": ">=0.33.2", - "typescript": ">=5.2.2", "tailwindcss": ">=3.4.3", - "postcss": ">=8.4.38", - "autoprefixer": ">=10.4.19" + "typescript": ">=5.2.2" }, "devDependencies": { "@types/js-cookie": "^3.0.6" diff --git a/public/logo/logo.jpg b/public/logo/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..92b64d2294c2ca6a6153dea034e00369155bb808 GIT binary patch literal 6426 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 literal 0 HcmV?d00001 From c4053c07331663dda95c304eeab2e4cc57cf97f9 Mon Sep 17 00:00:00 2001 From: prateek-pareek <97360950+prateek-pareek@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:52:28 +0530 Subject: [PATCH 2/5] fix --- app/reports/import/page.tsx | 17 + components/ui/charts/barChart.tsx | 19 +- components/ui/charts/barList.tsx | 3 +- components/ui/charts/lineChart.tsx | 11 +- components/ui/dashboard/dashboard.tsx | 4 +- components/ui/dummyData.tsx | 777 +++++++++++++++---------- components/ui/layout/index.tsx | 2 +- components/ui/report/import/import.tsx | 303 ++++++++++ components/ui/report/report.tsx | 175 +++--- package.json | 1 + 10 files changed, 891 insertions(+), 421 deletions(-) create mode 100644 app/reports/import/page.tsx create mode 100644 components/ui/report/import/import.tsx diff --git a/app/reports/import/page.tsx b/app/reports/import/page.tsx new file mode 100644 index 0000000..09c1c71 --- /dev/null +++ b/app/reports/import/page.tsx @@ -0,0 +1,17 @@ +"use client"; + +import React from "react"; +import Layout from "@/components/ui/layout/index"; +import ImportPage from "@/components/ui/report/import/import"; + +const Page: React.FC = () => { + return ( + + + + ); +}; + + + +export default Page \ No newline at end of file diff --git a/components/ui/charts/barChart.tsx b/components/ui/charts/barChart.tsx index 0f8801a..001d390 100644 --- a/components/ui/charts/barChart.tsx +++ b/components/ui/charts/barChart.tsx @@ -3,8 +3,9 @@ import { BarChart, Card, Divider } from '@tremor/react'; interface BarChartProps { data: { [key: string]: any }[]; - indexKey?: string; - categoryKeys?: string[]; + index?: string; + title?: string; + categories?: string[]; colors?: string[]; valueFormatter?: (number: number) => string; yAxisWidth?: number; @@ -12,9 +13,10 @@ interface BarChartProps { } const BarChartComponent: React.FC = ({ + title = "", data, - indexKey = 'age', - categoryKeys = ['This Year'], + index = 'age', + categories = ['This Year'], colors = ['blue'], valueFormatter, yAxisWidth = 45, @@ -22,10 +24,15 @@ const BarChartComponent: React.FC = ({ }) => { return ( +
+

+ {title} +

+
- `${Intl.NumberFormat('us').format(number).toString()}`; +const defaultFormatter = (number: number | bigint) => { return number }; const BarListChart: React.FC = ({ title = 'Top Destination Url', diff --git a/components/ui/charts/lineChart.tsx b/components/ui/charts/lineChart.tsx index cf1075b..7330e30 100644 --- a/components/ui/charts/lineChart.tsx +++ b/components/ui/charts/lineChart.tsx @@ -9,7 +9,7 @@ interface DataPoint { interface LineChartsProps { title?: string; subTitle?: string; - data: any[]; + data: any; categories?: string[]; colors?: string[]; valueFormatter?: (number: number | bigint) => string; @@ -19,14 +19,15 @@ interface LineChartsProps { cardClassName?: string; chartClassName?: string; index?: string; + props?: any } -const defaultFormatter = (number: number | bigint) => +const defaultFormatter = (number: number | bigint) => `${Intl.NumberFormat('us').format(number).toString()}`; const LineCharts: React.FC = ({ title = '', - subTitle="", + subTitle = "", data, categories = ['Organic'], colors = ['blue'], @@ -36,7 +37,8 @@ const LineCharts: React.FC = ({ startEndOnly = true, cardClassName = 'sm:mx-auto sm:max-w-md text-center', chartClassName = 'mt-6 h-32', - index="date" + index = "date", + props }) => { return ( @@ -47,6 +49,7 @@ const LineCharts: React.FC = ({ {subTitle} { /> +
-
- {chartsMetaData.map((chart, index) => ( + {/*
+ {chartTypes?.map((chart, index) => (
- {
))} -
-
- {chartsSet1.map((chart, index) => ( -
- +
*/} + +
+ {selectedCampaigns?.map((group, rowIndex) => ( +
+

{Campaigns.filter(data => data.key === group)[0]?.label}

+
+ {chartTypes?.map((chart, colIndex) => ( +
+ +
+ ))} +
))}
diff --git a/package.json b/package.json index 1994feb..a51fb07 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "js-cookie": "^3.0.5", "jspdf": "^2.5.1", "react-toastify": "^10.0.5", + "xlsx": "^0.18.5", "zod": "^3.23.7" }, "prettier": { From f41adc8b1bdec7bbcf07b56582f1e3217a9e5b69 Mon Sep 17 00:00:00 2001 From: prateek-pareek <97360950+prateek-pareek@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:04:18 +0530 Subject: [PATCH 3/5] issue fixed --- app/dashboard/layout.tsx | 27 +++- app/reports/layout.tsx | 27 +++- components/ui/charts/donutChart.tsx | 55 +++++++ components/ui/dashboard/dashboard.tsx | 1 + components/ui/layout/index.tsx | 4 +- components/ui/report/import/import.tsx | 202 +++++++++++++++++-------- components/ui/report/report.tsx | 63 ++++---- 7 files changed, 272 insertions(+), 107 deletions(-) create mode 100644 components/ui/charts/donutChart.tsx diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index 8ff29c4..23efb54 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -3,15 +3,36 @@ export const metadata = { title: 'Next.js', description: 'Generated by Next.js', } - +import { Analytics } from '@vercel/analytics/react'; +import { SessionProvider } from 'next-auth/react'; +import { SpeedInsights } from "@vercel/speed-insights/next" +import { NextUIProvider } from '@nextui-org/react'; +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { NotificationProvider } from '@/components/ui/NotificationContext'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( - - {children} + + + + + + +
+ + {children} + +
+ + +
+
+
+ + ) } diff --git a/app/reports/layout.tsx b/app/reports/layout.tsx index 25567fe..23efb54 100644 --- a/app/reports/layout.tsx +++ b/app/reports/layout.tsx @@ -3,15 +3,36 @@ export const metadata = { title: 'Next.js', description: 'Generated by Next.js', } - +import { Analytics } from '@vercel/analytics/react'; +import { SessionProvider } from 'next-auth/react'; +import { SpeedInsights } from "@vercel/speed-insights/next" +import { NextUIProvider } from '@nextui-org/react'; +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { NotificationProvider } from '@/components/ui/NotificationContext'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( - - {children} + + + + + + +
+ + {children} + +
+ + +
+
+
+ + ) } diff --git a/components/ui/charts/donutChart.tsx b/components/ui/charts/donutChart.tsx new file mode 100644 index 0000000..3d5661e --- /dev/null +++ b/components/ui/charts/donutChart.tsx @@ -0,0 +1,55 @@ + +import { Card, DonutChart, List, ListItem } from '@tremor/react'; + +const currencyFormatter = (number: any) => { + return number +}; +function classNames(...classes: any) { return classes.filter(Boolean).join(' '); } + +export default function Example(props: any) { + return ( + <> + +

+ {props.title} +

+ +

+ Category + Total/Share +

+ + {props.data.map((item: any) => ( + +
+ + + {item.name} + {(item?.amount)?.toFixed(2)} + +
+
+ + {(item?.total)?.toFixed(2)}/{item.share} + +
+
+ ))} +
+
+ + ); +} + diff --git a/components/ui/dashboard/dashboard.tsx b/components/ui/dashboard/dashboard.tsx index 1915f7b..9f9ed0e 100644 --- a/components/ui/dashboard/dashboard.tsx +++ b/components/ui/dashboard/dashboard.tsx @@ -12,6 +12,7 @@ const Dashboard = () => { const [startDate, setStartDate] = useState(new Date('2023-01-01').getTime()); const [endDate, setEndDate] = useState(new Date('2023-12-31').getTime()); const [filteredData, setFilteredData] = useState([]); + const handleChange = (event: React.ChangeEvent, isStart: boolean) => { const newValue = +event; if (isStart) { diff --git a/components/ui/layout/index.tsx b/components/ui/layout/index.tsx index e603386..9a13b43 100644 --- a/components/ui/layout/index.tsx +++ b/components/ui/layout/index.tsx @@ -191,8 +191,8 @@ const navLinks: NavLinkData[] = [ icon: CreditCardIcon, label: 'Reports', submenu: [ - { href: '#', label: 'Export' }, - { href: '#', label: 'Import' }, + { href: '/reports', label: 'Export' }, + { href: '/reports/import', label: 'Import' }, { href: '#', label: 'Schedule Automation' } ], }, diff --git a/components/ui/report/import/import.tsx b/components/ui/report/import/import.tsx index 6a3774b..6612bdd 100644 --- a/components/ui/report/import/import.tsx +++ b/components/ui/report/import/import.tsx @@ -1,13 +1,16 @@ "use client" import { useState } from "react"; -import BarListChart from "../../charts/barList"; +import PieChart from "../../charts/donutChart"; import LineCharts from "../../charts/lineChart"; import BarChartComponent from "../../charts/barChart"; import * as XLSX from 'xlsx'; import { Select, SelectItem } from "@nextui-org/react"; +import { toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import Cookies from "js-cookie"; -const ChartType = [{ key: "bar", label: "Bar Graph" }, { key: "line_chart", label: "Line_Chart" }] +const ChartType = [{ key: "bar", label: "Bar Graph" }, { key: "line_chart", label: "Line Graph" }, { key: "pie_chart", label: "Pie Chart" }] const Report = () => { const [file, setFile] = useState(); @@ -17,6 +20,7 @@ const Report = () => { const [selectedReports, setSelectedReports] = useState([]); const [filteredData, setFilteredData] = useState(); const [chartTypes, setChartTypes] = useState(); + const [rawData, setRawData] = useState(); const handleOnChange = (e: any) => { @@ -48,7 +52,7 @@ const Report = () => { if (obj.channel) uniqueChannels.add(obj.channel); result.push(obj); } - + setRawData(result) const groupedData = groupChartData(result, "campaign"); setFilteredData(groupedData); setSelectedCampaigns(Array.from(uniqueCampaigns)); @@ -58,29 +62,37 @@ const Report = () => { }; const handleOnSubmit = (e: any) => { - const fileReader = new FileReader(); - e.preventDefault(); - if (file) { - fileReader.onload = function (event: any) { - const text = event.target.result; - if (typeof text === 'string') { - parseCSV(text); + try { + const fileReader = new FileReader(); + e.preventDefault(); + if (file) { + fileReader.onload = function (event: any) { + const text = event.target.result; + if (typeof text === 'string') { + parseCSV(text); + } else { + const workbook = XLSX.read(text, { type: 'binary' }); + const sheetName = workbook.SheetNames[0]; + const csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); + parseCSV(csv); + } + }; + const fileName = file.name; + const fileExtension = fileName.split('.').pop()?.toLowerCase(); + if (fileExtension === 'csv') { + fileReader.readAsText(file); } else { - const workbook = XLSX.read(text, { type: 'binary' }); - const sheetName = workbook.SheetNames[0]; - const csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); - parseCSV(csv); + fileReader.readAsArrayBuffer(file); } - }; - const fileName = file.name; - const fileExtension = fileName.split('.').pop()?.toLowerCase(); - if (fileExtension === 'csv') { - fileReader.readAsText(file); + toast.success('File has been imported successfully.'); } else { - fileReader.readAsArrayBuffer(file); + toast.error("Error While Importing File") } + } catch { + toast.error("Error While Importing File") } + }; const groupChartData = (data: any[], groupByKey: string): any => { @@ -95,8 +107,57 @@ const Report = () => { return acc; }, {} as Record); }; + const getRandomColor = (): string => { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + }; + const groupAndCalculateShares = (data: any[], groupByKey1: string, groupByKey2: string, numericalValueKey: string, key: string): any => { + const groupedData: any = {}; + + data.forEach(item => { + const campaignKey = item[groupByKey1]; + const saleType = item[groupByKey2]; + const numericalValue = item[numericalValueKey]; + + if (!groupedData[campaignKey]) { + groupedData[campaignKey] = []; + } + + const existingEntryIndex = groupedData[campaignKey].findIndex((entry: any) => entry.name === saleType); + + if (existingEntryIndex !== -1) { + groupedData[campaignKey][existingEntryIndex].total += numericalValue; + } else { + groupedData[campaignKey].push({ + name: saleType, + total: numericalValue, + share: '', + color: getRandomColor() + }); + } + }); + + Object.keys(groupedData).forEach(campaignKey => { + const totalCampaignValue = groupedData[campaignKey].reduce((total: number, sale: any) => total + sale.total, 0); + + groupedData[campaignKey].forEach((sale: any) => { + sale.share = ((sale.total / totalCampaignValue) * 100).toFixed(1) + '%'; + }); + }); + let resultData = groupedData[key].map((obj: any) => { + return Object.fromEntries( + Object.entries(obj).map(([key, value]) => [key.replace(/^"(.*)"$/, '$1'), value]) + ); + }); + return resultData; + }; + + const transformDataForLineChart = (groupedData: any, valueKey: string): any[] => { - transformData(groupedData, valueKey, "campaign", "channel") const transformedData: any[] = []; Object.keys(groupedData).forEach(campaign => { groupedData[campaign].forEach((data: any) => { @@ -137,7 +198,6 @@ const Report = () => { } }); }); - console.log("example data", transformedData) return transformedData; }; @@ -184,54 +244,61 @@ const Report = () => {

You are only allowed to upload CSV, XLSX or XLS files.

-
- {chartTypes ? - - : null} - {ChartType && chartTypes ? - - : null} -
+
+ {chartTypes ? + + : null} + {ChartType && chartTypes ? + + : null} + {chartTypes ? + : null} +

{selectedCharts.includes("line_chart") ?
+

Line Graph

{selectedCampaigns?.map((group, rowIndex) => (

{group}

@@ -240,7 +307,6 @@ const Report = () => {
{
))}
: null} - {/*
+ {selectedCharts.includes("pie_chart") ?
+

Pie Chart

{selectedCampaigns?.map((group, rowIndex) => (

{group}

{selectedReports?.map((chart, colIndex) => (
-
))}
))} -
*/} +
: null} {selectedCharts.includes("bar") ?

Bar Graph

@@ -283,7 +356,6 @@ const Report = () => {
{ - const [value, setValue] = useState(0); + const [value, setValue] = useState(new Date('2023-01-01').getTime()); const [selectedChannels, setSelectedChannels] = useState([]); const [selectedCampaigns, setSelectedCampaigns] = useState([]); const [selectedReports, setSelectedReports] = useState([]); const [startDate, setStartDate] = useState(new Date('2023-01-01').getTime()); - const [endDate, setEndDate] = useState(new Date('2023-12-31').getTime()); + const [endDate, setEndDate] = useState(new Date('2024-01-28').getTime()); const [filteredData, setFilteredData] = useState(); const [chartTypes, setChartTypes] = useState(); - const handleChange = (event: any, isStart: boolean) => { + const handleChange = (event: React.ChangeEvent, isStart: boolean) => { const newValue = +event; if (isStart) { setValue(newValue); @@ -36,16 +34,13 @@ const Report = () => { }; const monthMilliseconds = 30.44 * 24 * 60 * 60 * 1000; - - - const applyFilters = () => { const filteredChartsMetaData = chartsMetaData.filter(meta => selectedReports.includes(meta.categories[0]) ); setChartTypes(filteredChartsMetaData) - let filteredData = groupChartData(ChartData); - // filteredData = filterDataByDate(filteredData, startDate, endDate); + let filteredDate = filterDataByDate(ChartData, startDate, endDate) + let filteredData = groupChartData(filteredDate); setFilteredData(filteredData) }; @@ -59,11 +54,12 @@ const Report = () => { return acc; }, {} as any); }; - const filterDataByDate = (data: any[], startDate: number, endDate: number): any[] => { - return data.filter(item => { - const itemDate = new Date(item.filterDate).getTime(); - return itemDate >= startDate && itemDate <= endDate; + const filterDataByDate = (data: any, startDate: number, endDate: number): any => { + const filtered: any = data.filter((entry: any) => { + const entryDate = new Date(entry.filterDate.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$2/$1/$3')).getTime(); + return entryDate >= value && entryDate <= endDate; }); + return filtered }; const transformDataForLineChart = (groupedData: any, valueKey: string): any[] => { @@ -103,26 +99,26 @@ const Report = () => { const downloadPDF = async () => { const pdf = new jsPDF(); try { - - let element = document.getElementById("graphPart"); - if (!element || !isVisible(element)) { - throw new Error(`Element with id "${data}" not found or not visible.`); - } - const canvas = await html2canvas(element); - const imgData = canvas.toDataURL("image/png"); - const imgWidth = canvas.width; - const imgHeight = canvas.height; - const aspectRatio = imgWidth / imgHeight; - const pdfWidth = pdf.internal.pageSize.getWidth() - 20; - const pdfHeight = pdfWidth / aspectRatio; - // if (i > 0) { - // pdf.addPage(); - // } - const x = (pdf.internal.pageSize.getWidth() - pdfWidth) / 2; - const y = (pdf.internal.pageSize.getHeight() - pdfHeight) / 2; - pdf.addImage(imgData, "PNG", x, y, pdfWidth, pdfHeight); - + let element = document.getElementById("graphPart"); + if (!element || !isVisible(element)) { + throw new Error(`Element with id "${data}" not found or not visible.`); + } + const canvas = await html2canvas(element); + const imgData = canvas.toDataURL("image/png"); + + const imgWidth = canvas.width; + const imgHeight = canvas.height; + const aspectRatio = imgWidth / imgHeight; + const pdfWidth = pdf.internal.pageSize.getWidth() - 20; + const pdfHeight = pdfWidth / aspectRatio; + // if (i > 0) { + // pdf.addPage(); + // } + const x = (pdf.internal.pageSize.getWidth() - pdfWidth) / 2; + const y = (pdf.internal.pageSize.getHeight() - pdfHeight) / 2; + pdf.addImage(imgData, "PNG", x, y, pdfWidth, pdfHeight); + pdf.save("chart.pdf"); } catch (error) { console.error("Error generating PDF:", error); @@ -158,7 +154,6 @@ const Report = () => { }} /> -
From ab6e5df41c4a2b012ed81b7394d6ff499b215794 Mon Sep 17 00:00:00 2001 From: prateek-pareek <97360950+prateek-pareek@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:17:06 +0530 Subject: [PATCH 4/5] fixed --- app/dashboard/layout.tsx | 6 +++--- app/reports/layout.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index 23efb54..18c69b2 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -7,7 +7,7 @@ import { Analytics } from '@vercel/analytics/react'; import { SessionProvider } from 'next-auth/react'; import { SpeedInsights } from "@vercel/speed-insights/next" import { NextUIProvider } from '@nextui-org/react'; -import { ThemeProvider as NextThemesProvider } from "next-themes"; +// import { ThemeProvider as NextThemesProvider } from "next-themes"; import { NotificationProvider } from '@/components/ui/NotificationContext'; export default function RootLayout({ children, @@ -20,7 +20,7 @@ export default function RootLayout({ - + {/* */}
{children} @@ -28,7 +28,7 @@ export default function RootLayout({
-
+ {/*
*/}
diff --git a/app/reports/layout.tsx b/app/reports/layout.tsx index 23efb54..18c69b2 100644 --- a/app/reports/layout.tsx +++ b/app/reports/layout.tsx @@ -7,7 +7,7 @@ import { Analytics } from '@vercel/analytics/react'; import { SessionProvider } from 'next-auth/react'; import { SpeedInsights } from "@vercel/speed-insights/next" import { NextUIProvider } from '@nextui-org/react'; -import { ThemeProvider as NextThemesProvider } from "next-themes"; +// import { ThemeProvider as NextThemesProvider } from "next-themes"; import { NotificationProvider } from '@/components/ui/NotificationContext'; export default function RootLayout({ children, @@ -20,7 +20,7 @@ export default function RootLayout({ - + {/* */}
{children} @@ -28,7 +28,7 @@ export default function RootLayout({
-
+ {/*
*/}
From 8e9b885002c53e5022c979c0e2c7a01c9ceaa7cc Mon Sep 17 00:00:00 2001 From: prateek-pareek <97360950+prateek-pareek@users.noreply.github.com> Date: Fri, 28 Jun 2024 22:30:58 +0530 Subject: [PATCH 5/5] automation page added --- app/reports/automation/page.tsx | 16 ++ .../ui/report/automation/automation.tsx | 226 ++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 app/reports/automation/page.tsx create mode 100644 components/ui/report/automation/automation.tsx diff --git a/app/reports/automation/page.tsx b/app/reports/automation/page.tsx new file mode 100644 index 0000000..a318962 --- /dev/null +++ b/app/reports/automation/page.tsx @@ -0,0 +1,16 @@ +"use client"; +import ScheduleAutomationPage from "@/components/ui/report/automation/automation" +import React from "react"; +import Layout from "@/components/ui/layout/index"; + +const Page: React.FC = () => { + return ( + + + + ); + }; + + + + export default Page \ No newline at end of file diff --git a/components/ui/report/automation/automation.tsx b/components/ui/report/automation/automation.tsx new file mode 100644 index 0000000..ecb5939 --- /dev/null +++ b/components/ui/report/automation/automation.tsx @@ -0,0 +1,226 @@ +import Head from 'next/head'; +import { useState } from 'react'; +import { Select, SelectItem } from "@nextui-org/react"; +import { RadioGroup, Radio } from "@nextui-org/react"; +import { DatePicker } from "@nextui-org/react"; +import { TimeInput } from "@nextui-org/react"; +import { Time } from "@internationalized/date"; +import { Checkbox } from "@nextui-org/react"; +interface ScheduleForm { + reportName: string; + format: string; + startDate: string; + recurring: boolean; + repeats: string; + startTime: string; + endTime: string; + email: string; +} + +const ScheduleAutomationPage = () => { + const [selectedReports, setSelectedReports] = useState([]); + const [selectedRepeat, setSelectedRepeat] = useState([]); + const [orientation, setOrientation] = useState("horizontal"); + const [checked, setChecked] = useState(false); + const [scheduleForm, setScheduleForm] = useState({ + reportName: '', + format: '', + startDate: '', + recurring: false, + repeats: '', + startTime: '', + endTime: '', + email: '', + }); + + const handleChange = (event: any) => { + setChecked(event.target.checked); + }; + const handleChanges = (event: any) => { + setOrientation(event.target.value); + }; + + const handleFormChange = (event: React.ChangeEvent) => { + const { name, value } = event.target; + setScheduleForm((prevForm) => ({ ...prevForm, [name]: value })); + }; + + const handleFormSubmit = (event: React.FormEvent) => { + event.preventDefault(); + + console.log(scheduleForm); + }; + const chartTypes = ['Windows assets details report', 'Linux assets details report', 'Mac assets details report', 'Network devices details report', 'Cloud resources details report']; + const repeatOptions = ['Daily', 'Weekly', 'Monthly']; + return ( +
+ + Schedule Automation Page + +

Schedule Automation Page

+ +
+
+ + +
+ +
+
+ +
+ + PDF (Portrait) + PDF (Landscape) + + +
+
+
+ +
+ +
+ + Manual + Schedule + +
+ +
+
+
+ + + + {orientation === "schedule" && ( + <> +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + { handleChange(e) }}> Recurring + +
+
+ + {checked && ( + <> +
+ + +
+ + )} + {!scheduleForm.recurring && ( +
+
+ + +
+
+ + +
+
+ )} + + )} + +
+ + +
+ + +
+ +
+ ); +}; + +export default ScheduleAutomationPage; \ No newline at end of file