Skip to content
Open
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
25 changes: 24 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ import PostPage from './pages/PostPage.tsx'
import CreateCommunityPage from './pages/CreateCommunityPage.tsx'
import {CommunityPage} from './pages/CommunityPage.tsx'
import { CommunitiesPage } from './pages/CommunitiesPage.tsx'
feat/auth-security-validation-128
import Register from './pages/Register.tsx' // Import the new page

function App() {
return (
<>
<div className="min-h-screen bg-background">
<Navbar />
<main className="container mx-auto px-4 py-6">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/register" element={<Register />} /> {/* New Security-focused route */}
<Route path="/create" element={<CreatePostPage />} />
<Route path="/post/:id" element={<PostPage />} />
<Route path="/communities/create" element={<CreateCommunityPage />} />
<Route path="/communities" element={<CommunitiesPage />} />
<Route path="/communities/:id" element={<CommunityPage />} />
</Routes>
</main>
</div>
</>

import MessagesPage from './pages/MessagesPage.tsx'
import EventsPage from './pages/EventsPage.tsx'
import EventDetailPage from './pages/EventDetailPage.tsx'
Expand Down Expand Up @@ -58,7 +80,8 @@ function App() {
<Footer />
<ScrollToTop />
</div>

)
}

export default App
export default App
106 changes: 106 additions & 0 deletions src/pages/Register.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { supabase } from "../supabase-client";
import { AlertCircle, CheckCircle2 } from "lucide-react";

const Register = () => {
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState<Record<string, string>>({});
const [serverError, setServerError] = useState("");

const [formData, setFormData] = useState({
fullName: "",
email: "",
password: "",
});

const validate = () => {
const newErrors: Record<string, string> = {};
if (formData.fullName.length < 2) newErrors.fullName = "Name must be at least 2 characters.";
if (!/\S+@\S+\.\S+/.test(formData.email)) newErrors.email = "Valid email is required.";
if (formData.password.length < 6) newErrors.password = "Password must be at least 6 characters.";

setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};

const handleRegister = async (e: React.FormEvent) => {
e.preventDefault();
setServerError("");
if (!validate()) return;

setLoading(true);
const { data, error } = await supabase.auth.signUp({
email: formData.email,
password: formData.password,
options: {
data: { full_name: formData.fullName }
}
});

if (error) {
// Handles the "Duplicate Check" requirement (400 error equivalent)
setServerError(error.message);
setLoading(false);
} else {
// Standardized success feedback
alert("Registration successful! Please check your email for verification.");
navigate("/");
}
};

return (
<div className="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold mb-6 text-center">Create Account</h2>

{serverError && (
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded-md flex items-center gap-2">
<AlertCircle size={18} /> {serverError}
</div>
)}

<form onSubmit={handleRegister} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700">Full Name</label>
<input
type="text"
className={`w-full p-2 border rounded ${errors.fullName ? 'border-red-500' : 'border-gray-300'}`}
onChange={(e) => setFormData({...formData, fullName: e.target.value})}
/>
{errors.fullName && <p className="text-red-500 text-xs mt-1">{errors.fullName}</p>}
</div>

<div>
<label className="block text-sm font-medium text-gray-700">Email Address</label>
<input
type="email"
className={`w-full p-2 border rounded ${errors.email ? 'border-red-500' : 'border-gray-300'}`}
onChange={(e) => setFormData({...formData, email: e.target.value})}
/>
{errors.email && <p className="text-red-500 text-xs mt-1">{errors.email}</p>}
</div>

<div>
<label className="block text-sm font-medium text-gray-700">Password (Min 6 chars)</label>
<input
type="password"
className={`w-full p-2 border rounded ${errors.password ? 'border-red-500' : 'border-gray-300'}`}
onChange={(e) => setFormData({...formData, password: e.target.value})}
/>
{errors.password && <p className="text-red-500 text-xs mt-1">{errors.password}</p>}
</div>

<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700 disabled:opacity-50"
>
{loading ? "Registering..." : "Register"}
</button>
</form>
</div>
);
};

export default Register;