Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 52 additions & 102 deletions frontend/app/auth/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import ErrorBoundary from '@/components/error/ErrorBoundary';
import { useToast } from '@/components/ui/ToastProvider';
import { useStellarWalletAuth } from '@/hooks/useStellarWalletAuth';
import { useAuth } from '@/hooks/useAuth';
import { useGoogleAuth } from '@/hooks/useGoogleAuth';
import { useGuestSession } from '@/hooks/useGuestSession';
import { signIn } from '@/lib/api/authApi';
import { WalletType } from '@/lib/stellar/types';
import WalletModal, { WalletType as ModalWalletType } from '@/components/ui/WalletModal';
import { useWalletModal } from '@/hooks/useWalletModal';
Expand All @@ -26,6 +29,8 @@ const SignInPage = () => {
clearError,
} = useStellarWalletAuth();
const { loginSuccess, loginFailure, setLoading } = useAuth();
const { signInWithGoogle } = useGoogleAuth();
const { startGuestSession, isStarting: isGuestStarting } = useGuestSession();
const { isOpen: isWalletModalOpen, openModal: openWalletModal, closeModal: closeWalletModal } = useWalletModal();
const [formData, setFormData] = useState({
username: '',
Expand Down Expand Up @@ -78,123 +83,59 @@ const SignInPage = () => {
}

try {
const response = await fetch('http://localhost:3000/auth/signIn', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: formData.username,
password: formData.password
}),
});

// Checking if response is ok before trying to parse JSON
if (!response.ok) {
try {
const errorData = await response.json();
// Handle specific error messages from server
if (response.status === 401) {
const errorMsg = 'Invalid email or password.';
showError('Login Failed', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else if (response.status === 404) {
const errorMsg = 'Account not found.';
showError('Account Not Found', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else if (response.status === 400) {
const errorMsg = errorData.message || 'Invalid input.';
showError('Invalid Input', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else if (response.status >= 500) {
const errorMsg = 'Server error. Please try again later.';
showError('Server Error', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else {
const errorMsg = errorData.message || 'Login failed. Please try again.';
showError('Login Failed', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
}
} catch {
// If response isn't JSON, use status text or default message
if (response.status === 401) {
const errorMsg = 'Invalid email or password.';
showError('Login Failed', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else if (response.status === 404) {
const errorMsg = 'Account not found.';
showError('Account Not Found', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} else {
const errorMsg = `Login failed: ${response.statusText || 'Please try again.'}`;
showError('Login Failed', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
}
}
setIsLoading(false);
setLoading(false);
return;
}

// Parse JSON only if response is ok
const data = await response.json();
const data = await signIn(formData.username, formData.password);

if (data.accessToken && data.refreshToken) {
// Update Redux state with both tokens
const user = {
id: data.user?.id || formData.username,
const user = data.user ?? {
id: formData.username,
email: formData.username,
username: data.user?.username || formData.username.split('@')[0],
username: formData.username.split('@')[0],
};

loginSuccess(user, data.accessToken, data.refreshToken);

// Show success toast
showSuccess('Login Successful', 'Welcome back!');
setIsLoading(false);
setLoading(false);

// Redirect to dashboard
router.push('/dashboard');
} else {
const errorMsg = 'Invalid response from server. Please try again.';
showError('Invalid Response', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
return;
}
} catch (error) {
console.error('Sign in error:', error);
const errorMsg = 'Network error.';
showError('Network Error', errorMsg);

const errorMsg = 'Invalid response from server. Please try again.';
showError('Invalid Response', errorMsg);
loginFailure(errorMsg);
setIsLoading(false);
setLoading(false);
} catch (error) {
const message =
error instanceof Error ? error.message : 'Login failed. Please try again.';
const isNetwork = message === 'Unexpected error occurred' || /network/i.test(message);
showError(isNetwork ? 'Network Error' : 'Login Failed', message);
loginFailure(message);
} finally {
setIsLoading(false);
setLoading(false);
}
};

const handleGoogleSignIn = () => {
showInfo('Google Sign-In', 'Redirecting to Google authentication...');
window.location.href = "http://localhost:3000/auth/google-authentication";
const handleGoogleSignIn = async () => {
try {
showInfo('Google Sign-In', 'Opening Google authentication...');
await signInWithGoogle();
showSuccess('Login Successful', 'Welcome back!');
router.push('/dashboard');
} catch (error) {
const message =
error instanceof Error ? error.message : 'Google sign-in failed';
showError('Google Sign-In Failed', message);
}
};

const handleGuestPlay = async () => {
try {
await startGuestSession();
showSuccess('Guest session started', 'You have 15 minutes to browse puzzles.');
router.push('/puzzles');
} catch (error) {
const message =
error instanceof Error ? error.message : 'Could not start a guest session';
showError('Guest Play Failed', message);
}
};

const handleWalletSelect = async (walletType: ModalWalletType) => {
Expand Down Expand Up @@ -339,6 +280,15 @@ const SignInPage = () => {
{isLoggingIn && 'Verifying...'}
{!isConnecting && !isSigning && !isLoggingIn && 'Connect Wallet'}
</button>

<button
type="button"
onClick={handleGuestPlay}
disabled={isGuestStarting}
className="w-full h-12 border-2 border-slate-600 text-slate-200 rounded-lg hover:bg-slate-800/80 transition-colors disabled:opacity-50"
>
{isGuestStarting ? 'Starting guest session...' : 'Continue as guest'}
</button>
</div>

{/* Terms and Privacy */}
Expand Down
163 changes: 23 additions & 140 deletions frontend/app/auth/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Image from "next/image";
import ErrorBoundary from "@/components/error/ErrorBoundary";
import { useToast } from "@/components/ui/ToastProvider";
import { useStellarWalletAuth } from "@/hooks/useStellarWalletAuth";
import { useGoogleAuth } from "@/hooks/useGoogleAuth";
import { register } from "@/lib/api/authApi";
import { WalletType } from "@/lib/stellar/types";


Expand All @@ -23,6 +25,7 @@ const SignUpPage = () => {
connectAndLogin,
clearError,
} = useStellarWalletAuth();
const { signInWithGoogle } = useGoogleAuth();
const [formData, setFormData] = useState({
username: "",
fullName: "",
Expand Down Expand Up @@ -115,156 +118,36 @@ const SignUpPage = () => {
}

try {
// Format request body to match server expectations
const requestBody = {
await register({
email: formData.email,
username: formData.username,
fullname: formData.fullName, // Server expects lowercase 'n'
fullname: formData.fullName,
password: formData.password,
userRole: "user", // Default role
provider: "local", // Local registration
};

console.log("Sending request with data:", requestBody); // Debug log

const response = await fetch(
"http://localhost:3000/users",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
},
);
passwordConfirm: formData.password,
});

// Log response details for debugging
console.log("Response status:", response.status);
console.log("Response headers:", response.headers);

// Checking if response is ok before trying to parse JSON
if (!response.ok) {
let errorMessage = "Registration failed. Please try again.";

try {
const errorData = await response.json();
console.log("Error response data:", errorData); // Debug log

// Safely extract error message
if (typeof errorData === "object" && errorData !== null) {
if (typeof errorData.message === "string") {
errorMessage = errorData.message;
} else if (typeof errorData.error === "string") {
errorMessage = errorData.error;
} else if (
Array.isArray(errorData.errors) &&
errorData.errors.length > 0
) {
errorMessage = errorData.errors[0];
}
}

// Handle specific error cases
if (response.status === 409) {
showError(
"Account Already Exists",
errorMessage ||
"User already exists with this email or username.",
);
} else if (response.status === 400) {
showError(
"Invalid Input",
errorMessage ||
"Invalid input data. Please check your information.",
);
} else if (response.status >= 500) {
showError("Server Error", "Server error. Please try again later.");
} else {
showError("Registration Failed", errorMessage);
}
} catch (parseError) {
console.error("Error parsing response:", parseError);
// If response isn't JSON, use status-based messages
if (response.status === 409) {
showError(
"Account Already Exists",
"An account with this email or username already exists.",
);
} else if (response.status === 400) {
showError(
"Invalid Input",
"Please check your input and try again.",
);
} else {
showError(
"Registration Failed",
`Error ${response.status}: ${response.statusText || "Please try again."}`,
);
}
}
setIsLoading(false);
return;
}

// Parse JSON only if response is ok
const data = await response.json();
console.log("Success response data:", data); // Debug log

if (
data.accessToken ||
data.id ||
data.email ||
data.message === "User created successfully" ||
data.success
) {
// If we get a token, store it
if (data.accessToken) {
try {
localStorage.setItem("accessToken", data.accessToken);
} catch (storageError) {
console.warn("Could not save token to localStorage:", storageError);
}
}

// Show success toast
showSuccess("Registration Successful", "Welcome to Mind Block!");

// Redirect to signin page or dashboard based on whether we got a token
setTimeout(() => {
if (data.accessToken) {
router.push("/dashboard");
} else {
router.push("/auth/signin");
}
}, 1000); // Small delay to show success message
} else {
showError(
"Invalid Response",
"Invalid response from server. Please try again.",
);
}
showSuccess("Account created", "You can now sign in.");
router.push("/auth/signin");
} catch (error) {
console.error("Sign up error:", error);
if (error instanceof TypeError && error.message.includes("fetch")) {
showError(
"Network Error",
"Could not connect to the server. Please check your internet connection and try again.",
);
} else {
showError(
"Network Error",
"An unexpected error occurred. Please try again.",
);
}
const message =
error instanceof Error ? error.message : "Registration failed. Please try again.";
showError("Registration Failed", message);
} finally {
setIsLoading(false);
}
};

const handleGoogleSignUp = () => {
showInfo("Google Sign-Up", "Redirecting to Google authentication...");
window.location.href =
"http://localhost:3000/auth/google-authentication";
const handleGoogleSignUp = async () => {
try {
showInfo("Google Sign-Up", "Opening Google authentication...");
await signInWithGoogle();
showSuccess("Login Successful", "Welcome to Mind Block!");
router.push("/dashboard");
} catch (error) {
const message =
error instanceof Error ? error.message : "Google sign-up failed";
showError("Google Sign-Up Failed", message);
}
};

const handleWalletConnect = async () => {
Expand Down
Loading
Loading