79 lines
2.9 KiB
TypeScript
79 lines
2.9 KiB
TypeScript
|
|
import { useFetcher, Link } from "react-router";
|
||
|
|
|
||
|
|
type Props = {
|
||
|
|
discordPingEnabled: boolean;
|
||
|
|
hasDiscordLinked: boolean;
|
||
|
|
success?: boolean;
|
||
|
|
};
|
||
|
|
|
||
|
|
export function NotificationsSection({ discordPingEnabled, hasDiscordLinked, success }: Props) {
|
||
|
|
const fetcher = useFetcher();
|
||
|
|
const optimisticEnabled =
|
||
|
|
fetcher.state !== "idle"
|
||
|
|
? fetcher.formData?.get("discordPingEnabled") === "true"
|
||
|
|
: discordPingEnabled;
|
||
|
|
|
||
|
|
const handleToggle = () => {
|
||
|
|
fetcher.submit(
|
||
|
|
{ intent: "update-discord-ping", discordPingEnabled: String(!optimisticEnabled) },
|
||
|
|
{ method: "post" }
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<div>
|
||
|
|
<h2 className="text-lg font-semibold">Notifications</h2>
|
||
|
|
<p className="text-sm text-muted-foreground">
|
||
|
|
Manage how you receive league notifications.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="rounded-lg border p-4 space-y-4">
|
||
|
|
<h3 className="text-sm font-medium">Discord Pings</h3>
|
||
|
|
|
||
|
|
{!hasDiscordLinked ? (
|
||
|
|
<p className="text-sm text-muted-foreground">
|
||
|
|
Link your Discord account in{" "}
|
||
|
|
<Link to="?section=account" className="text-primary underline-offset-4 hover:underline">
|
||
|
|
Account settings
|
||
|
|
</Link>{" "}
|
||
|
|
to enable Discord pings for league notifications.
|
||
|
|
</p>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<div className="flex items-center justify-between gap-4">
|
||
|
|
<div className="space-y-1">
|
||
|
|
<p className="text-sm">Ping me in standings updates</p>
|
||
|
|
<p className="text-xs text-muted-foreground">
|
||
|
|
When enabled, you'll be @mentioned in league Discord notifications and your
|
||
|
|
Discord display name will appear in place of your brackt username.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
role="switch"
|
||
|
|
aria-checked={optimisticEnabled}
|
||
|
|
onClick={handleToggle}
|
||
|
|
disabled={fetcher.state !== "idle"}
|
||
|
|
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${
|
||
|
|
optimisticEnabled ? "bg-primary" : "bg-input"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<span
|
||
|
|
className={`pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform ${
|
||
|
|
optimisticEnabled ? "translate-x-5" : "translate-x-0"
|
||
|
|
}`}
|
||
|
|
/>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
{success && (
|
||
|
|
<p className="text-sm text-green-600">Notification preference saved.</p>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|