diff --git a/src/App.css b/src/App.css
index c829a2b..7f31b0a 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,13 +1,13 @@
-button:not(.toggle-btn):focus-visible {
+button:not(.toggle-btn):not(.delete-btn):focus-visible {
outline: solid 4px var(--color-persianblue);
outline-offset: 8px;
}
-button:not(.toggle-btn):hover {
+button:not(.toggle-btn):not(.delete-btn):hover {
background-color: var(--color-zinc);
color: white;
cursor: pointer;
}
-button:not(.toggle-btn):active {
+button:not(.toggle-btn):not(.delete-btn):active {
background-color: var(--color-persianblue);
color: white;
}
@@ -17,4 +17,4 @@ button.active {
}
button.active:hover {
background-color: var(--color-persianblue);
-}
\ No newline at end of file
+}
diff --git a/src/components/Baseinput.jsx b/src/components/Baseinput.jsx
index cb5ecbf..5a388fc 100644
--- a/src/components/Baseinput.jsx
+++ b/src/components/Baseinput.jsx
@@ -33,7 +33,7 @@ function Baseinput({
block w-full h-11 px-4 py-2
bg-white text-black
${inputClassName}
- disabled:bg-gray-100 disabled:text-gray-500`}
+ disabled:bg-white disabled:text-eerie`}
aria-invalid={ariaInvalid}
aria-describedby={ariaDescribedBy}
disabled={disabled}
diff --git a/src/components/Button.jsx b/src/components/Button.jsx
index fdda22f..c077c74 100644
--- a/src/components/Button.jsx
+++ b/src/components/Button.jsx
@@ -2,53 +2,68 @@ import { useNavigate } from 'react-router-dom';
import { tv } from 'tailwind-variants/lite';
const buttonVariants = tv({
- // base styles for all buttons
- base: 'font-poppins flex items-center justify-center drop-shadow-[0_4px_4px_rgba(0,0,0,0.25)]',
- // all button variants
- variants: {
- size: {
- sm: 'h-12 w-[162px] text-base font-semibold rounded-lg lg:h-14 lg:w-[220px] lg:text-xl',
- md: 'h-11 w-[218px] text-base font-semibold rounded-lg lg:h-14 lg:w-[286px] lg:text-xl xl:h-16 xl:w-[327px] xl:text-2xl',
- lg: 'h-11 w-[345px] text-base font-medium rounded-md lg:w-[501px]',
- circ: 'h-11 w-11 text-2xl rounded-full'
- },
- color: {
- primary: 'bg-eerie text-white border-1 border-eerie',
- secondary: 'bg-white text-eerie border-1 border-eerie',
- gradient: 'bg-gradient-to-b from-electricgreen to-persianblue text-white'
- }
+ // base styles for all buttons
+ base: 'font-poppins flex items-center justify-center drop-shadow-[0_4px_4px_rgba(0,0,0,0.25)]',
+ // all button variants
+ variants: {
+ size: {
+ sm: 'h-12 w-[162px] text-base font-semibold rounded-lg lg:h-14 lg:w-[220px] lg:text-xl',
+ md: 'h-11 w-[218px] text-base font-semibold rounded-lg lg:h-14 lg:w-[286px] lg:text-xl xl:h-16 xl:w-[327px] xl:text-2xl',
+ lg: 'h-11 w-[345px] text-base font-medium rounded-md lg:w-[501px]',
+ circ: 'h-11 w-11 text-2xl rounded-full',
},
- // default button styles if no specified props
- defaultVariants: {
- size: 'sm',
- color: 'primary'
+ color: {
+ primary: 'bg-eerie text-white border-1 border-eerie',
+ secondary: 'bg-white text-eerie border-1 border-eerie',
+ gradient: 'bg-gradient-to-b from-electricgreen to-persianblue text-white',
},
- // conditional style cases for specific prop combinations
- compoundVariants: [
- // remove drop shadow and lower font weight for user selection button
- {
- color: 'secondary',
- size: 'md',
- className: 'drop-shadow-none !font-normal'
- }
- ]
+ },
+ // default button styles if no specified props
+ defaultVariants: {
+ size: 'sm',
+ color: 'primary',
+ },
+ // conditional style cases for specific prop combinations
+ compoundVariants: [
+ // remove drop shadow and lower font weight for user selection button
+ {
+ color: 'secondary',
+ size: 'md',
+ className: 'drop-shadow-none !font-normal',
+ },
+ ],
});
-export default function Button({ size, color, label, onClick, isActive, to, ...props }) {
- let navigate = useNavigate();
+export default function Button({
+ size,
+ color,
+ label,
+ onClick,
+ isActive,
+ to,
+ ...props
+}) {
+ let navigate = useNavigate();
- function handleClick(){
- if (to){
- navigate(to);
- } else {
- onClick();
- }
+ function handleClick() {
+ if (to) {
+ navigate(to);
+ } else {
+ onClick();
}
+ }
- return (
-
- );
-}
\ No newline at end of file
+ return (
+
+ );
+}
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index f67b214..eb185bf 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -9,6 +9,10 @@ import { HiMenu } from 'react-icons/hi';
//components
import MobileMenu from './MobileMenu';
+//firebase
+import { auth } from '../firebase';
+import { signOut } from 'firebase/auth';
+
function Navbar() {
const [isMenuOpen, setIsMenuOpen] = useState(false); // mobile menu state
const [isAuthenticated, setIsAuthenticated] = useState(false); // user authentication state
@@ -27,10 +31,15 @@ function Navbar() {
const toggleMenu = () => setIsMenuOpen(!isMenuOpen);
- const handleLogout = () => {
- localStorage.removeItem('authToken');
- setIsAuthenticated(false);
- navigate('/logout');
+ const handleLogout = async () => {
+ try {
+ await signOut(auth);
+ localStorage.removeItem('authToken');
+ setIsAuthenticated(false);
+ navigate('/logout');
+ } catch (error) {
+ console.error('Logout failed:', error);
+ }
};
// navbar for NON-authenticated user
@@ -123,7 +132,7 @@ function Navbar() {
Detox Challenge
-
+
-
+
},
{ path: 'journal', element: },
{ path: 'logout', element: },
+ { path: 'profile', element: },
{ path: 'error', element: },
{ path: 'challenges', element: },
- ],
+ ],
},
{
path: '*',
@@ -42,4 +44,4 @@ createRoot(document.getElementById('root')).render(
-);
\ No newline at end of file
+);
diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx
index 3861d2e..fdd4c0a 100644
--- a/src/pages/Login.jsx
+++ b/src/pages/Login.jsx
@@ -3,6 +3,8 @@ import Passwordinput from '../components/PasswordInput';
import Button from '../components/Button';
import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
+import { signInWithEmailAndPassword } from 'firebase/auth';
+import { auth } from '../firebase';
function Login() {
const navigate = useNavigate();
@@ -10,20 +12,40 @@ function Login() {
const [isValidEmail, setisValidEmail] = useState(false);
const [isValidPassword, setisValidPassword] = useState(false);
const [formSubmitMessage, setFormSubmitMessage] = useState('');
+ const buttonStyles =
+ 'h-11 w-[345px] text-base font-medium rounded-md lg:w-[501px] bg-eerie text-white border-1 border-eerie';
const setFormValue = (fieldName, value) => {
setFormValues((prevValue) => ({ ...prevValue, [fieldName]: value }));
};
- const handleSubmit = (e) => {
+ const handleSubmit = async (e) => {
e.preventDefault();
if (!isValidEmail || !isValidPassword) {
setFormSubmitMessage('Fill form properly');
} else {
- localStorage.setItem('authToken', 'my-auth-token');
+ //localStorage.setItem('authToken', 'my-auth-token');
const loginFormData = new FormData();
for (const key in formValues) {
loginFormData.append(key, formValues[key]);
}
- navigate('/dashboard');
+ try {
+ const { user } = await signInWithEmailAndPassword(
+ auth,
+ formValues.loginEmail,
+ formValues.loginPassword
+ );
+ console.log('Logged in user is: ', user.uid);
+ localStorage.setItem('authToken', user.uid);
+ navigate('/dashboard');
+ } catch (error) {
+ if (error.code === 'auth/user-not-found') {
+ setFormSubmitMessage('No user found with this email');
+ } else if (error.code === 'auth/wrong-password') {
+ setFormSubmitMessage('No usr found with this email');
+ } else {
+ setFormSubmitMessage('Login failed. Try again.');
+ }
+ }
+
console.log('Login Submission Data:', loginFormData);
}
};
@@ -84,7 +106,9 @@ function Login() {
)}
-
+
New user?{' '}
@@ -100,4 +124,4 @@ function Login() {
);
}
-export default Login;
\ No newline at end of file
+export default Login;
diff --git a/src/pages/Onboarding.jsx b/src/pages/Onboarding.jsx
index dc68c7c..f10e6f1 100644
--- a/src/pages/Onboarding.jsx
+++ b/src/pages/Onboarding.jsx
@@ -1,14 +1,45 @@
import Button from '../components/Button';
import { useEffect, useState } from 'react';
+import { doc, setDoc } from 'firebase/firestore';
+import { auth, db } from '../firebase';
+import { useNavigate } from 'react-router-dom';
export default function Onboarding() {
const [selectedConcerns, setSelectedConcerns] = useState([]);
-
+ const navigate = useNavigate();
// log the selectedConcerns after the array changes to update automatically
useEffect(() => {
console.log('Updated Concerns:', selectedConcerns);
}, [selectedConcerns]);
+ async function handleNext() {
+ if (!auth.currentUser) {
+ return;
+ }
+ const uid = auth.currentUser.uid;
+ await setDoc(
+ doc(db, 'users', uid),
+ { onboardingConcerns: selectedConcerns },
+ { merge: true }
+ )
+ .then(() => {
+ console.log('Onboarding data for profile is saved');
+ navigate('/dashboard');
+ })
+ .catch((error) => console.error('Error saving data:', error));
+ }
+ async function handleSkip() {
+ const uid = auth.currentUser.uid;
+ await setDoc(
+ doc(db, 'users', uid),
+ {
+ onboardingConcerns: [],
+ },
+ { merge: true }
+ );
+ navigate('/dashboard');
+ }
+
// function for toggling active state and storing the user's selected concern
function toggleConcern(concern) {
// if the clicked concern is not selectedConcerns, setSelectedConcerns
@@ -20,7 +51,7 @@ export default function Onboarding() {
} else {
// log the deselection
console.log(`${concern} button deselected!`);
- setSelectedConcerns(selectedConcerns.filter(item => item !== concern));
+ setSelectedConcerns(selectedConcerns.filter((item) => item !== concern));
}
}
@@ -39,53 +70,58 @@ export default function Onboarding() {
{/* button quiz grid */}
-
{/* next and skip buttons */}
-
-
+
+
diff --git a/src/pages/Profile.jsx b/src/pages/Profile.jsx
new file mode 100644
index 0000000..8a337c7
--- /dev/null
+++ b/src/pages/Profile.jsx
@@ -0,0 +1,107 @@
+import Button from '../components/Button';
+import Baseinput from '../components/Baseinput';
+import { useState, useEffect } from 'react';
+import { signOut, onAuthStateChanged } from 'firebase/auth';
+import { auth, db } from '../firebase';
+import { doc, getDoc } from 'firebase/firestore';
+import { useNavigate } from 'react-router-dom';
+
+function Profile() {
+ const [profileData, setProfileData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const navigate = useNavigate();
+ let inputClassName =
+ 'rounded-none border-0 border-b border-eerie bg-transparent focus:border-stone-600 focus:ring-0';
+ useEffect(() => {
+ const unsubscribe = onAuthStateChanged(auth, async (user) => {
+ if (user) {
+ const docRef = doc(db, 'users', user.uid);
+ const docSnap = await getDoc(docRef);
+ if (docSnap.exists()) setProfileData(docSnap.data());
+ setLoading(false);
+ } else {
+ setProfileData(null);
+ setLoading(false);
+ navigate('/logout');
+ }
+ });
+ return () => unsubscribe();
+ }, []);
+ const handleLogout = async () => {
+ await signOut(auth);
+ localStorage.removeItem('authToken');
+ navigate('/logout');
+ };
+ if (loading) return Loading
;
+ return (
+
+ );
+}
+
+export default Profile;
diff --git a/src/pages/Signup.jsx b/src/pages/Signup.jsx
index a7adab9..80b2649 100644
--- a/src/pages/Signup.jsx
+++ b/src/pages/Signup.jsx
@@ -3,6 +3,9 @@ import Passwordinput from '../components/PasswordInput';
import Button from '../components/Button';
import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
+import { createUserWithEmailAndPassword } from 'firebase/auth';
+import { auth, db } from '../firebase';
+import { doc, setDoc } from 'firebase/firestore';
function Signup() {
const navigate = useNavigate();
@@ -10,20 +13,35 @@ function Signup() {
const [isValidEmail, setisValidEmail] = useState(false);
const [isValidPassword, setisValidPassword] = useState(false);
const [formSubmitMessage, setFormSubmitMessage] = useState('');
+ const buttonStyles =
+ 'h-11 w-[345px] text-base font-medium rounded-md lg:w-[501px] bg-eerie text-white border-1 border-eerie';
const setFormValue = (fieldName, value) => {
setFormValues((prevValue) => ({ ...prevValue, [fieldName]: value }));
};
- const handleSubmit = (e) => {
+ const handleSubmit = async (e) => {
e.preventDefault();
+
if (!isValidEmail || !isValidPassword) {
setFormSubmitMessage('Fill form properly');
} else {
+ const userCredential = await createUserWithEmailAndPassword(
+ auth,
+ formValues.signupEmail,
+ formValues.signupPassword
+ );
+ const uid = userCredential.user.uid;
+
const signupFormData = new FormData();
for (const key in formValues) {
signupFormData.append(key, formValues[key]);
}
console.log('Submitting Signup Data:', signupFormData);
- localStorage.setItem('authToken', 'my-auth-token');
+ await setDoc(doc(db, 'users', uid), {
+ email: formValues.signupEmail,
+ password: formValues.signupPassword,
+ onboardingConcerns: [],
+ });
+ localStorage.setItem('authToken', uid);
navigate('/onboarding');
}
};
@@ -75,7 +93,9 @@ function Signup() {
)}
-
+
+ Complete Sign up
+