sendou.ink/app/features/settings/components/PreferencesTab.tsx
2026-06-17 17:32:54 +03:00

152 lines
4.2 KiB
TypeScript

import * as React from "react";
import { useTranslation } from "react-i18next";
import { Divider } from "~/components/Divider";
import { SendouButton } from "~/components/elements/Button";
import { SendouPopover } from "~/components/elements/Popover";
import { FormMessage } from "~/components/FormMessage";
import { Label } from "~/components/Label";
import { Config } from "~/config";
import { useUser } from "~/features/auth/core/user";
import { SendouForm } from "~/form/SendouForm";
import {
disableBuildAbilitySortingSchema,
disallowScrimPickupsFromUntrustedSchema,
spoilerFreeModeSchema,
} from "../settings-schemas";
export function PreferencesTab() {
const user = useUser();
if (!user) return null;
return (
<div className="stack md">
<PushNotificationsEnabler />
<Divider className="my-2" />
<div className="stack md">
<SendouForm
schema={disableBuildAbilitySortingSchema}
defaultValues={{
newValue: user.preferences.disableBuildAbilitySorting ?? false,
}}
autoSubmit
revalidateRoot
fullWidth
>
{({ FormField }) => <FormField name="newValue" />}
</SendouForm>
<SendouForm
schema={disallowScrimPickupsFromUntrustedSchema}
defaultValues={{
newValue:
user.preferences.disallowScrimPickupsFromUntrusted ?? false,
}}
autoSubmit
revalidateRoot
fullWidth
>
{({ FormField }) => <FormField name="newValue" />}
</SendouForm>
<SendouForm
schema={spoilerFreeModeSchema}
defaultValues={{
newValue: user.preferences.spoilerFreeMode ?? false,
}}
autoSubmit
revalidateRoot
fullWidth
>
{({ FormField }) => <FormField name="newValue" />}
</SendouForm>
</div>
</div>
);
}
function PushNotificationsEnabler() {
const { t } = useTranslation(["common"]);
const [notificationsPermsGranted, setNotificationsPermsGranted] =
React.useState<NotificationPermission | "not-supported">("default");
React.useEffect(() => {
if (!("serviceWorker" in navigator)) {
setNotificationsPermsGranted("not-supported");
return;
}
if (!("PushManager" in window)) {
setNotificationsPermsGranted("not-supported");
return;
}
setNotificationsPermsGranted(Notification.permission);
}, []);
function askPermission() {
Notification.requestPermission().then((permission) => {
setNotificationsPermsGranted(permission);
if (permission === "granted") {
initServiceWorker();
}
});
}
async function initServiceWorker() {
const swRegistration = await navigator.serviceWorker.register("sw-2.js");
const subscription = await swRegistration.pushManager.getSubscription();
if (subscription) {
sendSubscriptionToServer(subscription);
} else {
const subscription = await swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: Config.vapid.publicKey,
});
sendSubscriptionToServer(subscription);
}
}
function sendSubscriptionToServer(subscription: PushSubscription) {
fetch("/notifications/subscribe", {
method: "post",
body: JSON.stringify(subscription),
headers: { "content-type": "application/json" },
});
}
return (
<div>
<Label>{t("common:settings.notifications.title")}</Label>
{notificationsPermsGranted === "granted" ? (
<SendouPopover
trigger={
<SendouButton size="small" variant="minimal">
{t("common:actions.disable")}
</SendouButton>
}
>
{t("common:settings.notifications.disableInfo")}
</SendouPopover>
) : notificationsPermsGranted === "not-supported" ||
notificationsPermsGranted === "denied" ? (
<SendouPopover
trigger={
<SendouButton size="small" variant="minimal">
{t("common:actions.enable")}
</SendouButton>
}
>
{notificationsPermsGranted === "not-supported"
? t("common:settings.notifications.browserNotSupported")
: t("common:settings.notifications.permissionDenied")}
</SendouPopover>
) : (
<SendouButton size="small" variant="minimal" onPress={askPermission}>
{t("common:actions.enable")}
</SendouButton>
)}
<FormMessage type="info">
{t("common:settings.notifications.description")}
</FormMessage>
</div>
);
}