Add player bug reports and profile identity features

This commit is contained in:
2026-10-08 18:27:20 +05:00
parent 36e8d11eb4
commit 0b08672f4a
51 changed files with 3938 additions and 45 deletions

View File

@@ -7,13 +7,20 @@ import { UserRound, LockKeyhole, Mail } from "lucide-react";
import { api } from "./StartGame";
import { PasswordForm } from "./PasswordForm";
import { displayNameSchema } from "@/shared/account";
import {
defaultGlowColor,
type ProfileAppearance,
} from "@/shared/profile-appearance";
import { Username } from "./Username";
export function AccountSettings({
email,
displayName,
appearance,
passwordUpdated = false,
}: {
email: string;
displayName: string;
appearance: ProfileAppearance;
passwordUpdated?: boolean;
}) {
const { t } = useI18n();
@@ -25,6 +32,25 @@ export function AccountSettings({
[recoveryError, setRecoveryError] = useState(""),
[sending, setSending] = useState(false);
const router = useRouter();
const [color, setColor] = useState(appearance.glow_color ?? defaultGlowColor);
const [colorBusy, setColorBusy] = useState(false),
[colorError, setColorError] = useState(""),
[colorSaved, setColorSaved] = useState(false);
async function saveColor(event: React.FormEvent) {
event.preventDefault();
setColorBusy(true);
setColorError("");
setColorSaved(false);
try {
await api("profile", { glowColor: color }, "PATCH");
setColorSaved(true);
router.refresh();
} catch (error) {
setColorError((error as Error).message);
} finally {
setColorBusy(false);
}
}
async function save(event: React.FormEvent) {
event.preventDefault();
setError("");
@@ -119,6 +145,49 @@ export function AccountSettings({
</button>
</form>
</section>
<section className="settings-card glow-settings">
<h2>{t("Username glow")}</h2>
<p className="muted">
{appearance.name_glow
? t("Choose the color of your glow.")
: t("Support can award a glow for a confirmed bug report.")}
</p>
<div className="username-preview">
<Username
name={name}
appearance={{ ...appearance, glow_color: color }}
/>
</div>
{appearance.name_glow && (
<form onSubmit={saveColor}>
<label className="field">
{t("Glow color")}
<input
type="color"
value={color}
onChange={(event) => {
setColor(event.target.value);
setColorSaved(false);
}}
disabled={colorBusy}
/>
</label>
{colorError && (
<p role="alert" className="error-message">
{t(colorError)}
</p>
)}
{colorSaved && (
<p role="status" className="success-message">
{t("Glow color saved.")}
</p>
)}
<button className="button primary" disabled={colorBusy}>
{colorBusy ? t("Saving…") : t("Save glow color")}
</button>
</form>
)}
</section>
<section className="settings-card">
<div className="settings-heading">
<LockKeyhole size={22} />