From 18c0e1d57f7c0edaca9a0ddda4aa0c03f881006c Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:22:31 -0700 Subject: [PATCH] overwrite modal --- src/plugins/timezones/cache.ts | 8 +- src/plugins/timezones/components.tsx | 127 ++++++++++++++++++++++++++- src/plugins/timezones/settings.tsx | 2 +- src/plugins/timezones/styles.css | 1 + src/plugins/timezones/utils.ts | 8 +- 5 files changed, 136 insertions(+), 10 deletions(-) diff --git a/src/plugins/timezones/cache.ts b/src/plugins/timezones/cache.ts index 013f564ff..4eb9dc54e 100644 --- a/src/plugins/timezones/cache.ts +++ b/src/plugins/timezones/cache.ts @@ -13,7 +13,7 @@ import { fetchTimezone, fetchTimezonesBulk, Snowflake } from "./api"; import settings, { TimezoneOverwrites } from "./settings"; // TODO: cache invalidation -const TimezoneCache = createStore("UsersTimezoneCache", "TimezoneCache"); +const TimezoneCache = createStore("TimezoneCache", "TimezoneCache"); // A list of callbacks that will trigger on a completed debounced bulk fetch type BulkFetchCallback = (timezone: string | null) => void; @@ -54,10 +54,10 @@ export async function getUserTimezone( immediate: boolean = false, force: boolean = false, ): Promise { - const overwrites = settings.store.timezoneOverwrites ?? {} as TimezoneOverwrites; - const useApi = settings.store.enableApi; + const overwrites: TimezoneOverwrites = settings.store.timezoneOverwrites ?? {}; const overwrite = overwrites[userId]; - if (overwrite || !useApi) return overwrite ?? null; + if (overwrite !== undefined) return overwrite; + if (!settings.store.enableApi) return null; if (!force) { const cachedTimezone = await DataStore.get(userId, TimezoneCache); diff --git a/src/plugins/timezones/components.tsx b/src/plugins/timezones/components.tsx index 0e7146c24..9f3edcfde 100644 --- a/src/plugins/timezones/components.tsx +++ b/src/plugins/timezones/components.tsx @@ -6,13 +6,26 @@ import "./styles.css"; -import { ErrorBoundary } from "@components/index"; +import { ErrorBoundary, Link } from "@components/index"; import { findByPropsLazy } from "@webpack"; -import { React, Tooltip, useEffect, useState } from "@webpack/common"; +import { Button, Forms, React, SearchableSelect, Text, Tooltip, useEffect, useState } from "@webpack/common"; import { Snowflake } from "./api"; import { getUserTimezone } from "./cache"; -import { formatTimestamp } from "./utils"; +import { formatTimestamp, getTimezonesLazy } from "./utils"; +import { + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalProps, + ModalRoot, + openModal, +} from "@utils/modal"; +import { Margins } from "@utils/margins"; +import { SelectOption } from "@webpack/types"; +import settings, { TimezoneOverwrites } from "./settings"; +import { classes } from "@utils/misc"; // Based on Syncxv's vc-timezones user plugin // @@ -82,10 +95,116 @@ function LocalTimestampInner(props: LocalTimestampProps): JSX.Element | null { text={longTime} > {toolTipProps => <> - + { + toolTipProps.onClick(); + openModal(modalProps => + , + ); + }} + > {shortTimeFormatted} } ; } + +interface TimezoneOverrideModalProps { + userId: string, + modalProps: ModalProps, +} + +export function TimezoneOverrideModal(props: TimezoneOverrideModalProps) { + const [availableTimezones, setAvailableTimezones] = useState(); + const [timezone, setTimezone] = useState(); + + useEffect(() => { + getTimezonesLazy().then(timezones => { + const options: SelectOption[] = timezones.map(tz => { + const offset = new Intl.DateTimeFormat(undefined, { timeZone: tz, timeZoneName: "shortOffset" }) + .formatToParts(Date.now()) + .find(part => part.type === "timeZoneName")!.value; + + return { label: `${tz} (${offset})`, value: tz }; + }); + + options.unshift({ + label: "None (Ignore TimezoneDB)", + value: "NONE", // I would use null but SearchableSelect is bugged in that null values get converted into undefined + }); + + options.unshift({ + label: "Auto (Retrieved from TimezoneDB)", + value: undefined, + }); + + setAvailableTimezones(options); + }); + + const overwrites: TimezoneOverwrites = settings.store.timezoneOverwrites ?? {}; + const overwrite = overwrites[props.userId]; + setTimezone(overwrite === null ? "NONE" : overwrite); + }, []); + + function saveOverwrite() { + if (availableTimezones === undefined) return; + + const overwrites: TimezoneOverwrites = settings.store.timezoneOverwrites ?? {}; + if (timezone === undefined) { + delete overwrites[props.userId]; + } else if (timezone === "NONE") { + overwrites[props.userId] = null; + } else { + overwrites[props.userId] = timezone; + } + settings.store.timezoneOverwrites = overwrites; + + props.modalProps.onClose(); + } + + return + + + Set Timezone Override for User + + + + + + + This override will only be visible locally. +
+ To set your own Timezone for other users to see, + click _}>here to + authorize TimezoneDB. +
+ +
+ opt.value === timezone)} + placeholder="Select a Timezone" + maxVisibleItems={7} + closeOnSelect={true} + onChange={setTimezone} + /> +
+
+ + + + + +
; +} diff --git a/src/plugins/timezones/settings.tsx b/src/plugins/timezones/settings.tsx index 68293be67..64f71e44e 100644 --- a/src/plugins/timezones/settings.tsx +++ b/src/plugins/timezones/settings.tsx @@ -23,7 +23,7 @@ import { Text } from "@webpack/common"; import { Snowflake } from "./api"; -export type TimezoneOverwrites = Record; +export type TimezoneOverwrites = Record; const settings = definePluginSettings({ enableApi: { diff --git a/src/plugins/timezones/styles.css b/src/plugins/timezones/styles.css index c6ae082ee..3035c9c11 100644 --- a/src/plugins/timezones/styles.css +++ b/src/plugins/timezones/styles.css @@ -25,6 +25,7 @@ .timezone-message-item { margin-left: 4px; + cursor: pointer; } .vc-timezone-modal-header { diff --git a/src/plugins/timezones/utils.ts b/src/plugins/timezones/utils.ts index 1064e279e..227d045f8 100644 --- a/src/plugins/timezones/utils.ts +++ b/src/plugins/timezones/utils.ts @@ -27,6 +27,7 @@ export function formatTimestamp( day: "numeric", hour: "numeric", minute: "numeric", + timeZoneName: "shortOffset", }; const formatter = new Intl.DateTimeFormat(locale, { @@ -50,7 +51,12 @@ async function getTimezones(): Promise { } } - return await fetch(TIMEZONE_LIST).then(res => res.json()); + try { + return await fetch(TIMEZONE_LIST).then(res => res.json()); + } catch (e) { + new Logger("Timezones").error("Failed to fetch external timezones list", e); + return []; + } } export const getTimezonesLazy = makeLazy(getTimezones, 2);