chore: standardize security and quality foundations
Magent CI/CD / verify (push) Failing after 9m34s
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-17 20:03:47 +12:00
parent 5639dbcb83
commit f852e7c941
127 changed files with 17928 additions and 10741 deletions
+49 -53
View File
@@ -1,83 +1,83 @@
'use client'
"use client";
import PageHeading from '../ui/PageHeading'
import PageHeading from "../ui/PageHeading";
import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { authFetchOrThrow, getApiBase, getToken, UnauthorizedError } from '../lib/auth'
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { authFetchOrThrow, getApiBase, getToken, UnauthorizedError } from "../lib/auth";
type Profile = {
username?: string
}
username?: string;
};
export default function FeedbackPage() {
const router = useRouter()
const [profile, setProfile] = useState<Profile | null>(null)
const [category, setCategory] = useState('bug')
const [message, setMessage] = useState('')
const [status, setStatus] = useState<string | null>(null)
const [submitting, setSubmitting] = useState(false)
const router = useRouter();
const [profile, setProfile] = useState<Profile | null>(null);
const [category, setCategory] = useState("bug");
const [message, setMessage] = useState("");
const [status, setStatus] = useState<string | null>(null);
const [submitting, setSubmitting] = useState(false);
useEffect(() => {
if (!getToken()) {
router.push('/login')
return
router.push("/login");
return;
}
const load = async () => {
try {
const baseUrl = getApiBase()
const response = await authFetchOrThrow(`${baseUrl}/auth/me`)
const baseUrl = getApiBase();
const response = await authFetchOrThrow(`${baseUrl}/auth/me`);
if (!response.ok) {
throw new Error('Could not load profile.')
throw new Error("Could not load profile.");
}
const data = await response.json()
setProfile({ username: data?.username })
const data = await response.json();
setProfile({ username: data?.username });
} catch (error) {
if (error instanceof UnauthorizedError) {
router.push('/login')
return
router.push("/login");
return;
}
console.error(error)
console.error(error);
}
}
void load()
}, [router])
};
void load();
}, [router]);
const submit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()
setStatus(null)
event.preventDefault();
setStatus(null);
if (!message.trim()) {
setStatus('Please write a short message before sending.')
return
setStatus("Please write a short message before sending.");
return;
}
setSubmitting(true)
setSubmitting(true);
try {
const baseUrl = getApiBase()
const baseUrl = getApiBase();
const response = await authFetchOrThrow(`${baseUrl}/feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type: category,
message: message.trim(),
}),
})
});
if (!response.ok) {
const text = await response.text()
throw new Error(text || `Request failed: ${response.status}`)
const text = await response.text();
throw new Error(text || `Request failed: ${response.status}`);
}
setMessage('')
setStatus('Thanks! Your message has been sent.')
setMessage("");
setStatus("Thanks! Your message has been sent.");
} catch (error) {
if (error instanceof UnauthorizedError) {
router.push('/login')
return
router.push("/login");
return;
}
console.error(error)
setStatus('That did not send. Please try again.')
console.error(error);
setStatus("That did not send. Please try again.");
} finally {
setSubmitting(false)
setSubmitting(false);
}
}
};
return (
<main className="card feedback-page">
@@ -85,14 +85,10 @@ export default function FeedbackPage() {
<form className="account-panel account-form feedback-form" onSubmit={submit}>
<label htmlFor="feedback-user">Your username</label>
<input id="feedback-user" value={profile?.username ?? ''} readOnly />
<input id="feedback-user" value={profile?.username ?? ""} readOnly />
<label htmlFor="feedback-type">What is this about?</label>
<select
id="feedback-type"
value={category}
onChange={(event) => setCategory(event.target.value)}
>
<select id="feedback-type" value={category} onChange={(event) => setCategory(event.target.value)}>
<option value="bug">Bug (something is broken)</option>
<option value="feature">Feature idea (new option)</option>
</select>
@@ -109,9 +105,9 @@ export default function FeedbackPage() {
{status && <div className="status-banner">{status}</div>}
<button type="submit" disabled={submitting}>
{submitting ? 'Sending...' : 'Send feedback'}
{submitting ? "Sending..." : "Send feedback"}
</button>
</form>
</main>
)
);
}