Skip to content

Commit

Permalink
Merge branch 'master' into issue-electricitymaps#6966-Branch
Browse files Browse the repository at this point in the history
  • Loading branch information
Xeno-Tek authored Oct 9, 2024
2 parents 4d384db + e205b9f commit 4a4b539
Show file tree
Hide file tree
Showing 17 changed files with 116 additions and 49 deletions.
4 changes: 2 additions & 2 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { lazy, ReactElement, Suspense, useEffect, useLayoutEffect } from 'react'
import { Helmet } from 'react-helmet-async';
import { useTranslation } from 'react-i18next';
import trackEvent from 'utils/analytics';
import { metaTitleSuffix } from 'utils/constants';
import { metaTitleSuffix, TrackEvent } from 'utils/constants';

const MapWrapper = lazy(async () => import('features/map/MapWrapper'));
const LeftPanel = lazy(async () => import('features/panels/LeftPanel'));
Expand All @@ -29,7 +29,7 @@ const TimeControllerWrapper = lazy(() => import('features/time/TimeControllerWra
const isProduction = import.meta.env.PROD;

if (isProduction) {
trackEvent('App Loaded', {
trackEvent(TrackEvent.APP_LOADED, {
isNative: Capacitor.isNativePlatform(),
platform: Capacitor.getPlatform(),
});
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/TimeSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useAtom, useAtomValue } from 'jotai';
import { ChevronsLeftRight, Moon, Sun } from 'lucide-react';
import { ReactElement } from 'react';
import trackEvent from 'utils/analytics';
import { TimeAverages } from 'utils/constants';
import { TimeAverages, TrackEvent } from 'utils/constants';
import { useGetZoneFromPath } from 'utils/helpers';
import { isHourlyAtom, timeAverageAtom } from 'utils/state/atoms';

Expand Down Expand Up @@ -74,7 +74,7 @@ export const getThumbIcon = (
};

function trackTimeSliderEvent(selectedIndex: number, timeAverage: TimeAverages) {
trackEvent('Time Slider Button Interaction', {
trackEvent(TrackEvent.TIME_SLIDER_BUTTON, {
selectedIndex: `${timeAverage}: ${selectedIndex}`,
});
}
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/buttons/GithubButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, ButtonProps } from 'components/Button';
import { useTranslation } from 'react-i18next';
import { FaGithub } from 'react-icons/fa6';
import trackEvent from 'utils/analytics';
import { DEFAULT_ICON_SIZE } from 'utils/constants';
import { DEFAULT_ICON_SIZE, TrackEvent } from 'utils/constants';

interface GithubButtonProps
extends Omit<
Expand All @@ -26,7 +26,7 @@ export function GithubButton({
href="https://github.com/electricityMaps/electricitymaps-contrib"
icon={<FaGithub size={iconSize} />}
onClick={() => {
trackEvent('Contribute On GitHub Button Clicked');
trackEvent(TrackEvent.CONTRIBUTE_ON_GITHUB_BUTTON_CLICKED);
}}
{...restProps}
>
Expand Down
77 changes: 57 additions & 20 deletions web/src/features/charts/FuturePrice.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Accordion from 'components/Accordion';
import { HorizontalDivider } from 'components/Divider';
import getSymbolFromCurrency from 'currency-symbol-map';
import { i18n, TFunction } from 'i18next';
import { useAtom } from 'jotai';
import { ChevronsDownUpIcon, ChevronsUpDownIcon, Clock3, Info } from 'lucide-react';
Expand Down Expand Up @@ -46,7 +45,7 @@ export function FuturePrice({ futurePrice }: { futurePrice: FuturePriceData | nu
[filteredPriceData, granularity]
);

if (!futurePrice) {
if (!futurePrice || !isFuturePrice(futurePrice)) {
return null;
}

Expand Down Expand Up @@ -74,16 +73,27 @@ export function FuturePrice({ futurePrice }: { futurePrice: FuturePriceData | nu
<ul>
{Object.entries(filteredPriceData).map(
([date, price]: [string, number]) => (
<li key={date}>
<li
key={date}
className={
isNow(date, granularity)
? `rounded-md bg-price-light/10 dark:bg-price-dark/10`
: ''
}
>
{dateIsFirstHourOfTomorrow(new Date(date)) && (
<div className="flex flex-col py-1" data-test-id="tomorrow-label">
<HorizontalDivider />
<TommorowLabel date={date} t={t} i18n={i18n} />
</div>
)}
<div className="flex flex-row justify-items-end gap-2">
<div className="flex flex-row justify-items-end gap-2 px-1">
<TimeDisplay date={date} granularity={granularity} />
<PriceDisplay price={price} currency={futurePrice.currency} />
<PriceDisplay
price={price}
currency={futurePrice.currency}
i18n={i18n}
/>
<div className="flex h-full w-full flex-row self-center">
{hasNegativePrice && (
<div
Expand Down Expand Up @@ -141,10 +151,6 @@ export function FuturePrice({ futurePrice }: { futurePrice: FuturePriceData | nu
);
}

const isNow = (date: string, granularity: number): boolean =>
normalizeToGranularity(new Date(date), granularity).getTime() ==
normalizeToGranularity(new Date(), granularity).getTime();

function TommorowLabel({ date, t, i18n }: { date: string; t: TFunction; i18n: i18n }) {
const formattedDate = Intl.DateTimeFormat(i18n.language, {
dateStyle: 'medium',
Expand Down Expand Up @@ -175,10 +181,28 @@ export function PriceBar({
);
}

function PriceDisplay({ price, currency }: { price: number; currency: string }) {
function PriceDisplay({
price,
currency,
i18n,
}: {
price: number;
currency: string;
i18n: i18n;
}) {
const priceString = Intl.NumberFormat(i18n.languages[0], {
style: 'currency',
currency: currency,
maximumSignificantDigits: 4,
currencyDisplay: 'narrowSymbol',
}).format(price);
return (
<p className="min-w-[66px] text-nowrap text-sm font-semibold tabular-nums">
{`${price} ${getSymbolFromCurrency(currency)}`}
<p
className={`min-w-[66px] overflow-clip text-nowrap text-sm font-semibold tabular-nums ${
Number.isNaN(Number(priceString.at(-1))) ? 'text-end' : 'text-start'
}`}
>
{priceString}
</p>
);
}
Expand All @@ -190,7 +214,7 @@ function TimeDisplay({ date, granularity }: { date: string; granularity: number

if (isNow(date, granularity)) {
return (
<p className="min-w-[82px] text-sm" data-test-id="now-label">
<p className="min-w-[82px] text-sm font-semibold" data-test-id="now-label">
{t(`country-panel.price-chart.now`)}
</p>
);
Expand Down Expand Up @@ -263,16 +287,29 @@ const getColor = (
date: string,
granularity: number
): string => {
if (price === maxPrice) {
return 'bg-danger dark:bg-red-400';
} else if (price === minPrice) {
return 'bg-success dark:bg-emerald-500';
} else if (
if (
normalizeToGranularity(new Date(date), granularity) <
normalizeToGranularity(new Date(), granularity)
) {
return 'bg-[#18214F] dark:bg-[#848EC0] opacity-50';
return 'bg-price-light dark:bg-price-dark opacity-50';
} else if (price === maxPrice) {
return 'bg-danger dark:bg-red-400';
} else if (price === minPrice) {
return 'bg-success dark:bg-emerald-500';
} else {
return 'bg-[#18214F] dark:bg-[#848EC0]';
return 'bg-price-light dark:bg-price-dark';
}
};

const isNow = (date: string, granularity: number): boolean =>
normalizeToGranularity(new Date(date), granularity).getTime() ===
normalizeToGranularity(new Date(), granularity).getTime();

const isFuturePrice = (FuturePriceData: FuturePriceData): boolean => {
const keys = Object.keys(FuturePriceData.priceData);
const lastKey = keys.at(-1);
if (!lastKey) {
return false;
}
return new Date(lastKey) > new Date();
};
5 changes: 3 additions & 2 deletions web/src/features/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ExternalLink } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { twMerge } from 'tailwind-merge';
import trackEvent from 'utils/analytics';
import { TrackEvent } from 'utils/constants';

import Logo from './Logo';

Expand All @@ -27,7 +28,7 @@ function MenuLink({
onClick,
}: MenuLinkProps): JSX.Element {
const handleClick = () => {
trackEvent('HeaderLink Clicked', { linkId: id });
trackEvent(TrackEvent.HEADER_LINK_CLICKED, { linkId: id });
onClick?.();
};
return (
Expand Down Expand Up @@ -105,7 +106,7 @@ export default function Header(): JSX.Element {
</MenuLink>
<Button
onClick={() => {
trackEvent('HeaderLink Clicked', { linkId: 'get-data' });
trackEvent(TrackEvent.HEADER_LINK_CLICKED, { linkId: 'get-data' });
}}
backgroundClasses="my-2.5"
foregroundClasses="text-base font-normal lg:text-[1rem] py-1 px-6"
Expand Down
6 changes: 4 additions & 2 deletions web/src/features/map-controls/ConsumptionProductionToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ToggleButton from 'components/ToggleButton';
import { useAtom } from 'jotai';
import type { ReactElement } from 'react';
import trackEvent from 'utils/analytics';
import { Mode } from 'utils/constants';
import { Mode, TrackEvent } from 'utils/constants';
import { productionConsumptionAtom } from 'utils/state/atoms';

export default function ConsumptionProductionToggle(): ReactElement {
Expand All @@ -23,7 +23,9 @@ export default function ConsumptionProductionToggle(): ReactElement {
if (option === currentMode) {
return;
}
trackEvent('Production Consumption Clicked', { productionConsumption: option });
trackEvent(TrackEvent.PRODUCTION_CONSUMPTION_CLICKED, {
productionConsumption: option,
});
setCurrentMode(currentMode === Mode.PRODUCTION ? Mode.CONSUMPTION : Mode.PRODUCTION);
};

Expand Down
3 changes: 2 additions & 1 deletion web/src/features/map-controls/LanguageSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { languageNames } from 'translation/locales';
import trackEvent from 'utils/analytics';
import { TrackEvent } from 'utils/constants';

import MapButton from './MapButton';
import MapOptionSelector from './MapOptionSelector';
Expand All @@ -21,7 +22,7 @@ export function LanguageSelector({ isMobile }: { isMobile?: boolean }) {
const handleLanguageSelect = (languageKey: LanguageNamesKey) => {
i18n.changeLanguage(languageKey);
setSelectedLanguage(languageNames[languageKey]);
trackEvent('Language Selected', { language: languageNames[languageKey] });
trackEvent(TrackEvent.LANGUAGE_SELECTED, { language: languageNames[languageKey] });
};
return (
<MapOptionSelector
Expand Down
12 changes: 8 additions & 4 deletions web/src/features/map-controls/MapControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTransition } from 'react';
import { useTranslation } from 'react-i18next';
import { MoonLoader } from 'react-spinners';
import trackEvent from 'utils/analytics';
import { ThemeOptions, ToggleOptions } from 'utils/constants';
import { ThemeOptions, ToggleOptions, TrackEvent } from 'utils/constants';
import {
areWeatherLayersAllowedAtom,
colorblindModeAtom,
Expand Down Expand Up @@ -64,10 +64,14 @@ function WeatherButton({ type }: { type: 'wind' | 'solar' }) {

const onToggle = () => {
if (isEnabled) {
trackEvent(`${weatherId} Disabled`);
trackEvent(
weatherId == 'Wind' ? TrackEvent.WIND_DISABLED : TrackEvent.SOLAR_DISABLED
);
} else {
setIsLoadingLayer(true);
trackEvent(`${weatherId} Enabled`);
trackEvent(
weatherId == 'Wind' ? TrackEvent.WIND_ENABLED : TrackEvent.SOLAR_ENABLED
);
}

startTransition(() => {
Expand Down Expand Up @@ -105,7 +109,7 @@ function DesktopMapControls() {

const handleColorblindModeToggle = () => {
setIsColorblindModeEnabled(!isColorblindModeEnabled);
trackEvent('Colorblind Mode Toggled');
trackEvent(TrackEvent.COLORBLIND_MODE_TOGGLED);
};

return (
Expand Down
4 changes: 2 additions & 2 deletions web/src/features/map-controls/SpatialAggregatesToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ToggleButton from 'components/ToggleButton';
import { useAtom } from 'jotai';
import type { ReactElement } from 'react';
import trackEvent from 'utils/analytics';
import { SpatialAggregate } from 'utils/constants';
import { SpatialAggregate, TrackEvent } from 'utils/constants';
import { spatialAggregateAtom } from 'utils/state/atoms';

export default function SpatialAggregatesToggle(): ReactElement {
Expand All @@ -26,7 +26,7 @@ export default function SpatialAggregatesToggle(): ReactElement {
) {
return;
}
trackEvent('Spatial Aggregate Clicked', { spatialAggregate: option });
trackEvent(TrackEvent.SPATIAL_AGGREGATE_CLICKED, { spatialAggregate: option });
setCurrentMode(
currentMode === SpatialAggregate.COUNTRY
? SpatialAggregate.ZONE
Expand Down
4 changes: 2 additions & 2 deletions web/src/features/map-controls/ThemeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useAtom } from 'jotai';
import { LaptopMinimal, Moon, Palette, Smartphone, Sun } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import trackEvent from 'utils/analytics';
import { ThemeOptions } from 'utils/constants';
import { ThemeOptions, TrackEvent } from 'utils/constants';
import { themeAtom } from 'utils/state/atoms';

import MapButton from './MapButton';
Expand All @@ -17,7 +17,7 @@ export default function ThemeSelector({ isMobile }: { isMobile?: boolean }) {

const handleThemeChange = (mode: ThemeOptions) => {
setSelectedTheme(mode);
trackEvent('Theme Selected', { theme: mode });
trackEvent(TrackEvent.THEME_SELECTED, { theme: mode });
};

const ICONS = {
Expand Down
6 changes: 3 additions & 3 deletions web/src/features/panels/zone/DisplayByEmissionToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ToggleButton from 'components/ToggleButton';
import { useAtom, useAtomValue } from 'jotai';
import type { ReactElement } from 'react';
import trackEvent from 'utils/analytics';
import { LeftPanelToggleOptions } from 'utils/constants';
import { LeftPanelToggleOptions, TrackEvent } from 'utils/constants';
import { displayByEmissionsAtom, isConsumptionAtom } from 'utils/state/atoms';

export default function EmissionToggle(): ReactElement {
Expand All @@ -25,9 +25,9 @@ export default function EmissionToggle(): ReactElement {

const onSetCurrentMode = (option: string) => {
if (displayByEmissions) {
trackEvent('PanelProductionButton Clicked');
trackEvent(TrackEvent.PANEL_PRODUCTION_BUTTON_CLICKED);
} else {
trackEvent('PanelEmissionButton Clicked');
trackEvent(TrackEvent.PANEL_EMISSION_BUTTON_CLICKED);
}
if (
(option === LeftPanelToggleOptions.ELECTRICITY && displayByEmissions) ||
Expand Down
6 changes: 3 additions & 3 deletions web/src/features/panels/zone/EstimationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useTranslation } from 'react-i18next';
import { FaGithub } from 'react-icons/fa6';
import { ZoneMessage } from 'types';
import trackEvent from 'utils/analytics';
import { EstimationMethods } from 'utils/constants';
import { EstimationMethods, TrackEvent } from 'utils/constants';
import {
feedbackCardCollapsedNumberAtom,
hasEstimationFeedbackBeenSeenAtom,
Expand Down Expand Up @@ -136,7 +136,7 @@ function BaseCard({

const trackToggle = () => {
if (isCollapsed) {
trackEvent('EstimationCard Expanded', { cardType: cardType });
trackEvent(TrackEvent.ESTIMATION_CARD_EXPANDED, { cardType: cardType });
}
setFeedbackCardCollapsedNumber(feedbackCardCollapsedNumber + 1);
};
Expand Down Expand Up @@ -194,7 +194,7 @@ function BaseCard({
data-test-id="methodology-link"
className={`text-sm font-semibold text-black underline dark:text-white`}
onClick={() => {
trackEvent('EstimationCard Methodology Link Clicked', {
trackEvent(TrackEvent.ESTIMATION_CARD_METHODOLOGY_LINK_CLICKED, {
cardType: cardType,
});
}}
Expand Down
3 changes: 2 additions & 1 deletion web/src/features/panels/zone/MethodologyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { t } from 'i18next';
import { EmapsIcon } from 'icons/emapsIcon';
import { useState } from 'react';
import trackEvent from 'utils/analytics';
import { TrackEvent } from 'utils/constants';

export default function MethodologyCard() {
const [isCollapsed, setIsCollapsed] = useState(true);
Expand All @@ -14,7 +15,7 @@ export default function MethodologyCard() {
icon={<EmapsIcon styling="dark:text-white" />}
title={t('left-panel.applied-methodologies.title')}
className="text-md pt-2"
onOpen={() => trackEvent('AppliedMethodologies Expanded')}
onOpen={() => trackEvent(TrackEvent.APPLIED_METHODOLOGIES_EXPANDED)}
isCollapsed={isCollapsed}
setState={setIsCollapsed}
>
Expand Down
Loading

0 comments on commit 4a4b539

Please sign in to comment.