162 lines
4.9 KiB
TypeScript
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;
|