Browse Source

build bugs fixed state mangment optimized

main
sina_sajjadi 3 days ago
parent
commit
7396c18a3a
  1. 48
      src/app/(account-pages)/account/page.tsx
  2. 10
      src/app/(account-pages)/my-trips/page.tsx
  3. 45
      src/app/(account-pages)/passengers-list/PassengerTable.tsx
  4. 2
      src/app/(account-pages)/passengers-list/page.tsx
  5. 15
      src/app/(client-components)/(Header)/MainNav1.tsx
  6. 12
      src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx
  7. 4
      src/app/add-listing/[[...stepIndex]]/page.tsx
  8. 3
      src/app/add-new-passenger/page.tsx
  9. 18
      src/app/custom-history/page.tsx
  10. 3
      src/app/custom-trip/page.tsx
  11. 16
      src/app/forgot-password/page.tsx
  12. 109
      src/app/login/page.tsx
  13. 95
      src/app/signup/methodes/page.tsx
  14. 43
      src/app/signup/otp-code/page.tsx
  15. 10
      src/app/signup/page.tsx
  16. 39
      src/components/contexts/userContext.tsx

48
src/app/(account-pages)/account/page.tsx

@ -1,5 +1,6 @@
"use client"; "use client";
import React, { useState, ChangeEvent, FC } from "react";
import React, { useState, ChangeEvent, FC, useEffect } from "react";
import Label from "@/components/Label"; import Label from "@/components/Label";
import Avatar from "@/shared/Avatar"; import Avatar from "@/shared/Avatar";
import ButtonPrimary from "@/shared/ButtonPrimary"; import ButtonPrimary from "@/shared/ButtonPrimary";
@ -36,21 +37,23 @@ interface APIResponse {
const AccountPage: FC<AccountPageProps> = () => { const AccountPage: FC<AccountPageProps> = () => {
const router = useRouter(); const router = useRouter();
const { user, setUser, clerUser } = useUserContext();
const storedUser = localStorage.getItem("user");
let user: User | null = storedUser ? JSON.parse(storedUser) : null;
if (!user) {
router.replace("/");
return null; // Prevent rendering if no user data is found
}
// Redirect to home if user object is empty
useEffect(() => {
if (!Object.keys(user).length) {
router.replace("/");
}
}, [user, router]);
const { setStatus } = useUserContext();
// Return null to avoid rendering when redirecting
// if (!Object.keys(user).length) {
// return null;
// }
const [name, setName] = useState<string>(user.fullname || ""); const [name, setName] = useState<string>(user.fullname || "");
const [email, setEmail] = useState<string>(user.email || ""); const [email, setEmail] = useState<string>(user.email || "");
const [number, setNumber] = useState<string>(user.phone_number || ""); const [number, setNumber] = useState<string>(user.phone_number || "");
const [password, setPassword] = useState<string>("");
const [image, setImage] = useState<File | null>(null); const [image, setImage] = useState<File | null>(null);
const [imageURL, setImageURL] = useState<string | null>(null); const [imageURL, setImageURL] = useState<string | null>(null);
const [error, setError] = useState<string>(""); const [error, setError] = useState<string>("");
@ -66,9 +69,7 @@ const AccountPage: FC<AccountPageProps> = () => {
}, },
}); });
if (response.status === 204) { if (response.status === 204) {
localStorage.removeItem("user");
setStatus(false);
router.replace("/");
clerUser();
} else { } else {
setError("Something went wrong"); setError("Something went wrong");
} }
@ -84,9 +85,7 @@ const AccountPage: FC<AccountPageProps> = () => {
}; };
const signOutHandler = (): void => { const signOutHandler = (): void => {
localStorage.removeItem("user");
setStatus(false);
router.replace("/");
clerUser();
}; };
const changeHandler = async (): Promise<void> => { const changeHandler = async (): Promise<void> => {
@ -96,7 +95,6 @@ const AccountPage: FC<AccountPageProps> = () => {
const formData = new FormData(); const formData = new FormData();
formData.append("fullname", name); formData.append("fullname", name);
formData.append("email", email); formData.append("email", email);
formData.append("password", password);
if (imageURL) { if (imageURL) {
formData.append("avatar", imageURL); formData.append("avatar", imageURL);
} }
@ -113,14 +111,13 @@ const AccountPage: FC<AccountPageProps> = () => {
} }
); );
if (response.status === 200) { if (response.status === 200) {
user = {
setUser({
...user, ...user,
avatar: response.data.avatar, avatar: response.data.avatar,
email: response.data.email, email: response.data.email,
fullname: response.data.fullname, fullname: response.data.fullname,
phone_number: response.data.phone_number, phone_number: response.data.phone_number,
};
localStorage.setItem("user", JSON.stringify(user));
});
} else { } else {
setError("Something went wrong"); setError("Something went wrong");
} }
@ -171,7 +168,6 @@ const AccountPage: FC<AccountPageProps> = () => {
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
<span className="mt-1 text-xs">Change Image</span> <span className="mt-1 text-xs">Change Image</span>
</div> </div>
<input <input
@ -208,16 +204,6 @@ const AccountPage: FC<AccountPageProps> = () => {
type="text" type="text"
/> />
</div> </div>
<div>
<Label>Password</Label>
<Input
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
className="mt-1.5"
/>
</div>
{error && <p className="text-red-500 text-xs">{error}</p>}
<div className="flex flex-col pt-2 sm:flex-row"> <div className="flex flex-col pt-2 sm:flex-row">
<ButtonPrimary className="mt-8" loading={loading.change} onClick={changeHandler}> <ButtonPrimary className="mt-8" loading={loading.change} onClick={changeHandler}>
Update info Update info

10
src/app/(account-pages)/my-trips/page.tsx

@ -13,11 +13,19 @@ import React, { Fragment, useEffect, useState } from "react";
import ButtonSecondary from "@/shared/ButtonSecondary"; import ButtonSecondary from "@/shared/ButtonSecondary";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import StayCard2 from "@/components/StayCard2"; import StayCard2 from "@/components/StayCard2";
import { useRouter } from "next/navigation";
const MyTrips = () => { const MyTrips = () => {
const user = JSON.parse(localStorage.getItem("user"));
const router = useRouter()
let [categories] = useState(["Stays", "Experiences", "Cars"]); let [categories] = useState(["Stays", "Experiences", "Cars"]);
let [tours , setTours] = useState([]); let [tours , setTours] = useState([]);
const [ user ] =useState()
if(!user){
router.replace("/")
return null
}
useEffect(() => { useEffect(() => {
axiosInstance axiosInstance
.get("/api/tours/orders/", { .get("/api/tours/orders/", {

45
src/app/(account-pages)/passengers-list/PassengerTable.tsx

@ -1,30 +1,36 @@
"use client";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import React, { useState } from "react";
import { useUserContext } from "@/components/contexts/userContext";
import React, { useEffect, useState } from "react";
import { IoMdTrash } from "react-icons/io"; import { IoMdTrash } from "react-icons/io";
import { MdEdit } from "react-icons/md"; import { MdEdit } from "react-icons/md";
const PassengerTable = ({data}) => {
const user = JSON.parse(localStorage.getItem("user"))
const PassengerTable = ({ data }) => {
const { user } = useUserContext();
const [show , setShow] =useState(true)
const [show, setShow] = useState(true);
const deletHandler = async ()=>{
try{
const response = await axiosInstance.delete(`/api/account/passengers/${data.id}/` ,{
headers :{
Authorization : `token ${user.token}`
}
})
setShow(false)
}catch (error){
const deletHandler = async () => {
try {
const response = await axiosInstance.delete(
`/api/account/passengers/${data.id}/`,
{
headers: {
Authorization: `token ${user.token}`,
},
}
);
setShow(false);
} catch (error) {
console.log(error); console.log(error);
} }
}
};
return ( return (
<div className= {`${!show && "hidden" } sm:w-[500px] flex items-center justify-between p-4 bg-white rounded-xl shadow-sm border border-neutral-200 dark:bg-neutral-800`}>
<div
className={`${
!show && "hidden"
} sm:w-[500px] flex items-center justify-between p-4 bg-white rounded-xl shadow-sm border border-neutral-200 dark:bg-neutral-800`}
>
{/* Passenger Information */} {/* Passenger Information */}
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-sm text-neutral-500 dark:text-neutral-400"> <p className="text-sm text-neutral-500 dark:text-neutral-400">
@ -39,7 +45,8 @@ const [show , setShow] =useState(true)
<div className="flex space-x-6 text-neutral-500"> <div className="flex space-x-6 text-neutral-500">
<button className="hover:text-red-500 transition-colors"> <button className="hover:text-red-500 transition-colors">
<button type="submit"> <button type="submit">
<IoMdTrash onClick={deletHandler} className="text-2xl" /> {/* Increased size using text-2xl */}
<IoMdTrash onClick={deletHandler} className="text-2xl" />{" "}
{/* Increased size using text-2xl */}
</button> </button>
</button> </button>
<button className="hover:text-blue-500 transition-colors"> <button className="hover:text-blue-500 transition-colors">

2
src/app/(account-pages)/passengers-list/page.tsx

@ -7,8 +7,6 @@ import axiosInstance from "@/components/api/axios";
import Link from "next/link"; import Link from "next/link";
const PassengersList = () => { const PassengersList = () => {
const user = JSON.parse(localStorage.getItem("user"))
const [passengers , setPassenger ] = useState([]) const [passengers , setPassenger ] = useState([])

15
src/app/(client-components)/(Header)/MainNav1.tsx

@ -1,6 +1,6 @@
"use client" "use client"
import React, { FC, useContext, useEffect, useState } from "react";
import React, { FC, use, useContext, useEffect, useState } from "react";
import Logo from "@/shared/Logo"; import Logo from "@/shared/Logo";
import Navigation from "@/shared/Navigation/Navigation"; import Navigation from "@/shared/Navigation/Navigation";
import SearchDropdown from "./SearchDropdown"; import SearchDropdown from "./SearchDropdown";
@ -18,15 +18,8 @@ export interface MainNav1Props {
} }
const MainNav1: FC<MainNav1Props> = ({ className = "" }) => { const MainNav1: FC<MainNav1Props> = ({ className = "" }) => {
const { status, setStatus } =useUserContext();
const [userData , setUserData] =useState({})
useEffect(()=>{
setUserData(JSON.parse(localStorage.getItem("user")))
userData? setStatus(true) : setStatus(false)
const {user} = useUserContext()
} , [status])
console.log(status);
return ( return (
<div className={`nc-MainNav1 relative z-10 ${className}`}> <div className={`nc-MainNav1 relative z-10 ${className}`}>
@ -50,9 +43,9 @@ console.log(status);
<SwitchDarkMode /> <SwitchDarkMode />
<SearchDropdown className="flex items-center" /> <SearchDropdown className="flex items-center" />
<div className="px-1" /> <div className="px-1" />
{status ? (<Link href={"/account"}>
{Object.keys(user).length ? (<Link href={"/account"}>
<Avatar <Avatar
imgUrl={userData?.avatar}
imgUrl={user?.avatar}
sizeClass="w-10 h-10" sizeClass="w-10 h-10"
/> />
</Link> </Link>

12
src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx

@ -1,3 +1,4 @@
import React, { FC, useEffect, useState } from "react"; import React, { FC, useEffect, useState } from "react";
import Input from "@/shared/Input"; import Input from "@/shared/Input";
import Select from "@/shared/Select"; import Select from "@/shared/Select";
@ -7,6 +8,8 @@ import getImageURL from "@/components/api/getImageURL";
import ConfirmModal from "../../../shared/popUp"; import ConfirmModal from "../../../shared/popUp";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import PassengerTable from "@/app/(account-pages)/passengers-list/PassengerTable"; import PassengerTable from "@/app/(account-pages)/passengers-list/PassengerTable";
import { useUserContext } from "@/components/contexts/userContext";
import { useRouter } from "next/router";
export interface PageAddListing1Props { export interface PageAddListing1Props {
Passenger: any; Passenger: any;
@ -27,12 +30,19 @@ const PageAddListing1: FC<PageAddListing1Props> = ({
selectedPassenger, selectedPassenger,
setSelectedPassenger, // Receive the function to reset selectedPassenger setSelectedPassenger, // Receive the function to reset selectedPassenger
}) => { }) => {
const router = useRouter()
const { fullName, date, number, passport } = Passenger; const { fullName, date, number, passport } = Passenger;
const user = JSON.parse(localStorage.getItem("user"));
const { user } = useUserContext()
const [savedPassengers, setSavedPassengers] = useState([]); const [savedPassengers, setSavedPassengers] = useState([]);
if(!Object.keys(user).length){
router.replace("/")
}
useEffect(() => { useEffect(() => {
axiosInstance axiosInstance
.get("/api/account/passengers/", { .get("/api/account/passengers/", {

4
src/app/add-listing/[[...stepIndex]]/page.tsx

@ -9,6 +9,7 @@ import validatePassenger from "@/hooks/passengerValidation";
import { Context } from "@/components/contexts/tourDetails"; import { Context } from "@/components/contexts/tourDetails";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import { useUserContext } from "@/components/contexts/userContext";
export interface CommonLayoutProps { export interface CommonLayoutProps {
children: React.ReactNode; children: React.ReactNode;
@ -19,7 +20,8 @@ export interface CommonLayoutProps {
const CommonLayout: FC<CommonLayoutProps> = ({ params }) => { const CommonLayout: FC<CommonLayoutProps> = ({ params }) => {
const router = useRouter(); const router = useRouter();
const user = JSON.parse(localStorage.getItem("user"));
const {user} =useUserContext()
const [index, setIndex] = useState(1); const [index, setIndex] = useState(1);
const [passengers, setPassengers] = useState([]); const [passengers, setPassengers] = useState([]);

3
src/app/add-new-passenger/page.tsx

@ -8,6 +8,7 @@ import FormItem from "../add-listing/FormItem";
import getImageURL from "@/components/api/getImageURL"; import getImageURL from "@/components/api/getImageURL";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useUserContext } from "@/components/contexts/userContext";
export interface CommonLayoutProps { export interface CommonLayoutProps {
params: { params: {
@ -16,7 +17,7 @@ export interface CommonLayoutProps {
} }
const CommonLayout: FC<CommonLayoutProps> = () => { const CommonLayout: FC<CommonLayoutProps> = () => {
const user = JSON.parse(localStorage.getItem("user"));
const {user} = useUserContext()
const router = useRouter(); const router = useRouter();
const [passenger, setPassenger] = useState({ const [passenger, setPassenger] = useState({

18
src/app/custom-history/page.tsx

@ -1,27 +1,27 @@
'use client'; 'use client';
import React, { FC, useEffect, useState } from 'react';
import React, { FC, use, useEffect, useState } from 'react';
import axiosInstance from '@/components/api/axios'; import axiosInstance from '@/components/api/axios';
import { TrashIcon } from '@heroicons/react/24/outline'; // Import the Trash icon for the delete button import { TrashIcon } from '@heroicons/react/24/outline'; // Import the Trash icon for the delete button
import { FaWhatsapp } from "react-icons/fa"; import { FaWhatsapp } from "react-icons/fa";
import { useUserContext } from '@/components/contexts/userContext';
import { useRouter } from 'next/navigation';
export interface PageAddListing10Props {} export interface PageAddListing10Props {}
const PageAddListing10: FC<PageAddListing10Props> = () => { const PageAddListing10: FC<PageAddListing10Props> = () => {
const router = useRouter()
const [tours, setTours] = useState([]); const [tours, setTours] = useState([]);
const [toursDetail, setToursDetail] = useState([]); const [toursDetail, setToursDetail] = useState([]);
const [user, setUser] = useState(null);
const {user} = useUserContext();
useEffect(() => { useEffect(() => {
const userData = localStorage.getItem('user');
if (userData) {
const parsedUser = JSON.parse(userData);
setUser(parsedUser);
if (user) {
axiosInstance('/api/trip/custom/orders/', { axiosInstance('/api/trip/custom/orders/', {
headers: { headers: {
Authorization: `token ${parsedUser.token}`,
Authorization: `token ${user.token}`,
}, },
}) })
.then((response) => { .then((response) => {
@ -38,6 +38,8 @@ const PageAddListing10: FC<PageAddListing10Props> = () => {
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
}); });
}else{
router.replace("/")
} }
}, []); }, []);
@ -87,8 +89,6 @@ console.log(tours);
<button onClick={()=>{deleteTour(item)}} className="flex items-center text-red-500 hover:text-red-700"> <button onClick={()=>{deleteTour(item)}} className="flex items-center text-red-500 hover:text-red-700">
<TrashIcon className="w-5 h-5 mr-1" /> <TrashIcon className="w-5 h-5 mr-1" />
Delete Delete
{console.log(item)
}
</button> </button>
</div> </div>
</div> </div>

3
src/app/custom-trip/page.tsx

@ -7,6 +7,7 @@ import FormItem from "../add-listing/FormItem";
import Select from "@/shared/Select"; import Select from "@/shared/Select";
import Input from "@/shared/Input"; import Input from "@/shared/Input";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useUserContext } from "@/components/contexts/userContext";
interface City { interface City {
name: string; name: string;
@ -21,7 +22,7 @@ interface Country {
interface CommonLayoutProps {} interface CommonLayoutProps {}
const CommonLayout: FC<CommonLayoutProps> = () => { const CommonLayout: FC<CommonLayoutProps> = () => {
const user = JSON.parse(localStorage.getItem("user"));
const {user} = useUserContext()
const router = useRouter() const router = useRouter()

16
src/app/forgot-password/page.tsx

@ -36,34 +36,30 @@ const PageSignUp: FC<PageSignUpProps> = ({}) => {
}; };
const submitHandler = async ( const submitHandler = async (
name,
countryCode, countryCode,
phoneNumber, phoneNumber,
password, password,
confirmPassword confirmPassword
) => { ) => {
const form = { const form = {
name,
verification_methodes : "" ,
method : "reset" ,
countryCode, countryCode,
phoneNumber, phoneNumber,
password, password,
confirmPassword, confirmPassword,
}; };
if (validateForm(form)) {
setForm(form);
await axiosInstance await axiosInstance
.get(`/api/account/verfication/?range_phone=${countryCode}&phone_number=${phoneNumber}`) .get(`/api/account/verfication/?range_phone=${countryCode}&phone_number=${phoneNumber}`)
.then((response) => { .then((response) => {
setMethod(response.data.verification_method)
form.verification_methodes = response.data.verification_method
setForm(form)
router.push("/signup/methodes")
}) })
.catch((error) => { .catch((error) => {
console.error("Error fetching data:", error); console.error("Error fetching data:", error);
}); });
router.push("/signup/methodes")
} else {
console.log('Form has errors:', errors);
}
}; };
return ( return (
@ -133,7 +129,7 @@ const PageSignUp: FC<PageSignUpProps> = ({}) => {
<ButtonPrimary <ButtonPrimary
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
submitHandler(name, countryCode, phoneNumber, password, confirmPassword);
submitHandler(countryCode, phoneNumber, password, confirmPassword);
}} }}
> >
Continue Continue

109
src/app/login/page.tsx

@ -1,61 +1,58 @@
"use client"; "use client";
import React, { FC, useContext, useState } from "react";
import googleSvg from "@/images/Google.svg";
import React, { FC, useState, useEffect } from "react";
import Input from "@/shared/Input"; import Input from "@/shared/Input";
import ButtonPrimary from "@/shared/ButtonPrimary"; import ButtonPrimary from "@/shared/ButtonPrimary";
import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import axiosInstance from "@/components/api/axios"; import axiosInstance from "@/components/api/axios";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useUserContext } from "@/components/contexts/userContext"; import { useUserContext } from "@/components/contexts/userContext";
export interface PageLoginProps {}
const PageLogin: FC<PageLoginProps> = ({}) => {
export interface PageLoginProps {}
const PageLogin: FC<PageLoginProps> = () => {
const { user, setUser } = useUserContext();
const router = useRouter(); const router = useRouter();
let user = JSON.parse(localStorage.getItem("user"));
if (user) {
return router.replace("/")
}
const { setStatus } = useUserContext();
const [phoneNumber, setPhoneNumber] = useState("");
const [password, setPassword] = useState("");
const [countryCode, setCountryCode] = useState();
const [error, setError] = useState();
const [phoneNumber, setPhoneNumber] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [countryCode, setCountryCode] = useState<string>("");
const [error, setError] = useState<string>("");
// Redirect to home if the user is already logged in
useEffect(() => {
if (Object.keys(user).length) {
router.replace("/");
}
}, [user, router]);
const countryCodeHandler = (e) => {
const countryCodeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length <= 3) { if (e.target.value.length <= 3) {
setCountryCode(e.target.value); setCountryCode(e.target.value);
} }
}; };
const submitHandler = async (phoneNumber, password) => {
const submitHandler = async () => {
setError(""); setError("");
await axiosInstance
.post(`/api/account/login/`, {
try {
const response = await axiosInstance.post(`/api/account/login/`, {
phone_number: phoneNumber, phone_number: phoneNumber,
password, password,
})
.then((response) => {
if (response.status === 201) {
localStorage.setItem("user", JSON.stringify(response.data));
setStatus(true)
} else {
setError("something went wrong");
}
})
.catch((error) => {
setError(error.message)
}); });
if (response.status === 201) {
setUser(response.data);
} else {
setError("Something went wrong");
}
} catch (error) {
if (error instanceof Error) {
setError(error.message);
} else {
setError("An unknown error occurred");
}
}
}; };
return ( return (
@ -65,36 +62,23 @@ const PageLogin: FC<PageLoginProps> = ({}) => {
Login Login
</h2> </h2>
<div className="max-w-md mx-auto space-y-6"> <div className="max-w-md mx-auto space-y-6">
{/* Email/Password Form */}
<form className="grid grid-cols-1 gap-6" action="#" method="post">
<form className="grid grid-cols-1 gap-6" onSubmit={(e) => e.preventDefault()}>
<label className="block"> <label className="block">
<span className="text-neutral-800 dark:text-neutral-200">
Phone Number
</span>
<span className="text-neutral-800 dark:text-neutral-200">Phone Number</span>
<div className="flex items-center mt-1 rounded-2xl border border-neutral-200 bg-white dark:border-neutral-700 dark:bg-neutral-900 focus-within:ring-0"> <div className="flex items-center mt-1 rounded-2xl border border-neutral-200 bg-white dark:border-neutral-700 dark:bg-neutral-900 focus-within:ring-0">
{/* Plus Sign as Static Text */}
<span className="px-2 mr-[-15px] text-neutral-800 dark:text-neutral-200">
+
</span>
{/* Country Code Input */}
<span className="px-2 mr-[-15px] text-neutral-800 dark:text-neutral-200">+</span>
<input <input
value={countryCode}
onChange={(e) => {
countryCodeHandler(e);
}}
value={countryCode || ""}
onChange={countryCodeHandler}
type="number" type="number"
placeholder="98" placeholder="98"
maxLength={3} maxLength={3}
className="w-[50px] [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none p-2 mr-[-10px] text-center border-none outline-none focus:ring-0 focus:border-none bg-transparent text-neutral-800 dark:text-neutral-200" className="w-[50px] [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none p-2 mr-[-10px] text-center border-none outline-none focus:ring-0 focus:border-none bg-transparent text-neutral-800 dark:text-neutral-200"
/> />
{/* Divider Line */}
<span className="px-2 text-neutral-500">|</span> <span className="px-2 text-neutral-500">|</span>
{/* Phone Number Input */}
<input <input
value={phoneNumber} value={phoneNumber}
onChange={(e) => {
setPhoneNumber(e.target.value);
}}
onChange={(e) => setPhoneNumber(e.target.value)}
type="number" type="number"
placeholder="26363687" placeholder="26363687"
className="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none flex-1 p-2 border-none outline-none focus:ring-0 focus:border-none bg-transparent text-neutral-800 dark:text-neutral-200" className="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none flex-1 p-2 border-none outline-none focus:ring-0 focus:border-none bg-transparent text-neutral-800 dark:text-neutral-200"
@ -104,10 +88,7 @@ const PageLogin: FC<PageLoginProps> = ({}) => {
<label className="block"> <label className="block">
<span className="flex justify-between items-center text-neutral-800 dark:text-neutral-200"> <span className="flex justify-between items-center text-neutral-800 dark:text-neutral-200">
Password Password
<Link
href="/forgot-password"
className="text-sm underline font-medium"
>
<Link href="/forgot-password" className="text-sm underline font-medium">
Forgot password? Forgot password?
</Link> </Link>
</span> </span>
@ -115,23 +96,13 @@ const PageLogin: FC<PageLoginProps> = ({}) => {
type="password" type="password"
className="mt-1" className="mt-1"
value={password} value={password}
onChange={(e) => {
setPassword(e.target.value);
}}
onChange={(e) => setPassword(e.target.value)}
/> />
</label> </label>
{error && <p className="text-red-500 text-xs">{error}</p>} {error && <p className="text-red-500 text-xs">{error}</p>}
<ButtonPrimary
onClick={(e) => {
e.preventDefault();
submitHandler(phoneNumber, password);
}}
>
Continue
</ButtonPrimary>
<ButtonPrimary onClick={submitHandler}>Continue</ButtonPrimary>
</form> </form>
{/* Sign Up Link */}
<span className="block text-center text-neutral-700 dark:text-neutral-300"> <span className="block text-center text-neutral-700 dark:text-neutral-300">
<Link href="/signup" className="text-bronze font-semibold"> <Link href="/signup" className="text-bronze font-semibold">
Create an account Create an account

95
src/app/signup/methodes/page.tsx

@ -10,18 +10,18 @@ import { MdOutlineTextsms } from "react-icons/md";
function SelectMethods() { function SelectMethods() {
const router = useRouter(); const router = useRouter();
let User = JSON.parse(localStorage.getItem("user"));
if (User) {
return router.replace("/");
}
const { method, form } = useUserContext();
const { user } = useUserContext();
// if (Object.keys(user).length) {
// return router.replace("/");
// }
const { form } = useUserContext();
const [selectedMethod, setSelectedMethod] = useState(""); const [selectedMethod, setSelectedMethod] = useState("");
const [error, setError] = useState(""); const [error, setError] = useState("");
const [loading, setLoading] = useState("");
const [loading, setLoading] = useState(false);
const enabled = { const enabled = {
watsapp: method.join().includes("watsapp"),
sms: method.join().includes("sms"),
watsapp: form.verification_methodes.join().includes("watsapp"),
sms: form.verification_methodes.join().includes("sms"),
}; };
const handleMethodChange = (e) => { const handleMethodChange = (e) => {
@ -35,34 +35,65 @@ function SelectMethods() {
setSelectedMethod(e.target.value); setSelectedMethod(e.target.value);
} }
}; };
console.log(form);
const handleSubmit = async () => { const handleSubmit = async () => {
setLoading(true); setLoading(true);
try {
const response = await axiosInstance.post(
`/api/account/register/`,
{
fullname: form.name,
phone_number: form.phoneNumber,
verification_method: selectedMethod,
range_phone: form.countryCode,
password: form.password,
password_confirmation: form.confirmPassword,
},
{
headers: {
Accept: "application/json",
},
switch (form.method) {
case "register":
try {
const response = await axiosInstance.post(
`/api/account/register/`,
{
fullname: form.name,
phone_number: form.phoneNumber,
verification_method: selectedMethod,
range_phone: form.countryCode,
password: form.password,
password_confirmation: form.confirmPassword,
},
{
headers: {
Accept: "application/json",
},
}
);
response.status === 202 &&
(setLoading(false), router.replace("signup/otp-code"));
} catch (error) {
setError(error);
console.log(error);
setLoading(false);
} }
);
response.status === 202 &&
(
setLoading(false),
router.replace("signup/otp-code"));
} catch (error) {
setError(error);
console.log(error);
setLoading(false);
break;
case "reset":
try {
const response = await axiosInstance.post(
`/api/account/recover/`,
{
phone_number: form.phoneNumber,
verification_method: selectedMethod,
range_phone: form.countryCode,
password: form.password,
password_confirmation: form.confirmPassword,
},
{
headers: {
Accept: "application/json",
},
}
);
response.status === 202 &&
(setLoading(false), router.replace("signup/otp-code"));
} catch (error) {
setError(error);
console.log(error);
setLoading(false);
}
break;
default:
break;
} }
}; };

43
src/app/signup/otp-code/page.tsx

@ -11,21 +11,19 @@ export interface PageSignUpProps {}
const PageSignUp: FC<PageSignUpProps> = () => { const PageSignUp: FC<PageSignUpProps> = () => {
const router = useRouter(); const router = useRouter();
const user = JSON.parse(localStorage.getItem("user"));
const { form, setMethod, setStatus } = useUserContext();
const { form } = useUserContext();
const { user, setUser } = useUserContext();
useEffect(() => {
if (Object.keys(user).length) {
router.replace("/");
}
}, [user, router]);
const [otp, setOtp] = useState(["", "", "", "", ""]); const [otp, setOtp] = useState(["", "", "", "", ""]);
const [time, setTime] = useState(30); const [time, setTime] = useState(30);
const [error, setError] = useState(""); const [error, setError] = useState("");
const otpRefs = useRef<(HTMLInputElement | null)[]>([]); const otpRefs = useRef<(HTMLInputElement | null)[]>([]);
useEffect(() => {
if (user) {
router.replace("/");
}
}, [user, router]);
const handleOtpChange = (value: string, index: number) => { const handleOtpChange = (value: string, index: number) => {
if (/^[0-9]?$/.test(value)) { if (/^[0-9]?$/.test(value)) {
const newOtp = [...otp]; const newOtp = [...otp];
@ -37,7 +35,10 @@ const PageSignUp: FC<PageSignUpProps> = () => {
} }
}; };
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
const handleKeyDown = (
e: React.KeyboardEvent<HTMLInputElement>,
index: number
) => {
if (e.key === "Backspace" && !otp[index] && index > 0) { if (e.key === "Backspace" && !otp[index] && index > 0) {
otpRefs.current[index - 1]?.focus(); otpRefs.current[index - 1]?.focus();
} }
@ -45,7 +46,10 @@ const PageSignUp: FC<PageSignUpProps> = () => {
useEffect(() => { useEffect(() => {
if (time > 0) { if (time > 0) {
const timer = setInterval(() => setTime((prevTime) => prevTime - 1), 1000);
const timer = setInterval(
() => setTime((prevTime) => prevTime - 1),
1000
);
return () => clearInterval(timer); return () => clearInterval(timer);
} }
}, [time]); }, [time]);
@ -61,15 +65,13 @@ const PageSignUp: FC<PageSignUpProps> = () => {
setError(""); setError("");
try { try {
const response = await axiosInstance.post("/api/account/verify/", { const response = await axiosInstance.post("/api/account/verify/", {
method: "register",
method: form.method,
phone_number: form.phoneNumber, phone_number: form.phoneNumber,
code: otp.join(""), code: otp.join(""),
}); });
if (response.status === 201) { if (response.status === 201) {
localStorage.setItem("user", JSON.stringify(response.data));
setStatus(true);
router.replace("/");
setUser(response.data);
} else { } else {
setError("Something went wrong. Please try again."); setError("Something went wrong. Please try again.");
} }
@ -85,7 +87,8 @@ const PageSignUp: FC<PageSignUpProps> = () => {
Verification Code Verification Code
</h2> </h2>
<p className="text-center text-sm text-neutral-500 mb-4"> <p className="text-center text-sm text-neutral-500 mb-4">
Enter the 5-digit code that we sent to complete your account registration
Enter the 5-digit code that we sent to complete your account
registration
</p> </p>
<div className="max-w-sm mx-auto space-y-6"> <div className="max-w-sm mx-auto space-y-6">
<div className="flex justify-center space-x-2 mb-4"> <div className="flex justify-center space-x-2 mb-4">
@ -105,13 +108,17 @@ const PageSignUp: FC<PageSignUpProps> = () => {
<p className="text-center text-sm text-neutral-500 mb-4"> <p className="text-center text-sm text-neutral-500 mb-4">
Haven't got the confirmation code yet?{" "} Haven't got the confirmation code yet?{" "}
<button <button
className={`text-primary-600 hover:underline ${time > 0 ? "cursor-not-allowed opacity-50" : "cursor-pointer"}`}
className={`text-primary-600 hover:underline ${
time > 0 ? "cursor-not-allowed opacity-50" : "cursor-pointer"
}`}
onClick={handleResend} onClick={handleResend}
disabled={time > 0} disabled={time > 0}
> >
Resend Resend
</button> </button>
{time > 0 && <span className="text-xs text-neutral-400">({time} Seconds)</span>}
{time > 0 && (
<span className="text-xs text-neutral-400">({time} Seconds)</span>
)}
</p> </p>
{error && <p className="text-red-500 text-xs">{error}</p>} {error && <p className="text-red-500 text-xs">{error}</p>}
<ButtonPrimary <ButtonPrimary

10
src/app/signup/page.tsx

@ -13,11 +13,11 @@ export interface PageSignUpProps {}
const PageSignUp: FC<PageSignUpProps> = () => { const PageSignUp: FC<PageSignUpProps> = () => {
const router = useRouter(); const router = useRouter();
const storedUser = JSON.parse(localStorage.getItem("user"));
const {user} = useUserContext()
if (storedUser) {
if (Object.keys(user).length) {
router.replace("/"); router.replace("/");
return null; // Avoid rendering the component if the user is already logged in
return null;
} }
const { setForm, setMethod } = useUserContext(); const { setForm, setMethod } = useUserContext();
@ -46,6 +46,8 @@ const PageSignUp: FC<PageSignUpProps> = () => {
phoneNumber, phoneNumber,
password, password,
confirmPassword, confirmPassword,
verification_methodes : "" ,
method: "register",
}; };
if (validateForm(form)) { if (validateForm(form)) {
@ -55,7 +57,7 @@ const PageSignUp: FC<PageSignUpProps> = () => {
const response = await axiosInstance.get( const response = await axiosInstance.get(
`/api/account/verfication/?range_phone=${countryCode}&phone_number=${phoneNumber}` `/api/account/verfication/?range_phone=${countryCode}&phone_number=${phoneNumber}`
); );
setMethod(response.data.verification_method);
form.verification_methodes = response.data.verification_method ;
router.push("/signup/methodes"); router.push("/signup/methodes");
} catch (error) { } catch (error) {
console.error("Error fetching data:", error); console.error("Error fetching data:", error);

39
src/components/contexts/userContext.tsx

@ -1,14 +1,15 @@
"use client"; "use client";
import React, { createContext, useContext, useState, ReactNode } from "react";
import React, { createContext, useContext, useState, ReactNode, useEffect } from "react";
type UserContextType = { type UserContextType = {
status: boolean;
setStatus: (status: boolean) => void;
form: Record<string, any>; form: Record<string, any>;
setForm: (form: Record<string, any>) => void; setForm: (form: Record<string, any>) => void;
method: any[];
user: Record<string, any>;
setUser: (user: Record<string, any>) => void;
method: any[];
setMethod: (method: any[]) => void; setMethod: (method: any[]) => void;
clerUser: () => void;
}; };
const UserContext = createContext<UserContextType | undefined>(undefined); const UserContext = createContext<UserContextType | undefined>(undefined);
@ -18,19 +19,43 @@ type UserProviderProps = {
}; };
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => { export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [status, setStatus] = useState<boolean>(false);
const [form, setForm] = useState<Record<string, any>>({}); const [form, setForm] = useState<Record<string, any>>({});
const [user, setUser] = useState<Record<string, any>>({});
const [method, setMethod] = useState<any[]>([]); const [method, setMethod] = useState<any[]>([]);
// Load user from localStorage on initial render
useEffect(() => {
const storedUser = localStorage.getItem("user");
if (storedUser) {
setUser(JSON.parse(storedUser));
}
}, []);
// Save user to localStorage whenever user state changes
useEffect(() => {
if (Object.keys(user).length) {
localStorage.setItem("user", JSON.stringify(user));
} else {
localStorage.removeItem("user"); // Remove user if user state is empty
}
}, [user]);
// Clear user data from state and localStorage
const clerUser = () => {
setUser({});
localStorage.removeItem("user");
};
return ( return (
<UserContext.Provider <UserContext.Provider
value={{ value={{
status,
setStatus,
form, form,
setForm, setForm,
method, method,
setMethod, setMethod,
user,
setUser,
clerUser,
}} }}
> >
{children} {children}

Loading…
Cancel
Save