Files
flxn-app/src/features/settings/server.ts
T
kyle 3d8ee52a15 feat(telemetry): opt-in admin alert pushes
- telemetryAlerts metadata flag, admin-gated server fn
- alerts sent only to admins with the flag enabled
- settings toggle visible to admins only, under device notifications
2026-08-25 23:33:01 -07:00

168 lines
4.1 KiB
TypeScript

import { createServerFn } from "@tanstack/react-start";
import {
superTokensAdminFunctionMiddleware,
superTokensFunctionMiddleware,
} from "@/utils/supertokens";
// Whitelists: these values flow into Mantine's primaryColor / the
// data-mantine-color-scheme attribute — an unknown value crash-loops or
// unstyles the account's UI on every load.
const ACCENT_COLORS = [
"blue",
"red",
"green",
"yellow",
"grape",
"orange",
"pink",
"lime",
];
const COLOR_SCHEMES = ["light", "dark", "auto"];
export const updateUserColorScheme = createServerFn({ method: "POST" })
.validator((data: string) => data)
.middleware([superTokensFunctionMiddleware])
.handler(async ({ context, data }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
if (!COLOR_SCHEMES.includes(data)) return;
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
colorScheme: data,
});
return {
metadata: {
...metadata,
colorScheme: data,
},
};
});
export const updateUserLocale = createServerFn({ method: "POST" })
.validator((data: string) => data)
.middleware([superTokensFunctionMiddleware])
.handler(async ({ context, data }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
const { SUPPORTED_LOCALES } = await import("@/lib/i18n");
if (!(SUPPORTED_LOCALES as readonly string[]).includes(data)) return;
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
locale: data,
});
return {
metadata: {
...metadata,
locale: data,
},
};
});
export const updateUserTheme = createServerFn({ method: "POST" })
.validator((data: string) => data)
.middleware([superTokensFunctionMiddleware])
.handler(async ({ context, data }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
const { THEME_IDS } = await import("@/themes/registry");
if (!THEME_IDS.includes(data)) {
throw new Error("Unknown theme");
}
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
theme: data,
});
return {
metadata: {
...metadata,
theme: data,
},
};
});
export const updateUserSeenThemesHint = createServerFn({ method: "POST" })
.middleware([superTokensFunctionMiddleware])
.handler(async ({ context }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
seenThemesHint: true,
});
return {
metadata: {
...metadata,
seenThemesHint: true,
},
};
});
export const updateUserAccentColor = createServerFn({ method: "POST" })
.validator((data: string) => data)
.middleware([superTokensFunctionMiddleware])
.handler(async ({ context, data }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
if (!ACCENT_COLORS.includes(data)) return;
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
accentColor: data,
});
return {
metadata: {
...metadata,
accentColor: data,
},
};
});
export const updateUserTelemetryAlerts = createServerFn({ method: "POST" })
.validator((data: boolean) => data === true)
.middleware([superTokensAdminFunctionMiddleware])
.handler(async ({ context, data }) => {
const { userAuthId, metadata } = context;
if (!userAuthId) return;
const { updateUserMetadataFields } = await import(
"@/utils/supertokens-core.server"
);
await updateUserMetadataFields(userAuthId, {
telemetryAlerts: data,
});
return {
metadata: {
...metadata,
telemetryAlerts: data,
},
};
});