@@ -300,6 +300,14 @@ app.prepare().then(() => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validar que usuarios normales no puedan usar el prefijo "anon"
|
||||||
|
// Solo permitir si viene exactamente con el formato anon#### (4 dígitos)
|
||||||
|
const anonPattern = /^anon\d{4}$/;
|
||||||
|
if (username.toLowerCase().startsWith('anon') && !anonPattern.test(username)) {
|
||||||
|
socket.emit('error', 'El prefijo "anon" está reservado para usuarios anónimos del sistema');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Verificar si el usuario ya existe
|
// Verificar si el usuario ya existe
|
||||||
const existingUser = Array.from(connectedUsers.values()).find(u => u.username === username);
|
const existingUser = Array.from(connectedUsers.values()).find(u => u.username === username);
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default function Chat({ username, onUsernameChange, onSocketReady, onWatc
|
|||||||
const [tempUsername, setTempUsername] = useState(username || '');
|
const [tempUsername, setTempUsername] = useState(username || '');
|
||||||
const [hoveredUser, setHoveredUser] = useState(null);
|
const [hoveredUser, setHoveredUser] = useState(null);
|
||||||
const [showCopiedTooltip, setShowCopiedTooltip] = useState(false);
|
const [showCopiedTooltip, setShowCopiedTooltip] = useState(false);
|
||||||
|
const [showUsernameForm, setShowUsernameForm] = useState(false);
|
||||||
const messagesEndRef = useRef(null);
|
const messagesEndRef = useRef(null);
|
||||||
|
|
||||||
// Auto-scroll al final de los mensajes
|
// Auto-scroll al final de los mensajes
|
||||||
@@ -124,6 +125,16 @@ export default function Chat({ username, onUsernameChange, onSocketReady, onWatc
|
|||||||
|
|
||||||
newSocket.on('error', (error) => {
|
newSocket.on('error', (error) => {
|
||||||
console.error('Error del servidor:', error);
|
console.error('Error del servidor:', error);
|
||||||
|
|
||||||
|
// Si el error es sobre el prefijo "anon", resetear el usuario para que vuelva al formulario
|
||||||
|
if (error.includes('prefijo "anon"') || error.includes('anon')) {
|
||||||
|
alert(error);
|
||||||
|
if (onUsernameChange) {
|
||||||
|
onUsernameChange('');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setMessages(prev => [
|
setMessages(prev => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
@@ -164,10 +175,33 @@ export default function Chat({ username, onUsernameChange, onSocketReady, onWatc
|
|||||||
|
|
||||||
const handleUsernameSubmit = (e) => {
|
const handleUsernameSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (tempUsername.trim().length >= 2) {
|
|
||||||
if (onUsernameChange) {
|
// Si no hay nombre, usar anónimo
|
||||||
onUsernameChange(tempUsername.trim());
|
if (!tempUsername.trim() || tempUsername.trim().length < 2) {
|
||||||
|
handleSkipUsername();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedUsername = tempUsername.trim();
|
||||||
|
|
||||||
|
// Validar que no use el prefijo reservado "anon"
|
||||||
|
if (normalizedUsername.toLowerCase().startsWith('anon')) {
|
||||||
|
alert('⚠️ El prefijo "anon" está reservado para usuarios anónimos.\n\nPor favor, elige otro nombre de usuario.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onUsernameChange) {
|
||||||
|
onUsernameChange(normalizedUsername);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSkipUsername = () => {
|
||||||
|
// Generar usuario anónimo: anon + 4 dígitos aleatorios
|
||||||
|
const randomNum = Math.floor(1000 + Math.random() * 9000);
|
||||||
|
const anonUsername = `anon${randomNum}`;
|
||||||
|
|
||||||
|
if (onUsernameChange) {
|
||||||
|
onUsernameChange(anonUsername);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,7 +226,7 @@ export default function Chat({ username, onUsernameChange, onSocketReady, onWatc
|
|||||||
<form onSubmit={handleUsernameSubmit} className="space-y-4">
|
<form onSubmit={handleUsernameSubmit} className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Nombre de usuario
|
Nombre de usuario (opcional)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -202,15 +236,26 @@ export default function Chat({ username, onUsernameChange, onSocketReady, onWatc
|
|||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
minLength={2}
|
minLength={2}
|
||||||
maxLength={30}
|
maxLength={30}
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
🚫 El prefijo "anon" está reservado para usuarios anónimos
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded-lg transition-colors"
|
className="w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Unirse
|
Unirse con este nombre
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleSkipUsername}
|
||||||
|
className="w-full bg-gray-400 hover:bg-gray-500 text-white font-medium py-2 px-4 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
Continuar como anónimo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user