diff --git a/components/common/HoverTooltip.js b/components/common/HoverTooltip.js index 2a98ab84..59fd6277 100644 --- a/components/common/HoverTooltip.js +++ b/components/common/HoverTooltip.js @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { Tooltip } from 'react-basics'; import styles from './HoverTooltip.module.css'; -export function HoverTooltip({ tooltip }) { +export function HoverTooltip({ children }) { const [position, setPosition] = useState({ x: -1000, y: -1000 }); useEffect(() => { @@ -18,8 +18,8 @@ export function HoverTooltip({ tooltip }) { }, []); return ( -
- +
+
); } diff --git a/components/common/WorldMap.js b/components/common/WorldMap.js index 55a13f0b..a371e2d3 100644 --- a/components/common/WorldMap.js +++ b/components/common/WorldMap.js @@ -15,7 +15,7 @@ import styles from './WorldMap.module.css'; export function WorldMap({ data, className }) { const { basePath } = useRouter(); const [tooltip, setTooltip] = useState(); - const [theme] = useTheme(); + const { theme } = useTheme(); const colors = useMemo( () => ({ baseColor: THEME_COLORS[theme].primary, diff --git a/components/input/LanguageButton.js b/components/input/LanguageButton.js index e2a51223..049b49f3 100644 --- a/components/input/LanguageButton.js +++ b/components/input/LanguageButton.js @@ -9,9 +9,9 @@ export function LanguageButton() { const { locale, saveLocale, dir } = useLocale(); const items = Object.keys(languages).map(key => ({ ...languages[key], value: key })); - function handleSelect(value) { - //saveLocale(value); - console.log('WTFFFF'); + function handleSelect(value, close) { + saveLocale(value); + close(); } return ( @@ -22,24 +22,28 @@ export function LanguageButton() { -
- {items.map(({ value, label }) => { - return ( -
- {label} - {value === locale && ( - - - - )} -
- ); - })} -
+ {close => { + return ( +
+ {items.map(({ value, label }) => { + return ( +
+ {label} + {value === locale && ( + + + + )} +
+ ); + })} +
+ ); + }}
); diff --git a/components/input/ThemeButton.js b/components/input/ThemeButton.js index b945ab7d..8ab0cdcd 100644 --- a/components/input/ThemeButton.js +++ b/components/input/ThemeButton.js @@ -5,7 +5,7 @@ import Icons from 'components/icons'; import styles from './ThemeButton.module.css'; export function ThemeButton() { - const [theme, setTheme] = useTheme(); + const { theme, saveTheme } = useTheme(); const transitions = useTransition(theme, { initial: { opacity: 1 }, @@ -21,7 +21,7 @@ export function ThemeButton() { }); function handleClick() { - setTheme(theme === 'light' ? 'dark' : 'light'); + saveTheme(theme === 'light' ? 'dark' : 'light'); } return ( diff --git a/components/messages.js b/components/messages.js index fb0dee3c..0de3a44c 100644 --- a/components/messages.js +++ b/components/messages.js @@ -123,7 +123,11 @@ export const labels = defineMessages({ reports: { id: 'label.reports', defaultMessage: 'Reports' }, eventData: { id: 'label.event-data', defaultMessage: 'Event data' }, funnel: { id: 'label.funnel', defaultMessage: 'Funnel' }, + url: { id: 'label.url', defaultMessage: 'URL' }, urls: { id: 'label.urls', defaultMessage: 'URLs' }, + add: { id: 'label.add', defaultMessage: 'Add' }, + window: { id: 'label.window', defaultMessage: 'Window' }, + addUrl: { id: 'label.add-url', defaultMessage: 'Add URL' }, }); export const messages = defineMessages({ diff --git a/components/metrics/BarChart.js b/components/metrics/BarChart.js index 8e1784df..9206b800 100644 --- a/components/metrics/BarChart.js +++ b/components/metrics/BarChart.js @@ -1,102 +1,39 @@ -import { useState, useRef, useEffect, useMemo, useCallback } from 'react'; -import { StatusLight, Loading } from 'react-basics'; +import { useState, useRef, useEffect, useCallback } from 'react'; +import { Loading } from 'react-basics'; import classNames from 'classnames'; import Chart from 'chart.js/auto'; import HoverTooltip from 'components/common/HoverTooltip'; import Legend from 'components/metrics/Legend'; import { formatLongNumber } from 'lib/format'; -import { dateFormat } from 'lib/date'; import useLocale from 'hooks/useLocale'; import useTheme from 'hooks/useTheme'; -import { DEFAULT_ANIMATION_DURATION, THEME_COLORS } from 'lib/constants'; +import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import styles from './BarChart.module.css'; +function defaultRenderYLabel(label) { + return +label > 1000 ? formatLongNumber(label) : label; +} + export function BarChart({ datasets, unit, animationDuration = DEFAULT_ANIMATION_DURATION, stacked = false, loading = false, - onCreate = () => {}, - onUpdate = () => {}, + renderXLabel, + renderYLabel, + XAxisType = 'time', + YAxisType = 'linear', + renderTooltip, + onCreate, + onUpdate, className, }) { const canvas = useRef(); const chart = useRef(null); const [tooltip, setTooltip] = useState(null); const { locale } = useLocale(); - const [theme] = useTheme(); - - const colors = useMemo( - () => ({ - text: THEME_COLORS[theme].gray700, - line: THEME_COLORS[theme].gray200, - }), - [theme], - ); - - const renderYLabel = label => { - return +label > 1000 ? formatLongNumber(label) : label; - }; - - const renderXLabel = useCallback( - (label, index, values) => { - const d = new Date(values[index].value); - - switch (unit) { - case 'minute': - return dateFormat(d, 'h:mm', locale); - case 'hour': - return dateFormat(d, 'p', locale); - case 'day': - return dateFormat(d, 'MMM d', locale); - case 'month': - return dateFormat(d, 'MMM', locale); - case 'year': - return dateFormat(d, 'YYY', locale); - default: - return label; - } - }, - [locale, unit], - ); - - const renderTooltip = useCallback( - model => { - const { opacity, labelColors, dataPoints } = model.tooltip; - - if (!dataPoints?.length || !opacity) { - setTooltip(null); - return; - } - - const formats = { - millisecond: 'T', - second: 'pp', - minute: 'p', - hour: 'h:mm aaa - PP', - day: 'PPPP', - week: 'PPPP', - month: 'LLLL yyyy', - quarter: 'qqq', - year: 'yyyy', - }; - - setTooltip( -
-
{dateFormat(new Date(dataPoints[0].raw.x), formats[unit], locale)}
-
- -
- {formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label} -
-
-
-
, - ); - }, - [unit], - ); + const { theme, colors } = useTheme(); const getOptions = useCallback(() => { return { @@ -117,12 +54,12 @@ export function BarChart({ }, tooltip: { enabled: false, - external: renderTooltip, + external: renderTooltip ? renderTooltip.bind(null, setTooltip) : undefined, }, }, scales: { x: { - type: 'time', + type: XAxisType, stacked: true, time: { unit, @@ -131,34 +68,44 @@ export function BarChart({ display: false, }, border: { - color: colors.line, + color: colors.chart.line, }, ticks: { - color: colors.text, + color: colors.chart.text, autoSkip: false, maxRotation: 0, callback: renderXLabel, }, }, y: { - type: 'linear', + type: YAxisType, min: 0, beginAtZero: true, stacked, grid: { - color: colors.line, + color: colors.chart.line, }, border: { - color: colors.line, + color: colors.chart.line, }, ticks: { color: colors.text, - callback: renderYLabel, + callback: renderYLabel || defaultRenderYLabel, }, }, }, }; - }, [animationDuration, renderTooltip, renderXLabel, stacked, colors, unit, locale]); + }, [ + animationDuration, + renderTooltip, + renderXLabel, + XAxisType, + YAxisType, + stacked, + colors, + unit, + locale, + ]); const createChart = () => { Chart.defaults.font.family = 'Inter'; @@ -173,7 +120,7 @@ export function BarChart({ options, }); - onCreate(chart.current); + onCreate?.(chart.current); }; const updateChart = () => { @@ -186,7 +133,7 @@ export function BarChart({ chart.current.options = getOptions(); - onUpdate(chart.current); + onUpdate?.(chart.current); chart.current.update(); }; @@ -208,7 +155,11 @@ export function BarChart({
- {tooltip && } + {tooltip && ( + +
{tooltip}
+
+ )} ); } diff --git a/components/metrics/DataTable.js b/components/metrics/DataTable.js index 086f98ae..a2c1a568 100644 --- a/components/metrics/DataTable.js +++ b/components/metrics/DataTable.js @@ -5,8 +5,8 @@ import { useSpring, animated, config } from 'react-spring'; import classNames from 'classnames'; import NoData from 'components/common/NoData'; import { formatNumber, formatLongNumber } from 'lib/format'; +import useMessages from 'hooks/useMessages'; import styles from './DataTable.module.css'; -import useMessages from '../../hooks/useMessages'; export function DataTable({ data = [], diff --git a/components/metrics/DataTable.module.css b/components/metrics/DataTable.module.css index c5b2bd7c..04e12e9b 100644 --- a/components/metrics/DataTable.module.css +++ b/components/metrics/DataTable.module.css @@ -1,9 +1,9 @@ .table { position: relative; - height: 100%; display: grid; grid-template-rows: fit-content(100%) auto; overflow: hidden; + flex: 1; } .body { diff --git a/components/metrics/MetricsBar.module.css b/components/metrics/MetricsBar.module.css index 0e305c70..eaf81c48 100644 --- a/components/metrics/MetricsBar.module.css +++ b/components/metrics/MetricsBar.module.css @@ -1,7 +1,7 @@ .bar { display: flex; cursor: pointer; - min-height: 80px; + min-height: 110px; gap: 20px; flex-wrap: wrap; } diff --git a/components/metrics/PageviewsChart.js b/components/metrics/PageviewsChart.js index 6ea16226..0dcf0ac5 100644 --- a/components/metrics/PageviewsChart.js +++ b/components/metrics/PageviewsChart.js @@ -1,33 +1,73 @@ -import { useMemo } from 'react'; -import { colord } from 'colord'; +import { useCallback, useMemo } from 'react'; +import { StatusLight } from 'react-basics'; import BarChart from './BarChart'; -import { THEME_COLORS } from 'lib/constants'; import useTheme from 'hooks/useTheme'; import useMessages from 'hooks/useMessages'; import useLocale from 'hooks/useLocale'; +import { dateFormat } from 'lib/date'; +import { formatLongNumber } from 'lib/format'; -export function PageviewsChart({ websiteId, data, unit, records, className, loading, ...props }) { +export function PageviewsChart({ websiteId, data, unit, className, loading, ...props }) { const { formatMessage, labels } = useMessages(); - const [theme] = useTheme(); + const { colors } = useTheme(); const { locale } = useLocale(); - const colors = useMemo(() => { - const primaryColor = colord(THEME_COLORS[theme].primary); - return { - views: { - hoverBackgroundColor: primaryColor.alpha(0.7).toRgbString(), - backgroundColor: primaryColor.alpha(0.4).toRgbString(), - borderColor: primaryColor.alpha(0.7).toRgbString(), - hoverBorderColor: primaryColor.toRgbString(), - }, - visitors: { - hoverBackgroundColor: primaryColor.alpha(0.9).toRgbString(), - backgroundColor: primaryColor.alpha(0.6).toRgbString(), - borderColor: primaryColor.alpha(0.9).toRgbString(), - hoverBorderColor: primaryColor.toRgbString(), - }, - }; - }, [theme]); + const renderXLabel = useCallback( + (label, index, values) => { + const d = new Date(values[index].value); + + switch (unit) { + case 'minute': + return dateFormat(d, 'h:mm', locale); + case 'hour': + return dateFormat(d, 'p', locale); + case 'day': + return dateFormat(d, 'MMM d', locale); + case 'month': + return dateFormat(d, 'MMM', locale); + case 'year': + return dateFormat(d, 'YYY', locale); + default: + return label; + } + }, + [locale, unit], + ); + + const renderTooltip = useCallback( + (setTooltip, model) => { + const { opacity, labelColors, dataPoints } = model.tooltip; + + if (!dataPoints?.length || !opacity) { + setTooltip(null); + return; + } + + const formats = { + millisecond: 'T', + second: 'pp', + minute: 'p', + hour: 'h:mm aaa - PP', + day: 'PPPP', + week: 'PPPP', + month: 'LLLL yyyy', + quarter: 'qqq', + year: 'yyyy', + }; + + setTooltip( + <> +
{dateFormat(new Date(dataPoints[0].raw.x), formats[unit], locale)}
+
+ + {formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label} + +
+ , + ); + }, + [unit], + ); const datasets = useMemo(() => { if (!data) return []; @@ -37,13 +77,13 @@ export function PageviewsChart({ websiteId, data, unit, records, className, load label: formatMessage(labels.uniqueVisitors), data: data.sessions, borderWidth: 1, - ...colors.visitors, + ...colors.chart.visitors, }, { label: formatMessage(labels.pageViews), data: data.pageviews, borderWidth: 1, - ...colors.views, + ...colors.chart.views, }, ]; }, [data, locale, colors]); @@ -55,8 +95,9 @@ export function PageviewsChart({ websiteId, data, unit, records, className, load className={className} datasets={datasets} unit={unit} - records={records} loading={loading} + renderXLabel={renderXLabel} + renderTooltip={renderTooltip} /> ); } diff --git a/components/metrics/WebsiteHeader.module.css b/components/metrics/WebsiteHeader.module.css index e5ebcca7..68fd22f8 100644 --- a/components/metrics/WebsiteHeader.module.css +++ b/components/metrics/WebsiteHeader.module.css @@ -1,3 +1,9 @@ +.header { + display: flex; + flex-direction: row; + align-items: center; +} + .title { display: flex; flex-direction: row; diff --git a/components/pages/reports/ReportHeader.js b/components/pages/reports/ReportHeader.js index 90d58ca8..7da47245 100644 --- a/components/pages/reports/ReportHeader.js +++ b/components/pages/reports/ReportHeader.js @@ -16,8 +16,6 @@ export function ReportHeader({ report, icon }) { const { id, websiteId, name, parameters } = report || {}; const { value, startDate, endDate } = parameters?.dateRange || {}; - console.log('REPORT HEADER', report); - const handleSelect = websiteId => { updateReport(id, { websiteId }); }; diff --git a/components/pages/reports/funnel/FunnelChart.js b/components/pages/reports/funnel/FunnelChart.js index 307c78ee..aecd48a7 100644 --- a/components/pages/reports/funnel/FunnelChart.js +++ b/components/pages/reports/funnel/FunnelChart.js @@ -1,184 +1,60 @@ -import Chart from 'chart.js/auto'; -import classNames from 'classnames'; -import { colord } from 'colord'; -import HoverTooltip from 'components/common/HoverTooltip'; -import Legend from 'components/metrics/Legend'; -import useLocale from 'hooks/useLocale'; +import { useCallback, useMemo } from 'react'; +import { Loading } from 'react-basics'; import useMessages from 'hooks/useMessages'; import useTheme from 'hooks/useTheme'; -import { DEFAULT_ANIMATION_DURATION, THEME_COLORS } from 'lib/constants'; +import BarChart from 'components/metrics/BarChart'; import { formatLongNumber } from 'lib/format'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Loading, StatusLight } from 'react-basics'; import styles from './FunnelChart.module.css'; -export function FunnelChart({ - data, - animationDuration = DEFAULT_ANIMATION_DURATION, - stacked = false, - loading = false, - onCreate = () => {}, - onUpdate = () => {}, - className, -}) { +export function FunnelChart({ report, data, loading, className }) { const { formatMessage, labels } = useMessages(); - const canvas = useRef(); - const chart = useRef(null); - const [tooltip, setTooltip] = useState(null); - const { locale } = useLocale(); - const [theme] = useTheme(); + const { colors } = useTheme(); - const datasets = useMemo(() => { - const primaryColor = colord(THEME_COLORS[theme].primary); - return [ - { - label: formatMessage(labels.uniqueVisitors), - data: data, - borderWidth: 1, - hoverBackgroundColor: primaryColor.alpha(0.9).toRgbString(), - backgroundColor: primaryColor.alpha(0.6).toRgbString(), - borderColor: primaryColor.alpha(0.9).toRgbString(), - hoverBorderColor: primaryColor.toRgbString(), - }, - ]; - }, [data]); + const { parameters } = report || {}; - const colors = useMemo( - () => ({ - text: THEME_COLORS[theme].gray700, - line: THEME_COLORS[theme].gray200, - }), - [theme], + const renderXLabel = useCallback( + (label, index) => { + return parameters.urls[index]; + }, + [parameters], ); - const renderYLabel = label => { - return +label > 1000 ? formatLongNumber(label) : label; - }; - - const renderTooltip = useCallback(model => { - const { opacity, labelColors, dataPoints } = model.tooltip; + const renderTooltip = useCallback((setTooltip, model) => { + const { opacity, dataPoints } = model.tooltip; if (!dataPoints?.length || !opacity) { setTooltip(null); return; } - setTooltip( -
-
- -
-
{dataPoints[0].raw.x}
-
{formatLongNumber(dataPoints[0].raw.y)}
-
-
-
-
, - ); + setTooltip(`${formatLongNumber(dataPoints[0].raw.y)} ${formatMessage(labels.visitors)}`); }, []); - const getOptions = useCallback(() => { - return { - responsive: true, - maintainAspectRatio: false, - animation: { - duration: animationDuration, - resize: { - duration: 0, - }, - active: { - duration: 0, - }, + const datasets = useMemo(() => { + return [ + { + label: formatMessage(labels.uniqueVisitors), + data: data, + borderWidth: 1, + ...colors.chart.visitors, }, - plugins: { - legend: { - display: false, - }, - tooltip: { - enabled: false, - external: renderTooltip, - }, - }, - scales: { - x: { - grid: { - display: false, - }, - border: { - color: colors.line, - }, - ticks: { - color: colors.text, - autoSkip: false, - maxRotation: 0, - }, - }, - y: { - type: 'linear', - min: 0, - beginAtZero: true, - stacked, - grid: { - color: colors.line, - }, - border: { - color: colors.line, - }, - ticks: { - color: colors.text, - callback: renderYLabel, - }, - }, - }, - }; - }, [animationDuration, renderTooltip, stacked, colors, locale]); + ]; + }, [data]); - const createChart = () => { - Chart.defaults.font.family = 'Inter'; - - const options = getOptions(); - - chart.current = new Chart(canvas.current, { - type: 'bar', - data: { datasets }, - options, - }); - - onCreate(chart.current); - }; - - const updateChart = () => { - setTooltip(null); - - chart.current.data.datasets[0].data = datasets[0].data; - chart.current.data.datasets[0].label = datasets[0].label; - - chart.current.options = getOptions(); - - onUpdate(chart.current); - - chart.current.update(); - }; - - useEffect(() => { - if (datasets) { - if (!chart.current) { - createChart(); - } else { - updateChart(); - } - } - }, [datasets, theme, animationDuration, locale]); + if (loading) { + return ; + } return ( - <> -
- {loading && } - -
- - {tooltip && } - + ); } diff --git a/components/pages/reports/funnel/FunnelChart.module.css b/components/pages/reports/funnel/FunnelChart.module.css index f071a29e..9e1690b3 100644 --- a/components/pages/reports/funnel/FunnelChart.module.css +++ b/components/pages/reports/funnel/FunnelChart.module.css @@ -1,23 +1,3 @@ -.chart { - position: relative; - height: 400px; - overflow: hidden; -} - -.tooltip { - display: flex; - flex-direction: column; - gap: 10px; -} - -.tooltip .value { - display: flex; - flex-direction: column; - text-transform: lowercase; -} - -@media only screen and (max-width: 992px) { - .chart { - /*height: 200px;*/ - } +.loading { + height: 300px; } diff --git a/components/pages/reports/funnel/FunnelParameters.js b/components/pages/reports/funnel/FunnelParameters.js index d387686e..f43728c7 100644 --- a/components/pages/reports/funnel/FunnelParameters.js +++ b/components/pages/reports/funnel/FunnelParameters.js @@ -1,5 +1,6 @@ import { useMessages } from 'hooks'; import { + Button, Icon, Form, FormButtons, @@ -8,29 +9,38 @@ import { PopupTrigger, Popup, SubmitButton, + Text, TextField, } from 'react-basics'; import Icons from 'components/icons'; import { updateReport } from 'store/reports'; -import { useRef } from 'react'; +import { useRef, useState } from 'react'; import styles from './FunnelParameters.module.css'; export function FunnelParameters({ report }) { const { formatMessage, labels } = useMessages(); const ref = useRef(null); const { id, websiteId, parameters, isLoading } = report || {}; + const queryDisabled = !websiteId || parameters?.urls?.length < 2; const handleSubmit = values => { - console.log({ values }); - updateReport(id, { parameters: values, isLoading: false }); + updateReport(id, { parameters: values, isLoading: false, update: Date.now() }); }; - console.log('PARAMETERS', parameters); + const handleAdd = url => { + updateReport(id, { parameters: { ...parameters, urls: parameters.urls.concat(url) } }); + }; + + const handleRemove = index => { + const urls = [...parameters.urls]; + urls.splice(index, 1); + updateReport(id, { parameters: { ...parameters, urls } }); + }; return ( <>
- + - }> - hi + }> +
+ {parameters?.urls.map((url, index) => { + return ( +
+ {url} + handleRemove(index)}> + + +
+ ); + })} +
- + {formatMessage(labels.query)} @@ -51,14 +72,40 @@ export function FunnelParameters({ report }) { ); } -function AddURLButton() { +function AddURLButton({ onAdd }) { + const [url, setUrl] = useState(''); + const { formatMessage, labels } = useMessages(); + + const handleAdd = close => { + onAdd?.(url); + setUrl(''); + close(); + }; + + const handleChange = e => { + setUrl(e.target.value); + }; + return ( - HALLO + {close => { + return ( + + + + + + + + + ); + }} ); diff --git a/components/pages/reports/funnel/FunnelParameters.module.css b/components/pages/reports/funnel/FunnelParameters.module.css index 0e68e095..d60048a7 100644 --- a/components/pages/reports/funnel/FunnelParameters.module.css +++ b/components/pages/reports/funnel/FunnelParameters.module.css @@ -4,4 +4,22 @@ margin-left: 10px; border: 1px solid var(--base400); border-radius: var(--border-radius); -} \ No newline at end of file + width: 400px; +} + +.urls { + display: flex; + flex-direction: column; + gap: 10px; +} + +.url { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 12px; + border: 1px solid var(--base400); + border-radius: var(--border-radius); + box-shadow: 1px 1px 1px var(--base400); +} diff --git a/components/pages/reports/funnel/FunnelReport.js b/components/pages/reports/funnel/FunnelReport.js index 3c466050..da422d54 100644 --- a/components/pages/reports/funnel/FunnelReport.js +++ b/components/pages/reports/funnel/FunnelReport.js @@ -7,21 +7,35 @@ import ReportMenu from '../ReportMenu'; import ReportBody from '../ReportBody'; import Funnel from 'assets/funnel.svg'; import { useReport } from 'hooks'; +import useApi from 'hooks/useApi'; export default function FunnelReport({ reportId }) { - const report = useReport(reportId); + const report = useReport(reportId, { window: 60, urls: ['/', '/docs'] }); + const { post, useQuery } = useApi(); + const { data, isLoading, error } = useQuery( + ['report:funnel', report?.update], + () => { + const { websiteId, parameters } = report || {}; - console.log('REPORT', { report }); + return post(`/reports/funnel`, { + websiteId: websiteId, + ...parameters, + startAt: +parameters.dateRange.startDate, + endAt: +parameters.dateRange.endDate, + }); + }, + { enabled: !!report?.update }, + ); return ( - + } report={report} /> - - + + ); diff --git a/components/pages/reports/funnel/FunnelTable.js b/components/pages/reports/funnel/FunnelTable.js index 27b4bbfc..7b726e48 100644 --- a/components/pages/reports/funnel/FunnelTable.js +++ b/components/pages/reports/funnel/FunnelTable.js @@ -1,12 +1,17 @@ import DataTable from 'components/metrics/DataTable'; +import { useMessages } from 'hooks'; -export function FunnelTable({ ...props }) { - const { data } = props; +export function FunnelTable({ data }) { + const { formatMessage, labels } = useMessages(); - const tableData = - data?.map(a => ({ x: a.x, y: a.y, z: Math.floor(a.y / data[0].y) * 100 })) || []; - - return ; + return ( + + ); } export default FunnelTable; diff --git a/components/pages/settings/profile/ThemeSetting.js b/components/pages/settings/profile/ThemeSetting.js index f4503268..54a8dac8 100644 --- a/components/pages/settings/profile/ThemeSetting.js +++ b/components/pages/settings/profile/ThemeSetting.js @@ -6,13 +6,13 @@ import Moon from 'assets/moon.svg'; import styles from './ThemeSetting.module.css'; export function ThemeSetting() { - const [theme, setTheme] = useTheme(); + const { theme, saveTheme } = useTheme(); return (