From 291562f6c257c5240d977e30beec1ffd562a3b9f Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 29 Mar 2024 16:04:39 -0700 Subject: [PATCH] Updated timezone hook, fixed chart rendering, added icons. --- .../profile/DateRangeSetting.module.css | 3 + src/app/(main)/profile/DateRangeSetting.tsx | 4 +- .../(main)/profile/TimezoneSetting.module.css | 4 ++ src/app/(main)/profile/TimezoneSetting.tsx | 13 +++-- src/components/common/Favicon.tsx | 3 +- src/components/hooks/queries/useReport.ts | 2 +- .../hooks/queries/useWebsitePageviews.ts | 2 +- src/components/hooks/useTheme.ts | 58 ++++++++++--------- src/components/hooks/useTimezone.ts | 22 ++++--- src/components/metrics/EventsChart.tsx | 2 +- src/components/metrics/ReferrersTable.tsx | 17 ++++-- src/pages/api/send.ts | 20 ++++--- src/store/app.ts | 7 +++ src/tracker/index.js | 2 + 14 files changed, 94 insertions(+), 65 deletions(-) create mode 100644 src/app/(main)/profile/DateRangeSetting.module.css diff --git a/src/app/(main)/profile/DateRangeSetting.module.css b/src/app/(main)/profile/DateRangeSetting.module.css new file mode 100644 index 00000000..9de13efe --- /dev/null +++ b/src/app/(main)/profile/DateRangeSetting.module.css @@ -0,0 +1,3 @@ +.field { + width: 200px; +} diff --git a/src/app/(main)/profile/DateRangeSetting.tsx b/src/app/(main)/profile/DateRangeSetting.tsx index a1ae7bc7..c57a209a 100644 --- a/src/app/(main)/profile/DateRangeSetting.tsx +++ b/src/app/(main)/profile/DateRangeSetting.tsx @@ -3,6 +3,7 @@ import { Button, Flexbox } from 'react-basics'; import { useDateRange, useMessages } from 'components/hooks'; import { DEFAULT_DATE_RANGE } from 'lib/constants'; import { DateRange } from 'lib/types'; +import styles from './DateRangeSetting.module.css'; export function DateRangeSetting() { const { formatMessage, labels } = useMessages(); @@ -13,8 +14,9 @@ export function DateRangeSetting() { const handleReset = () => setDateRange(DEFAULT_DATE_RANGE); return ( - + n.toLowerCase().includes(search.toLowerCase())) - : listTimeZones(); + ? timezones.filter(n => n.toLowerCase().includes(search.toLowerCase())) + : timezones; const handleReset = () => saveTimezone(getTimezone()); return ( saveTimezone(value)} menuProps={{ className: styles.menu }} allowSearch={true} onSearch={setSearch} diff --git a/src/components/common/Favicon.tsx b/src/components/common/Favicon.tsx index 2793c0d0..cdaeaf4b 100644 --- a/src/components/common/Favicon.tsx +++ b/src/components/common/Favicon.tsx @@ -16,7 +16,8 @@ export function Favicon({ domain, ...props }) { diff --git a/src/components/hooks/queries/useReport.ts b/src/components/hooks/queries/useReport.ts index ef571d00..4dade4db 100644 --- a/src/components/hooks/queries/useReport.ts +++ b/src/components/hooks/queries/useReport.ts @@ -8,7 +8,7 @@ export function useReport(reportId: string, defaultParameters: { [key: string]: const [report, setReport] = useState(null); const [isRunning, setIsRunning] = useState(false); const { get, post } = useApi(); - const [timezone] = useTimezone(); + const { timezone } = useTimezone(); const { formatMessage, labels } = useMessages(); const baseParameters = { diff --git a/src/components/hooks/queries/useWebsitePageviews.ts b/src/components/hooks/queries/useWebsitePageviews.ts index 91db3717..960c9584 100644 --- a/src/components/hooks/queries/useWebsitePageviews.ts +++ b/src/components/hooks/queries/useWebsitePageviews.ts @@ -4,7 +4,7 @@ export function useWebsitePageviews(websiteId: string, options?: { [key: string] const { get, useQuery } = useApi(); const [dateRange] = useDateRange(websiteId); const { startDate, endDate, unit } = dateRange; - const [timezone] = useTimezone(); + const { timezone } = useTimezone(); const { query: { url, referrer, os, browser, device, country, region, city, title }, } = useNavigation(); diff --git a/src/components/hooks/useTheme.ts b/src/components/hooks/useTheme.ts index f2a2d448..aa2b1d38 100644 --- a/src/components/hooks/useTheme.ts +++ b/src/components/hooks/useTheme.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import useStore, { setTheme } from 'store/app'; import { getItem, setItem } from 'next-basics'; import { DEFAULT_THEME, THEME_COLORS, THEME_CONFIG } from 'lib/constants'; @@ -10,38 +10,40 @@ export function useTheme() { const theme = useStore(selector) || getItem(THEME_CONFIG) || DEFAULT_THEME; const primaryColor = colord(THEME_COLORS[theme].primary); - const colors = { - theme: { - ...THEME_COLORS[theme], - }, - chart: { - text: THEME_COLORS[theme].gray700, - line: THEME_COLORS[theme].gray200, - views: { - hoverBackgroundColor: primaryColor.alpha(0.7).toRgbString(), - backgroundColor: primaryColor.alpha(0.4).toRgbString(), - borderColor: primaryColor.alpha(0.7).toRgbString(), - hoverBorderColor: primaryColor.toRgbString(), + const colors = useMemo(() => { + return { + theme: { + ...THEME_COLORS[theme], }, - visitors: { - hoverBackgroundColor: primaryColor.alpha(0.9).toRgbString(), - backgroundColor: primaryColor.alpha(0.6).toRgbString(), - borderColor: primaryColor.alpha(0.9).toRgbString(), - hoverBorderColor: primaryColor.toRgbString(), + chart: { + text: THEME_COLORS[theme].gray700, + line: THEME_COLORS[theme].gray200, + 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(), + }, }, - }, - map: { - baseColor: THEME_COLORS[theme].primary, - fillColor: THEME_COLORS[theme].gray100, - strokeColor: THEME_COLORS[theme].primary, - hoverColor: THEME_COLORS[theme].primary, - }, - }; + map: { + baseColor: THEME_COLORS[theme].primary, + fillColor: THEME_COLORS[theme].gray100, + strokeColor: THEME_COLORS[theme].primary, + hoverColor: THEME_COLORS[theme].primary, + }, + }; + }, [theme]); - function saveTheme(value) { + const saveTheme = (value: string) => { setItem(THEME_CONFIG, value); setTheme(value); - } + }; useEffect(() => { document.body.setAttribute('data-theme', theme); diff --git a/src/components/hooks/useTimezone.ts b/src/components/hooks/useTimezone.ts index 3dbb52b3..8bd76504 100644 --- a/src/components/hooks/useTimezone.ts +++ b/src/components/hooks/useTimezone.ts @@ -1,20 +1,18 @@ -import { useState, useCallback } from 'react'; -import { getTimezone } from 'lib/date'; -import { getItem, setItem } from 'next-basics'; +import { setItem } from 'next-basics'; import { TIMEZONE_CONFIG } from 'lib/constants'; +import useStore, { setTimezone } from 'store/app'; + +const selector = (state: { timezone: string }) => state.timezone; export function useTimezone() { - const [timezone, setTimezone] = useState(getItem(TIMEZONE_CONFIG) || getTimezone()); + const timezone = useStore(selector); - const saveTimezone = useCallback( - (value: string) => { - setItem(TIMEZONE_CONFIG, value); - setTimezone(value); - }, - [setTimezone], - ); + const saveTimezone = (value: string) => { + setItem(TIMEZONE_CONFIG, value); + setTimezone(value); + }; - return [timezone, saveTimezone]; + return { timezone, saveTimezone }; } export default useTimezone; diff --git a/src/components/metrics/EventsChart.tsx b/src/components/metrics/EventsChart.tsx index 87e65276..9e98b6ce 100644 --- a/src/components/metrics/EventsChart.tsx +++ b/src/components/metrics/EventsChart.tsx @@ -22,7 +22,7 @@ export interface EventsChartProps { export function EventsChart({ websiteId, className, token }: EventsChartProps) { const [{ startDate, endDate, unit, offset }] = useDateRange(websiteId); const { locale } = useLocale(); - const [timezone] = useTimezone(); + const { timezone } = useTimezone(); const { query: { url, event }, } = useNavigation(); diff --git a/src/components/metrics/ReferrersTable.tsx b/src/components/metrics/ReferrersTable.tsx index 0f5f5f58..7dceedd8 100644 --- a/src/components/metrics/ReferrersTable.tsx +++ b/src/components/metrics/ReferrersTable.tsx @@ -1,18 +1,23 @@ import MetricsTable, { MetricsTableProps } from './MetricsTable'; import FilterLink from 'components/common/FilterLink'; +import Favicon from 'components/common/Favicon'; import { useMessages } from 'components/hooks'; +import { Flexbox } from 'react-basics'; export function ReferrersTable(props: MetricsTableProps) { const { formatMessage, labels } = useMessages(); const renderLink = ({ x: referrer }) => { return ( - + + + + ); }; diff --git a/src/pages/api/send.ts b/src/pages/api/send.ts index bf6fc213..b078a904 100644 --- a/src/pages/api/send.ts +++ b/src/pages/api/send.ts @@ -20,16 +20,17 @@ import * as yup from 'yup'; export interface CollectRequestBody { payload: { - data: { [key: string]: any }; - hostname: string; - ip: string; - language: string; - referrer: string; - screen: string; - title: string; - url: string; website: string; - name: string; + data?: { [key: string]: any }; + hostname?: string; + ip?: string; + language?: string; + name?: string; + referrer?: string; + screen?: string; + tag?: string; + title?: string; + url: string; }; type: CollectionType; } @@ -72,6 +73,7 @@ const schema = { url: yup.string(), website: yup.string().uuid().required(), name: yup.string().max(50), + tag: yup.string().max(50), }) .required(), type: yup diff --git a/src/store/app.ts b/src/store/app.ts index f71a245b..4d547d4e 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -6,8 +6,10 @@ import { DEFAULT_THEME, LOCALE_CONFIG, THEME_CONFIG, + TIMEZONE_CONFIG, } from 'lib/constants'; import { getItem } from 'next-basics'; +import { getTimezone } from 'lib/date'; function getDefaultTheme() { return typeof window !== 'undefined' @@ -20,6 +22,7 @@ function getDefaultTheme() { const initialState = { locale: getItem(LOCALE_CONFIG) || DEFAULT_LOCALE, theme: getItem(THEME_CONFIG) || getDefaultTheme() || DEFAULT_THEME, + timezone: getItem(TIMEZONE_CONFIG) || getTimezone(), dateRange: getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE, shareToken: null, user: null, @@ -32,6 +35,10 @@ export function setTheme(theme: string) { store.setState({ theme }); } +export function setTimezone(timezone: string) { + store.setState({ timezone }); +} + export function setLocale(locale: string) { store.setState({ locale }); } diff --git a/src/tracker/index.js b/src/tracker/index.js index 1c2fcc20..36110537 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -18,6 +18,7 @@ const attr = currentScript.getAttribute.bind(currentScript); const website = attr(_data + 'website-id'); const hostUrl = attr(_data + 'host-url'); + const tag = attr(_data + 'tag'); const autoTrack = attr(_data + 'auto-track') !== _false; const excludeSearch = attr(_data + 'exclude-search') === _true; const domain = attr(_data + 'domains') || ''; @@ -216,6 +217,7 @@ ...getPayload(), name: obj, data: typeof data === 'object' ? data : undefined, + tag, }); } else if (typeof obj === 'object') { return send(obj);