From 103a9a3825538b99686d415d2314c828cd229ade Mon Sep 17 00:00:00 2001 From: Sudeepthi-Mounika Date: Wed, 29 Oct 2025 01:43:30 +0530 Subject: [PATCH 1/3] feat(scope): Updatedlogin --- app/login/page.tsx | 14 +- package-lock.json | 38 ++- package.json | 7 +- src/components/Auth.tsx | 499 ++++++++++++++-------------------------- src/lib/firebase.ts | 58 ++--- 5 files changed, 231 insertions(+), 385 deletions(-) diff --git a/app/login/page.tsx b/app/login/page.tsx index e96dbd9..b9d7faf 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -18,7 +18,7 @@ export default function LoginPage() { if (loading) { return ( -
+

Loading...

@@ -32,12 +32,14 @@ export default function LoginPage() { return null } - // Show login component for unauthenticated users + // Responsive Fullscreen login with advanced background & centering return ( -
-
- +
+
+
+ +
) -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index f2b09c3..fa777e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "dumpit", "version": "0.0.1", "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -20,8 +21,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -29,7 +30,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } }, @@ -252,6 +253,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.13.tgz", "integrity": "sha512-GfiI1JxJ7ecluEmDjPzseRXk/PX31hS7+tjgBopL7XjB2hLUdR+0FTMXy2Q3/hXezypDvU6or7gVFizDESrkXw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/component": "0.6.4", "@firebase/logger": "0.4.0", @@ -309,6 +311,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.13.tgz", "integrity": "sha512-j6ANZaWjeVy5zg6X7uiqh6lM6o3n3LD1+/SJFNs9V781xyryyZWXe+tmnWNWPkP086QfJoNkWN9pMQRqSG4vMg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/app": "0.9.13", "@firebase/component": "0.6.4", @@ -321,7 +324,8 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@firebase/auth": { "version": "0.23.2", @@ -731,6 +735,7 @@ "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -1040,6 +1045,15 @@ "node": ">=6" } }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1542,9 +1556,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.22.tgz", - "integrity": "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==", + "version": "20.19.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", + "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1575,6 +1589,7 @@ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1686,6 +1701,7 @@ "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", @@ -1917,6 +1933,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2191,6 +2208,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -2703,6 +2721,7 @@ "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4073,6 +4092,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4887,6 +4907,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5147,6 +5168,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -5159,6 +5181,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -5849,6 +5872,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 876bb42..17f8751 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -22,8 +23,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -31,7 +32,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } } diff --git a/src/components/Auth.tsx b/src/components/Auth.tsx index 7b239c3..36f18f5 100644 --- a/src/components/Auth.tsx +++ b/src/components/Auth.tsx @@ -1,353 +1,204 @@ 'use client' -import { Loader2, LogIn, UserPlus } from 'lucide-react'; -import { useState } from 'react'; -import { useAuth } from '../contexts/AuthContext'; +import Image from "next/image" +import { useState } from "react" +import { + GoogleAuthProvider, + signInWithPopup, + signInWithEmailAndPassword, + createUserWithEmailAndPassword, +} from "firebase/auth" +import { auth } from "@/lib/firebase" + +const GoogleLogo = () => ( + + + + + + + + +) export function Auth() { - const [isLogin, setIsLogin] = useState(true); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [username, setUsername] = useState(''); - const [loading, setLoading] = useState(false); - const [googleLoading, setGoogleLoading] = useState(false); - const [error, setError] = useState(''); - const [usernameError, setUsernameError] = useState(''); - const [usernameSuggestions, setUsernameSuggestions] = useState([]); - const { signIn, signUp, signInWithGoogle } = useAuth(); - - // Username validation regex: 3-20 characters, lowercase, numbers, underscores, hyphens - const usernameRegex = /^[a-z0-9_-]{3,20}$/; - - // Map Firebase error codes to user-friendly messages - const getFriendlyErrorMessage = (errorCode: string): string => { - switch (errorCode) { - case 'auth/email-already-in-use': - return 'This email is already registered. Try signing in instead.'; - case 'auth/weak-password': - return 'Password should be at least 6 characters long.'; - case 'auth/invalid-email': - return 'Please enter a valid email address.'; - case 'auth/user-not-found': - return 'No account found with this email. Please sign up first.'; - case 'auth/wrong-password': - return 'Incorrect password. Please try again.'; - case 'auth/too-many-requests': - return 'Too many failed attempts. Please try again later.'; - case 'auth/network-request-failed': - return 'Network error. Please check your connection and try again.'; - case 'auth/user-disabled': - return 'This account has been disabled. Please contact support.'; - default: - return 'An unexpected error occurred. Please try again.'; + const [loading, setLoading] = useState(false) + const [error, setError] = useState("") + const [tab, setTab] = useState("login") // login or signup + const [showPassword, setShowPassword] = useState(false) + const [email, setEmail] = useState("") + const [password, setPassword] = useState("") + const [emailTouched, setEmailTouched] = useState(false) + const [passwordTouched, setPasswordTouched] = useState(false) + + // Input validations + const emailValid = email.includes("@") && email.includes(".") + const passwordValid = password.length >= 6 + + // Email/Password login or signup + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setEmailTouched(true) + setPasswordTouched(true) + if (!emailValid || !passwordValid) { + setError("Please fix the errors above") + return } - }; - - const validateUsernameFormat = (username: string): boolean => { - return usernameRegex.test(username); - }; - - const checkUsernameUniqueness = async (username: string): Promise => { + setLoading(true) + setError("") try { - const response = await fetch('/api/check-username', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username }), - }); - - if (!response.ok) { - console.error('API error:', response.status); - return false; // Assume taken on error - } - - const data = await response.json(); - return data.available; - } catch (error) { - console.error('Error checking username uniqueness:', error); - return false; // Assume taken on error - } - }; - - const generateUsernameSuggestions = (baseUsername: string): string[] => { - const suggestions: string[] = []; - const cleanBase = baseUsername.replace(/[^a-z0-9_-]/g, '').toLowerCase(); - - // Add numbers - for (let i = 1; i <= 5; i++) { - suggestions.push(`${cleanBase}${i}`); - } - - // Add underscores with numbers - for (let i = 1; i <= 3; i++) { - suggestions.push(`${cleanBase}_${i}`); - } - - return suggestions.slice(0, 5); // Return first 5 suggestions - }; - - const handleUsernameChange = async (value: string) => { - setUsername(value); - setUsernameError(''); - setUsernameSuggestions([]); - - if (value.trim() === '') return; - - // Check format - if (!validateUsernameFormat(value)) { - setUsernameError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - return; - } - - // Check uniqueness - const isAvailable = await checkUsernameUniqueness(value); - if (!isAvailable) { - setUsernameError('This username is already taken.'); - const suggestions = generateUsernameSuggestions(value); - setUsernameSuggestions(suggestions); - } - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setError(''); - setLoading(true); - - try { - if (isLogin) { - const { error } = await signIn(email, password); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + if (tab === "login") { + await signInWithEmailAndPassword(auth, email, password) } else { - // Validate username for signup - if (!username.trim()) { - setError('Username is required'); - setLoading(false); - return; - } - - if (!validateUsernameFormat(username)) { - setError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - setLoading(false); - return; - } - - const isAvailable = await checkUsernameUniqueness(username); - if (!isAvailable) { - setError('This username is already taken. Please choose a different one.'); - setLoading(false); - return; - } - - const { error } = await signUp(email, password, username); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + await createUserWithEmailAndPassword(auth, email, password) } - } catch (err) { - console.error('Auth error:', err); - setError('An unexpected error occurred. Please try again.'); - setLoading(false); + } catch (e: any) { + setError(e.message || "Authentication failed") } - }; - + setLoading(false) + } + + // Google sign in const handleGoogleSignIn = async () => { - setError(''); - setGoogleLoading(true); - + setLoading(true) + setError("") try { - const { error } = await signInWithGoogle(); - if (error) { - setError(getFriendlyErrorMessage(error.code || '') || 'Failed to sign in with Google'); - } - // Success - auth state change will trigger navigation - } catch (err) { - console.error('Google auth error:', err); - setError('An unexpected error occurred with Google sign-in. Please try again.'); - } finally { - setGoogleLoading(false); + const provider = new GoogleAuthProvider() + await signInWithPopup(auth, provider) + } catch (e: any) { + setError("Google sign-in failed: " + (e.message || "")) } - }; + setLoading(false) + } + // UI return ( -
-
-
-
-
- D -
-

DumpIt

-

Your Personal Resource Vault

-
- -
- +
+
+ {/* Logo & Header */} +
+ + DumpIt Logo + +

DumpIt

+
Your Personal Resource Vault
+
+ {/* Tab switch */} +
+ {["login", "signup"].map(item => ( + ))} +
+ {/* Form */} +
+
+ + setEmail(e.target.value)} + onBlur={() => setEmailTouched(true)} + /> + {emailTouched && !emailValid &&
Enter a valid email
}
- - - {!isLogin && ( -
- - handleUsernameChange(e.target.value)} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all ${ - usernameError ? 'border-red-500' : 'border-gray-300' - }`} - placeholder="johndoe" - required={!isLogin} - /> - {usernameError && ( -

{usernameError}

- )} - {usernameSuggestions.length > 0 && ( -
-

Try these instead:

-
- {usernameSuggestions.map((suggestion) => ( - - ))} -
-
- )} -
- )} - -
- - setEmail(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="you@example.com" - required - /> -
- -
- - setPassword(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="••••••••" - required - minLength={6} - /> -
- - {error && ( -
- {error} -
- )} - - - -
-
- or continue with -
-
- +
+ + setPassword(e.target.value)} + onBlur={() => setPasswordTouched(true)} + /> - + {passwordTouched && !passwordValid &&
Password must be at least 6 characters
} +
+ {error && ( +
{error}
+ )} + + + {/* Social login separator and Google */} +
+ + OR + +
+ + {/* Legal/support links */} +
+ By logging in, you accept our Privacy Policy. + Need help? Contact Support
- ); + ) } diff --git a/src/lib/firebase.ts b/src/lib/firebase.ts index 01b5fbe..de062f8 100644 --- a/src/lib/firebase.ts +++ b/src/lib/firebase.ts @@ -1,52 +1,20 @@ -import { isSupported as analyticsSupported, getAnalytics } from 'firebase/analytics'; -import { initializeApp } from 'firebase/app'; -import { getAuth } from 'firebase/auth'; -import { getFirestore } from 'firebase/firestore'; +// src/lib/firebase.ts +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; -// Read config from Next.js env. These should be set in your .env as NEXT_PUBLIC_FIREBASE_* const firebaseConfig = { - apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, - authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, - projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, - storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, - appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, - measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + apiKey: "AIzaSyBMPM93qI02vLppxEOwIRF13JZqRf_kbQs", + authDomain: "dumpit-50760.firebaseapp.com", + projectId: "dumpit-50760", + storageBucket: "dumpit-50760.appspot.com", + messagingSenderId: "924635227217", + appId: "1:924635227217:web:aecaee9b8591294e274470", + measurementId: "G-FX15XKQWJN" }; -// Validate required keys -const requiredKeys = ['apiKey', 'authDomain', 'projectId', 'appId'] as const; -const missing = requiredKeys.filter((k) => !(firebaseConfig as any)[k]); -const isDummyConfig = missing.length > 0 || firebaseConfig.apiKey?.includes('Dummy') || firebaseConfig.apiKey?.includes('dummy'); +const app = initializeApp(firebaseConfig); -if (isDummyConfig) { - // eslint-disable-next-line no-console - console.warn( - '⚠️ Firebase configuration is incomplete or using dummy values. \n' + - 'Please add NEXT_PUBLIC_FIREBASE_* environment variables to your .env.local file.\n' + - 'See FIREBASE_SETUP.md for instructions.' - ); -} - -// Initialize Firebase -const app = initializeApp(firebaseConfig as any); export const auth = getAuth(app); export const db = getFirestore(app); - -// Guard analytics initialization: it will fail in SSR or if measurementId is not provided -(async () => { - try { - if (firebaseConfig.measurementId && typeof window !== 'undefined') { - const ok = await analyticsSupported(); - if (ok) { - getAnalytics(app); - } - } - } catch (err) { - // Not fatal — analytics optional, but surface the error to console for debugging - // eslint-disable-next-line no-console - console.warn('Firebase analytics not available:', err); - } -})(); - -export default app; +// REMOVE analytics initialization here! From 8129484d87f5875d7533f4fdad1c0ff4fa752d1c Mon Sep 17 00:00:00 2001 From: Sudeepthi-Mounika Date: Wed, 29 Oct 2025 23:27:33 +0530 Subject: [PATCH 2/3] feat(scope): Updatedlogin --- app/login/page.tsx | 21 +- package-lock.json | 38 ++- package.json | 7 +- public/Google.png | Bin 0 -> 2450 bytes src/components/Auth.tsx | 496 ++++++++++++++-------------------------- src/lib/firebase.ts | 58 ++--- 6 files changed, 230 insertions(+), 390 deletions(-) create mode 100644 public/Google.png diff --git a/app/login/page.tsx b/app/login/page.tsx index e96dbd9..5144e31 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -16,28 +16,25 @@ export default function LoginPage() { } }, [user, loading, router]) + // Loading spinner (fullscreen, responsive) if (loading) { return ( -
+
-
-

Loading...

+
+

Loading...

) } // If user is authenticated, don't render anything (effect will redirect) - if (user) { - return null - } + if (user) return null - // Show login component for unauthenticated users + // Main login page layout (centered) return ( -
-
- -
+
+
) -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index f2b09c3..fa777e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "dumpit", "version": "0.0.1", "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -20,8 +21,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -29,7 +30,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } }, @@ -252,6 +253,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.13.tgz", "integrity": "sha512-GfiI1JxJ7ecluEmDjPzseRXk/PX31hS7+tjgBopL7XjB2hLUdR+0FTMXy2Q3/hXezypDvU6or7gVFizDESrkXw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/component": "0.6.4", "@firebase/logger": "0.4.0", @@ -309,6 +311,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.13.tgz", "integrity": "sha512-j6ANZaWjeVy5zg6X7uiqh6lM6o3n3LD1+/SJFNs9V781xyryyZWXe+tmnWNWPkP086QfJoNkWN9pMQRqSG4vMg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/app": "0.9.13", "@firebase/component": "0.6.4", @@ -321,7 +324,8 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@firebase/auth": { "version": "0.23.2", @@ -731,6 +735,7 @@ "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -1040,6 +1045,15 @@ "node": ">=6" } }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1542,9 +1556,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.22.tgz", - "integrity": "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==", + "version": "20.19.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", + "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1575,6 +1589,7 @@ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1686,6 +1701,7 @@ "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", @@ -1917,6 +1933,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2191,6 +2208,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -2703,6 +2721,7 @@ "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4073,6 +4092,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4887,6 +4907,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5147,6 +5168,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -5159,6 +5181,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -5849,6 +5872,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 876bb42..17f8751 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -22,8 +23,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -31,7 +32,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } } diff --git a/public/Google.png b/public/Google.png new file mode 100644 index 0000000000000000000000000000000000000000..5a7b3c3f967ebc6c1e2bc78cc30ac69e3318a814 GIT binary patch literal 2450 zcmV;D32pX?P))Cy#VS!G3hoXCZ$U0FB|r| zxal(?9HK=2_4MjJE$J;76rn)qCJg+*0RHmZ|NHa)@6bYo_d|pF`rX^`h=Tp??EU4m z_WSqW@8dJ7Lf7lt^r)lw$i?q|cI{$U>{(9hPeb|B(eaRq`{Uy2IXCi!BmB~K{Lg3n z$y5BrMEk%g{p6|r*@pe!o&DpnoxJ&y%b$+2_|xG0qtmW-zlXr!$3chd^Q52dbZqsr zuk2n_=Mn()lN0x(6zfnj?OrYLbtv+elJ99O_o5j3yJu#b_Po*i;p_e1%59^vH*l>& z;kgw~s!qJLE{Lx?T()z5sQ1#hBzLVuNUmXQuC+Iye>S9OKaAONzJooI!a1FiqSLKE zjnz7tq&T00Je9Z=eMEr(00;(2L_t(|ob8)wd)h`2fCVBpjz9+z0=td_4j3DZ?KF2< zYETGHucS@V91Tfn5;vsn|NmTx%OJ#Rg?6<|I`20>Pb2ANW_M;ssvrOW0000000000 z000000000000000000005H;CscK0CD*>AVo`<=|eiTyY0MLMH1*tJZU2DvLoQFIC@YGW+Z3{?=w_|6f}zZ2s++ox z-9Q_xxJklq;JA6rVX9{83L!rSrOsXH zC~BkvI7HSSvsRj+Ks10ulrxUHoD8uQIE|S*Vl6hNs!{NB(D~?bvNiGs(vwzx!{+cq9>F$8Rmjn z$`NF~289~UI>>`yb%{THoL{?-hqQPC>&$usD6e& zgg83W$N!9j6vf*|<=lRti?&Cj9v%dRGmIQn>Olu(g_y}niV7Ls*Dt0W2fwZ}@8MvR z5wJ?39xOx06d!RR*zpaay!4!ti}~pG_t*Ud6}%e3EBCj4_z~$So2xA-BobSRpHPZQ zf%PMX5Q-bA#7Hsm zvxlNw=kVopAhr`1YK4G~q5ACi|C}p}CQA8`_yVX>fEd`sQ%V`8kSPqq1SvSU+BPuFNIrblK2X ze-(Nx!>O_%*I7Rv0dCDN!;xa@$#sQ~PhY}udy%12Ha1tiUlT66Zg0h3v9EI}JS+@1 z?&4nN^7>j>)=%je-a{I0V;d&pVM%^V$IzqRPe|Ruz6=4w9ZH5bQHD1nHGE1%aC-}3 zxN#*)!+4U8A#xc;Yq%b{Vd@V4bx0VlQK=WGViC1rl1jN))RhhlZ%1tSjE3P|l;ORI z4KLF$ypJ%%?`T%m@S88f5LFJZfgxc-Ds9{Uz>ueP7`26KL+8be zgGbFzzj`T-Fe(IZ^&KKfscofR3o-pp8VeE);w40m(&|bFxD3;hj?i7anEpn1R3v5~ zwb`ITNa@AXn8|LMPP~~HwDXim?}l#9DIF|EjJxmjo!1_McAmBf+yuFi(ySE&hX21s z`kkkrlc)Xg_jrrSQOZd=+-p*^MPiolCF2=to1yg`#uUSo1Ol}j?gr1-(Md{kCmnEq zzPp&7F6Q6yZ7p`wU7HN~lR-4mLIuVQ}rvWTpNar*nrfS$XR zna5}@cj-%hg0yB(vsk`Cv=x`?-%jIxg48B7vvmD~D5|~SixFeaNNE)8rkwXTv=?JD z;8p)z_f1i1BPcfw6+=-pdO zyv@czHO_Gyt)4OX$)vr%P>NKKzHadH)OqN9*FvAD$_-VWq{QB*oyD0-znz%|FHZ-K zhSahaM6y(Abn`PmmiqqVB1PKACKnZ){q#ao>^0n$6|3Lt8LIo2lGM)&GL_yO*c;rX zIC*fx$me_KjYhxUXmzE0-mvXF6JhUfPeqzDL~mNSOL5v$QU{<@eD5ER<}Dd*jt=N9 zp@@en&XtWw_t7yW?<6CEr2gwtT&Fk%UQF31+rqH-X{Nzhi{jAaL4~5C`eAA@CaI4u z7Agj*83B>RNrS^q&{3opMQL0%k`YWU5Q-ENRUDo+*a}isRC}MVCZ9&!%gj+$snx|n z*ojeM_4@qg+o;voUOnano`K+sOGWf z$c!j8rR8%~;@@w8ovTX)QZhuY^K+VVD{vs~@cE6$`J!aC^7xT-^!lr$H^OR3s^K@0 zlbrvi+gw4tAr-6JwPWcy-gd^rhSBX>BtI@@Lb=>;wL~NDn2vG&>a|+^@+$0{c$7+| zvSl@!{eHjMw5*E#_sS+F0000000000000000000000000000000IV+m0Xp0ZC_oR1 Qe*gdg07*qoM6N<$f{07PD*ylh literal 0 HcmV?d00001 diff --git a/src/components/Auth.tsx b/src/components/Auth.tsx index 7b239c3..96a55db 100644 --- a/src/components/Auth.tsx +++ b/src/components/Auth.tsx @@ -1,353 +1,203 @@ 'use client' -import { Loader2, LogIn, UserPlus } from 'lucide-react'; -import { useState } from 'react'; -import { useAuth } from '../contexts/AuthContext'; +import Image from "next/image" +import { useState } from "react" +import { + GoogleAuthProvider, + signInWithPopup, + signInWithEmailAndPassword, + createUserWithEmailAndPassword, +} from "firebase/auth" +import { auth } from "@/lib/firebase" export function Auth() { - const [isLogin, setIsLogin] = useState(true); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [username, setUsername] = useState(''); - const [loading, setLoading] = useState(false); - const [googleLoading, setGoogleLoading] = useState(false); - const [error, setError] = useState(''); - const [usernameError, setUsernameError] = useState(''); - const [usernameSuggestions, setUsernameSuggestions] = useState([]); - const { signIn, signUp, signInWithGoogle } = useAuth(); - - // Username validation regex: 3-20 characters, lowercase, numbers, underscores, hyphens - const usernameRegex = /^[a-z0-9_-]{3,20}$/; - - // Map Firebase error codes to user-friendly messages - const getFriendlyErrorMessage = (errorCode: string): string => { - switch (errorCode) { - case 'auth/email-already-in-use': - return 'This email is already registered. Try signing in instead.'; - case 'auth/weak-password': - return 'Password should be at least 6 characters long.'; - case 'auth/invalid-email': - return 'Please enter a valid email address.'; - case 'auth/user-not-found': - return 'No account found with this email. Please sign up first.'; - case 'auth/wrong-password': - return 'Incorrect password. Please try again.'; - case 'auth/too-many-requests': - return 'Too many failed attempts. Please try again later.'; - case 'auth/network-request-failed': - return 'Network error. Please check your connection and try again.'; - case 'auth/user-disabled': - return 'This account has been disabled. Please contact support.'; - default: - return 'An unexpected error occurred. Please try again.'; + const [loading, setLoading] = useState(false) + const [error, setError] = useState("") + const [tab, setTab] = useState("login") + const [showPassword, setShowPassword] = useState(false) + const [email, setEmail] = useState("") + const [password, setPassword] = useState("") + const [emailTouched, setEmailTouched] = useState(false) + const [passwordTouched, setPasswordTouched] = useState(false) + + const emailValid = email.includes("@") && email.includes(".") + const passwordValid = password.length >= 6 + + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setEmailTouched(true) + setPasswordTouched(true) + if (!emailValid || !passwordValid) { + setError("Please fix the errors above") + return } - }; - - const validateUsernameFormat = (username: string): boolean => { - return usernameRegex.test(username); - }; - - const checkUsernameUniqueness = async (username: string): Promise => { + setLoading(true) + setError("") try { - const response = await fetch('/api/check-username', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username }), - }); - - if (!response.ok) { - console.error('API error:', response.status); - return false; // Assume taken on error - } - - const data = await response.json(); - return data.available; - } catch (error) { - console.error('Error checking username uniqueness:', error); - return false; // Assume taken on error - } - }; - - const generateUsernameSuggestions = (baseUsername: string): string[] => { - const suggestions: string[] = []; - const cleanBase = baseUsername.replace(/[^a-z0-9_-]/g, '').toLowerCase(); - - // Add numbers - for (let i = 1; i <= 5; i++) { - suggestions.push(`${cleanBase}${i}`); - } - - // Add underscores with numbers - for (let i = 1; i <= 3; i++) { - suggestions.push(`${cleanBase}_${i}`); - } - - return suggestions.slice(0, 5); // Return first 5 suggestions - }; - - const handleUsernameChange = async (value: string) => { - setUsername(value); - setUsernameError(''); - setUsernameSuggestions([]); - - if (value.trim() === '') return; - - // Check format - if (!validateUsernameFormat(value)) { - setUsernameError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - return; - } - - // Check uniqueness - const isAvailable = await checkUsernameUniqueness(value); - if (!isAvailable) { - setUsernameError('This username is already taken.'); - const suggestions = generateUsernameSuggestions(value); - setUsernameSuggestions(suggestions); - } - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setError(''); - setLoading(true); - - try { - if (isLogin) { - const { error } = await signIn(email, password); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + if (tab === "login") { + await signInWithEmailAndPassword(auth, email, password) } else { - // Validate username for signup - if (!username.trim()) { - setError('Username is required'); - setLoading(false); - return; - } - - if (!validateUsernameFormat(username)) { - setError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - setLoading(false); - return; - } - - const isAvailable = await checkUsernameUniqueness(username); - if (!isAvailable) { - setError('This username is already taken. Please choose a different one.'); - setLoading(false); - return; - } - - const { error } = await signUp(email, password, username); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + await createUserWithEmailAndPassword(auth, email, password) } - } catch (err) { - console.error('Auth error:', err); - setError('An unexpected error occurred. Please try again.'); - setLoading(false); + } catch (e: any) { + setError(e.message || "Authentication failed") } - }; - + setLoading(false) + } + const handleGoogleSignIn = async () => { - setError(''); - setGoogleLoading(true); - + setLoading(true) + setError("") try { - const { error } = await signInWithGoogle(); - if (error) { - setError(getFriendlyErrorMessage(error.code || '') || 'Failed to sign in with Google'); - } - // Success - auth state change will trigger navigation - } catch (err) { - console.error('Google auth error:', err); - setError('An unexpected error occurred with Google sign-in. Please try again.'); - } finally { - setGoogleLoading(false); + const provider = new GoogleAuthProvider() + await signInWithPopup(auth, provider) + } catch (e: any) { + setError("Google sign-in failed: " + (e.message || "")) } - }; + setLoading(false) + } return ( -
-
-
-
-
- D -
-

DumpIt

-

Your Personal Resource Vault

-
- -
+
+
+ + DumpIt Logo + +

DumpIt

+
Your Personal Resource Vault
+
+ {["login", "signup"].map(item => ( - -
- -
- {!isLogin && ( -
- - handleUsernameChange(e.target.value)} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all ${ - usernameError ? 'border-red-500' : 'border-gray-300' - }`} - placeholder="johndoe" - required={!isLogin} - /> - {usernameError && ( -

{usernameError}

- )} - {usernameSuggestions.length > 0 && ( -
-

Try these instead:

-
- {usernameSuggestions.map((suggestion) => ( - - ))} -
-
- )} -
+ ))} +
+ +
+ + ) => setEmail(e.target.value)} + onBlur={() => setEmailTouched(true)} + /> + {emailTouched && !emailValid && ( +
Enter a valid email
)} - -
- - setEmail(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="you@example.com" - required - /> -
- -
- +
+
+ +
setPassword(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="••••••••" + className={`w-full rounded-lg border border-gray-300 p-3 pr-12 text-base bg-white + focus:outline-none focus:ring-2 focus:ring-[#2075f7] transition-all + ${passwordTouched && !passwordValid && "border-red-400 bg-red-50"}`} + placeholder="Enter password" required minLength={6} + onChange={(e: React.ChangeEvent) => setPassword(e.target.value)} + onBlur={() => setPasswordTouched(true)} /> +
- - {error && ( -
- {error} -
+ {passwordTouched && !passwordValid && ( +
Password must be at least 6 characters
)} - - - -
-
- or continue with -
-
- - - +
+ {error && ( +
{error}
+ )} + + +
+ + OR + +
+ +
+ By logging in, you accept our Privacy Policy. + Need help? Contact Support
- ); + ) } diff --git a/src/lib/firebase.ts b/src/lib/firebase.ts index 01b5fbe..de062f8 100644 --- a/src/lib/firebase.ts +++ b/src/lib/firebase.ts @@ -1,52 +1,20 @@ -import { isSupported as analyticsSupported, getAnalytics } from 'firebase/analytics'; -import { initializeApp } from 'firebase/app'; -import { getAuth } from 'firebase/auth'; -import { getFirestore } from 'firebase/firestore'; +// src/lib/firebase.ts +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; -// Read config from Next.js env. These should be set in your .env as NEXT_PUBLIC_FIREBASE_* const firebaseConfig = { - apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, - authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, - projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, - storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, - appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, - measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + apiKey: "AIzaSyBMPM93qI02vLppxEOwIRF13JZqRf_kbQs", + authDomain: "dumpit-50760.firebaseapp.com", + projectId: "dumpit-50760", + storageBucket: "dumpit-50760.appspot.com", + messagingSenderId: "924635227217", + appId: "1:924635227217:web:aecaee9b8591294e274470", + measurementId: "G-FX15XKQWJN" }; -// Validate required keys -const requiredKeys = ['apiKey', 'authDomain', 'projectId', 'appId'] as const; -const missing = requiredKeys.filter((k) => !(firebaseConfig as any)[k]); -const isDummyConfig = missing.length > 0 || firebaseConfig.apiKey?.includes('Dummy') || firebaseConfig.apiKey?.includes('dummy'); +const app = initializeApp(firebaseConfig); -if (isDummyConfig) { - // eslint-disable-next-line no-console - console.warn( - '⚠️ Firebase configuration is incomplete or using dummy values. \n' + - 'Please add NEXT_PUBLIC_FIREBASE_* environment variables to your .env.local file.\n' + - 'See FIREBASE_SETUP.md for instructions.' - ); -} - -// Initialize Firebase -const app = initializeApp(firebaseConfig as any); export const auth = getAuth(app); export const db = getFirestore(app); - -// Guard analytics initialization: it will fail in SSR or if measurementId is not provided -(async () => { - try { - if (firebaseConfig.measurementId && typeof window !== 'undefined') { - const ok = await analyticsSupported(); - if (ok) { - getAnalytics(app); - } - } - } catch (err) { - // Not fatal — analytics optional, but surface the error to console for debugging - // eslint-disable-next-line no-console - console.warn('Firebase analytics not available:', err); - } -})(); - -export default app; +// REMOVE analytics initialization here! From e7b8f7e986ccc68c9edc7e19e35033f0975f77d2 Mon Sep 17 00:00:00 2001 From: "bmanojkumar2976@gmail.com" <2400090001@kluniversity.in> Date: Sun, 23 Nov 2025 01:50:40 +0530 Subject: [PATCH 3/3] fix: resolve merge conflicts in Auth.tsx and login/page.tsx --- app/login/page.tsx | 23 +- package-lock.json | 38 ++- package.json | 7 +- public/Google.png | Bin 0 -> 2450 bytes src/components/Auth.tsx | 552 +++++++++++++++++----------------------- src/lib/firebase.ts | 58 +---- 6 files changed, 294 insertions(+), 384 deletions(-) create mode 100644 public/Google.png diff --git a/app/login/page.tsx b/app/login/page.tsx index e96dbd9..80544e3 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -10,7 +10,6 @@ export default function LoginPage() { const router = useRouter() useEffect(() => { - // If user is already authenticated, redirect to dashboard if (!loading && user) { router.push('/dashboard') } @@ -18,26 +17,16 @@ export default function LoginPage() { if (loading) { return ( -
+
-
-

Loading...

+
+

Loading...

) } - // If user is authenticated, don't render anything (effect will redirect) - if (user) { - return null - } + if (user) return null - // Show login component for unauthenticated users - return ( -
-
- -
-
- ) -} \ No newline at end of file + return +} diff --git a/package-lock.json b/package-lock.json index f2b09c3..fa777e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "dumpit", "version": "0.0.1", "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -20,8 +21,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -29,7 +30,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } }, @@ -252,6 +253,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.13.tgz", "integrity": "sha512-GfiI1JxJ7ecluEmDjPzseRXk/PX31hS7+tjgBopL7XjB2hLUdR+0FTMXy2Q3/hXezypDvU6or7gVFizDESrkXw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/component": "0.6.4", "@firebase/logger": "0.4.0", @@ -309,6 +311,7 @@ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.13.tgz", "integrity": "sha512-j6ANZaWjeVy5zg6X7uiqh6lM6o3n3LD1+/SJFNs9V781xyryyZWXe+tmnWNWPkP086QfJoNkWN9pMQRqSG4vMg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@firebase/app": "0.9.13", "@firebase/component": "0.6.4", @@ -321,7 +324,8 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@firebase/auth": { "version": "0.23.2", @@ -731,6 +735,7 @@ "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -1040,6 +1045,15 @@ "node": ">=6" } }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1542,9 +1556,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.22.tgz", - "integrity": "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==", + "version": "20.19.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", + "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1575,6 +1589,7 @@ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1686,6 +1701,7 @@ "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", @@ -1917,6 +1933,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2191,6 +2208,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -2703,6 +2721,7 @@ "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4073,6 +4092,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4887,6 +4907,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5147,6 +5168,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -5159,6 +5181,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -5849,6 +5872,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 876bb42..17f8751 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@heroicons/react": "^2.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "firebase": "^9.23.0", @@ -22,8 +23,8 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@types/node": "^20.0.0", - "@types/react": "^18.3.5", + "@types/node": "20.19.23", + "@types/react": "18.3.26", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^9.9.1", @@ -31,7 +32,7 @@ "globals": "^15.9.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", - "typescript": "^5.5.3", + "typescript": "5.9.3", "typescript-eslint": "^8.3.0" } } diff --git a/public/Google.png b/public/Google.png new file mode 100644 index 0000000000000000000000000000000000000000..5a7b3c3f967ebc6c1e2bc78cc30ac69e3318a814 GIT binary patch literal 2450 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 Qe*gdg07*qoM6N<$f{07PD*ylh literal 0 HcmV?d00001 diff --git a/src/components/Auth.tsx b/src/components/Auth.tsx index 7b239c3..54d2daa 100644 --- a/src/components/Auth.tsx +++ b/src/components/Auth.tsx @@ -1,353 +1,281 @@ 'use client' -import { Loader2, LogIn, UserPlus } from 'lucide-react'; -import { useState } from 'react'; -import { useAuth } from '../contexts/AuthContext'; +import Image from "next/image" +import { useState } from "react" +import { + GoogleAuthProvider, + signInWithPopup, + signInWithEmailAndPassword, + createUserWithEmailAndPassword, +} from "firebase/auth" +import { auth } from "@/lib/firebase" export function Auth() { - const [isLogin, setIsLogin] = useState(true); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [username, setUsername] = useState(''); - const [loading, setLoading] = useState(false); - const [googleLoading, setGoogleLoading] = useState(false); - const [error, setError] = useState(''); - const [usernameError, setUsernameError] = useState(''); - const [usernameSuggestions, setUsernameSuggestions] = useState([]); - const { signIn, signUp, signInWithGoogle } = useAuth(); + const [loading, setLoading] = useState(false) + const [error, setError] = useState("") + const [tab, setTab] = useState<"login" | "signup">("login") + const [showPassword, setShowPassword] = useState(false) + const [email, setEmail] = useState("") + const [password, setPassword] = useState("") + const [emailTouched, setEmailTouched] = useState(false) + const [passwordTouched, setPasswordTouched] = useState(false) - // Username validation regex: 3-20 characters, lowercase, numbers, underscores, hyphens - const usernameRegex = /^[a-z0-9_-]{3,20}$/; + const emailValid = email.includes("@") && email.includes(".") + const passwordValid = password.length >= 6 - // Map Firebase error codes to user-friendly messages - const getFriendlyErrorMessage = (errorCode: string): string => { - switch (errorCode) { - case 'auth/email-already-in-use': - return 'This email is already registered. Try signing in instead.'; - case 'auth/weak-password': - return 'Password should be at least 6 characters long.'; - case 'auth/invalid-email': - return 'Please enter a valid email address.'; - case 'auth/user-not-found': - return 'No account found with this email. Please sign up first.'; - case 'auth/wrong-password': - return 'Incorrect password. Please try again.'; - case 'auth/too-many-requests': - return 'Too many failed attempts. Please try again later.'; - case 'auth/network-request-failed': - return 'Network error. Please check your connection and try again.'; - case 'auth/user-disabled': - return 'This account has been disabled. Please contact support.'; - default: - return 'An unexpected error occurred. Please try again.'; - } - }; - - const validateUsernameFormat = (username: string): boolean => { - return usernameRegex.test(username); - }; - - const checkUsernameUniqueness = async (username: string): Promise => { - try { - const response = await fetch('/api/check-username', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username }), - }); - - if (!response.ok) { - console.error('API error:', response.status); - return false; // Assume taken on error - } - - const data = await response.json(); - return data.available; - } catch (error) { - console.error('Error checking username uniqueness:', error); - return false; // Assume taken on error - } - }; - - const generateUsernameSuggestions = (baseUsername: string): string[] => { - const suggestions: string[] = []; - const cleanBase = baseUsername.replace(/[^a-z0-9_-]/g, '').toLowerCase(); - - // Add numbers - for (let i = 1; i <= 5; i++) { - suggestions.push(`${cleanBase}${i}`); - } - - // Add underscores with numbers - for (let i = 1; i <= 3; i++) { - suggestions.push(`${cleanBase}_${i}`); - } - - return suggestions.slice(0, 5); // Return first 5 suggestions - }; - - const handleUsernameChange = async (value: string) => { - setUsername(value); - setUsernameError(''); - setUsernameSuggestions([]); - - if (value.trim() === '') return; - - // Check format - if (!validateUsernameFormat(value)) { - setUsernameError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - return; - } - - // Check uniqueness - const isAvailable = await checkUsernameUniqueness(value); - if (!isAvailable) { - setUsernameError('This username is already taken.'); - const suggestions = generateUsernameSuggestions(value); - setUsernameSuggestions(suggestions); + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setEmailTouched(true) + setPasswordTouched(true) + + if (!emailValid || !passwordValid) { + setError("Please fix the errors above") + return } - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setError(''); - setLoading(true); + setLoading(true) + setError("") + try { - if (isLogin) { - const { error } = await signIn(email, password); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + if (tab === "login") { + await signInWithEmailAndPassword(auth, email, password) } else { - // Validate username for signup - if (!username.trim()) { - setError('Username is required'); - setLoading(false); - return; - } - - if (!validateUsernameFormat(username)) { - setError('Username must be 3-20 characters, lowercase letters, numbers, underscores, or hyphens only.'); - setLoading(false); - return; - } - - const isAvailable = await checkUsernameUniqueness(username); - if (!isAvailable) { - setError('This username is already taken. Please choose a different one.'); - setLoading(false); - return; - } - - const { error } = await signUp(email, password, username); - if (error) { - setError(getFriendlyErrorMessage(error.code || '')); - setLoading(false); - } - // Success - auth state change will trigger navigation + await createUserWithEmailAndPassword(auth, email, password) } - } catch (err) { - console.error('Auth error:', err); - setError('An unexpected error occurred. Please try again.'); - setLoading(false); + } catch (e: any) { + setError(e.message || "Authentication failed") + } finally { + setLoading(false) } - }; - + } + const handleGoogleSignIn = async () => { - setError(''); - setGoogleLoading(true); + setLoading(true) + setError("") try { - const { error } = await signInWithGoogle(); - if (error) { - setError(getFriendlyErrorMessage(error.code || '') || 'Failed to sign in with Google'); - } - // Success - auth state change will trigger navigation - } catch (err) { - console.error('Google auth error:', err); - setError('An unexpected error occurred with Google sign-in. Please try again.'); + const provider = new GoogleAuthProvider() + await signInWithPopup(auth, provider) + } catch (e: any) { + setError("Google sign-in failed: " + (e.message || "")) } finally { - setGoogleLoading(false); + setLoading(false) } - }; + } return ( -
-
-
-
-
- D -
-

DumpIt

-

Your Personal Resource Vault

+
+
+
+
+ DumpIt Logo
+
+ +

+ DumpIt +

+ +

+ Your Personal Resource Vault +

-
+
+ {(["login", "signup"] as const).map((item) => ( - -
+ ))} +
-
- {!isLogin && ( -
- - handleUsernameChange(e.target.value)} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all ${ - usernameError ? 'border-red-500' : 'border-gray-300' - }`} - placeholder="johndoe" - required={!isLogin} - /> - {usernameError && ( -

{usernameError}

- )} - {usernameSuggestions.length > 0 && ( -
-

Try these instead:

-
- {usernameSuggestions.map((suggestion) => ( - - ))} -
-
- )} -
+ +
+ + setEmail(e.target.value)} + onBlur={() => setEmailTouched(true)} + disabled={loading} + /> + {emailTouched && !emailValid && ( +

+ Please enter a valid email address +

)} +
-
- - setEmail(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="you@example.com" - required - /> -
- -
- +
+ +
setPassword(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" - placeholder="••••••••" + className={`w-full rounded-lg border-2 p-3 pr-12 text-sm sm:text-base bg-white focus:outline-none transition-all + ${passwordTouched && !passwordValid + ? "border-red-400 bg-red-50 focus:ring-2 focus:ring-red-400" + : "border-gray-300 focus:border-[#2075f7] focus:ring-2 focus:ring-blue-200" + }`} + placeholder="Enter password" required minLength={6} + onChange={(e) => setPassword(e.target.value)} + onBlur={() => setPasswordTouched(true)} + disabled={loading} /> +
- - {error && ( -
- {error} -
+ {passwordTouched && !passwordValid && ( +

+ Password must be at least 6 characters +

)} +
- - -
-
- or continue with -
+ {error && ( +
+ {error}
- - - + )} + + + + +
+
+ OR +
+
+ + + +
+ + By logging in, you accept our{" "} + + Privacy Policy + + . + + + Need help?{" "} + + Contact Support + +
- ); + ) } diff --git a/src/lib/firebase.ts b/src/lib/firebase.ts index 01b5fbe..de062f8 100644 --- a/src/lib/firebase.ts +++ b/src/lib/firebase.ts @@ -1,52 +1,20 @@ -import { isSupported as analyticsSupported, getAnalytics } from 'firebase/analytics'; -import { initializeApp } from 'firebase/app'; -import { getAuth } from 'firebase/auth'; -import { getFirestore } from 'firebase/firestore'; +// src/lib/firebase.ts +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; -// Read config from Next.js env. These should be set in your .env as NEXT_PUBLIC_FIREBASE_* const firebaseConfig = { - apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, - authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, - projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, - storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, - appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, - measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + apiKey: "AIzaSyBMPM93qI02vLppxEOwIRF13JZqRf_kbQs", + authDomain: "dumpit-50760.firebaseapp.com", + projectId: "dumpit-50760", + storageBucket: "dumpit-50760.appspot.com", + messagingSenderId: "924635227217", + appId: "1:924635227217:web:aecaee9b8591294e274470", + measurementId: "G-FX15XKQWJN" }; -// Validate required keys -const requiredKeys = ['apiKey', 'authDomain', 'projectId', 'appId'] as const; -const missing = requiredKeys.filter((k) => !(firebaseConfig as any)[k]); -const isDummyConfig = missing.length > 0 || firebaseConfig.apiKey?.includes('Dummy') || firebaseConfig.apiKey?.includes('dummy'); +const app = initializeApp(firebaseConfig); -if (isDummyConfig) { - // eslint-disable-next-line no-console - console.warn( - '⚠️ Firebase configuration is incomplete or using dummy values. \n' + - 'Please add NEXT_PUBLIC_FIREBASE_* environment variables to your .env.local file.\n' + - 'See FIREBASE_SETUP.md for instructions.' - ); -} - -// Initialize Firebase -const app = initializeApp(firebaseConfig as any); export const auth = getAuth(app); export const db = getFirestore(app); - -// Guard analytics initialization: it will fail in SSR or if measurementId is not provided -(async () => { - try { - if (firebaseConfig.measurementId && typeof window !== 'undefined') { - const ok = await analyticsSupported(); - if (ok) { - getAnalytics(app); - } - } - } catch (err) { - // Not fatal — analytics optional, but surface the error to console for debugging - // eslint-disable-next-line no-console - console.warn('Firebase analytics not available:', err); - } -})(); - -export default app; +// REMOVE analytics initialization here!