Skip to content

Commit

Permalink
added ui feedback for invalid credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
MateoGlzAlon committed Dec 30, 2024
1 parent 120c830 commit 1f70f7d
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 104 deletions.
163 changes: 87 additions & 76 deletions app/(pages)/createProject/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import PageFrame from '@/components/generalComponents/pageFrame/PageFrame';
import { useRouter } from 'next/navigation'
import TokenManager from '@/app/apis/TokenManager';


function CreateProjectPage() {

const router = useRouter()
const router = useRouter();

const [formData, setFormData] = useState({
name: '',
Expand All @@ -19,11 +17,11 @@ function CreateProjectPage() {
type: '',
dateCreated: '',
fundingGoal: '',
//TO-DO: use userId
userId: '',
});

const [images, setImages] = useState([])
const [images, setImages] = useState([]);
const [imagePreviews, setImagePreviews] = useState([]);

const handleChange = (e) => {
const { name, value } = e.target;
Expand All @@ -32,123 +30,136 @@ function CreateProjectPage() {

const handleImageChange = (e) => {
const files = Array.from(e.target.files);
if (files.length > 3) {
if (files.length + images.length > 3) {
alert('You can upload up to 3 images only.');
return;
}
setImages(files);
const newImages = [...images, ...files];
const previews = newImages.map((file) => URL.createObjectURL(file));
setImages(newImages);
setImagePreviews(previews);
};

const handleSubmit = async (e) => {
e.preventDefault();
const updatedFormData = { ...formData, dateCreated: new Date().toISOString(), userId: TokenManager.getClaims().userId };


try {

const res = await createProjectPOST(updatedFormData, images);

router.push(`/projects/${res}`);
} catch (error) {
console.error('Error creating project with data:', updatedFormData, error);
}

};

return (
<PageFrame>
<div className="min-h-screen bg-gray-100 flex flex-col items-center p-6">
<div className="w-full max-w-lg bg-white rounded-lg shadow-lg p-8">
<h1 className="text-2xl font-bold text-center mb-6">Create a New Project</h1>

<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-gray-700 font-semibold">Project name</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter project name"
required
/>
<div className="min-h-screen flex justify-center items-center p-6">
<div className="w-full max-w-4xl bg-white rounded-lg border-4 p-8">
<h1 className="text-3xl font-bold text-center mb-6 ">New Project</h1>

<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div>
<label className="block text-gray-700 font-medium">Project Name</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter project name"
required
/>
</div>

<div>
<label className="block text-gray-700 font-medium">Location</label>
<input
type="text"
name="location"
value={formData.location}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter project location"
required
/>
</div>
</div>

<div>
<label className="block text-gray-700 font-semibold">Description</label>
<label className="block text-gray-700 font-medium">Description</label>
<textarea
name="description"
value={formData.description}
onChange={handleChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-600"
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Describe your project"
rows="4"
required
/>
</div>

<div>
<label className="block text-gray-700 font-semibold">Category</label>
<select
name="type"
value={formData.type}
onChange={handleChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-600"
required
>
<option value="">Select a category</option>
{DATA.projectTypes.map((item) => (
<option value={item} key={item}>
{item}
</option>
))}

</select>
</div>

<div>
<label className="block text-gray-700 font-semibold">Location</label>
<input
type="text"
name="location"
value={formData.location}
onChange={handleChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter project location"
required
/>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div>
<label className="block text-gray-700 font-medium">Category</label>
<select
name="type"
value={formData.type}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-600"
required
>
<option value="">Select a category</option>
{DATA.projectTypes.map((item) => (
<option value={item} key={item}>
{item}
</option>
))}
</select>
</div>

<div>
<label className="block text-gray-700 font-medium">Funding Goal</label>
<input
type="number"
name="fundingGoal"
value={formData.fundingGoal}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter fundraising goal"
required
/>
</div>
</div>

<div>
<label className="block text-gray-700 font-semibold">Funding Goal</label>
<input
type="number"
name="fundingGoal"
value={formData.fundingGoal}
onChange={handleChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-600"
placeholder="Enter fundraising goal"
required
/>
</div>

<div>
<label className="block text-gray-700 font-semibold">Project Images (Up to 3)</label>
<label className="block text-gray-700 font-medium">Project Images (Up to 3)</label>
<input
type="file"
name="images"
onChange={handleImageChange}
className="w-full px-4 py-2 border rounded-lg mt-1 focus:outline-none"
className="w-full px-4 py-3 border rounded-lg mt-2 focus:outline-none"
accept="image/*"
multiple
required
/>
<div className="flex mt-4 gap-4">
{imagePreviews.map((preview, index) => (
<img
key={index}
src={preview}
alt={`preview-${index}`}
className="w-24 h-24 object-cover rounded-lg border"
/>
))}
</div>
</div>

<div className="text-center">
<div className="text-center mt-6">
<button
type="submit"
className="px-6 py-3 bg-indigo-600 text-white font-semibold rounded-lg hover:bg-indigo-700 transition duration-300"
className="px-8 py-4 bg-indigo-600 text-white font-semibold rounded-lg hover:bg-indigo-700 transition duration-300"
>
Create Project
</button>
Expand Down
27 changes: 20 additions & 7 deletions app/(pages)/login/page.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
"use client"

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/ui/button"; // Using your existing Button component
import Image from "next/image"; // For the placeholder image
import { Button } from "@/components/ui/button";
import Image from "next/image";
import AuthAPI from "@/app/apis/AuthAPI";
import { useWebSocket } from "@/components/generalComponents/WebSocketContext";
import getProjectIdsOwnedByUserGET from "@/components/fetchComponents/GET/getProjectIdsOwnedByUserGET";
Expand All @@ -12,6 +12,9 @@ import PageFrame from "@/components/generalComponents/pageFrame/PageFrame";
export default function LoginPage() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState(""); // To store the error message
const [usernameError, setUsernameError] = useState(false); // To highlight the username input on error
const [passwordError, setPasswordError] = useState(false); // To highlight the password input on error
const { setupStompClient } = useWebSocket();
const router = useRouter();

Expand All @@ -27,6 +30,10 @@ export default function LoginPage() {

const handleSubmit = async (e) => {
e.preventDefault();
setErrorMessage("");
setUsernameError(false);
setPasswordError(false);

try {
const loginResponse = await handleLogIn(username, password);

Expand All @@ -40,15 +47,16 @@ export default function LoginPage() {
// Navigate to the homepage
router.push("/");
} else {
console.error("Login failed. Please check your credentials.");
setErrorMessage("Invalid username or password. Please try again.");
setUsernameError(true);
setPasswordError(true);
}
} catch (error) {
console.error("Error during login submission:", error.message);
}
};

return (

<div className="min-h-screen flex bg-white">
{/* Left Section with Image and Text */}
<div className="flex flex-col justify-center items-center w-1/2 bg-gray-100 p-8">
Expand Down Expand Up @@ -79,6 +87,7 @@ export default function LoginPage() {
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<form className="space-y-6" onSubmit={handleSubmit}>
{/* Username */}
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email address
Expand All @@ -92,11 +101,12 @@ export default function LoginPage() {
required
value={username}
onChange={(e) => setUsername(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className={`w-full px-3 py-2 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${usernameError ? 'border-red-500' : 'border-gray-300'}`}
/>
</div>
</div>

{/* Password */}
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
Expand All @@ -110,12 +120,15 @@ export default function LoginPage() {
required
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className={`w-full px-3 py-2 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${passwordError ? 'border-red-500' : 'border-gray-300'}`}
/>
</div>
</div>

{/* Error message */}
{errorMessage && <div className="text-red-500 text-sm mt-2">{errorMessage}</div>}

{/* Submit Button */}
<div>
<Button type="submit" variant="default" className="w-full">
Log In
Expand Down
35 changes: 26 additions & 9 deletions app/(pages)/register/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ export default function RegisterPage() {
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [emailError, setEmailError] = useState(''); // State for email-specific errors
const router = useRouter();

function handleRegister(name, email, password) {

registerUserPOST(name, email, password, "user", `https://avatar.iran.liara.run/public/boy?username=${name}`);

return registerUserPOST(name, email, password, "user", "https://raisehub-crowdfunding-bucket.s3.eu-west-3.amazonaws.com/placeholder_raisehub.png");
}

const handleSubmit = (e) => {
const handleSubmit = async (e) => {
e.preventDefault();

// Validate passwords match
Expand All @@ -31,12 +30,23 @@ export default function RegisterPage() {

// Clear error message if validation is successful
setErrorMessage('');
setEmailError(''); // Reset email error message

// Handle registration logic here (e.g., create user)
handleRegister(name, email, password);

// After successful registration, redirect to the login page
router.push('/login');
const registerResponse = await handleRegister(name, email, password);

console.log("REG RESPONSE: " + registerResponse);

if (registerResponse === 409) {
// Email is already registered
setEmailError("This email is already registered.");
} else if (registerResponse === 200) {
// Successful registration, redirect to login
router.push('/login');
} else {
// Handle other errors (e.g., server error)
setErrorMessage("An error occurred. Please try again.");
}
};

return (
Expand Down Expand Up @@ -104,9 +114,16 @@ export default function RegisterPage() {
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className={`w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm
${emailError ? 'border-red-500' : 'border-gray-300'}`}
/>
</div>
{/* Display email error message under email input */}
{emailError && (
<div className="mt-1 text-sm text-red-500">
{emailError}
</div>
)}
</div>

<div>
Expand Down
Loading

0 comments on commit 1f70f7d

Please sign in to comment.