1
0
peddlers-of-ketran/client/src/NameSetter.tsx

162 lines
4.9 KiB
TypeScript

import React, { useState, KeyboardEvent, useRef, useContext } from "react";
import {
Input,
Button,
Box,
Typography,
Tooltip,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from "@mui/material";
import { GlobalContext, Session } from "./GlobalContext";
interface NameSetterProps {
onNameSet?: () => void;
initialName?: string;
initialPassword?: string;
}
const NameSetter: React.FC<NameSetterProps> = ({ onNameSet, initialName = "", initialPassword = "" }) => {
const { session, sendJsonMessage } = useContext(GlobalContext);
const [editName, setEditName] = useState<string>(initialName);
const [editPassword, setEditPassword] = useState<string>(initialPassword);
const [showDialog, setShowDialog] = useState<boolean>(!session.name);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const nameInputRef = useRef<HTMLInputElement>(null);
const passwordInputRef = useRef<HTMLInputElement>(null);
const setName = (name: string) => {
setIsSubmitting(true);
sendJsonMessage({
type: "player-name",
data: { name, password: editPassword ? editPassword : undefined },
});
if (onNameSet) {
onNameSet();
}
setShowDialog(false);
setIsSubmitting(false);
setEditName("");
setEditPassword("");
};
const handleNameKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {
if (event.key === "Enter") {
event.preventDefault();
if (passwordInputRef.current) {
passwordInputRef.current.focus();
}
}
};
const handlePasswordKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {
if (event.key === "Enter") {
event.preventDefault();
handleSubmit();
}
};
const handleSubmit = () => {
const newName = editName.trim();
if (!newName || (session?.name && session.name === newName)) {
return;
}
setName(newName);
};
const handleOpenDialog = () => {
setEditName(session.name || "");
setEditPassword("");
setShowDialog(true);
// Focus the name input when dialog opens
setTimeout(() => {
if (nameInputRef.current) {
nameInputRef.current.focus();
}
}, 100);
};
const handleCloseDialog = () => {
setShowDialog(false);
setEditName("");
setEditPassword("");
};
const hasNameChanged = editName.trim() !== (session.name || "");
const canSubmit = editName.trim() && hasNameChanged && !isSubmitting;
return (
<Box sx={{ gap: 1, display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
{session.name && !showDialog && (
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Typography>You are logged in as: {session.name}</Typography>
<Button variant="outlined" size="small" onClick={handleOpenDialog}>
Change Name
</Button>
</Box>
)}
{/* Dialog for name change */}
<Dialog open={showDialog} onClose={handleCloseDialog} maxWidth="sm" fullWidth>
<DialogTitle>{session.name ? "Change Your Name" : "Enter Your Name"}</DialogTitle>
<DialogContent>
<Box sx={{ display: "flex", flexDirection: "column", gap: 2, pt: 1 }}>
<Typography variant="body2" color="text.secondary">
{session.name ? "Enter a new name to change your current name." : "Enter your name to join the lobby."}
</Typography>
<Typography variant="caption" color="text.secondary">
You can optionally set a password to reserve this name; supply it again to takeover the name from another
client.
</Typography>
<Input
inputRef={nameInputRef}
type="text"
value={editName}
onChange={(e): void => {
setEditName(e.target.value);
}}
onKeyDown={handleNameKeyDown}
placeholder="Your name"
fullWidth
autoFocus
/>
<Input
inputRef={passwordInputRef}
type="password"
value={editPassword}
onChange={(e): void => setEditPassword(e.target.value)}
onKeyDown={handlePasswordKeyDown}
placeholder="Optional password"
fullWidth
/>
<Tooltip title="Optional: choose a short password to reserve this name. Keep it secret.">
<span />
</Tooltip>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseDialog} disabled={isSubmitting}>
Cancel
</Button>
<Button
variant="contained"
onClick={handleSubmit}
disabled={!canSubmit}
color={hasNameChanged ? "primary" : "inherit"}
>
{isSubmitting ? "Changing..." : session.name ? "Change Name" : "Join"}
</Button>
</DialogActions>
</Dialog>
</Box>
);
};
export default NameSetter;