Skip to content

Commit

Permalink
feat: Add support for Custom charts and cards widgets (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavier-Charles authored Nov 29, 2023
1 parent 1f8b083 commit b6ca6a7
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FC } from "react";

interface IProps {
title: string | undefined;
value: string | React.ReactNode | undefined;
}

const CustomCardModule: FC<IProps> = ({ title, value }) => {
return (
<div className="flex flex-col justify-center items-center border border-solid border-btnRingVariant300 !rounded-2xl p-5 m-5">
{title && (
<h6 className="text-primaryVariant100 fontGroup-support text-center uppercase mb-0.5">
{title}
</h6>
)}
{value && (
<div className="whitespace-nowrap prose-p:fontGroup-major prose-p:!text-4xl text-primary mb-0 text-center">
{value}
</div>
)}
</div>
);
};

export default CustomCardModule;
123 changes: 123 additions & 0 deletions packages/frontend/src/components/custom-modules/CustomChartModule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { FC, useMemo } from "react";
import {
ApexAreaChart,
ApexBarChart,
ApexDonutChart,
ApexLineChart,
ApexPieChart,
themeColors,
} from "@alphaday/ui-kit";
import { TCustomMetaChart } from "src/api/services";
import { TCustomSeries } from "src/api/types";
import { getXSeries, getYSeries } from "src/api/utils/customDataUtils";

export interface IChartModuleProps {
id: number;
series: TCustomSeries;
meta: TCustomMetaChart | undefined;
name: string;
}

const CustomChartModule: FC<IChartModuleProps> = ({
id,
series,
meta,
name,
}) => {
const labels = useMemo(() => {
return getXSeries(series, meta, name);
}, [meta, series, name]);

const options = {
id,
sparkline: {
enabled: false,
},
background: "transparent",
redrawOnWindowResize: true,
height: "500px",
labels,
dataLabels: {
enabled: false,
},
plotOptions: {
pie: {
donut: {
background: "transparent",
},
},
},
stroke: {
colors: undefined,
},
legend: {
show: true,
fontSize: "11px",
position: "left",
offsetX: 0,
offsetY: 0,
height: 500,
labels: {
colors: [themeColors.primaryVariant100],
useSeriesColors: false,
},
markers: {
radius: 3,
},
},
};

const ySeries = useMemo(() => {
return getYSeries(series, meta, name);
}, [meta, series, name]);

if (meta?.layout.variant === "donut") {
return (
<ApexDonutChart
options={options}
series={ySeries}
width="400px"
height="500px"
/>
);
}
if (meta?.layout.variant === "pie") {
return (
<ApexPieChart
options={options}
series={ySeries}
width="400px"
height="500px"
/>
);
}
if (meta?.layout.variant === "bar") {
return (
<ApexBarChart
options={options}
series={ySeries}
width="400px"
height="500px"
/>
);
}
if (meta?.layout.variant === "area") {
return (
<ApexAreaChart
options={options}
series={ySeries}
width="400px"
height="500px"
/>
);
}
return (
<ApexLineChart
options={options}
series={ySeries}
width="400px"
height="500px"
/>
);
};
export default CustomChartModule;
10 changes: 10 additions & 0 deletions packages/frontend/src/config/widgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ const WIDGETS_CONFIG = {
WIDGET_HEIGHT: 400,
ADJUSTABLE: true,
},
[ETemplateNameRegistry.CustomCard]: {
MAX_PAGE_NUMBER: 10,
WIDGET_HEIGHT: DEFAULT_WIDGET_HEIGHT,
ADJUSTABLE: false,
},
[ETemplateNameRegistry.CustomChart]: {
MAX_PAGE_NUMBER: 10,
WIDGET_HEIGHT: DEFAULT_WIDGET_HEIGHT,
ADJUSTABLE: false,
},
[ETemplateNameRegistry.CustomTable]: {
MAX_PAGE_NUMBER: 10,
WIDGET_HEIGHT: 400,
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export enum ETemplateNameRegistry {
Calendar = "CALENDAR",
Chat = "CHAT",
Countdown = "COUNTDOWN",
CustomCard = "CUSTOM_CARD",
CustomChart = "CUSTOM_CHART",
CustomTable = "CUSTOM_TABLE",
Dao = "DAO",
Discord = "DISCORD",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { FC, useMemo } from "react";
import { EWidgetData, useGetCustomItemsQuery } from "src/api/services";
import { customDataAsCardData } from "src/api/utils/customDataUtils";
import { Logger } from "src/api/utils/logging";
import CustomCardModule from "src/components/custom-modules/CustomCardModule";
import { IModuleContainer } from "src/types";

const CustomChartContainer: FC<IModuleContainer> = ({ moduleData }) => {
/* eslint-disable @typescript-eslint/naming-convention */
const { name, custom_data, custom_meta, endpoint_url, data_type } =
moduleData.widget;
/* eslint-enable @typescript-eslint/naming-convention */

const { data } = useGetCustomItemsQuery(
{
endpointUrl: endpoint_url || "",
},
{
skip: data_type === EWidgetData.Static,
}
);

const cardData = useMemo(() => {
let dataToUse;
if (data_type === EWidgetData.Static) {
if (!custom_data) {
Logger.error(
`CustomCardContainer: missing data for widget ${name}`
);
return undefined;
}
dataToUse = custom_data;
} else {
dataToUse = data?.results ?? [];
}
if (dataToUse) {
if (custom_meta != null) {
if (custom_meta.layout_type !== "card") {
Logger.error(
`CustomCardContainer: invalid layout type, expected "card" in widget ${name}`
);
return customDataAsCardData(dataToUse, undefined, name);
}
return customDataAsCardData(dataToUse, custom_meta, name);
}
}
return customDataAsCardData(dataToUse, undefined, name);
}, [custom_data, custom_meta, data?.results, data_type, name]);

return <CustomCardModule title={cardData?.title} value={cardData?.value} />;
};

export default CustomChartContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { FC, useMemo } from "react";
import { EWidgetData, useGetCustomItemsQuery } from "src/api/services";
import { customDataAsSeries } from "src/api/utils/customDataUtils";
import { Logger } from "src/api/utils/logging";
import CustomChartModule from "src/components/custom-modules/CustomChartModule";
import { IModuleContainer } from "src/types";

const CustomChartContainer: FC<IModuleContainer> = ({ moduleData }) => {
/* eslint-disable @typescript-eslint/naming-convention */
const { id, name, custom_data, custom_meta, endpoint_url, data_type } =
moduleData.widget;
/* eslint-enable @typescript-eslint/naming-convention */

const { data } = useGetCustomItemsQuery(
{
endpointUrl: endpoint_url || "",
},
{
skip: data_type === EWidgetData.Static,
}
);

const series = useMemo(() => {
if (data_type === EWidgetData.Static) {
if (!custom_data) {
Logger.error(
`CustomChartContainer: missing data for widget ${name}`
);
return [];
}
return customDataAsSeries(custom_data);
}
return customDataAsSeries(data?.results ?? []);
}, [custom_data, data?.results, data_type, name]);

const meta = useMemo(() => {
if (custom_meta?.layout_type !== "chart") {
Logger.warn(
`CustomChartContainer: invalid layout type, expected chart in widget ${name}`
);
return undefined;
}
return custom_meta;
}, [custom_meta, name]);

return (
<CustomChartModule id={id} series={series} meta={meta} name={name} />
);
};

export default CustomChartContainer;
6 changes: 6 additions & 0 deletions packages/frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ export const TEMPLATES_DICT: Partial<TTemplatesDict> = {
verasity_tokenomics_template: lazy(
() => import("./containers/client/VerasityTokenomicsContainer")
),
custom_chart_template: lazy(
() => import("./containers/custom-modules/CustomChartContainer")
),
custom_card_template: lazy(
() => import("./containers/custom-modules/CustomCardContainer")
),
};

export type TFullSizeRoute = {
Expand Down

0 comments on commit b6ca6a7

Please sign in to comment.