From dc99d43f610275c72290f8a81281cb27746ca72d Mon Sep 17 00:00:00 2001 From: ismailbenlaredj Date: Mon, 27 Nov 2023 09:24:12 +0100 Subject: [PATCH] fix(hotfix): pages --- src/components/navbar/Navbar.jsx | 17 +- src/components/profile/AvatarUploadImage.jsx | 16 +- src/components/profile/Profile.jsx | 130 ++++----- src/components/signup/SignUpForm.jsx | 251 ------------------ src/constants/inputs.js | 88 ++++++ src/lib/firebase/firestoreFunctions.js | 17 +- src/pages/account/index.jsx | 66 +++-- src/pages/add-item/index.jsx | 54 +++- src/pages/addItemPage/index.jsx | 227 ---------------- src/pages/{ => auth}/reset-password/index.jsx | 0 src/pages/auth/signin/index.jsx | 20 ++ src/pages/auth/signup/index.jsx | 92 +++++++ src/pages/login/index.jsx | 5 - src/pages/products/index.jsx | 49 ++-- src/pages/signeup/index.jsx | 12 - 15 files changed, 401 insertions(+), 643 deletions(-) delete mode 100644 src/components/signup/SignUpForm.jsx create mode 100644 src/constants/inputs.js delete mode 100644 src/pages/addItemPage/index.jsx rename src/pages/{ => auth}/reset-password/index.jsx (100%) create mode 100644 src/pages/auth/signin/index.jsx create mode 100644 src/pages/auth/signup/index.jsx delete mode 100644 src/pages/login/index.jsx delete mode 100644 src/pages/signeup/index.jsx diff --git a/src/components/navbar/Navbar.jsx b/src/components/navbar/Navbar.jsx index 3ed69d6..a520486 100644 --- a/src/components/navbar/Navbar.jsx +++ b/src/components/navbar/Navbar.jsx @@ -14,6 +14,7 @@ import { useAuth } from "@/context/AuthContext"; import AccountMenu from "./AccountMenu"; import LanguageMenu from "./LanguageMenu"; +import Button from "../button/Button"; const navigation = [ { name: "Home", href: "/", icon: AiOutlineHome }, @@ -38,7 +39,7 @@ function Navbar() {
Logo ) : (
- - + +
)} diff --git a/src/components/profile/AvatarUploadImage.jsx b/src/components/profile/AvatarUploadImage.jsx index cb99a81..27482be 100644 --- a/src/components/profile/AvatarUploadImage.jsx +++ b/src/components/profile/AvatarUploadImage.jsx @@ -16,11 +16,17 @@ function AvatarUploadImage({ image, setFile, file }) {
- avatar + {!image && !file ? ( +
+ Add image +
+ ) : ( + avatar + )}

Change your profile picture diff --git a/src/components/profile/Profile.jsx b/src/components/profile/Profile.jsx index b7b0ca9..840570b 100644 --- a/src/components/profile/Profile.jsx +++ b/src/components/profile/Profile.jsx @@ -1,6 +1,7 @@ -import React from "react"; +/* eslint-disable @next/next/no-img-element */ import { useEffect, useState } from "react"; import { AiOutlineEdit, AiOutlineMail, AiOutlinePhone } from "react-icons/ai"; +import { BsBasketFill } from "react-icons/bs"; import { GoLocation } from "react-icons/go"; import { getDocData } from "@/lib/firebase/firestoreFunctions"; @@ -10,111 +11,84 @@ import Button from "@/components/button/Button"; import { useAuth } from "@/context/AuthContext"; import EditProfile from "./EditProfile"; -import { collection, getDocs } from "firebase/firestore"; -import { db } from "@/lib/firebase/firebase"; const Profile = () => { const { currentUser } = useAuth(); const [editProfile, setEditProfile] = useState(false); const [userData, setUserData] = useState({}); - const [hideAltTextBio, setHideAltTextBio] = useState(false); useEffect(() => { - // Fetch user data when the component mounts - getUserData(); - }, []); - - useEffect(() => { - console.log(userData); - }, [userData]); - - async function getUserData() { - try { - const userdata = collection(db, "users"); - const response = await getDocs(userdata); - - const data = response.docs.map((doc) => ({ - data: doc.data(), - publicPhoneNumber: doc.data()["phone number"], - })); - + getDocData("users", currentUser.uid).then((data) => { setUserData(data); - } catch (error) { - console.error("Error fetching user data:", error); - // Handle the error here (e.g., show an error message to the user) - } - } - - const { name, avatarurl, bio, email, location } = userData[0]?.data || {}; - const { publicPhoneNumber } = userData[0] || {}; - - const handleIconClick = () => { - setHideAltTextBio(true); - }; + }); + }, []); + const { name, avatarUrl, bio, publicEmail, publicPhoneNumber, location } = + userData; return ( <> {editProfile && ( )} -

-

My account

-
-
-
+
+

+ My account +

+
+
+ {!avatarUrl ? ( +
+ {name && name[0]} +
+ ) : ( {hideAltTextBio -
+ )}
-
-
-

- {name} -

-

- {`${(bio && bio) || "Add Bio"}`} -

+
+ +
+
+

+ {name} +

+

+ {`${(bio && bio) || "Add Bio"}`} +

+
-
-
- +
+
+ + {publicEmail} +
+
+ + + {publicPhoneNumber}
-
-
- - {email} -
-
- - {publicPhoneNumber} -
-
- - {location} -
+
+ + {location}
diff --git a/src/components/signup/SignUpForm.jsx b/src/components/signup/SignUpForm.jsx deleted file mode 100644 index 25862c0..0000000 --- a/src/components/signup/SignUpForm.jsx +++ /dev/null @@ -1,251 +0,0 @@ -import React, { useState } from "react"; -import { useForm } from "react-hook-form"; - -import { useAuth } from "@/context/AuthContext"; - -const SignUpForm = () => { - const { signup } = useAuth(); - const { - register, - getValues, - handleSubmit, - formState: { errors }, - } = useForm(); // Initialize react-hook-form - - const [formData, setFormData] = useState({ - name: "", - email: "", - password: "", - confirmPassword: "", - phone: "", - location: "", - }); - const [firebaseInitialized, setFirebaseInitialized] = useState(true); - - const handleChange = (e) => { - const { name, value } = e.target; - setFormData({ - ...formData, - [name]: value, - }); - }; - - const onSubmit = async (data) => { - try { - if (!firebaseInitialized) { - console.log("Firebase is not yet initialized. Please wait."); - return; - } - const { email, password, confirmPassword, phone, location } = data; - - // Add validation logic for email and password - if (email === "" || password === "") { - console.error("Email and password are required."); - return; - } - if (!isValidEmail(email)) { - console.error("Invalid email format."); - return; - } - if (password.length < 6) { - console.error("Password must have at least 6 characters."); - return; - } - if (confirmPassword.length < 6) { - console.error("Password and Confirm Password do not match."); - - return; - } - if (phone === "") { - console.error("Phone number is required."); - return; - } - // Validate the location (country and city) - const locationParts = location.split(","); - if (locationParts.length !== 2) { - console.error( - "Location must be in the format 'Country, City'.", - ); - return; - } - - // Create a user with email and password - const userCredential = await signup(email, password); - } catch (error) { - console.error("Error signing up:", error.message); - } - }; - - const isValidEmail = (email) => { - const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i; - return emailRegex.test(email); - }; - - return ( -
-
-

Sign Up

-
-
- - - {errors.name && ( - - {errors.name.message} - - )} -
-
- - - {errors.email && ( - - {errors.email.type === "required" - ? "Email is required." - : "Invalid email format."} - - )} -
-
- - - {errors.password && ( - - {errors.password.type === "required" - ? "Password is required." - : "Password must have at least 6 characters."} - - )} -
-
- - { - const password = getValues("password"); - return ( - match === password || - "Passwords should match!" - ); - }, - })} - value={formData.confirmPassword} - onChange={handleChange} - placeholder='Confirm password' - /> - {errors.confirmPassword && ( - - {errors.confirmPassword.type === "required" - ? "Confirm Passwordnpm is required." - : "Passwords do not match."} - - )} -
-
- - -
-
- - -
-
- - - Sign Up With - -
-
- ); -}; - -export default SignUpForm; diff --git a/src/constants/inputs.js b/src/constants/inputs.js new file mode 100644 index 0000000..ebf9d66 --- /dev/null +++ b/src/constants/inputs.js @@ -0,0 +1,88 @@ +export const signupInputs = (func) => { + return [ + { + name: "name", + type: "text", + labelText: "Your Name", + placeholder: "Your Name", + requiredMessage: "Enter a name please", + validation: { + maxLength: { + value: 30, + message: "30 character max", + }, + }, + }, + { + name: "email", + type: "email", + labelText: "Email", + placeholder: "mail@mail.com", + requiredMessage: "Email is required", + validation: { + maxLength: (v) => + v.length <= 50 || + "The email should have at most 50 characters", + matchPattern: (v) => + /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || + "Email address must be a valid address", + }, + }, + { + name: "password", + type: "password", + labelText: "Your Password", + placeholder: "Enter your password", + requiredMessage: "Enter a password please", + validation: { + minLength: { + value: 8, + message: "Password must be at least 8 characters", + }, + maxLength: { + value: 30, + message: "30 characters max", + }, + }, + }, + { + name: "confirmPassword", + type: "password", + labelText: "Confirm password", + placeholder: "Enter your password again", + requiredMessage: "Enter a password please", + validation: { + validate: (match) => { + const password = func("password"); + return match === password || "Passwords should match!"; + }, + }, + }, + { + name: "location", + type: "text", + labelText: "Your Location", + placeholder: "Enter your location", + requiredMessage: "Enter a location please", + validatiophonen: { + maxLength: { + value: 50, + message: "50 characters max", + }, + }, + }, + { + name: "phone", + type: "number", + labelText: "Your Phone Number", + placeholder: "Enter your phone number", + requiredMessage: "Enter a phone number please", + validation: { + pattern: { + value: /^\d{10}$/, + message: "Enter a valid 10-digit phone number", + }, + }, + }, + ]; +}; diff --git a/src/lib/firebase/firestoreFunctions.js b/src/lib/firebase/firestoreFunctions.js index 8f05bd8..be19739 100644 --- a/src/lib/firebase/firestoreFunctions.js +++ b/src/lib/firebase/firestoreFunctions.js @@ -8,6 +8,7 @@ import { limit, orderBy, query, + setDoc, updateDoc, where, } from "firebase/firestore"; @@ -40,11 +41,17 @@ import { db } from "./firebase"; */ // set user or item -export const setDoc = async (data, collectionStr) => { - await addDoc(collection(db, collectionStr), { - // user data or item data - ...data, - }); +export const dbAddDoc = async (data, collectionStr, docId) => { + if (docId) { + await setDoc(doc(db, collectionStr, docId), { + ...data, + }); + } else { + await addDoc(collection(db, collectionStr), { + // user data or item data + ...data, + }); + } }; //get item diff --git a/src/pages/account/index.jsx b/src/pages/account/index.jsx index 835ead2..14446fd 100644 --- a/src/pages/account/index.jsx +++ b/src/pages/account/index.jsx @@ -1,11 +1,15 @@ import Link from "next/link"; +import { useRouter } from "next/router"; // Import useRouter import { useEffect, useState } from "react"; import { AiOutlineDelete, AiOutlineEdit } from "react-icons/ai"; -import { useRouter } from "next/router"; // Import useRouter + import { getItemsByUser } from "@/lib/firebase/firestoreFunctions"; + +import Button from "@/components/button/Button"; import DeleteWarning from "@/components/delete-warning"; import ItemCard from "@/components/itemcard/ItemCard"; import Profile from "@/components/profile/Profile"; + import { useAuth } from "@/context/AuthContext"; export default function MyAccount() { @@ -39,35 +43,41 @@ export default function MyAccount() { )}
-

- My Items: -

- +
+

+ My Items: +

+ +
- {items.map((item) => ( -
-
- - setDeleteWarningItem(item.id) - } - className='text-red text-3xl cursor-pointer' - /> - - - + {items.length < 1 && ( +

No items

+ )} + {items.length > 0 && + items.map((item) => ( +
+
+ + setDeleteWarningItem(item.id) + } + className='text-red text-3xl cursor-pointer' + /> + + + +
+
- -
- ))} + ))}
diff --git a/src/pages/add-item/index.jsx b/src/pages/add-item/index.jsx index 7a76127..120aeab 100644 --- a/src/pages/add-item/index.jsx +++ b/src/pages/add-item/index.jsx @@ -2,10 +2,10 @@ import { clsx } from "clsx"; import { serverTimestamp } from "firebase/firestore"; import { useRouter } from "next/router"; import { appWithTranslation } from "next-i18next"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; -import { setDoc, updateDocData } from "@/lib/firebase/firestoreFunctions"; +import { dbAddDoc, updateDocData } from "@/lib/firebase/firestoreFunctions"; import UseUploadImage from "@/lib/hooks/useUploadImage"; import Button from "@/components/button/Button"; @@ -63,7 +63,7 @@ function AddItemPage() { profileImage: currentUser.photoURL, }, }; - await setDoc(itemData, "items"); + await dbAddDoc(itemData, "items"); reset(); }; const updateItem = async (data) => { @@ -85,6 +85,16 @@ function AddItemPage() { await updateDocData("items", itemQueryData.id, itemData); router.push(`/item/${itemQueryData.id}`); }; + + useEffect(() => { + // Check if the user is not logged in and redirect to 404 page + if (!currentUser) { + router.push("/auth/signin"); + return; // Stop further execution of the useEffect + } + + // Fetch items only if the user is logged in + }, [currentUser]); return (

@@ -153,10 +163,42 @@ function AddItemPage() { className='mt-1 p-2 block w-full border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green' > + + + + + + + + + {errors.category && ( + + {errors.category.message} + + )} +

+
+ + {errors.category && ( diff --git a/src/pages/addItemPage/index.jsx b/src/pages/addItemPage/index.jsx deleted file mode 100644 index 4b6ef80..0000000 --- a/src/pages/addItemPage/index.jsx +++ /dev/null @@ -1,227 +0,0 @@ - -import Button from "@/components/button/Button"; -import React, { useState, useRef } from "react"; - -import { BiSolidDownArrow } from "react-icons/bi"; - -export default function Index() { - const [title, setTitle] = useState(""); - const [category, setCategory] = useState(""); - const [state, setState] = useState(""); - const [city, setCity] = useState(""); - const [price, setPrice] = useState(); - const [description, setDescription] = useState(""); - const [selectedPhotos, setSelectedPhotos] = useState([]); - const [deleteIndices, setDeleteIndices] = useState([]); - - const fileInputRef = useRef(null); - - const handleFileChange = (e) => { - const files = e.target.files; - const photoURLs = [...selectedPhotos]; - - for (let i = 0; i < files.length; i++) { - const photoURL = URL.createObjectURL(files[i]); - photoURLs.push(photoURL); - } - - setSelectedPhotos(photoURLs); - }; - - const handleDelete = (index) => { - const updatedPhotos = [...selectedPhotos]; - updatedPhotos.splice(index, 1); - setSelectedPhotos(updatedPhotos); - setDeleteIndices([...deleteIndices, index]); - }; - - const handleUploadClick = () => { - fileInputRef.current.click(); - }; - - return ( -
-
-

- Add an Item -

-
-
- - -
- -
- - -
- -
- - -
-
- -