import React, { useState, useEffect } from 'react'; import { Box, Container, Paper, TextField, Button, Typography, Grid, Alert, CircularProgress, Tabs, Tab, AppBar, Toolbar, Card, CardContent, Divider, Avatar } from '@mui/material'; import { Person, PersonAdd, AccountCircle, ExitToApp } from '@mui/icons-material'; import 'react-phone-number-input/style.css'; import PhoneInput from 'react-phone-number-input'; import { E164Number } from 'libphonenumber-js/core'; import './PhoneInput.css'; // Import conversion utilities import { formatApiRequest, parseApiResponse, handleApiResponse, extractApiData, isSuccessResponse, debugConversion, type ApiResponse } from '../types/conversion'; import { AuthResponse, BaseUser, Guest } from '../types/types' interface LoginRequest { login: string; password: string; } interface RegisterRequest { username: string; email: string; firstName: string; lastName: string; password: string; phone?: string; } const API_BASE_URL = 'https://backstory-beta.ketrenos.com/api/1.0'; const BackstoryTestApp: React.FC = () => { const [currentUser, setCurrentUser] = useState(null); const [guestSession, setGuestSession] = useState(null); const [tabValue, setTabValue] = useState(0); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [phone, setPhone] = useState(null); // Login form state const [loginForm, setLoginForm] = useState({ login: '', password: '' }); // Register form state const [registerForm, setRegisterForm] = useState({ username: '', email: '', firstName: '', lastName: '', password: '', phone: '' }); // Create guest session on component mount useEffect(() => { createGuestSession(); checkExistingAuth(); }, []); useEffect(() => { if (phone !== registerForm.phone && phone) { console.log({ phone }); setRegisterForm({ ...registerForm, phone }); } }, [phone, registerForm]); const createGuestSession = () => { const sessionId = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const guest: Guest = { sessionId, createdAt: new Date(), lastActivity: new Date(), ipAddress: 'unknown', userAgent: navigator.userAgent }; setGuestSession(guest); debugConversion(guest, 'Guest Session'); }; const checkExistingAuth = () => { const token = localStorage.getItem('accessToken'); const userData = localStorage.getItem('userData'); if (token && userData) { try { const user = JSON.parse(userData); // Convert dates back to Date objects if they're stored as strings if (user.createdAt && typeof user.createdAt === 'string') { user.createdAt = new Date(user.createdAt); } if (user.updatedAt && typeof user.updatedAt === 'string') { user.updatedAt = new Date(user.updatedAt); } if (user.lastLogin && typeof user.lastLogin === 'string') { user.lastLogin = new Date(user.lastLogin); } setCurrentUser(user); } catch (e) { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); localStorage.removeItem('userData'); } } }; const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(null); setSuccess(null); try { // Format request data for API (camelCase to snake_case) const requestData = formatApiRequest({ login: loginForm.login, password: loginForm.password }); debugConversion(requestData, 'Login Request'); const response = await fetch(`${API_BASE_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData) }); // Use conversion utility to handle response const authResponse = await handleApiResponse(response); debugConversion(authResponse, 'Login Response'); // Store tokens in localStorage localStorage.setItem('accessToken', authResponse.accessToken); localStorage.setItem('refreshToken', authResponse.refreshToken); localStorage.setItem('userData', JSON.stringify(authResponse.user)); setCurrentUser(authResponse.user); setSuccess('Login successful!'); // Clear form setLoginForm({ login: '', password: '' }); } catch (err) { console.error('Login error:', err); setError(err instanceof Error ? err.message : 'Login failed'); } finally { setLoading(false); } }; const handleRegister = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(null); setSuccess(null); try { const candidateData = { username: registerForm.username, email: registerForm.email, firstName: registerForm.firstName, lastName: registerForm.lastName, fullName: `${registerForm.firstName} ${registerForm.lastName}`, phone: registerForm.phone || undefined, userType: 'candidate', status: 'active', createdAt: new Date(), updatedAt: new Date(), skills: [], experience: [], education: [], preferredJobTypes: [], languages: [], certifications: [], location: { city: '', country: '', remote: true } }; // Format request data for API (camelCase to snake_case, dates to ISO strings) const requestData = formatApiRequest(candidateData); debugConversion(requestData, 'Registration Request'); const response = await fetch(`${API_BASE_URL}/candidates`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData) }); // Use conversion utility to handle response const result = await handleApiResponse(response); debugConversion(result, 'Registration Response'); setSuccess('Registration successful! You can now login.'); // Clear form and switch to login tab setRegisterForm({ username: '', email: '', firstName: '', lastName: '', password: '', phone: '' }); setTabValue(0); } catch (err) { console.error('Registration error:', err); setError(err instanceof Error ? err.message : 'Registration failed'); } finally { setLoading(false); } }; const handleLogout = () => { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); localStorage.removeItem('userData'); setCurrentUser(null); setSuccess('Logged out successfully'); createGuestSession(); }; const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { setTabValue(newValue); setError(null); setSuccess(null); }; // API helper function for authenticated requests const makeAuthenticatedRequest = async (url: string, options: RequestInit = {}) => { const token = localStorage.getItem('accessToken'); const headers = { 'Content-Type': 'application/json', ...(token && { 'Authorization': `Bearer ${token}` }), ...options.headers, }; const response = await fetch(url, { ...options, headers, }); return handleApiResponse(response); }; // If user is logged in, show their profile if (currentUser) { return ( Welcome, {currentUser.username} User Profile Username: {currentUser.username} Email: {currentUser.email} Status: {currentUser.status} Phone: {currentUser.phone || 'Not provided'} Last Login: { currentUser.lastLogin ? currentUser.lastLogin.toLocaleString() : 'N/A' } Member Since: {currentUser.createdAt.toLocaleDateString()} ); } const validateInput = (value: string) => { if (!value) return 'This field is required'; // Username: alphanumeric, 3-20 characters, no @ const usernameRegex = /^[a-zA-Z0-9]{3,20}$/; // Email: basic email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (usernameRegex.test(value)) return ''; if (emailRegex.test(value)) return ''; return 'Enter a valid username (3-20 alphanumeric characters) or email'; }; const handleLoginChange = (event: React.ChangeEvent) => { const { value } = event.target; setLoginForm({ ...loginForm, login: value }); setError(validateInput(value)); }; return ( Backstory Platform {guestSession && ( Guest Session Active Session ID: {guestSession.sessionId} Created: {guestSession.createdAt.toLocaleString()} )} } label="Login" /> } label="Register" /> {error && ( {error} )} {success && ( {success} )} {tabValue === 0 && ( Sign In setLoginForm({ ...loginForm, password: e.target.value })} margin="normal" required disabled={loading} variant="outlined" autoComplete='current-password' /> )} {tabValue === 1 && ( Create Account setRegisterForm({ ...registerForm, firstName: e.target.value })} required disabled={loading} variant="outlined" /> setRegisterForm({ ...registerForm, lastName: e.target.value })} required disabled={loading} variant="outlined" /> setRegisterForm({ ...registerForm, username: e.target.value })} margin="normal" required disabled={loading} variant="outlined" /> setRegisterForm({ ...registerForm, email: e.target.value })} margin="normal" required disabled={loading} variant="outlined" /> setPhone(v as E164Number)} /> {/* setRegisterForm({ ...registerForm, phone: e.target.value })} margin="normal" disabled={loading} variant="outlined" /> */} setRegisterForm({ ...registerForm, password: e.target.value })} margin="normal" required disabled={loading} variant="outlined" /> )} ); }; export { BackstoryTestApp };