save, create and view reports in dashboard

This commit is contained in:
Carl-Gerhard Lindesvärd
2023-10-19 11:56:52 +02:00
parent 2cb6bbfdd3
commit 4576453aef
28 changed files with 686 additions and 403 deletions

View File

@@ -0,0 +1,89 @@
import { useDispatch, useSelector } from "@/redux";
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
import { changeDateRanges, changeInterval } from "./reportSlice";
import { Combobox } from "../ui/combobox";
import { type IInterval } from "@/types";
export function ReportDateRange() {
const dispatch = useDispatch();
const interval = useSelector((state) => state.report.interval);
return (
<>
<RadioGroup>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(1));
}}
>
Today
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(7));
}}
>
7 days
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(14));
}}
>
14 days
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(30));
}}
>
1 month
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(90));
}}
>
3 month
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(180));
}}
>
6 month
</RadioGroupItem>
<RadioGroupItem
onClick={() => {
dispatch(changeDateRanges(356));
}}
>
1 year
</RadioGroupItem>
</RadioGroup>
<div className="w-full max-w-[200px]">
<Combobox
placeholder="Interval"
onChange={(value) => {
dispatch(changeInterval(value as IInterval));
}}
value={interval}
items={[
{
label: "Hour",
value: "hour",
},
{
label: "Day",
value: "day",
},
{
label: "Month",
value: "month",
},
]}
></Combobox>
</div>
</>
);
}

View File

@@ -1,7 +1,6 @@
import { api } from "@/utils/api";
import {
CartesianGrid,
Legend,
Line,
LineChart,
Tooltip,
@@ -10,22 +9,13 @@ import {
} from "recharts";
import { ReportLineChartTooltip } from "./ReportLineChartTooltop";
import { useFormatDateInterval } from "@/hooks/useFormatDateInterval";
import {
type IChartBreakdown,
type IChartEvent,
type IInterval,
} from "@/types";
import { type IChartInput } from "@/types";
import { getChartColor } from "@/utils/theme";
import { ReportTable } from "./ReportTable";
import { useEffect, useRef, useState } from "react";
import { AutoSizer } from "@/components/AutoSizer";
type ReportLineChartProps = {
interval: IInterval;
startDate: Date;
endDate: Date;
events: IChartEvent[];
breakdowns: IChartBreakdown[];
type ReportLineChartProps = IChartInput & {
showTable?: boolean;
};
@@ -36,16 +26,20 @@ export function ReportLineChart({
events,
breakdowns,
showTable,
chartType,
name,
}: ReportLineChartProps) {
const [visibleSeries, setVisibleSeries] = useState<string[]>([]);
const chart = api.chartMeta.chart.useQuery(
{
interval,
chartType: "linear",
chartType,
startDate,
endDate,
events,
breakdowns,
name,
},
{
enabled: events.length > 0,
@@ -58,25 +52,23 @@ export function ReportLineChart({
useEffect(() => {
if (!ref.current && chart.data) {
const max = 20;
setVisibleSeries(
chart.data?.series?.slice(0, max).map((serie) => serie.name) ?? [],
);
// ref.current = true;
}
}, [chart.data]);
return (
<>
);
// ref.current = true;
}
}, [chart.data]);
return (
<>
{chart.isSuccess && chart.data?.series?.[0]?.data && (
<>
<AutoSizer disableHeight>
{({ width }) => (
<LineChart width={width} height={width * 0.5}>
{/* <Legend /> */}
<LineChart width={width} height={Math.min(width * 0.5, 400)}>
<YAxis dataKey={"count"}></YAxis>
<Tooltip content={<ReportLineChartTooltip />} />
{/* <Tooltip /> */}
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="date"

View File

@@ -0,0 +1,9 @@
import { useQueryParams } from "@/hooks/useQueryParams";
import { z } from "zod";
export const useReportId = () =>
useQueryParams(
z.object({
reportId: z.string().optional(),
}),
);

View File

@@ -1,4 +1,5 @@
import {
type IChartInput,
type IChartBreakdown,
type IChartEvent,
type IInterval,
@@ -6,32 +7,17 @@ import {
import { getDaysOldDate } from "@/utils/date";
import { type PayloadAction, createSlice } from "@reduxjs/toolkit";
type InitialState = {
events: IChartEvent[];
breakdowns: IChartBreakdown[];
interval: IInterval;
startDate: Date;
endDate: Date;
};
type InitialState = IChartInput;
// First approach: define the initial state using that type
const initialState: InitialState = {
name: "",
chartType: "linear",
startDate: getDaysOldDate(7),
endDate: new Date(),
interval: "day",
breakdowns: [
{
id: "A",
name: 'properties.id'
}
],
events: [
{
id: "A",
name: "sign_up",
filters: []
},
],
breakdowns: [],
events: [],
};
const IDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] as const;
@@ -40,6 +26,12 @@ export const reportSlice = createSlice({
name: "counter",
initialState,
reducers: {
reset() {
return initialState
},
setReport(state, action: PayloadAction<IChartInput>) {
return action.payload
},
// Events
addEvent: (state, action: PayloadAction<Omit<IChartEvent, "id">>) => {
state.events.push({
@@ -111,21 +103,23 @@ export const reportSlice = createSlice({
},
changeDateRanges: (state, action: PayloadAction<number>) => {
if(action.payload === 1) {
if (action.payload === 1) {
state.interval = "hour";
} else if(action.payload <= 30) {
} else if (action.payload <= 30) {
state.interval = "day";
} else {
state.interval = "month";
}
state.startDate = getDaysOldDate(action.payload);
state.endDate = new Date();
}
},
},
});
// Action creators are generated for each case reducer function
export const {
reset,
setReport,
addEvent,
removeEvent,
changeEvent,

View File

@@ -0,0 +1,36 @@
import { Button } from "@/components/ui/button";
import { useReportId } from "../hooks/useReportId";
import { api } from "@/utils/api";
import { useSelector } from "@/redux";
export function ReportSave() {
const { reportId } = useReportId();
const save = api.report.save.useMutation();
const update = api.report.update.useMutation();
const report = useSelector((state) => state.report);
if (reportId) {
return <Button onClick={() => {
update.mutate({
reportId,
report,
dashboardId: "9227feb4-ad59-40f3-b887-3501685733dd",
projectId: "f7eabf0c-e0b0-4ac0-940f-1589715b0c3d",
});
}}>Update</Button>;
} else {
return (
<Button
onClick={() => {
save.mutate({
report,
dashboardId: "9227feb4-ad59-40f3-b887-3501685733dd",
projectId: "f7eabf0c-e0b0-4ac0-940f-1589715b0c3d",
});
}}
>
Create
</Button>
);
}
}

View File

@@ -1,11 +1,13 @@
import { ReportEvents } from "./ReportEvents";
import { ReportBreakdowns } from "./ReportBreakdowns";
import { ReportSave } from "./ReportSave";
export function ReportSidebar() {
return (
<div className="flex flex-col gap-4 p-4">
<ReportEvents />
<ReportBreakdowns />
<ReportSave />
</div>
);
}