diff --git a/app/components/BarChart.client.tsx b/app/components/BarChart.client.tsx index ac3a85e..95c3655 100644 --- a/app/components/BarChart.client.tsx +++ b/app/components/BarChart.client.tsx @@ -26,7 +26,7 @@ export default function BarChart({ setSeries([ { - name: "Page Views", + name: "Views", data: displayData.map(({ count, label }) => ({ x: label, y: count })), }, ]); @@ -87,7 +87,6 @@ export default function BarChart({ }, }, xaxis: { - categories: displayData.map(({ label }) => label), axisBorder: { show: true, color: "#1e293b", diff --git a/app/components/BrushChart.client.tsx b/app/components/BrushChart.client.tsx deleted file mode 100644 index 6c30068..0000000 --- a/app/components/BrushChart.client.tsx +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ - -import ReactApexChart from "react-apexcharts"; - -type Props = { - data: number[][]; -}; - -export default function BrushChart({ data }: Props) { - const range = Math.min( - 7 * 24 * 60 * 60 * 1000, - data[data.length - 1][0] - data[0][0] - ); - - const options = { - chart: { - id: "chart2", - type: "line", - height: 230, - offsetX: -10, - offsetY: 0, - toolbar: { - show: true, - autoSelected: "selection", - tools: { - download: true, - selection: true, - zoom: true, - zoomin: true, - zoomout: true, - pan: false, - reset: false, - }, - }, - events: { - mounted: function ( - _: never, - { config }: { config: { xaxis: { range: number | undefined } } } - ) { - config.xaxis.range = undefined; - }, - }, - }, - colors: ["#64748b"], - fill: { - opacity: 1, - }, - stroke: { - width: 3, - curve: "smooth", - colors: ["#64748b"], - }, - grid: { - show: false, - }, - dataLabels: { - enabled: false, - }, - markers: { - size: 0, - }, - plotOptions: { - area: { - fillTo: "origin", - }, - }, - tooltip: { - x: { - format: "dd MMM yyyy", - }, - }, - xaxis: { - type: "datetime", - labels: { - datetimeFormatter: { - year: "yyyy", - month: "MMM 'yy", - day: "dd MMM 'yy", - hour: "", - }, - }, - axisBorder: { - show: true, - color: "#1e293b", - }, - axisTicks: { - show: false, - }, - range, - }, - yaxis: { - min: 0, - max: Math.max(...data.map((d) => d[1])) + 1, - forceNiceScale: true, - labels: { - formatter(val: number) { - return Math.round(val); - }, - }, - axisBorder: { - show: true, - color: "#1e293b", - }, - axisTicks: { - show: false, - }, - tickAmount: 4, - }, - }; - - const optionsLine = { - chart: { - id: "chart1", - height: 130, - type: "area", - brush: { - target: "chart2", - enabled: true, - }, - selection: { - enabled: true, - fill: { - color: "transparent", - opacity: 0.1, - }, - stroke: { - width: 1, - dashArray: 3, - color: "#475569", - opacity: 0.4, - }, - xaxis: { - min: data[0][0], - max: data[data.length - 1][0], - }, - }, - }, - colors: ["#0284C7"], - fill: { - type: "gradient", - gradient: { - opacityFrom: 0.91, - opacityTo: 0.1, - }, - }, - xaxis: { - type: "datetime", - tooltip: { - enabled: false, - }, - labels: { - formatter: function (_: never, timestamp: number) { - const date = new Date(new Date(timestamp).setHours(0, 0, 0, 0)); - return date.toLocaleDateString(undefined, { - year: "2-digit", - month: "short", - day: "numeric", - }); - }, - }, - }, - yaxis: { - show: false, - }, - }; - - const series = [ - { - name: "Page Views", - data: data, - }, - ]; - - return ( -
-
- {/* @ts-ignore */} - -
-
- {/* @ts-ignore */} - -
-
- ); -} diff --git a/app/components/TimeSeriesChart.client.tsx b/app/components/TimeSeriesChart.client.tsx new file mode 100644 index 0000000..237dcce --- /dev/null +++ b/app/components/TimeSeriesChart.client.tsx @@ -0,0 +1,118 @@ +import type { ApexOptions } from "apexcharts"; +import { useEffect, useState } from "react"; +import ReactApexChart from "react-apexcharts"; +import { DashboardElement } from "~/types/dashboard"; + +type Props = { + data: Omit[]; +}; + +export default function TimeSeriesChart({ data }: Props) { + const [series, setSeries] = useState([]); + const [options, setOptions] = useState({}); + + useEffect(() => { + const seriesData = data.map(({ count, label }) => [ + new Date(label).getTime(), + count, + ]); + + setSeries([ + { + name: "Page Views", + data: seriesData, + }, + ]); + + setOptions({ + chart: { + id: "chart2", + type: "line", + zoom: { + type: "x", + enabled: true, + autoScaleYaxis: true, + }, + height: 230, + offsetX: -10, + offsetY: 0, + toolbar: { + show: true, + autoSelected: "selection", + }, + }, + colors: ["#64748b"], + fill: { + opacity: 1, + }, + stroke: { + width: 3, + curve: "smooth", + colors: ["#64748b"], + }, + grid: { + show: false, + }, + dataLabels: { + enabled: false, + }, + markers: { + size: 0, + }, + plotOptions: { + area: { + fillTo: "origin", + }, + }, + xaxis: { + type: "datetime", + tickAmount: 8, + labels: { + formatter(val) { + return new Date(val).toLocaleDateString(undefined, { + year: "2-digit", + month: "short", + day: "numeric", + }); + }, + }, + axisBorder: { + show: true, + color: "#1e293b", + }, + axisTicks: { + show: false, + }, + }, + yaxis: { + min: 0, + max: Math.max(...seriesData.map((d) => d[1])) + 1, + forceNiceScale: true, + labels: { + formatter(val) { + return String(Math.round(val)); + }, + }, + axisBorder: { + show: true, + color: "#1e293b", + }, + axisTicks: { + show: false, + }, + tickAmount: 4, + }, + }); + }, [data]); + + return ( +
+ +
+ ); +} diff --git a/app/routes/app/dashboard.$id.tsx b/app/routes/app/dashboard.$id.tsx index 006511a..b64fc19 100644 --- a/app/routes/app/dashboard.$id.tsx +++ b/app/routes/app/dashboard.$id.tsx @@ -16,7 +16,7 @@ import classNames from "~/utils/class-names"; import { generateWebsiteColor, generateWebsiteInitials } from "~/utils/website"; import BarChart from "~/components/BarChart.client"; -// import BrushChart from "~/components/BrushChart.client"; +import TimeSeriesChart from "~/components/TimeSeriesChart.client"; import Button from "~/components/Button"; import H2 from "~/components/SectionHeader"; import LayoutGrid from "~/components/LayoutGrid"; @@ -30,7 +30,7 @@ type LoaderData = { website: Website; element: Path | Browser | Platform | Referrer | undefined; paths: DashboardElement[]; - periods: DashboardElement[]; + periods: Omit[]; browsers: DashboardElement[]; platforms: DashboardElement[]; referrers: DashboardElement[]; @@ -53,13 +53,12 @@ export const loader: LoaderFunction = async ({ request, params }) => { const [periods, browsers, paths, platforms, referrers] = await Promise.all([ db.$queryRaw` SELECT - "Period"."id", MAKE_DATE("Period"."year", "Period"."month", "Period"."day") as "label", COUNT(*) as "count" FROM "Event" INNER JOIN "Period" ON "Event"."periodId" = "Period"."id" WHERE "Event"."websiteId" = ${website.id} - GROUP BY 1, 2 - ORDER BY 2 ASC`, + GROUP BY 1 + ORDER BY 1`, db.$queryRaw` SELECT "Browser"."id", @@ -159,14 +158,10 @@ export default function DashboardRoute() {

Page Views Chart

{isMounted ? ( - // [ - // new Date(period.value).getTime(), - // period.count, - // ])} - // /> -
+ ) : (