mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-07 05:42:55 -04:00
* move to a list on load instead of each reqest, move refresh and set database to toolbox * add option to hide your own timezone from showing * fix auth cancel, add fist run toast, fix label, add default to sys timezone when showing if nothing at all is set * Update index.tsx
This commit is contained in:
parent
aa63557c11
commit
64a429cfbd
3 changed files with 110 additions and 96 deletions
|
@ -24,19 +24,17 @@ export function SetTimezoneModal({ userId, modalProps, database }: { userId: str
|
||||||
const [currentValue, setCurrentValue] = useState<string | null>(timezones[userId] ?? null);
|
const [currentValue, setCurrentValue] = useState<string | null>(timezones[userId] ?? null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!database) return;
|
|
||||||
|
|
||||||
const localTimezone = timezones[userId];
|
const localTimezone = timezones[userId];
|
||||||
const shouldUseDatabase =
|
const shouldUseDatabase =
|
||||||
settings.store.useDatabase &&
|
settings.store.useDatabase &&
|
||||||
(settings.store.preferDatabaseOverLocal || !localTimezone);
|
(settings.store.preferDatabaseOverLocal || !localTimezone);
|
||||||
|
|
||||||
if (shouldUseDatabase) {
|
const value = shouldUseDatabase
|
||||||
getTimezone(userId).then(e => setCurrentValue(e ?? localTimezone));
|
? getTimezone(userId) ?? localTimezone
|
||||||
} else {
|
: localTimezone;
|
||||||
setCurrentValue(localTimezone);
|
|
||||||
}
|
setCurrentValue(value ?? Intl.DateTimeFormat().resolvedOptions().timeZone);
|
||||||
}, [userId, settings.store.useDatabase, settings.store.preferDatabaseOverLocal, database]);
|
}, [userId, settings.store.useDatabase, settings.store.preferDatabaseOverLocal]);
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return Intl.supportedValuesOf("timeZone").map(timezone => {
|
return Intl.supportedValuesOf("timeZone").map(timezone => {
|
||||||
|
|
|
@ -4,55 +4,45 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DataStore } from "@api/index";
|
import { openModal } from "@utils/index";
|
||||||
import { openModal } from "@utils/modal";
|
|
||||||
import { OAuth2AuthorizeModal, showToast, Toasts } from "@webpack/common";
|
import { OAuth2AuthorizeModal, showToast, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
import { databaseTimezones } from ".";
|
const databaseTimezones: Record<string, { value: string | null; }> = {};
|
||||||
|
|
||||||
export const DOMAIN = "https://timezone.creations.works";
|
const DOMAIN = "https://timezone.creations.works";
|
||||||
export const REDIRECT_URI = `${DOMAIN}/auth/discord/callback`;
|
const REDIRECT_URI = `${DOMAIN}/auth/discord/callback`;
|
||||||
export const CLIENT_ID = "1377021506810417173";
|
const CLIENT_ID = "1377021506810417173";
|
||||||
|
|
||||||
export const DATASTORE_KEY = "vencord-database-timezones";
|
|
||||||
|
|
||||||
const pendingRequests: Record<string, Promise<string | null>> = {};
|
|
||||||
|
|
||||||
export async function setUserDatabaseTimezone(userId: string, timezone: string | null) {
|
export async function setUserDatabaseTimezone(userId: string, timezone: string | null) {
|
||||||
databaseTimezones[userId] = {
|
databaseTimezones[userId] = { value: timezone };
|
||||||
value: timezone,
|
|
||||||
expires: Date.now() + 60 * 60 * 1000 // 1 hour
|
|
||||||
};
|
|
||||||
await DataStore.set(DATASTORE_KEY, databaseTimezones);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTimezone(userId: string, force?: boolean): Promise<string | null> {
|
export function getTimezone(userId: string): string | null {
|
||||||
const now = Date.now();
|
return databaseTimezones[userId]?.value ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
const cached = databaseTimezones[userId];
|
export async function loadDatabaseTimezones(): Promise<boolean> {
|
||||||
if (cached && now < cached.expires && !force) return cached.value;
|
try {
|
||||||
|
const res = await fetch(`${DOMAIN}/list`, {
|
||||||
|
headers: { Accept: "application/json" }
|
||||||
|
});
|
||||||
|
|
||||||
if (!pendingRequests[userId]) {
|
if (res.ok) {
|
||||||
pendingRequests[userId] = (async () => {
|
const json = await res.json();
|
||||||
const res = await fetch(`${DOMAIN}/get?id=${userId}`, {
|
for (const id in json) {
|
||||||
headers: { Accept: "application/json" }
|
databaseTimezones[id] = {
|
||||||
});
|
value: json[id]?.timezone ?? null
|
||||||
|
};
|
||||||
let value: string | null = null;
|
|
||||||
if (res.ok) {
|
|
||||||
const json = await res.json();
|
|
||||||
if (json?.timezone && typeof json.timezone === "string") {
|
|
||||||
value = json.timezone;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserDatabaseTimezone(userId, value);
|
return true;
|
||||||
delete pendingRequests[userId];
|
}
|
||||||
return value;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
return pendingRequests[userId];
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to fetch timezones list:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setTimezone(timezone: string): Promise<boolean> {
|
export async function setTimezone(timezone: string): Promise<boolean> {
|
||||||
|
@ -92,6 +82,8 @@ export function authModal(callback?: () => void) {
|
||||||
permissions={0n}
|
permissions={0n}
|
||||||
cancelCompletesFlow={false}
|
cancelCompletesFlow={false}
|
||||||
callback={async (res: any) => {
|
callback={async (res: any) => {
|
||||||
|
if (!res || !res.location) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = new URL(res.location);
|
const url = new URL(res.location);
|
||||||
|
|
||||||
|
@ -109,10 +101,10 @@ export function authModal(callback?: () => void) {
|
||||||
showToast("Authorization successful!", Toasts.Type.SUCCESS);
|
showToast("Authorization successful!", Toasts.Type.SUCCESS);
|
||||||
callback?.();
|
callback?.();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error("Error during authorization:", e);
|
||||||
showToast("Unexpected error during authorization", Toasts.Type.FAILURE);
|
showToast("Unexpected error during authorization", Toasts.Type.FAILURE);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a Discord client mod
|
* Vencord, a Discord client mod
|
||||||
* Copyright (c) 2024 Vendicated and contributors
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -17,15 +17,9 @@ import { findByPropsLazy } from "@webpack";
|
||||||
import { Button, Menu, showToast, Toasts, Tooltip, useEffect, UserStore, useState } from "@webpack/common";
|
import { Button, Menu, showToast, Toasts, Tooltip, useEffect, UserStore, useState } from "@webpack/common";
|
||||||
import { Message, User } from "discord-types/general";
|
import { Message, User } from "discord-types/general";
|
||||||
|
|
||||||
import { authModal, deleteTimezone, getTimezone, setUserDatabaseTimezone } from "./database";
|
import { authModal, deleteTimezone, getTimezone, loadDatabaseTimezones, setUserDatabaseTimezone } from "./database";
|
||||||
import { SetTimezoneModal } from "./TimezoneModal";
|
import { SetTimezoneModal } from "./TimezoneModal";
|
||||||
|
|
||||||
type CacheEntry = {
|
|
||||||
value: string | null;
|
|
||||||
expires: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export let databaseTimezones: Record<string, CacheEntry> = {};
|
|
||||||
export let timezones: Record<string, string | null> = {};
|
export let timezones: Record<string, string | null> = {};
|
||||||
export const DATASTORE_KEY = "vencord-timezones";
|
export const DATASTORE_KEY = "vencord-timezones";
|
||||||
|
|
||||||
|
@ -33,6 +27,12 @@ const classes = findByPropsLazy("timestamp", "compact", "contentOnly");
|
||||||
const locale = findByPropsLazy("getLocale");
|
const locale = findByPropsLazy("getLocale");
|
||||||
|
|
||||||
export const settings = definePluginSettings({
|
export const settings = definePluginSettings({
|
||||||
|
"Show Own Timezone": {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Show your own timezone in profiles and message headers",
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
|
||||||
"24h Time": {
|
"24h Time": {
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
description: "Show time in 24h format",
|
description: "Show time in 24h format",
|
||||||
|
@ -70,8 +70,7 @@ export const settings = definePluginSettings({
|
||||||
<Button onClick={() => {
|
<Button onClick={() => {
|
||||||
authModal(async () => {
|
authModal(async () => {
|
||||||
openModal(modalProps => <SetTimezoneModal userId={UserStore.getCurrentUser().id} modalProps={modalProps} database={true} />);
|
openModal(modalProps => <SetTimezoneModal userId={UserStore.getCurrentUser().id} modalProps={modalProps} database={true} />);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}}>
|
}}>
|
||||||
Set Timezone on Database
|
Set Timezone on Database
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -94,6 +93,13 @@ export const settings = definePluginSettings({
|
||||||
Reset Database Timezones
|
Reset Database Timezones
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
askedTimezone: {
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
description: "Whether the user has been asked to set their timezone",
|
||||||
|
hidden: true,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,6 +118,7 @@ interface Props {
|
||||||
timestamp?: string;
|
timestamp?: string;
|
||||||
type: "message" | "profile";
|
type: "message" | "profile";
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimestampComponent = ErrorBoundary.wrap(({ userId, timestamp, type }: Props) => {
|
const TimestampComponent = ErrorBoundary.wrap(({ userId, timestamp, type }: Props) => {
|
||||||
const [currentTime, setCurrentTime] = useState(timestamp || Date.now());
|
const [currentTime, setCurrentTime] = useState(timestamp || Date.now());
|
||||||
const [timezone, setTimezone] = useState<string | null>(null);
|
const [timezone, setTimezone] = useState<string | null>(null);
|
||||||
|
@ -123,7 +130,7 @@ const TimestampComponent = ErrorBoundary.wrap(({ userId, timestamp, type }: Prop
|
||||||
(settings.store.preferDatabaseOverLocal || !localTimezone);
|
(settings.store.preferDatabaseOverLocal || !localTimezone);
|
||||||
|
|
||||||
if (shouldUseDatabase) {
|
if (shouldUseDatabase) {
|
||||||
getTimezone(userId).then(e => setTimezone(e ?? localTimezone));
|
setTimezone(getTimezone(userId) ?? localTimezone);
|
||||||
} else {
|
} else {
|
||||||
setTimezone(localTimezone);
|
setTimezone(localTimezone);
|
||||||
}
|
}
|
||||||
|
@ -178,45 +185,18 @@ const TimestampComponent = ErrorBoundary.wrap(({ userId, timestamp, type }: Prop
|
||||||
);
|
);
|
||||||
}, { noop: true });
|
}, { noop: true });
|
||||||
|
|
||||||
|
|
||||||
const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: { user: User; }) => {
|
const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: { user: User; }) => {
|
||||||
if (user?.id == null) return;
|
if (user?.id == null) return;
|
||||||
|
|
||||||
const setTimezoneItem = (
|
const setTimezoneItem = (
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
label="Set Timezone"
|
label="Set Local Timezone"
|
||||||
id="set-timezone"
|
id="set-timezone"
|
||||||
action={() => openModal(modalProps => <SetTimezoneModal userId={user.id} modalProps={modalProps} />)}
|
action={() => openModal(modalProps => <SetTimezoneModal userId={user.id} modalProps={modalProps} />)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
children.push(<Menu.MenuSeparator />, setTimezoneItem);
|
children.push(<Menu.MenuSeparator />, setTimezoneItem);
|
||||||
|
|
||||||
if (settings.store.useDatabase) {
|
|
||||||
const refreshTimezoneItem = (
|
|
||||||
<Menu.MenuItem
|
|
||||||
label="Refresh Timezone"
|
|
||||||
id="refresh-timezone"
|
|
||||||
action={async () => {
|
|
||||||
showToast("Refreshing timezone...", Toasts.Type.CLOCK);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const timezone = await getTimezone(user.id, true);
|
|
||||||
|
|
||||||
if (timezone) {
|
|
||||||
showToast("Timezone refreshed successfully!", Toasts.Type.SUCCESS);
|
|
||||||
} else {
|
|
||||||
showToast("Timezone reset successfully!", Toasts.Type.SUCCESS);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to refresh timezone:", error);
|
|
||||||
showToast("Failed to refresh timezone.", Toasts.Type.FAILURE);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
children.push(refreshTimezoneItem);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
|
@ -246,31 +226,75 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
toolboxActions: {
|
||||||
|
"Set Database Timezone": () => {
|
||||||
|
authModal(async () => {
|
||||||
|
openModal(modalProps => <SetTimezoneModal userId={UserStore.getCurrentUser().id} modalProps={modalProps} database={true} />);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"Refresh Database Timezones": async () => {
|
||||||
|
try {
|
||||||
|
const good = await loadDatabaseTimezones();
|
||||||
|
|
||||||
|
if (good) {
|
||||||
|
showToast("Timezones refreshed successfully!", Toasts.Type.SUCCESS);
|
||||||
|
} else {
|
||||||
|
showToast("Timezones Failed to refresh!", Toasts.Type.FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("Failed to refresh timezone:", error);
|
||||||
|
showToast("Failed to refresh timezones.", Toasts.Type.FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
databaseTimezones = await DataStore.get<Record<string, CacheEntry>>(DATASTORE_KEY) || {};
|
|
||||||
timezones = await DataStore.get<Record<string, string>>(DATASTORE_KEY) || {};
|
timezones = await DataStore.get<Record<string, string>>(DATASTORE_KEY) || {};
|
||||||
|
|
||||||
|
if (settings.store.useDatabase) {
|
||||||
|
await loadDatabaseTimezones();
|
||||||
|
|
||||||
|
if (!settings.store.askedTimezone) {
|
||||||
|
showToast(
|
||||||
|
"",
|
||||||
|
Toasts.Type.MESSAGE,
|
||||||
|
{
|
||||||
|
duration: 10000,
|
||||||
|
component: (
|
||||||
|
<Button
|
||||||
|
color={Button.Colors.GREEN}
|
||||||
|
onClick={() => {
|
||||||
|
authModal(async () => {
|
||||||
|
openModal(modalProps => <SetTimezoneModal userId={UserStore.getCurrentUser().id} modalProps={modalProps} database={true} />);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Want to save your timezone to the database? Click here to set it.
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
position: Toasts.Position.BOTTOM
|
||||||
|
}
|
||||||
|
);
|
||||||
|
settings.store.askedTimezone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
getTime,
|
getTime,
|
||||||
|
|
||||||
|
|
||||||
renderProfileTimezone: (props?: { user?: User; }) => {
|
renderProfileTimezone: (props?: { user?: User; }) => {
|
||||||
if (!settings.store.showProfileTime || !props?.user?.id) return null;
|
if (!settings.store.showProfileTime || !props?.user?.id) return null;
|
||||||
|
if (props.user.id === UserStore.getCurrentUser().id && !settings.store["Show Own Timezone"]) return null;
|
||||||
|
|
||||||
return <TimestampComponent
|
return <TimestampComponent userId={props.user.id} type="profile" />;
|
||||||
userId={props.user.id}
|
|
||||||
type="profile"
|
|
||||||
/>;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderMessageTimezone: (props?: { message?: Message; }) => {
|
renderMessageTimezone: (props?: { message?: Message; }) => {
|
||||||
if (!settings.store.showMessageHeaderTime || !props?.message) return null;
|
if (!settings.store.showMessageHeaderTime || !props?.message) return null;
|
||||||
|
if (props.message.author.id === UserStore.getCurrentUser().id && !settings.store["Show Own Timezone"]) return null;
|
||||||
|
|
||||||
return <TimestampComponent
|
return <TimestampComponent userId={props.message.author.id} timestamp={props.message.timestamp.toISOString()} type="message" />;
|
||||||
userId={props.message.author.id}
|
|
||||||
timestamp={props.message.timestamp.toISOString()}
|
|
||||||
type="message"
|
|
||||||
/>;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue