From c2ef1976e382ded1c32d412f1934bfa50da011eb Mon Sep 17 00:00:00 2001 From: MHR81 Date: Wed, 24 Dec 2025 22:49:41 +0330 Subject: [PATCH] fix layout & responsive everything --- package-lock.json | 14 +- src/components/Toast.jsx | 116 ++-- src/components/layout/Header/header.jsx | 8 +- src/components/layout/Sidebar/sidebar.jsx | 22 +- src/components/layout/layout.jsx | 49 +- src/pages/CafeManagement/CafeManagement.jsx | 271 ++++---- src/pages/CafeManagement/EditCafe.jsx | 648 +++++++++----------- src/pages/Dashboard/Dashboard.jsx | 19 +- src/pages/Login/Login.jsx | 193 +++--- src/pages/Stats/Stats.jsx | 19 +- 10 files changed, 650 insertions(+), 709 deletions(-) diff --git a/package-lock.json b/package-lock.json index a774968..8133728 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2883,9 +2883,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -3892,10 +3892,10 @@ } }, "node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", - "license": "ISC", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", diff --git a/src/components/Toast.jsx b/src/components/Toast.jsx index 7ee8656..489769b 100644 --- a/src/components/Toast.jsx +++ b/src/components/Toast.jsx @@ -1,63 +1,71 @@ import { useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; +import { AnimatePresence, motion } from "framer-motion"; + +// Redux import { hideToast } from "../redux/slices/toastSlice"; -import { motion, AnimatePresence } from "framer-motion"; //eslint-disable-line no-unused-vars + +// Animation Variants +const ANIMATION_VARIANTS = { + mobile: { + initial: { y: 100, opacity: 0 }, + animate: { y: 0, opacity: 1 }, + exit: { y: 100, opacity: 0 }, + }, + desktop: { + initial: { x: -100, opacity: 0 }, + animate: { x: 0, opacity: 1 }, + exit: { x: -100, opacity: 0 }, + }, +}; + +const TOAST_COLORS = { + success: "bg-green-500", + error: "bg-red-500", + info: "bg-blue-500", +}; + +const TOAST_DURATION = 3000; export default function Toast() { - const { message, type, visible } = useSelector((state) => state.toast); - const dispatch = useDispatch(); + const { message, type, visible } = useSelector((state) => state.toast); + const dispatch = useDispatch(); + const isMobile = typeof window !== "undefined" && window.innerWidth < 768; - useEffect(() => { - if (visible) { - const timer = setTimeout(() => dispatch(hideToast()), 3000); - return () => clearTimeout(timer); - } - }, [visible, dispatch]); + // Auto-hide toast after duration + useEffect(() => { + if (visible) { + const timer = setTimeout(() => dispatch(hideToast()), TOAST_DURATION); + return () => clearTimeout(timer); + } + }, [visible, dispatch]); - const bgColor = - type === "success" - ? "bg-green-500" - : type === "error" - ? "bg-red-500" - : "bg-blue-500"; + const bgColor = TOAST_COLORS[type] || TOAST_COLORS.info; + const variants = isMobile ? ANIMATION_VARIANTS.mobile : ANIMATION_VARIANTS.desktop; - // موبایل: از پایین بیا و برگرد پایین - const mobileVariants = { - initial: { y: 100, opacity: 0 }, - animate: { y: 0, opacity: 1 }, - exit: { y: 100, opacity: 0 } - }; - - // دسکتاپ: از چپ بیا - const desktopVariants = { - initial: { x: -100, opacity: 0 }, - animate: { x: 0, opacity: 1 }, - exit: { x: -100, opacity: 0 } - }; - - // تعیین حالت بر اساس اندازه صفحه - const isMobile = typeof window !== "undefined" && window.innerWidth < 768; - const variants = isMobile ? mobileVariants : desktopVariants; - - return ( - - {visible && ( - - {message} - - )} - - ); + return ( + + {visible && ( + +

{message}

+
+ )} +
+ ); } diff --git a/src/components/layout/Header/header.jsx b/src/components/layout/Header/header.jsx index 119cfe3..3064c37 100644 --- a/src/components/layout/Header/header.jsx +++ b/src/components/layout/Header/header.jsx @@ -32,15 +32,15 @@ import Pic from "../../../assets/icons/pic.png"; const Header = ({ title }) => { return ( -
-

{title}

+
+ {/*

{title}

*/} -
+
search
-
+
user

سارا راد

arrow diff --git a/src/components/layout/Sidebar/sidebar.jsx b/src/components/layout/Sidebar/sidebar.jsx index f225438..42a9cac 100644 --- a/src/components/layout/Sidebar/sidebar.jsx +++ b/src/components/layout/Sidebar/sidebar.jsx @@ -1,4 +1,3 @@ -import React, { useState } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import LogoDM from "../../../assets/icons/LogoDM.svg"; import { BiBarChartAlt2 } from "react-icons/bi"; @@ -7,10 +6,9 @@ import { PiCoffee } from "react-icons/pi"; import { HiOutlineLogout } from "react-icons/hi"; import { FiMenu, FiX } from "react-icons/fi"; -const Sidebar = () => { +export default function Sidebar({ className, isOpen, setIsOpen }) { const location = useLocation(); const navigate = useNavigate(); - const [isOpen, setIsOpen] = useState(false); const isActive = (path) => location.pathname === path; @@ -37,7 +35,7 @@ const Sidebar = () => { <>
{/* عنوان */} -

کافه های شما

+

کافه های شما

- {/* نمایش خطا */} - {error && ( -
- {error} -
- )} - - {/* نمایش لودینگ */} - {loading ? ( -
-
در حال بارگذاری...
-
- ) : ( - <> - {/* هدر جدول */} -
-

لوگو

-

اسم

-

آدرس

-

ریتینگ

-

ساعت کاری

-

ادیت

-
- - {/* ردیف‌های جدول - دسکتاپ */} - {cafes.length > 0 ? ( - <> - {/* نمای دسکتاپ */} -
- {cafes.map((cafe) => ( - - {/* لوگو */} - لوگو - - {/* نام */} -

{cafe.Name}

- - {/* آدرس */} -

- {cafe.address} -

- - {/* ریتینگ */} -
- ستاره -

{cafe.rating || 0}

-
- - {/* ساعت کاری */} -
- لوگو -

{cafe.openinghour || "نامشخص"}

-
- - {/* دکمه ادیت */} - -

ادیت کافه

- - -
- ))} -
- - {/* نمای موبایل - کارت‌ها */} -
- {cafes.map((cafe) => ( -
-
- لوگو -
-

{cafe.Name}

-

{cafe.address}

-
-
- -
-
- ستاره - {cafe.rating || 0} -
-
- لوگو - {cafe.openinghour || "نامشخص"} -
-
- - - ادیت کافه - - -
- ))} -
- - ) : ( -
- هیچ کافه‌ای یافت نشد -
- )} - - )} + {/* محتوای اصلی */} + {renderContent()} ); }; diff --git a/src/pages/CafeManagement/EditCafe.jsx b/src/pages/CafeManagement/EditCafe.jsx index 8a18a1d..932fbc7 100644 --- a/src/pages/CafeManagement/EditCafe.jsx +++ b/src/pages/CafeManagement/EditCafe.jsx @@ -1,99 +1,131 @@ import React, { useState, useEffect } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import Bg1 from "../../assets/icons/bg1.svg"; import { GrLocation } from "react-icons/gr"; import { BiEdit } from "react-icons/bi"; import { FaRegStar } from "react-icons/fa"; +import { IoMdCheckmark, IoMdClose } from "react-icons/io"; + +// Assets +import Bg1 from "../../assets/icons/bg1.svg"; +import Vector9 from "../../assets/icons/Vector9.svg"; import Vector11 from "../../assets/icons/Vector11.svg"; import Vector12 from "../../assets/icons/Vector12.svg"; import Vector13 from "../../assets/icons/Vector13.svg"; import Vector14 from "../../assets/icons/Vector14.svg"; import Vector15 from "../../assets/icons/Vector15.svg"; -import Vector9 from "../../assets/icons/Vector9.svg"; import Vector16 from "../../assets/icons/Vector16.svg"; -import Sperso from "../../assets/icons/sperso.svg"; -import Coffee2 from "../../assets/icons/coffee2.svg"; import Coffee1 from "../../assets/icons/coffee1.svg"; +import Coffee2 from "../../assets/icons/coffee2.svg"; import Coffee3 from "../../assets/icons/coffee3.svg"; +import Sperso from "../../assets/icons/sperso.svg"; import Edit from "../../assets/icons/edit.svg"; -import { IoMdCheckmark, IoMdClose } from "react-icons/io"; + +// Services import cafeService from "../../services/cafe"; +// Constants +const DEFAULT_CATEGORIES = [ + "نوشیدنی سرد", + "نوشیدنی گرم", + "کیک و دسر", + "صبحانه", + "ساندویچ و برگر", + "سالاد و پیش غذا", +]; + +const CAFE_FEATURES = [ + { icon: Coffee3, label: "منو کافه:", width: "lg:w-[140px]" }, + { icon: Vector15, label: "ساعت کاری:", value: "23 - 8" }, + { icon: Vector14, label: "رزرو :", value: "رزرو آنلاین" }, + { icon: Vector11, label: "موسیقی :", value: "موسیقی زنده آخر هفته" }, + { icon: Vector13, label: "پارکینگ :", value: "عمومی" }, + { icon: Vector12, label: "دسترسی آسان :", value: "مناسب افراد ناتوان" }, +]; + +const CAFE_PRODUCTS = [ + { + name: "اسپرسو100%", + price: "118.000", + image: Sperso, + description: "45 میلی لیتر، قهوه، 100% عربیکا، دم شده با دستگاه اسپرسو ساز، به همراه یک عدد آب معدنی مینی", + }, + { + name: "کارامل ماکیاتو", + price: "149.000", + image: Coffee1, + description: "220 میلی لیتر، 2 شات اسپرسو 30% روبوستا، 70% عربیکا، یک لکه فوم شیر، سیروپ کارامل", + }, + { + name: "اسپرسو آفوگاتو", + price: "118.000", + image: Coffee2, + description: "اسپرسو، یک اسکوپ بستنی وانیلی", + }, +]; + export default function EditCafe() { const { id } = useParams(); const navigate = useNavigate(); + + // State Management const [cafeData, setCafeData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); - const [categories, setCategories] = useState(() => { - const saved = localStorage.getItem('cafeCategories'); - return saved ? JSON.parse(saved) : [ - "نوشیدنی سرد", - "نوشیدنی گرم", - "کیک و دسر", - "صبحانه", - "ساندویچ و برگر", - "سالاد و پیش غذا", - ]; + const saved = localStorage.getItem("cafeCategories"); + return saved ? JSON.parse(saved) : DEFAULT_CATEGORIES; }); - const [isEditMode, setIsEditMode] = useState(false); - const [isAdding, setIsAdding] = useState(false); + const [isAddingCategory, setIsAddingCategory] = useState(false); const [newCategory, setNewCategory] = useState(""); const [editingIndex, setEditingIndex] = useState(null); const [editValue, setEditValue] = useState(""); - // دریافت اطلاعات کافه + // Effects useEffect(() => { - const getCafeData = async () => { - setLoading(true); - setError(""); - try { - const res = await cafeService.getCafeList(); - if (res.data.success && res.data.data) { - const cafe = res.data.data.find(c => c._id === id); - if (cafe) { - setCafeData(cafe); - console.log("✅ Cafe data loaded:", cafe); - } else { - setError("کافه مورد نظر یافت نشد"); - } - } else { - setError("داده‌های کافه معتبر نیست"); - } - } catch (error) { - console.error("❌ Error loading cafe:", error); - if (error.response) { - setError(error.response.data.message || "خطا در دریافت اطلاعات کافه"); - } else if (error.request) { - setError("خطا در برقراری ارتباط با سرور"); - } else { - setError("خطای نامشخص رخ داده است"); - } - } finally { - setLoading(false); - } - }; - - if (id) { - getCafeData(); - } + fetchCafeData(); }, [id]); - // ذخیره دسته‌بندی‌ها در localStorage useEffect(() => { - localStorage.setItem('cafeCategories', JSON.stringify(categories)); + localStorage.setItem("cafeCategories", JSON.stringify(categories)); }, [categories]); - // Handlers + // API Calls + const fetchCafeData = async () => { + setLoading(true); + setError(""); + try { + const res = await cafeService.getCafeList(); + if (res.data.success && res.data.data) { + const cafe = res.data.data.find((c) => c._id === id); + if (cafe) { + setCafeData(cafe); + console.log("✅ Cafe data loaded:", cafe); + } else { + setError("کافه مورد نظر یافت نشد"); + } + } else { + setError("داده‌های کافه معتبر نیست"); + } + } catch (error) { + console.error("❌ Error loading cafe:", error); + const errorMessage = + error.response?.data?.message || + (error.request ? "خطا در برقراری ارتباط با سرور" : "خطای نامشخص رخ داده است"); + setError(errorMessage); + } finally { + setLoading(false); + } + }; + + // Category Handlers const handleAddCategory = () => { if (newCategory.trim()) { setCategories([...categories, newCategory.trim()]); setNewCategory(""); - setIsAdding(false); + setIsAddingCategory(false); setTimeout(() => { - const scrollContainer = document.querySelector('.categories-scroll'); + const scrollContainer = document.querySelector(".categories-scroll"); if (scrollContainer) { scrollContainer.scrollLeft = scrollContainer.scrollWidth; } @@ -102,16 +134,15 @@ export default function EditCafe() { }; const handleDeleteCategory = (index) => { - const newCategories = categories.filter((_, i) => i !== index); - setCategories(newCategories); + setCategories(categories.filter((_, i) => i !== index)); }; - const handleStartEdit = (index) => { + const handleEditCategory = (index) => { setEditingIndex(index); setEditValue(categories[index]); }; - const handleSaveEdit = () => { + const handleSaveCategory = () => { if (editValue.trim()) { const newCategories = [...categories]; newCategories[editingIndex] = editValue.trim(); @@ -126,6 +157,7 @@ export default function EditCafe() { setEditValue(""); }; + // Render States if (loading) { return (
@@ -153,307 +185,221 @@ export default function EditCafe() { } return ( - <> - -
-

ادیت {cafeData.Name}

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

ادیت {cafeData.Name}

+ + {/* Main Container */} +
+ {/* Cafe Info Section */} +
+ {/* Image */} +
+ {cafeData.Name} +
+ + {/* Info */} +
+ {/* Action Buttons */} +
+ +
-
-
- - + {/* Basic Info */} +
+
+

{cafeData.Name}

+
- -

{cafeData.Name}

-
- -
- - {cafeData.address || "آدرس موجود نیست"} -
-
- -
- - {cafeData.rating || 0} +
+ + {cafeData.address || "آدرس موجود نیست"}
-

درباره کافه

- - {cafeData.description || "توضیحاتی برای این کافه وجود ندارد."} - -
- -

- ویژگی ها -

- -
-
- - - منو کافه: - -
- -
- - ساعت کاری: - 23 - 8 -
- -
- - رزرو : - رزرو آنلاین -
- -
- - موسیقی : - موسیقی زنده آخر هفته -
- -
- - پارکینگ : - عمومی -
- -
- - دسترسی آسان : - مناسب افراد ناتوان -
- -
- -
+
+ + {cafeData.rating || 0}
-
-
-
-
-
- Logo setIsEditMode(!isEditMode)} - title={isEditMode ? "خروج از حالت ویرایش" : "ویرایش عنوان‌ها"} - /> - عنوان -
- - {!isEditMode ? ( - <> - {categories.map((category, index) => ( - {category} - ))} - - ) : ( - <> - {categories.map((category, index) => ( -
- {editingIndex === index ? ( - <> -
- - -
- setEditValue(e.target.value)} - className="border-2 border-[#bb8f70] rounded-lg px-2 py-1 text-sm focus:outline-none focus:border-[#7f4629] w-[100px] text-center" - autoFocus - /> - - ) : ( - <> -
- handleStartEdit(index)} - title="ویرایش" - /> - {category} - handleDeleteCategory(index)} - title="حذف" - /> -
- - )} -
- ))} - - )} -
-
- - {isEditMode && ( -
- {!isAdding ? ( - - ) : ( -
-
- - { - setIsAdding(false); - setNewCategory(""); - }} - title="لغو" - /> -
- setNewCategory(e.target.value)} - placeholder="عنوان جدید" - className="border-2 border-[#bb8f70] rounded-lg px-2 py-1 text-sm focus:outline-none focus:border-[#7f4629] w-[100px] text-center" - autoFocus - /> -
- )} -
- )} -
-
-
- -
- Logo -

افزودن زیر عنوان

-
- -
- Logo - Logo -

قهوه ها

-
-
- -
- Logo -

آیتم

-
- -
-
-

اسپرسو100%

- Logo -
- قیمت - 118.000 -
- - 45 میلی لیتر، قهوه، 100% عربیکا، دم شده با دستگاه اسپرسو ساز، - به همراه یک عدد آب معدنی مینی - -
-
- -
-

- کارامل ماکیاتو -

- Logo -
- قیمت - 149.000 -
- - 220 میلی لیتر، 2 شات اسپرسو 30% روبوستا، 70% عربیکا، یک لکه - فوم شیر، سیروپ کارامل - -
-
- -
-

- اسپرسو آفوگاتو -

- Logo -
- قیمت - 118.000 -
- - اسپرسو، یک اسکوپ بستنی وانیلی - -
-
-
+

درباره کافه

+

+ {cafeData.description || "توضیحاتی برای این کافه وجود ندارد."} +

-
- - ); - } +
+ + {/* Features Section */} +
+

ویژگی ها

+
+ {CAFE_FEATURES.map((feature, idx) => ( +
+ {feature.label} + + {feature.label} + + {feature.value && ( + {feature.value} + )} +
+ ))} + +
+
+ + {/* Categories Section */} +
+
+

دسته‌بندی‌ها

+ +
+ +
+ {categories.map((category, idx) => ( +
+ {isEditMode && editingIndex === idx ? ( +
+
+ + +
+ setEditValue(e.target.value)} + className="border-2 border-[#bb8f70] rounded-lg px-2 py-1 text-xs md:text-sm focus:outline-none focus:border-[#7f4629] min-w-[100px]" + autoFocus + /> +
+ ) : ( +
+ {category} + {isEditMode && ( + <> + handleEditCategory(idx)} + className="text-[#7f4629] cursor-pointer hover:text-[#5f494f] w-4 h-4 ml-1" + title="ویرایش" + /> + handleDeleteCategory(idx)} + className="text-white bg-[#a79fa1] rounded cursor-pointer hover:bg-[#9a8f91] w-4 h-4" + title="حذف" + /> + + )} +
+ )} +
+ ))} + + {isEditMode && !isAddingCategory && ( + + )} + + {isEditMode && isAddingCategory && ( +
+
+ + { + setIsAddingCategory(false); + setNewCategory(""); + }} + className="text-red-600 cursor-pointer hover:text-red-800 w-5 h-5" + title="لغو" + /> +
+ setNewCategory(e.target.value)} + placeholder="دسته جدید" + className="border-2 border-[#bb8f70] rounded-lg px-2 py-1 text-xs md:text-sm focus:outline-none focus:border-[#7f4629] min-w-[100px]" + autoFocus + /> +
+ )} +
+
+ + {/* Products Section */} +
+

محصولات

+
+ {CAFE_PRODUCTS.map((product, idx) => ( +
+

{product.name}

+ {product.name} +
+ قیمت: + {product.price} +
+

+ {product.description} +

+
+ ))} +
+
+
+ + ); +} diff --git a/src/pages/Dashboard/Dashboard.jsx b/src/pages/Dashboard/Dashboard.jsx index 5be2154..96f017e 100644 --- a/src/pages/Dashboard/Dashboard.jsx +++ b/src/pages/Dashboard/Dashboard.jsx @@ -1,14 +1,15 @@ -import {useProfile} from "../../hooks/useProfile"; +import React from "react"; +import { useProfile } from "../../hooks/useProfile"; -const Dashboard = () => { +export default function Dashboard() { useProfile(); - return ( -
- صفحه داشبورد -
+
+

صفحه داشبورد

+
+

محتوای داشبورد به‌زودی اضافه خواهد شد

+
+
); -}; - -export default Dashboard; \ No newline at end of file +} \ No newline at end of file diff --git a/src/pages/Login/Login.jsx b/src/pages/Login/Login.jsx index cba36af..903bbb3 100644 --- a/src/pages/Login/Login.jsx +++ b/src/pages/Login/Login.jsx @@ -1,202 +1,179 @@ -import React, { useState } from 'react'; -import Loginpic from '../../assets/image/loginpic.jpg'; -import { FiLock } from 'react-icons/fi'; +import React, { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { FiLock } from "react-icons/fi"; import { FaRegUser } from "react-icons/fa6"; + +// Assets +import Loginpic from "../../assets/image/loginpic.jpg"; import LogoDM from "../../assets/icons/LogoDM.svg"; -import { useNavigate, Navigate } from 'react-router-dom'; -import authService from '../../services/auth'; -import { useDispatch } from 'react-redux'; -import { setToken } from '../../redux/slices/authSlice'; -import { setProfile } from '../../redux/slices/profileSlice'; +// Redux +import { setToken } from "../../redux/slices/authSlice"; +import { setProfile } from "../../redux/slices/profileSlice"; -const Login = () => { - const [userName, setUserName] = useState(''); - const [password, setPassword] = useState(''); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); +// Services +import authService from "../../services/auth"; + +export default function Login() { const navigate = useNavigate(); const dispatch = useDispatch(); + // State Management + const [userName, setUserName] = useState(""); + const [password, setPassword] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + // Handle Login const handleLogin = async (e) => { e.preventDefault(); - setError(''); + setError(""); setLoading(true); - const loginData = { - userName: userName, - password: password - }; - try { - const res = await authService.login(loginData); - if (res.data.success && res.data.data && res.data.data.tokens.accessToken) { + const res = await authService.login({ userName, password }); + if (res.data.success && res.data.data?.tokens?.accessToken) { dispatch(setToken(res.data.data.tokens.accessToken)); - navigate('/dashboard'); dispatch(setProfile(res.data.data.admin)); - console.log('login:', res.data.data.admin); + console.log("✅ Login successful:", res.data.data.admin); + navigate("/dashboard"); + } else { + setError("اطلاعات دریافتی معتبر نیست"); } - - console.log('Response:', res); } catch (error) { - setLoading(false); - console.error('❌ Login error:', error); - // if (error.response) { - // setError(error.response.data.message || error.response.data.en_message || 'نام کاربری یا رمز عبور اشتباه است'); - // } else if (error.request) { - // setError('خطا در برقراری ارتباط با سرور'); - // } else { - // console.error('Error setting up request'); - // setError('خطای نامشخص رخ داده است'); - // } + console.error("❌ Login error:", error); + const errorMessage = + error.response?.data?.message || + (error.request ? "خطا در برقراری ارتباط با سرور" : "خطای نامشخص رخ داده است"); + setError(errorMessage); } finally { setLoading(false); } - }; return ( -
-
-
+
+ {/* Header */} +
+
+ {/* Left Section */}
-
- Logo -
+ Logo
- - +
- + {/* Center Links (Hidden on Mobile) */} + -
- -
+ {/* Right Section */} +
-
+
-
-
-
-
+ {/* Main Content */} +
+ {/* Left Side - Login Form */} +
+
+ {/* Breadcrumb */} +
ورود - > + > خانه
+ {/* Header */}
-

- ورود ادمین -

-

- دسترسی ویژه برای مدیریت و گزارش‌ها -

+

ورود ادمین

+

دسترسی ویژه برای مدیریت و گزارش‌ها

+ {/* Login Form */}
+ {/* Error Message */} {error && (
{error}
)} + {/* Username Field */}
- +
setUserName(e.target.value)} placeholder="userName" - className="w-full pl-14 pr-6 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors" + className="w-full pl-12 pr-4 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors text-sm" dir="ltr" + required /> - +
+ {/* Password Field */}
- +
setPassword(e.target.value)} placeholder="password" - className="w-full pl-14 pr-6 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors" + className="w-full pl-12 pr-4 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors text-sm" dir="ltr" + required /> - +
+ {/* Forgot Password */} + {/* Submit Button */}
-
- Coffee workspace + {/* Right Side - Image (Hidden on Mobile) */} +
+ Coffee workspace
); -}; - - - -export default Login; \ No newline at end of file +} \ No newline at end of file diff --git a/src/pages/Stats/Stats.jsx b/src/pages/Stats/Stats.jsx index 4d3980d..c118e08 100644 --- a/src/pages/Stats/Stats.jsx +++ b/src/pages/Stats/Stats.jsx @@ -1,9 +1,12 @@ -const Stats = () => { - return ( -
- صفحه آمار و تحلیل -
- ); -}; +import React from "react"; -export default Stats; \ No newline at end of file +export default function Stats() { + return ( +
+

آمار و تحلیل

+
+

محتوای آمار و تحلیل به‌زودی اضافه خواهد شد

+
+
+ ); +} \ No newline at end of file