Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 0 additions & 8 deletions Backend/.env-example

This file was deleted.

2 changes: 1 addition & 1 deletion Backend/app/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class User(Base):
id = Column(String, primary_key=True, default=generate_uuid)
username = Column(String, unique=True, nullable=False)
email = Column(String, unique=True, nullable=False)
password_hash = Column(Text, nullable=False)
password_hash = Column(Text, nullable=False) # Restored for now
role = Column(String, nullable=False) # 'creator' or 'brand'
profile_image = Column(Text, nullable=True)
bio = Column(Text, nullable=True)
Expand Down
2 changes: 1 addition & 1 deletion Backend/app/routes/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def create_user(user: UserCreate):
"id": user_id,
"username": user.username,
"email": user.email,
"password_hash": user.password_hash,
"password_hash": user.password_hash,
"role": user.role,
"profile_image": user.profile_image,
"bio": user.bio,
Expand Down
13 changes: 10 additions & 3 deletions Frontend/src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ReactNode,
useEffect,
} from "react";
import { useNavigate } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
import { supabase, User } from "../utils/supabase";

interface AuthContextType {
Expand All @@ -25,6 +25,7 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
const [user, setUser] = useState<User | null>(null);
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const navigate = useNavigate();
const location = useLocation();

useEffect(() => {
supabase.auth.getSession().then(({ data }) => {
Expand All @@ -34,14 +35,20 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
const { data: listener } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user || null);
if (session?.user) {
// Only redirect to dashboard if not on /reset-password and not during password recovery

if (
session?.user &&
location.pathname !== "/reset-password" &&
event !== "PASSWORD_RECOVERY"
) {
navigate("/dashboard");
}
}
);

return () => listener.subscription.unsubscribe();
}, []);
}, [location.pathname, navigate]);

const login = () => {
setIsAuthenticated(true);
Expand Down
37 changes: 32 additions & 5 deletions Frontend/src/pages/ForgotPassword.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { useState } from "react";
import { Link } from "react-router-dom";
import { ArrowLeft, Check, Rocket } from "lucide-react";
import { supabase } from "../utils/supabase";

export default function ForgotPasswordPage() {
const [email, setEmail] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [error, setError] = useState("");
const [showSignupPrompt, setShowSignupPrompt] = useState(false);

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsLoading(true);
setError("");
setShowSignupPrompt(false);

try {
// In a real app, you would call your auth API here
await new Promise((resolve) => setTimeout(resolve, 1500));
// Check if the email exists in the users table before sending a reset link
const { data: users, error: userError } = await supabase
.from("users")
.select("id")
.eq("email", email)
.maybeSingle();
if (userError) throw userError;
if (!users) {
// If the email does not exist, prompt the user to sign up
setShowSignupPrompt(true);
setIsLoading(false);
return;
}
// Send the password reset email using Supabase Auth
const { error } = await supabase.auth.resetPasswordForEmail(email, {
Comment on lines +24 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Regarding the email lookup in the users table and the subsequent call to resetPasswordForEmail:

  1. Case Sensitivity: Supabase Auth typically normalizes emails to lowercase. If your users table stores emails as they are entered, or if you want to ensure case-insensitive lookup matching Supabase's behavior, it's advisable to convert the input email to lowercase before querying and before passing to resetPasswordForEmail. This would be .eq("email", email.toLowerCase()) and supabase.auth.resetPasswordForEmail(email.toLowerCase(), ...).
  2. Placeholder Text: The current placeholder you@example.com (CASE sensitive) (line 129) could be confusing if Supabase Auth itself handles emails case-insensitively. Aligning the logic (e.g., by using toLowerCase()) would make the UX more consistent.

Could you clarify if emails are stored/handled case-sensitively throughout, or if normalizing to lowercase here would be more appropriate?

redirectTo: window.location.origin + "/reset-password"
});
if (error) throw error;
setIsSubmitted(true);
} catch (err) {
setError("Something went wrong. Please try again.");
} catch (err: any) {

setError(err.message || "Something went wrong. Please try again.");
} finally {
setIsLoading(false);
}
Expand Down Expand Up @@ -88,6 +108,12 @@ export default function ForgotPasswordPage() {
</div>
)}

{showSignupPrompt && (
<div className="mb-6 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg text-yellow-700 dark:text-yellow-400 text-sm animate-[pulse_1s_ease-in-out]">
No account found with this email. <Link to="/signup" className="underline text-purple-600">Sign up?</Link>
</div>
)}

<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-2">
<label
Expand All @@ -103,7 +129,8 @@ export default function ForgotPasswordPage() {
onChange={(e) => setEmail(e.target.value)}
required
className="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-400 focus:border-transparent bg-white dark:bg-gray-700 text-gray-900 dark:text-white transition-all duration-200"
placeholder="you@example.com"
// Email is case sensitive for password reset
placeholder="you@example.com (CASE sensitive)"
/>
</div>

Expand Down
Loading