mirror of
https://github.com/UiO-Gaming/name-100-uio-gamers.git
synced 2026-11-05 13:56:53 +01:00
show loading state on guess submission
This commit is contained in:
3 files changed
+39
-23
No files matched your search
@@ -7,9 +7,10 @@ interface GuessFormProps {
|
||||
onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
onSubmit: (e: React.FormEvent) => void;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const GuessForm: React.FC<GuessFormProps> = ({ input, onInputChange, onSubmit, disabled }) => {
|
||||
const GuessForm: React.FC<GuessFormProps> = ({ input, onInputChange, onSubmit, disabled, loading }) => {
|
||||
const { language } = useLanguage();
|
||||
const t = translations[language];
|
||||
return (
|
||||
@@ -19,21 +20,23 @@ const GuessForm: React.FC<GuessFormProps> = ({ input, onInputChange, onSubmit, d
|
||||
value={input}
|
||||
onChange={onInputChange}
|
||||
className={`focus:border-accent-primary h-12 w-60 rounded border px-2 py-1 focus:outline-none md:w-75 ${
|
||||
disabled
|
||||
disabled || loading
|
||||
? "cursor-not-allowed border-gray-500 bg-gray-400 opacity-50"
|
||||
: "bg-background-secondary duration-300"
|
||||
}`}
|
||||
placeholder={t.placeholder}
|
||||
disabled={disabled}
|
||||
placeholder={loading ? t.loading || "Loading..." : t.placeholder}
|
||||
disabled={disabled || loading}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className={`rounded px-4 py-1 text-white ${
|
||||
!input || disabled ? "cursor-not-allowed bg-gray-400 opacity-50" : "bg-accent-primary cursor-pointer"
|
||||
!input || disabled || loading
|
||||
? "cursor-not-allowed bg-gray-400 opacity-50"
|
||||
: "bg-accent-primary cursor-pointer"
|
||||
}`}
|
||||
disabled={disabled || !input}
|
||||
disabled={disabled || !input || loading}
|
||||
>
|
||||
{t.submit}
|
||||
{loading ? t.loading || "Loading..." : t.submit}
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@ export default function HomeClient({ session }: { session: Session }) {
|
||||
const [matches, setMatches] = useState<Match[]>([]);
|
||||
const [timer, setTimer] = useState(0);
|
||||
const [timerStarted, setTimerStarted] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [howToPlayOpen, setHowToPlayOpen] = useState(false);
|
||||
const [repeatMessage, setRepeatMessage] = useState("");
|
||||
@@ -77,24 +78,33 @@ export default function HomeClient({ session }: { session: Session }) {
|
||||
return;
|
||||
}
|
||||
setRepeatMessage("");
|
||||
const res = await fetch("/api/guess", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ input: trimmedInput }),
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.name && matches.some((m) => m.name && m.name.toLowerCase() === data.name.toLowerCase())) {
|
||||
setRepeatMessage(t.alreadySubmitted);
|
||||
setInput("");
|
||||
return;
|
||||
}
|
||||
setMatches((prev) => [...prev, { input: trimmedInput, ...data }]);
|
||||
if (data.correct && !timerStarted) {
|
||||
startTimer();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/guess", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ input: trimmedInput }),
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.name && matches.some((m) => m.name && m.name.toLowerCase() === data.name.toLowerCase())) {
|
||||
setRepeatMessage(t.alreadySubmitted);
|
||||
setInput("");
|
||||
return;
|
||||
}
|
||||
setMatches((prev) => [...prev, { input: trimmedInput, ...data }]);
|
||||
if (data.correct && !timerStarted) {
|
||||
startTimer();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting guess:", error);
|
||||
setRepeatMessage("An error occurred. Please try again.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setInput("");
|
||||
}
|
||||
setInput("");
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -136,6 +146,7 @@ export default function HomeClient({ session }: { session: Session }) {
|
||||
}}
|
||||
onSubmit={handleSubmit}
|
||||
disabled={correctMatchesCount === GOAL_AMOUNT}
|
||||
loading={loading}
|
||||
/>
|
||||
<Score matchesCount={correctMatchesCount} />
|
||||
{repeatMessage && <div className="mb-2 font-semibold text-red-500">{repeatMessage}</div>}
|
||||
|
||||
@@ -4,6 +4,7 @@ export const translations = {
|
||||
alreadySubmitted: "You have already entered that name!",
|
||||
placeholder: "Enter the username of a member...",
|
||||
submit: "Submit",
|
||||
loading: "Loading...",
|
||||
howToPlayTitle: "How to Play",
|
||||
howToPlay1: "Any Discord username or nickname who has the paying member role should be accepted.",
|
||||
howToPlay2: "No repeats allowed.",
|
||||
@@ -24,6 +25,7 @@ export const translations = {
|
||||
alreadySubmitted: "Du har allerede skrevet det navnet!",
|
||||
placeholder: "Skriv brukernavnet til et medlem...",
|
||||
submit: "Send",
|
||||
loading: "Laster...",
|
||||
howToPlayTitle: "Slik spiller du",
|
||||
howToPlay1: "Alle bør Discordbrukernavn eller kallenavn som har betalende medlem rollen godtas.",
|
||||
howToPlay2: "Du kan ikke gjenta navn.",
|
||||
|
||||
Reference in new issue
Block a user