From e1e507b7450b552c57a2d3c3c1b135821d2cd922 Mon Sep 17 00:00:00 2001 From: asmaamostafa74 Date: Tue, 1 Jul 2025 15:04:16 +0300 Subject: [PATCH 1/4] update profile --- src/api/auth/updateUser.ts | 16 ++++++ src/components/profile/ProfileDetails.tsx | 65 +++++++++++++++++++++-- src/components/profile/ProfileSidebar.tsx | 5 +- src/components/stores/userStore.ts | 2 + 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/api/auth/updateUser.ts diff --git a/src/api/auth/updateUser.ts b/src/api/auth/updateUser.ts new file mode 100644 index 0000000..5719d35 --- /dev/null +++ b/src/api/auth/updateUser.ts @@ -0,0 +1,16 @@ +import { axios } from "@/lib/axios"; + +interface UpdateUserPayload { + name?: string; + email?: string; + phone?: string; + phone_country?: string; +} + +export const updateUser = async (payload: UpdateUserPayload) => { + + const response = await axios.post("/user/update", payload, { + }); + + return response.data; +}; diff --git a/src/components/profile/ProfileDetails.tsx b/src/components/profile/ProfileDetails.tsx index 9d62878..b23e158 100644 --- a/src/components/profile/ProfileDetails.tsx +++ b/src/components/profile/ProfileDetails.tsx @@ -1,6 +1,52 @@ -import React from "react"; +"use client" +import React, { useEffect, useState } from "react"; +import { useAuthStore } from "../stores/userStore"; +import { updateUser } from "@/api/auth/updateUser"; +import { toast } from "sonner"; const ProfileDetails = () => { + const user = useAuthStore((state) => state.user); + const setUser = useAuthStore((state) => state.setUser); + const [formData, setFormData] = useState({ + name: "", + email: "", + phone: "", + job: "", + }); + + console.log(user) + + useEffect(() => { + if (user) { + setFormData({ + name: user.name || "", + email: user.email || "", + phone: user.phone || "", + job: user.job || "" + }); + } + }, [user]); + +const handleUpdate = async () => { + try { + const updatedUser = await updateUser({ + name: formData.name, + phone: formData.phone, + phone_country: "EG", + }); + + setUser(updatedUser.user); + + toast.success("تم تحديث البيانات بنجاح"); + } catch (error: any) { + toast.error( + error?.response?.data?.message || "حدث خطأ أثناء تحديث البيانات" + ); + console.error("Update failed:", error); + } +}; + + return (
@@ -18,6 +64,8 @@ const ProfileDetails = () => { id="name" placeholder="وليد السيد" className="w-full h-16 border border-[#9C9C9C] rounded-[12px] px-4" + value={formData.name} + onChange={(e) => setFormData({ ...formData, name: e.target.value })} />
@@ -34,6 +82,8 @@ const ProfileDetails = () => { id="tel" placeholder="123 4434 543" className="lg:w-[358px] w-full h-16 border border-[#9C9C9C] rounded-[12px] px-4" + value={formData.phone} + onChange={(e) => setFormData({ ...formData, phone: e.target.value })} />
@@ -49,6 +99,8 @@ const ProfileDetails = () => { id="email" placeholder="Walid Elsayed22@Gmail.com" className="lg:w-[358px] w-full h-16 border border-[#9C9C9C] rounded-[12px] px-4" + value={formData.email} + readOnly />

لا يمكن تغيير البريد الإلكتروني المستخدم لتسجيل الدخول @@ -67,12 +119,17 @@ const ProfileDetails = () => { id="job" placeholder="UI UX Designer" className="lg:w-[358px] w-full h-16 border border-[#9C9C9C] rounded-[12px] px-4" + value={formData.job} + onChange={(e) => setFormData({ ...formData, job: e.target.value })} />

-
- حفظ التعديلات -
+
); }; diff --git a/src/components/profile/ProfileSidebar.tsx b/src/components/profile/ProfileSidebar.tsx index 28b5780..8e96bc1 100644 --- a/src/components/profile/ProfileSidebar.tsx +++ b/src/components/profile/ProfileSidebar.tsx @@ -1,8 +1,11 @@ import Image from "next/image"; import React from "react"; import ProfileTabs from "./ProfileTabs"; +import { useAuthStore } from "../stores/userStore"; const ProfileSidebar = ({ activeTab, setActiveTab }) => { + const user = useAuthStore((state) => state.user); + return (
{ className="absolute bottom-0 right-0" /> -

وليد السيد

+

{user?.name}

UI UX Designer

diff --git a/src/components/stores/userStore.ts b/src/components/stores/userStore.ts index 3f21533..7235ea8 100644 --- a/src/components/stores/userStore.ts +++ b/src/components/stores/userStore.ts @@ -5,6 +5,8 @@ interface User { id: number; name: string; email: string; + phone: string; + job: string; } interface AuthState { From d247200061da6f4f28ecbd6717c03ff8c984b1e2 Mon Sep 17 00:00:00 2001 From: asmaamostafa74 Date: Wed, 2 Jul 2025 09:50:43 +0300 Subject: [PATCH 2/4] handle logout --- src/api/auth/logout.tsx | 7 ++++ src/components/profile/ProfileDetails.tsx | 6 +-- src/components/profile/ProfileTabs.tsx | 47 ++++++++++++++++++----- 3 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 src/api/auth/logout.tsx diff --git a/src/api/auth/logout.tsx b/src/api/auth/logout.tsx new file mode 100644 index 0000000..809a79a --- /dev/null +++ b/src/api/auth/logout.tsx @@ -0,0 +1,7 @@ +import { axios } from "@/lib/axios"; + +export const logOut = async () => { + const response = await axios.post(`/user/logout`, { + }); + return response.data; +}; diff --git a/src/components/profile/ProfileDetails.tsx b/src/components/profile/ProfileDetails.tsx index b23e158..03f2639 100644 --- a/src/components/profile/ProfileDetails.tsx +++ b/src/components/profile/ProfileDetails.tsx @@ -8,9 +8,9 @@ const ProfileDetails = () => { const user = useAuthStore((state) => state.user); const setUser = useAuthStore((state) => state.setUser); const [formData, setFormData] = useState({ - name: "", - email: "", - phone: "", + name: user?.name, + email: user?.email, + phone: user?.phone, job: "", }); diff --git a/src/components/profile/ProfileTabs.tsx b/src/components/profile/ProfileTabs.tsx index 2799ecb..2aa776c 100644 --- a/src/components/profile/ProfileTabs.tsx +++ b/src/components/profile/ProfileTabs.tsx @@ -4,20 +4,49 @@ import Favorite from "../icons/profile/Favorite"; import Bookmarks from "../icons/profile/Bookmarks"; import MyProducts from "../icons/profile/MyProducts"; import Logout from "../icons/profile/Logout"; +import { logOut } from "@/api/auth/logout"; +import { toast } from "sonner"; + +interface ProfileTabsProps { + activeTab: string; + setActiveTab: (tab: string) => void; +} + +interface TabItem { + key: string; + icon: React.ReactNode; + label: string; +} + +const ProfileTabs: React.FC = ({ activeTab, setActiveTab }) => { + const handleTabClick = async (tabKey: string): Promise => { + if (tabKey === "logout") { + try { + await logOut(); + toast.success("Logged out successfully") + window.location.href = "/"; + } catch { + toast.error("Logout failed"); + } + } else { + setActiveTab(tabKey); + } + }; + + const tabs: TabItem[] = [ + { key: "profile", icon: , label: "الملف الشخصي" }, + { key: "favorite", icon: , label: "المفضلة" }, + { key: "bookmarks", icon: , label: "المحفوظات" }, + { key: "products", icon: , label: "منتجاتي" }, + { key: "logout", icon: , label: "تسجيل الخروج" }, + ]; -const ProfileTabs = ({ activeTab, setActiveTab }) => { return (
- {[ - { key: "profile", icon: , label: "الملف الشخصي" }, - { key: "favorite", icon: , label: "المفضلة" }, - { key: "bookmarks", icon: , label: "المحفوظات" }, - { key: "products", icon: , label: "منتجاتي" }, - { key: "logout", icon: , label: "تسجيل الخروج" }, - ].map((tab) => ( + {tabs.map((tab: TabItem) => (
setActiveTab(tab.key)} + onClick={() => handleTabClick(tab.key)} className="flex items-center gap-3 cursor-pointer mb-4" > {tab.icon} From e3b2893595baefb4afc6f2dfe4ba42da34c8007f Mon Sep 17 00:00:00 2001 From: asmaamostafa74 Date: Wed, 2 Jul 2025 10:04:52 +0300 Subject: [PATCH 3/4] fix header icons --- src/components/general/header/Header.tsx | 21 ++++++++++++++------- src/components/profile/ProfileTabs.tsx | 9 ++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/components/general/header/Header.tsx b/src/components/general/header/Header.tsx index 522b7a4..8746182 100644 --- a/src/components/general/header/Header.tsx +++ b/src/components/general/header/Header.tsx @@ -17,6 +17,7 @@ const Header = () => { const pathname = usePathname(); const user = useAuthStore((state) => state.user); const isSignedIn = !!user; + const [hydrated, setHydrated] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isScrolled, setIsScrolled] = useState(false); @@ -51,6 +52,10 @@ const Header = () => { setIsMobileMenuOpen(!isMobileMenuOpen); }; + useEffect(() => { + setHydrated(true); + }, []); + return ( <> { whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > - {isSignedIn ? ( - - - - ) : ( - - )} + {hydrated && ( + isSignedIn ? ( + + + + ) : ( + + ) + )} = ({ activeTab, setActiveTab }) => { + const clearUser = useAuthStore((state) => state.clearUser); + const router = useRouter(); + const handleTabClick = async (tabKey: string): Promise => { if (tabKey === "logout") { try { await logOut(); + clearUser(); toast.success("Logged out successfully") - window.location.href = "/"; + router.push("/") } catch { toast.error("Logout failed"); } From 090c40f4a6dc73add4418ea59d7b7db94018cecd Mon Sep 17 00:00:00 2001 From: asmaamostafa74 Date: Wed, 2 Jul 2025 13:52:43 +0300 Subject: [PATCH 4/4] in stock --- src/components/ProductsPage/ProductCard.tsx | 10 +++++++++- src/types/product.ts | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/components/ProductsPage/ProductCard.tsx b/src/components/ProductsPage/ProductCard.tsx index 6d6c403..b0ec462 100644 --- a/src/components/ProductsPage/ProductCard.tsx +++ b/src/components/ProductsPage/ProductCard.tsx @@ -23,6 +23,7 @@ const ProductCard = ({ product }: ProductCardProps) => { const isNew = true; const price = parseInt(product.price); const discount = parseInt(product.discount); + const isAvailable = product.types?.some((type) => type.in_stock); const handleAddToCart = async (e: React.MouseEvent) => { e.preventDefault(); @@ -301,7 +302,7 @@ const handleAddToCart = async (e: React.MouseEvent) => { )} - @@ -313,6 +314,7 @@ const handleAddToCart = async (e: React.MouseEvent) => { > + ))} ) => { > (5) + */} + + {isAvailable ? "متوفر" : "غير متوفر"} diff --git a/src/types/product.ts b/src/types/product.ts index 90ecfb5..987d1fc 100644 --- a/src/types/product.ts +++ b/src/types/product.ts @@ -12,6 +12,11 @@ export type ProductOptionTypes = { in_stock: boolean; }; +export type ProductTypeOption = { + value: string; + in_stock: boolean; +}; + export interface ProductTypes { id: number; name: { @@ -25,6 +30,7 @@ export interface ProductTypes { price: string; discount: string; options: ProductOptionTypes[]; + types: ProductTypeOption[]; category_id: number; brand_id: number | null; is_active: number;