Equicord/src/equicordplugins/timezones/database.tsx
Creation's 43e8870dbc
feat(timezones): add a database option (#272)
* add a database option for timezones

* forgot to remove wrong comments lol
2025-05-28 09:25:51 -04:00

125 lines
3.8 KiB
TypeScript

/*
* Vencord, a Discord client mod
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
type CacheEntry = {
value: string | null;
expires: number;
};
import { DataStore } from "@api/index";
import { openModal } from "@utils/modal";
import { OAuth2AuthorizeModal, showToast, Toasts } from "@webpack/common";
export const DOMAIN = "https://timezone.creations.works";
export const REDIRECT_URI = `${DOMAIN}/auth/discord/callback`;
export const CLIENT_ID = "1377021506810417173";
export const DATASTORE_KEY = "vencord-database-timezones";
export let databaseTimezones: Record<string, CacheEntry> = {};
(async () => {
databaseTimezones = await DataStore.get<Record<string, CacheEntry>>(DATASTORE_KEY) || {};
})();
const pendingRequests: Record<string, Promise<string | null>> = {};
export async function setUserDatabaseTimezone(userId: string, timezone: string | null) {
databaseTimezones[userId] = {
value: timezone,
expires: Date.now() + 60 * 60 * 1000 // 1 hour
};
await DataStore.set(DATASTORE_KEY, databaseTimezones);
}
export async function getTimezone(userId: string): Promise<string | null> {
const now = Date.now();
const cached = databaseTimezones[userId];
if (cached && now < cached.expires) return cached.value;
if (!pendingRequests[userId]) {
pendingRequests[userId] = (async () => {
const res = await fetch(`${DOMAIN}/get?id=${userId}`, {
headers: { Accept: "application/json" }
});
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);
delete pendingRequests[userId];
return value;
})();
}
return pendingRequests[userId];
}
export async function setTimezone(timezone: string): Promise<boolean> {
const res = await fetch(`${DOMAIN}/set?timezone=${encodeURIComponent(timezone)}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
credentials: "include"
});
return res.ok;
}
export async function deleteTimezone(): Promise<boolean> {
const res = await fetch(`${DOMAIN}/delete`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
credentials: "include"
});
return res.ok;
}
export function authModal(callback?: () => void) {
openModal(modalProps => (
<OAuth2AuthorizeModal
{...modalProps}
clientId={CLIENT_ID}
redirectUri={REDIRECT_URI}
responseType="code"
scopes={["identify"]}
permissions={0n}
cancelCompletesFlow={false}
callback={async (res: any) => {
try {
const url = new URL(res.location);
const r = await fetch(url, {
credentials: "include",
headers: { Accept: "application/json" }
});
const json = await r.json();
if (!r.ok) {
showToast(json.message ?? "Authorization failed", Toasts.Type.FAILURE);
return;
}
showToast("Authorization successful!", Toasts.Type.SUCCESS);
callback?.();
} catch (e) {
showToast("Unexpected error during authorization", Toasts.Type.FAILURE);
}
}}
/>
));
}