mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-02-24 15:35:11 +00:00
overwrite modal
This commit is contained in:
parent
f7e07bb797
commit
18c0e1d57f
5 changed files with 136 additions and 10 deletions
|
@ -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<string | null> {
|
||||
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<string | null>(userId, TimezoneCache);
|
||||
|
|
|
@ -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 => <>
|
||||
<span className={classes} {...toolTipProps}>
|
||||
<span {...toolTipProps}
|
||||
className={classes}
|
||||
onClick={() => {
|
||||
toolTipProps.onClick();
|
||||
openModal(modalProps =>
|
||||
<TimezoneOverrideModal
|
||||
userId={props.userId}
|
||||
modalProps={modalProps} />,
|
||||
);
|
||||
}}
|
||||
>
|
||||
{shortTimeFormatted}
|
||||
</span>
|
||||
</>}
|
||||
</Tooltip>
|
||||
</>;
|
||||
}
|
||||
|
||||
interface TimezoneOverrideModalProps {
|
||||
userId: string,
|
||||
modalProps: ModalProps,
|
||||
}
|
||||
|
||||
export function TimezoneOverrideModal(props: TimezoneOverrideModalProps) {
|
||||
const [availableTimezones, setAvailableTimezones] = useState<SelectOption[]>();
|
||||
const [timezone, setTimezone] = useState<string | "NONE" | undefined>();
|
||||
|
||||
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 <ModalRoot {...props.modalProps}>
|
||||
<ModalHeader className="vc-timezone-modal-header">
|
||||
<Forms.FormTitle tag="h2">
|
||||
Set Timezone Override for User
|
||||
</Forms.FormTitle>
|
||||
<ModalCloseButton onClick={props.modalProps.onClose} />
|
||||
</ModalHeader>
|
||||
|
||||
<ModalContent className="vc-timezone-modal-content">
|
||||
<Text variant="text-md/normal">
|
||||
This override will only be visible locally.
|
||||
<br />
|
||||
To set your own Timezone for other users to see,
|
||||
click <Link onClick={/* TODO */ _ => _}>here</Link> to
|
||||
authorize TimezoneDB.
|
||||
</Text>
|
||||
|
||||
<section className={classes(Margins.bottom16, Margins.top16)}>
|
||||
<SearchableSelect
|
||||
options={availableTimezones ?? []}
|
||||
value={availableTimezones?.find(opt => opt.value === timezone)}
|
||||
placeholder="Select a Timezone"
|
||||
maxVisibleItems={7}
|
||||
closeOnSelect={true}
|
||||
onChange={setTimezone}
|
||||
/>
|
||||
</section>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter className="vc-timezone-modal-footer">
|
||||
<Button
|
||||
color={Button.Colors.BRAND}
|
||||
disabled={availableTimezones === undefined}
|
||||
onClick={saveOverwrite}>
|
||||
Save
|
||||
</Button>
|
||||
<Button color={Button.Colors.RED} onClick={props.modalProps.onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import { Text } from "@webpack/common";
|
|||
|
||||
import { Snowflake } from "./api";
|
||||
|
||||
export type TimezoneOverwrites = Record<Snowflake, string>;
|
||||
export type TimezoneOverwrites = Record<Snowflake, string | null>;
|
||||
|
||||
const settings = definePluginSettings({
|
||||
enableApi: {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
.timezone-message-item {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vc-timezone-modal-header {
|
||||
|
|
|
@ -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<string[]> {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue