feat: guest user

This commit is contained in:
2026-05-13 22:31:47 +03:00
parent cf9052ab7a
commit 11b8a483c4
6 changed files with 148 additions and 7 deletions
+44
View File
@@ -1,11 +1,33 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
import LoginForm from '../components/auth/LoginForm';
import RegisterForm from '../components/auth/RegisterForm';
import miniLogo from '../assets/mini-logo.png';
import { authService } from '../services/authService';
import { useAuthStore } from '../store/authStore';
export default function AuthPage() {
const [isLogin, setIsLogin] = useState(true);
const [guestError, setGuestError] = useState('');
const [isGuestLoading, setIsGuestLoading] = useState(false);
const navigate = useNavigate();
const setUser = useAuthStore((state) => state.setUser);
const handleGuestLogin = async () => {
setGuestError('');
setIsGuestLoading(true);
try {
await authService.guestLogin();
const user = await authService.getCurrentUser();
setUser(user);
navigate('/chat');
} catch (err: any) {
setGuestError(err.response?.data?.detail || 'Не удалось войти как гость');
} finally {
setIsGuestLoading(false);
}
};
return (
<div className="w-screen h-screen flex items-center justify-center p-3 md:p-4 relative overflow-hidden" style={{ backgroundColor: '#F5F5F1' }}>
@@ -59,6 +81,28 @@ export default function AuthPage() {
</motion.div>
</AnimatePresence>
<div className="mt-5 md:mt-6">
{guestError && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="p-3 mb-4 bg-error-soft/10 border-b-2 border-error-soft text-error-soft text-sm font-inter"
>
{guestError}
</motion.div>
)}
<motion.button
type="button"
disabled={isGuestLoading}
onClick={handleGuestLogin}
whileTap={{ scale: 0.97 }}
className="w-full py-[14px] px-8 rounded-full font-inter font-semibold uppercase tracking-wider border-2 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
style={{ borderColor: '#6B705C', color: '#6B705C' }}
>
{isGuestLoading ? 'Вход...' : 'Войти как гость'}
</motion.button>
</div>
{/* Switch */}
<div className="mt-5 md:mt-6 text-center text-xs md:text-sm font-inter" style={{ color: '#8B8B8B' }}>
{isLogin ? (
+48 -7
View File
@@ -182,16 +182,57 @@ export default function ChatPage() {
}
// Update chat list with new last message
setChats(prevChats =>
prevChats.map(chat =>
setChats(prevChats => {
const existingIndex = prevChats.findIndex(chat => chat.chat_id === message.chat_id);
if (existingIndex === -1) {
const otherUserId = message.sender_id === user?.id ? selectedChat?.user_id : message.sender_id;
const newChat: Chat = {
chat_id: message.chat_id,
user_id: otherUserId || 0,
last_message: message.content,
avatar_url: null,
display_name: 'Новый чат'
};
const updated = [newChat, ...prevChats];
setChatsCache(updated);
if (otherUserId) {
userService.getUserById(otherUserId)
.then((userData) => {
setChats(current => {
const hydrated = current.map(chat =>
chat.chat_id === message.chat_id
? {
...chat,
user_id: userData.id,
display_name: userData.display_name || userData.username,
avatar_url: userData.avatar_url || null
}
: chat
);
setChatsCache(hydrated);
return hydrated;
});
})
.catch((err) => {
console.error('Failed to load chat user:', err);
});
}
return updated;
}
const updated = prevChats.map(chat =>
chat.chat_id === message.chat_id
? { ...chat, last_message: message.content }
: chat
)
);
// Update cache
updateChatCache(message.chat_id, { last_message: message.content });
);
setChatsCache(updated);
updateChatCache(message.chat_id, { last_message: message.content });
return updated;
});
} catch (error) {
console.error('Error parsing WebSocket message:', error);
}
+5
View File
@@ -27,6 +27,11 @@ export const authService = {
return response.data;
},
guestLogin: async () => {
const response = await apiClient.post('/auth/guest');
return response.data;
},
register: async (data: RegisterData) => {
const response = await apiClient.post('/auth/register', data);
return response.data;