finnal pages
This commit is contained in:
parent
872a98fd9f
commit
e72cd844f5
32
src/App.jsx
32
src/App.jsx
|
|
@ -1,11 +1,9 @@
|
||||||
import "./styles/App.css";
|
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
||||||
import Layout from "./components/layout/layout";
|
import Login, { ProtectedRoute } from './pages/Login/Login';
|
||||||
import Login from "./pages/Login/Login";
|
import Layout from './components/Layout/Layout';
|
||||||
import Dashboard from "./pages/Dashboard/Dashboard";
|
import Dashboard from './pages/Dashboard/Dashboard';
|
||||||
import CafeManagement from "./pages/CafeManagement/CafeManagement";
|
import CafeManagement from './pages/CafeManagement/CafeManagement';
|
||||||
import EditCafe from "./pages/CafeManagement/EditCafe";
|
import EditCafe from './pages/CafeManagement/EditCafe';
|
||||||
import Stats from "./pages/Stats/Stats";
|
|
||||||
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -13,17 +11,23 @@ function App() {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
|
||||||
<Route path="/" element={<Layout />}>
|
<Route
|
||||||
<Route index element={<Navigate to="/dashboard" replace />} />
|
path="/"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Layout />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Route path="dashboard" element={<Dashboard />} />
|
<Route path="dashboard" element={<Dashboard />} />
|
||||||
|
|
||||||
<Route path="cafe-management" element={<CafeManagement />} />
|
<Route path="cafe-management" element={<CafeManagement />} />
|
||||||
|
|
||||||
<Route path="edit-cafe/:id" element={<EditCafe />} />
|
<Route path="edit-cafe/:id" element={<EditCafe />} />
|
||||||
|
<Route path="stats" element={<div>صفحه آمار و تحلیل</div>} />
|
||||||
|
|
||||||
<Route path="stats" element={<Stats />} />
|
<Route index element={<Navigate to="/dashboard" replace />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Outlet, useLocation } from "react-router-dom";
|
import { Outlet, useLocation } from "react-router-dom";
|
||||||
import Sidebar from "./sidebar";
|
import Sidebar from "./Sidebar";
|
||||||
import Header from "./header";
|
import Header from "./Header";
|
||||||
|
|
||||||
export default function Layout() {
|
export default function Layout() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
@ -24,16 +24,22 @@ export default function Layout() {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row h-screen bg-[#FDF8F4]">
|
<div className="flex flex-row min-h-screen bg-[#FDF8F4]">
|
||||||
<div className="fixed right-0 top-0 bottom-0 z-40">
|
{/* Sidebar - در موبایل overlay، در دسکتاپ ثابت */}
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<div className="flex-1 flex flex-col min-h-screen w-full lg:mr-[220px]">
|
||||||
|
{showHeader && (
|
||||||
|
<div className="fixed top-0 right-0 left-0 lg:right-[220px] z-30 bg-[#FDF8F4]">
|
||||||
|
<Header title="مدیریت کافهها" />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col mr-[220px] h-screen">
|
<main className={`flex-1 w-full overflow-x-hidden p-4 md:p-6 bg-[#FDF8F4] ${showHeader ? 'pt-20 lg:pt-24' : 'pt-16 lg:pt-6'}`}>
|
||||||
{showHeader && <Header title="مدیریت کافهها" />}
|
<div className="max-w-full mx-auto">
|
||||||
|
|
||||||
<main className="flex-1 overflow-y-auto p-6 bg-[#FDF8F4] pt-[80px]">
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,109 +1,172 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import LogoDM from "../../assets/icons/LogoDM.svg";
|
import LogoDM from "../../assets/icons/LogoDM.svg";
|
||||||
import { BiBarChartAlt2 } from "react-icons/bi";
|
import { BiBarChartAlt2 } from "react-icons/bi";
|
||||||
import { AiOutlinePieChart } from "react-icons/ai";
|
import { AiOutlinePieChart } from "react-icons/ai";
|
||||||
import { PiCoffee } from "react-icons/pi";
|
import { PiCoffee } from "react-icons/pi";
|
||||||
import { HiOutlineLogout } from "react-icons/hi";
|
import { HiOutlineLogout } from "react-icons/hi";
|
||||||
|
import { FiMenu, FiX } from "react-icons/fi";
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
// چک کردن صفحه فعال
|
|
||||||
const isActive = (path) => location.pathname === path;
|
const isActive = (path) => location.pathname === path;
|
||||||
|
|
||||||
// تابع خروج
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
localStorage.removeItem("token");
|
try {
|
||||||
navigate("/login");
|
localStorage.removeItem('accessToken');
|
||||||
|
localStorage.removeItem('refreshToken');
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
localStorage.removeItem('adminInfo');
|
||||||
|
|
||||||
|
console.log('Tokens cleared from localStorage');
|
||||||
|
console.log('Current token:', localStorage.getItem('token'));
|
||||||
|
|
||||||
|
window.location.href = '/login';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Logout error:', error);
|
||||||
|
window.location.href = '/login';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeSidebar = () => setIsOpen(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
className="sm:hidden fixed top-3 right-3 z-[70] bg-[#7F4629] text-white p-2.5 rounded-lg shadow-lg"
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
>
|
||||||
|
{isOpen ? <FiX className="w-5 h-5" /> : <FiMenu className="w-5 h-5" />}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isOpen && (
|
||||||
|
<div
|
||||||
|
className="sm:hidden fixed inset-0 bg-black/50 z-[60]"
|
||||||
|
onClick={closeSidebar}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<aside
|
<aside
|
||||||
dir="rtl"
|
dir="rtl"
|
||||||
className="fixed right-0 top-0 z-50 flex h-screen w-[220px] flex-col bg-[#EFEEEE] rounded-tl-3xl rounded-bl-3xl shadow-xl border-l border-[#D9CAB3]"
|
className={`
|
||||||
|
fixed top-0 right-0 z-[65]
|
||||||
|
h-screen w-[260px]
|
||||||
|
flex flex-col
|
||||||
|
bg-[#EFEEEE]
|
||||||
|
rounded-tl-2xl rounded-bl-2xl
|
||||||
|
shadow-xl border-l border-[#D9CAB3]
|
||||||
|
transition-transform duration-300 ease-in-out
|
||||||
|
${isOpen ? 'translate-x-0' : 'translate-x-full'}
|
||||||
|
sm:translate-x-0 sm:w-[220px]
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
<div className="flex justify-center mt-6">
|
<div className="flex justify-center mt-5 mb-2">
|
||||||
<img src={LogoDM} className="h-12 w-12" alt="Logo" />
|
<img src={LogoDM} className="h-10 w-10 sm:h-12 sm:w-12" alt="Logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav className="w-[85%] mr-4 mt-8 space-y-4">
|
<nav className="flex-1 px-3 mt-6 space-y-3 overflow-y-auto">
|
||||||
{/* داشبورد */}
|
|
||||||
<Link
|
<Link
|
||||||
to="/dashboard"
|
to="/dashboard"
|
||||||
className={`group relative flex items-center gap-3 rounded-xl p-3 transition-all duration-300 hover:shadow-md ${
|
onClick={closeSidebar}
|
||||||
isActive("/dashboard") ? "bg-[#7F4629] shadow-md" : "hover:bg-[#7F4629]"
|
className={`group flex items-center gap-2.5 rounded-lg p-2.5 transition-all duration-200 ${
|
||||||
|
isActive("/dashboard")
|
||||||
|
? "bg-[#7F4629] shadow-md"
|
||||||
|
: "hover:bg-[#7F4629]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<BiBarChartAlt2
|
<BiBarChartAlt2
|
||||||
className={`w-6 h-6 transition-colors ${
|
className={`w-5 h-5 flex-shrink-0 transition-colors ${
|
||||||
isActive("/dashboard") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/dashboard")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`font-medium transition-colors ${
|
className={`text-sm font-medium transition-colors ${
|
||||||
isActive("/dashboard") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/dashboard")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
داشبورد
|
داشبورد
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* مدیریت کافهها */}
|
|
||||||
<Link
|
<Link
|
||||||
to="/cafe-management"
|
to="/cafe-management"
|
||||||
className={`group flex items-center gap-3 rounded-xl p-3 transition-all duration-300 hover:shadow-md ${
|
onClick={closeSidebar}
|
||||||
isActive("/cafe-management") ? "bg-[#7F4629] shadow-md" : "hover:bg-[#7F4629]"
|
className={`group flex items-center gap-2.5 rounded-lg p-2.5 transition-all duration-200 ${
|
||||||
|
isActive("/cafe-management")
|
||||||
|
? "bg-[#7F4629] shadow-md"
|
||||||
|
: "hover:bg-[#7F4629]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<PiCoffee
|
<PiCoffee
|
||||||
className={`w-6 h-6 transition-colors ${
|
className={`w-5 h-5 flex-shrink-0 transition-colors ${
|
||||||
isActive("/cafe-management") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/cafe-management")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`font-medium transition-colors ${
|
className={`text-sm font-medium transition-colors ${
|
||||||
isActive("/cafe-management") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/cafe-management")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
مدیریت کافه ها
|
مدیریت کافه ها
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* آمار و تحلیل */}
|
|
||||||
<Link
|
<Link
|
||||||
to="/stats"
|
to="/stats"
|
||||||
className={`group flex items-center gap-3 rounded-xl p-3 transition-all duration-300 hover:shadow-md ${
|
onClick={closeSidebar}
|
||||||
isActive("/stats") ? "bg-[#7F4629] shadow-md" : "hover:bg-[#7F4629]"
|
className={`group flex items-center gap-2.5 rounded-lg p-2.5 transition-all duration-200 ${
|
||||||
|
isActive("/stats")
|
||||||
|
? "bg-[#7F4629] shadow-md"
|
||||||
|
: "hover:bg-[#7F4629]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<AiOutlinePieChart
|
<AiOutlinePieChart
|
||||||
className={`w-6 h-6 transition-colors ${
|
className={`w-5 h-5 flex-shrink-0 transition-colors ${
|
||||||
isActive("/stats") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/stats")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`font-medium transition-colors ${
|
className={`text-sm font-medium transition-colors ${
|
||||||
isActive("/stats") ? "text-white" : "text-[#402E32] group-hover:text-white"
|
isActive("/stats")
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#402E32] group-hover:text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
آمار و تحلیل
|
آمار و تحلیل
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
</nav>
|
||||||
|
|
||||||
{/* خروج */}
|
<div className="p-3 border-t border-[#D9CAB3]">
|
||||||
<button
|
<button
|
||||||
onClick={handleLogout}
|
onClick={() => {
|
||||||
className="group flex items-center gap-3 rounded-xl p-3 transition-all duration-300 hover:bg-[#7F4629] hover:shadow-md mt-18 w-full text-right"
|
handleLogout();
|
||||||
|
closeSidebar();
|
||||||
|
}}
|
||||||
|
className="group flex items-center gap-2.5 rounded-lg p-2.5 transition-all duration-200 hover:bg-[#7F4629] w-full"
|
||||||
>
|
>
|
||||||
<HiOutlineLogout className="w-6 h-6 text-[#402E32] transition-colors group-hover:text-white" />
|
<HiOutlineLogout className="w-5 h-5 flex-shrink-0 text-[#402E32] transition-colors group-hover:text-white" />
|
||||||
<span className="text-[#402E32] font-medium transition-colors group-hover:text-white">
|
<span className="text-sm text-[#402E32] font-medium transition-colors group-hover:text-white">
|
||||||
خروج
|
خروج
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,106 +1,126 @@
|
||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { BiEdit } from "react-icons/bi";
|
import { BiEdit } from "react-icons/bi";
|
||||||
import Search from "../../assets/icons/search.svg";
|
import axios from "axios";
|
||||||
import Arrow from "../../assets/icons/arrow.svg";
|
|
||||||
import Vector7 from "../../assets/icons/Vector7.svg";
|
|
||||||
import Vector8 from "../../assets/icons/Vector8.svg";
|
|
||||||
import Vector9 from "../../assets/icons/Vector9.svg";
|
import Vector9 from "../../assets/icons/Vector9.svg";
|
||||||
import Star1 from "../../assets/icons/Star1.svg";
|
import Star1 from "../../assets/icons/Star1.svg";
|
||||||
import Group from "../../assets/icons/Group.svg";
|
import Group from "../../assets/icons/Group.svg";
|
||||||
import Pic from "../../assets/icons/pic.png";
|
|
||||||
import Pic1 from "../../assets/icons/pic1.svg";
|
import Pic1 from "../../assets/icons/pic1.svg";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const cafes = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "کافه ترنج",
|
|
||||||
location: "اصفهان - خیابان آذر",
|
|
||||||
rating: 3.7,
|
|
||||||
category: "دسته بندی",
|
|
||||||
logo: Pic1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "کافه سیب",
|
|
||||||
location: "تهران - خیابان ولیعصر",
|
|
||||||
rating: 4.2,
|
|
||||||
category: "کافه سنتی",
|
|
||||||
logo: Pic1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "کافه داونتاون",
|
|
||||||
location: "شیراز - خیابان زند",
|
|
||||||
rating: 4.0,
|
|
||||||
category: "کافه فرهنگی",
|
|
||||||
logo: Pic1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const CafeManagement = () => {
|
const CafeManagement = () => {
|
||||||
|
const [cafes, setCafes] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
// دریافت لیست کافهها از API
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchCafes = () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError("");
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get("https://cafeju.maksiran.ir/api/cafe/v1/get-cafe-list")
|
||||||
|
.then((response) => {
|
||||||
|
console.log("✅ Cafes loaded successfully:", response.data);
|
||||||
|
|
||||||
|
if (response.data.success && response.data.data) {
|
||||||
|
setCafes(response.data.data);
|
||||||
|
} else {
|
||||||
|
setError("دادههای دریافتی معتبر نیست");
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("❌ Error loading cafes:", error);
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
if (error.response) {
|
||||||
|
setError(error.response.data.message || "خطا در دریافت لیست کافهها");
|
||||||
|
} else if (error.request) {
|
||||||
|
setError("خطا در برقراری ارتباط با سرور");
|
||||||
|
} else {
|
||||||
|
setError("خطای نامشخص رخ داده است");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchCafes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section dir="rtl" className="-mt-12">
|
<section dir="rtl" className="-mt-12 w-full max-w-full overflow-x-hidden">
|
||||||
{/* ===== Header ===== */}
|
{/* دکمه افزودن */}
|
||||||
{/* <header className="flex items-center gap-4">
|
|
||||||
<h3 className="text-[#402E32] w-[90%] font-bold">مدیریت کافه</h3>
|
|
||||||
|
|
||||||
<div className="w-12 h-10 border-2 border-[#8B8886] flex justify-center items-center rounded-2xl bg-[#E6DBCC]">
|
|
||||||
<img src={Search} alt="لوگو" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-45 h-10 border-2 border-[#8B8886] flex justify-center items-center rounded-2xl bg-[#E6DBCC]">
|
|
||||||
<img src={Pic} className="w-10 h-10 shadow-2xl ml-1" alt="لوگو" />
|
|
||||||
<p className="text-[#402E32] -mt-1.5 pl-1.5">سارا راد</p>
|
|
||||||
<img src={Arrow} alt="لوگو" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<img src={Vector7} alt="لوگو" />
|
|
||||||
</header> */}
|
|
||||||
|
|
||||||
{/* ===== Add Button ===== */}
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<button className="w-45 h-12 bg-[#7F4629] text-white mt-8 rounded-3xl flex items-center justify-center gap-3 hover:bg-amber-950 transition-all cursor-pointer">
|
<button className="w-45 h-12 bg-[#7F4629] text-white mt-8 rounded-3xl flex items-center justify-center gap-3 hover:bg-amber-950 transition-all cursor-pointer">
|
||||||
<p className="-mt-0.5">افزودن شعبه جدید</p>
|
<p className="-mt-0.5">افزودن شعبه جدید</p>
|
||||||
<img src={Vector9} alt="لوگو" />
|
<img src={Vector9} alt="لوگو" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ===== Title ===== */}
|
{/* عنوان */}
|
||||||
<h3 className="text-[#402E32] w-[90%] font-bold mt-10">کافه های شما</h3>
|
<h3 className="text-[#402E32] w-[90%] font-bold mt-10">کافه های شما</h3>
|
||||||
|
|
||||||
{/* ===== Table Header ===== */}
|
{/* نمایش خطا */}
|
||||||
<div className="mt-10 grid grid-cols-6 gap-x-42 bg-[#EFEEEE] px-4 py-3 rounded-xl text-[#402E32] font-medium">
|
{error && (
|
||||||
|
<div className="bg-red-50 border-2 border-red-300 text-red-700 px-4 py-3 rounded-xl mt-4">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* نمایش لودینگ */}
|
||||||
|
{loading ? (
|
||||||
|
<div className="flex justify-center items-center mt-20">
|
||||||
|
<div className="text-[#7F4629] text-xl font-bold">در حال بارگذاری...</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{/* هدر جدول */}
|
||||||
|
<div className="mt-10 hidden md:grid grid-cols-6 gap-x-42 bg-[#EFEEEE] px-4 py-3 rounded-xl text-[#402E32] font-medium">
|
||||||
<h3>لوگو</h3>
|
<h3>لوگو</h3>
|
||||||
<h3>اسم</h3>
|
<h3>اسم</h3>
|
||||||
<h3>لوکیشن</h3>
|
<h3>آدرس</h3>
|
||||||
<h3>ریتینگ</h3>
|
<h3>ریتینگ</h3>
|
||||||
<h3>دسته</h3>
|
<h3>ساعت کاری</h3>
|
||||||
<h3>ادیت</h3>
|
<h3>ادیت</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ===== Table Rows ===== */}
|
{/* ردیفهای جدول - دسکتاپ */}
|
||||||
<div className="grid grid-cols-6 gap-y-9 gap-x-33 mt-10 text-[#402E32] font-medium pl-4">
|
{cafes.length > 0 ? (
|
||||||
|
<>
|
||||||
|
{/* نمای دسکتاپ */}
|
||||||
|
<div className="hidden md:grid grid-cols-6 gap-y-9 gap-x-33 mt-10 text-[#402E32] font-medium pl-4">
|
||||||
{cafes.map((cafe) => (
|
{cafes.map((cafe) => (
|
||||||
<React.Fragment key={cafe.id}>
|
<React.Fragment key={cafe._id}>
|
||||||
<img src={cafe.logo} className="w-10 h-10" alt="لوگو" />
|
{/* لوگو */}
|
||||||
<h3 className="whitespace-nowrap -mr-2">{cafe.name}</h3>
|
<img
|
||||||
<h3 className="whitespace-nowrap -mr-7">{cafe.location}</h3>
|
src={cafe.photo || Pic1}
|
||||||
|
className="w-10 h-10 rounded-full object-cover"
|
||||||
|
alt="لوگو"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* نام */}
|
||||||
|
<h3 className="whitespace-nowrap -mr-2">{cafe.Name}</h3>
|
||||||
|
|
||||||
|
{/* آدرس */}
|
||||||
|
<h3 className="whitespace-nowrap -mr-7 overflow-hidden text-ellipsis">
|
||||||
|
{cafe.address}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* ریتینگ */}
|
||||||
<div className="flex gap-1 mr-5">
|
<div className="flex gap-1 mr-5">
|
||||||
<img className="w-6 h-6" src={Star1} alt="ستاره" />
|
<img className="w-6 h-6" src={Star1} alt="ستاره" />
|
||||||
<h3>{cafe.rating}</h3>
|
<h3>{cafe.rating || 0}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* ساعت کاری */}
|
||||||
<div className="flex gap-1 whitespace-nowrap">
|
<div className="flex gap-1 whitespace-nowrap">
|
||||||
<img className="w-5 h-5" src={Group} alt="لوگو" />
|
<img className="w-5 h-5" src={Group} alt="لوگو" />
|
||||||
<h3 className="-mt-1">{cafe.category}</h3>
|
<h3 className="-mt-1">{cafe.openinghour || "نامشخص"}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ===== دکمه ادیت ===== */}
|
{/* دکمه ادیت */}
|
||||||
<Link
|
<Link
|
||||||
to={`/edit-cafe/${cafe.id}`}
|
to={`/edit-cafe/${cafe._id}`}
|
||||||
className="flex justify-center whitespace-nowrap gap-2 border-2 border-[#BB8F70] px-10 py-3 rounded-3xl font-light -mt-1.5 -mx-4 hover:bg-[#7F4629] hover:text-white hover:border-none cursor-pointer transition-all duration-500"
|
className="flex justify-center whitespace-nowrap gap-2 border-2 border-[#BB8F70] px-10 py-3 rounded-3xl font-light -mt-1.5 -mx-4 hover:bg-[#7F4629] hover:text-white hover:border-none cursor-pointer transition-all duration-500"
|
||||||
>
|
>
|
||||||
<h3>ادیت کافه</h3>
|
<h3>ادیت کافه</h3>
|
||||||
|
|
@ -109,101 +129,54 @@ const CafeManagement = () => {
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* نمای موبایل - کارتها */}
|
||||||
|
<div className="md:hidden mt-6 space-y-4">
|
||||||
|
{cafes.map((cafe) => (
|
||||||
|
<div key={cafe._id} className="bg-white border-2 border-[#8b8886] rounded-xl p-4">
|
||||||
|
<div className="flex items-start gap-4 mb-4">
|
||||||
|
<img
|
||||||
|
src={cafe.photo || Pic1}
|
||||||
|
className="w-16 h-16 rounded-full object-cover flex-shrink-0"
|
||||||
|
alt="لوگو"
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<h3 className="font-bold text-[#402E32] mb-1">{cafe.Name}</h3>
|
||||||
|
<p className="text-sm text-gray-600">{cafe.address}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between mb-3 text-sm">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<img className="w-5 h-5" src={Star1} alt="ستاره" />
|
||||||
|
<span>{cafe.rating || 0}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<img className="w-4 h-4" src={Group} alt="لوگو" />
|
||||||
|
<span>{cafe.openinghour || "نامشخص"}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to={`/edit-cafe/${cafe._id}`}
|
||||||
|
className="flex justify-center items-center gap-2 w-full border-2 border-[#BB8F70] py-2 rounded-full font-medium hover:bg-[#7F4629] hover:text-white hover:border-[#7F4629] transition-all duration-300"
|
||||||
|
>
|
||||||
|
<span>ادیت کافه</span>
|
||||||
|
<BiEdit className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="text-center mt-20 text-gray-500">
|
||||||
|
هیچ کافهای یافت نشد
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CafeManagement;
|
export default CafeManagement;
|
||||||
|
|
||||||
// const CafeManagement = () => {
|
|
||||||
// return (
|
|
||||||
// <section dir="rtl" className="">
|
|
||||||
// <header className="flex items-center gap-4">
|
|
||||||
// <h3 className="text-[#402E32] w-[90%] font-bold">مدیریت کافه</h3>
|
|
||||||
// <div className="w-12 h-10 border-2 border-[#8B8886] flex justify-center items-center rounded-2xl bg-[#E6DBCC]">
|
|
||||||
// <img className="" src={Search} alt="لوگو" />
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// <div className="w-35 h-10 border-2 border-[#8B8886] flex justify-center items-center rounded-2xl bg-[#E6DBCC]">
|
|
||||||
// <img src={Pic} className="w-10 h-10 shadow-2xl ml-1" alt="لوگو" />
|
|
||||||
// <p className="text-[#402E32] -mt-1.5 pl-1.5">سارا راد</p>
|
|
||||||
// <img className="" src={Arrow} alt="لوگو" />
|
|
||||||
// </div>
|
|
||||||
// <img src={Vector7} />
|
|
||||||
// </header>
|
|
||||||
|
|
||||||
// <div className="flex items-center justify-between">
|
|
||||||
// <button className="w-45 h-10 bg-[#7F4629] text-white mt-8 rounded-3xl flex items-center justify-center gap-3 hover:bg-amber-950 transition-all cursor-pointer">
|
|
||||||
// <p className="-mt-1.5">افزودن شعبه جدید</p>
|
|
||||||
// <img className="" src={Vector9} alt="لوگو" />
|
|
||||||
// </button>
|
|
||||||
// <img className="mt-8" src={Vector8} alt="لوگو" />
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// <h3 className="text-[#402E32] w-[90%] font-bold mt-10">کافه های شما</h3>
|
|
||||||
|
|
||||||
// <div className=" mt-32 grid grid-cols-6 gap-x-42 bg-[#EFEEEE] px-4 py-3 rounded-xl text-[#402E32] font-medium ">
|
|
||||||
// <h3>لوگو</h3>
|
|
||||||
// <h3>اسم</h3>
|
|
||||||
// <h3>لوکیشن</h3>
|
|
||||||
// <h3>ریتینگ</h3>
|
|
||||||
// <h3>دسته</h3>
|
|
||||||
// <h3 className="">ادیت</h3>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// <div className="grid grid-cols-6 grid-rows-4 gap-y-9 gap-x-33 mt-10 text-[#402E32] font-medium pl-4">
|
|
||||||
// <img src={Pic1} className="w-10 h-10" />
|
|
||||||
// <h3 className="whitespace-nowrap -mr-2">کافه ترنج</h3>
|
|
||||||
// <h3 className="whitespace-nowrap -mr-7">اصفهان - خیابان آذر </h3>
|
|
||||||
// <div className="flex gap-1 mr-5">
|
|
||||||
// <img className="w-6 h-6" src={Star1} />
|
|
||||||
// <h3>3.7</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex gap-1 whitespace-nowrap">
|
|
||||||
// <img className="w-5 h-5" src={Group} alt="لوگو" />
|
|
||||||
// <h3 className="-mt-1">دسته بندی</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex justify-center whitespace-nowrap gap-1 border-2 border-[#BB8F70] px-7 py-2 rounded-3xl font-light -mt-1.5 -mx-4 hover:bg-[#7F4629] hover:text-white hover:border-none cursor-pointer duration-600">
|
|
||||||
// <h3>ادیت کافه</h3>
|
|
||||||
// {/* <img className="w-3 h-3 mt-2" src={Vector10} alt="لوگو" /> */}
|
|
||||||
// <BiEdit className="w-3.5 h-3.5 mt-2" />
|
|
||||||
// </div>
|
|
||||||
// <img src={Pic1} className="w-10 h-10" />
|
|
||||||
// <h3 className="whitespace-nowrap -mr-2">کافه ترنج</h3>
|
|
||||||
// <h3 className="whitespace-nowrap -mr-7">اصفهان - خیابان آذر </h3>
|
|
||||||
// <div className="flex gap-1 mr-5">
|
|
||||||
// <img className="w-6 h-6" src={Star1} />
|
|
||||||
// <h3>3.7</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex gap-1 whitespace-nowrap">
|
|
||||||
// <img className="w-5 h-5" src={Group} alt="لوگو" />
|
|
||||||
// <h3 className="-mt-1">دسته بندی</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex justify-center whitespace-nowrap gap-1 border-2 border-[#BB8F70] px-7 py-2 rounded-3xl font-light -mt-1.5 -mx-4 hover:bg-[#7F4629] hover:text-white hover:border-none cursor-pointer duration-600">
|
|
||||||
// <h3>ادیت کافه</h3>
|
|
||||||
// {/* <img className="w-3 h-3 mt-2" src={Vector10} alt="لوگو" /> */}
|
|
||||||
// <BiEdit className="w-3.5 h-3.5 mt-2" />
|
|
||||||
// </div>
|
|
||||||
// <img src={Pic1} className="w-10 h-10" />
|
|
||||||
// <h3 className="whitespace-nowrap -mr-2">کافه ترنج</h3>
|
|
||||||
// <h3 className="whitespace-nowrap -mr-7">اصفهان - خیابان آذر </h3>
|
|
||||||
// <div className="flex gap-1 mr-5">
|
|
||||||
// <img className="w-6 h-6" src={Star1} alt="لوگو" />
|
|
||||||
// <h3>3.7</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex gap-1 whitespace-nowrap">
|
|
||||||
// <img className="w-5 h-5" src={Group} alt="لوگو" />
|
|
||||||
|
|
||||||
// <h3 className="-mt-1">دسته بندی</h3>
|
|
||||||
// </div>
|
|
||||||
// <div className="flex justify-center whitespace-nowrap gap-1 border-2 border-[#BB8F70] px-5 py-2 rounded-3xl font-light -mt-1.5 -mx-4 hover:bg-[#7F4629] hover:text-white hover:border-none cursor-pointer transition-all duration-600">
|
|
||||||
// <h3>ادیت کافه</h3>
|
|
||||||
// {/* <img className="w-3 h-3 mt-2" src={Vector10} alt="لوگو" /> */}
|
|
||||||
// <BiEdit className="w-3.5 h-3.5 mt-2" />
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </section>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default CafeManagement;
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { useParams, useNavigate } from "react-router-dom";
|
||||||
|
import axios from "axios";
|
||||||
import Bg1 from "../../assets/icons/bg1.svg";
|
import Bg1 from "../../assets/icons/bg1.svg";
|
||||||
import {GrLocation} from "react-icons/gr";
|
import {GrLocation} from "react-icons/gr";
|
||||||
import {BiEdit} from "react-icons/bi";
|
import {BiEdit} from "react-icons/bi";
|
||||||
import {FaRegStar} from "react-icons/fa";
|
import {FaRegStar} from "react-icons/fa";
|
||||||
import {PiCoffee} from "react-icons/pi";
|
|
||||||
import {IoMdTime} from "react-icons/io";
|
|
||||||
import {LuCalendar1} from "react-icons/lu";
|
|
||||||
import Vector11 from "../../assets/icons/Vector11.svg";
|
import Vector11 from "../../assets/icons/Vector11.svg";
|
||||||
import Vector12 from "../../assets/icons/Vector12.svg";
|
import Vector12 from "../../assets/icons/Vector12.svg";
|
||||||
import Vector13 from "../../assets/icons/Vector13.svg";
|
import Vector13 from "../../assets/icons/Vector13.svg";
|
||||||
|
|
@ -18,11 +17,46 @@ import Coffee2 from "../../assets/icons/coffee2.svg";
|
||||||
import Coffee1 from "../../assets/icons/coffee1.svg";
|
import Coffee1 from "../../assets/icons/coffee1.svg";
|
||||||
import Coffee3 from "../../assets/icons/coffee3.svg";
|
import Coffee3 from "../../assets/icons/coffee3.svg";
|
||||||
import Edit from "../../assets/icons/edit.svg";
|
import Edit from "../../assets/icons/edit.svg";
|
||||||
import { MdDelete } from "react-icons/md";
|
|
||||||
import { IoMdCheckmark, IoMdClose } from "react-icons/io";
|
import { IoMdCheckmark, IoMdClose } from "react-icons/io";
|
||||||
|
|
||||||
const EditCafe = () => {
|
const EditCafe = () => {
|
||||||
// State برای نگهداری عنوانها با localStorage
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [cafeData, setCafeData] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id) {
|
||||||
|
setLoading(true);
|
||||||
|
setError("");
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(`https://cafeju.maksiran.ir/api/cafe/v1/get-cafe-profile-by-cafe/${id}`)
|
||||||
|
.then((response) => {
|
||||||
|
console.log("✅ Cafe data loaded:", response.data);
|
||||||
|
if (response.data.success && response.data.data) {
|
||||||
|
setCafeData(response.data.data);
|
||||||
|
} else {
|
||||||
|
setError("دادههای کافه معتبر نیست");
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("❌ Error loading cafe:", error);
|
||||||
|
setLoading(false);
|
||||||
|
if (error.response) {
|
||||||
|
setError(error.response.data.message || "خطا در دریافت اطلاعات کافه");
|
||||||
|
} else if (error.request) {
|
||||||
|
setError("خطا در برقراری ارتباط با سرور");
|
||||||
|
} else {
|
||||||
|
setError("خطای نامشخص رخ داده است");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
const [categories, setCategories] = useState(() => {
|
const [categories, setCategories] = useState(() => {
|
||||||
const saved = localStorage.getItem('cafeCategories');
|
const saved = localStorage.getItem('cafeCategories');
|
||||||
return saved ? JSON.parse(saved) : [
|
return saved ? JSON.parse(saved) : [
|
||||||
|
|
@ -35,52 +69,40 @@ const EditCafe = () => {
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
// ذخیره تغییرات در localStorage
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem('cafeCategories', JSON.stringify(categories));
|
localStorage.setItem('cafeCategories', JSON.stringify(categories));
|
||||||
}, [categories]);
|
}, [categories]);
|
||||||
|
|
||||||
// State برای فعال کردن حالت ویرایش
|
|
||||||
const [isEditMode, setIsEditMode] = useState(false);
|
const [isEditMode, setIsEditMode] = useState(false);
|
||||||
|
|
||||||
// State برای مدیریت حالت اضافه کردن
|
|
||||||
const [isAdding, setIsAdding] = useState(false);
|
const [isAdding, setIsAdding] = useState(false);
|
||||||
const [newCategory, setNewCategory] = useState("");
|
const [newCategory, setNewCategory] = useState("");
|
||||||
|
|
||||||
// State برای مدیریت حالت ویرایش
|
|
||||||
const [editingIndex, setEditingIndex] = useState(null);
|
const [editingIndex, setEditingIndex] = useState(null);
|
||||||
const [editValue, setEditValue] = useState("");
|
const [editValue, setEditValue] = useState("");
|
||||||
|
|
||||||
// تابع اضافه کردن عنوان جدید
|
|
||||||
const handleAddCategory = () => {
|
const handleAddCategory = () => {
|
||||||
if (newCategory.trim()) {
|
if (newCategory.trim()) {
|
||||||
setCategories([...categories, newCategory.trim()]);
|
setCategories([...categories, newCategory.trim()]);
|
||||||
setNewCategory("");
|
setNewCategory("");
|
||||||
setIsAdding(false);
|
setIsAdding(false);
|
||||||
// اسکرول رو به ابتدا (راست برای RTL) برمیگردونیم
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const scrollContainer = document.querySelector('.categories-scroll');
|
const scrollContainer = document.querySelector('.categories-scroll');
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
// برای RTL باید scrollLeft رو به حداکثر ببریم
|
|
||||||
scrollContainer.scrollLeft = scrollContainer.scrollWidth;
|
scrollContainer.scrollLeft = scrollContainer.scrollWidth;
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// تابع حذف عنوان
|
|
||||||
const handleDeleteCategory = (index) => {
|
const handleDeleteCategory = (index) => {
|
||||||
const newCategories = categories.filter((_, i) => i !== index);
|
const newCategories = categories.filter((_, i) => i !== index);
|
||||||
setCategories(newCategories);
|
setCategories(newCategories);
|
||||||
};
|
};
|
||||||
|
|
||||||
// تابع شروع ویرایش
|
|
||||||
const handleStartEdit = (index) => {
|
const handleStartEdit = (index) => {
|
||||||
setEditingIndex(index);
|
setEditingIndex(index);
|
||||||
setEditValue(categories[index]);
|
setEditValue(categories[index]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// تابع ذخیره ویرایش
|
|
||||||
const handleSaveEdit = () => {
|
const handleSaveEdit = () => {
|
||||||
if (editValue.trim()) {
|
if (editValue.trim()) {
|
||||||
const newCategories = [...categories];
|
const newCategories = [...categories];
|
||||||
|
|
@ -91,12 +113,37 @@ const EditCafe = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// تابع لغو ویرایش
|
|
||||||
const handleCancelEdit = () => {
|
const handleCancelEdit = () => {
|
||||||
setEditingIndex(null);
|
setEditingIndex(null);
|
||||||
setEditValue("");
|
setEditValue("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center items-center h-screen">
|
||||||
|
<div className="text-[#7F4629] text-2xl font-bold">در حال بارگذاری...</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="p-6">
|
||||||
|
<div className="bg-red-50 border-2 border-red-300 text-red-700 px-4 py-3 rounded-xl">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cafeData) {
|
||||||
|
return (
|
||||||
|
<div className="p-6 text-center text-gray-500">
|
||||||
|
اطلاعات کافه یافت نشد
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -117,104 +164,107 @@ const EditCafe = () => {
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<section dir="rtl">
|
<section dir="rtl" className="lg:-mt-12">
|
||||||
<h3 className="text-[#402E32] font-bold">ادیت کافه ترنج</h3>
|
<h3 className="text-[#402E32] font-bold mb-4 lg:mb-0">ادیت {cafeData.Name}</h3>
|
||||||
|
|
||||||
<div className="mt-9 border-2 border-[#8b8886] p-10 rounded-2xl flex gap-4">
|
<div className="mt-4 lg:mt-9 border-2 border-[#8b8886] p-4 lg:p-10 rounded-2xl flex flex-col lg:flex-row gap-4">
|
||||||
<div>
|
<div className="w-full lg:w-auto">
|
||||||
<img className="w-[461px]" src={Bg1} alt="Logo"/>
|
<img className="w-full lg:w-[461px] rounded-lg" src={cafeData.photo || Bg1} alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative flex flex-col gap-4.5">
|
<div className="relative flex flex-col gap-4 lg:gap-4.5 w-full">
|
||||||
<div className="absolute top-2 left-0 -mt-5">
|
<div className="flex gap-2 justify-end lg:absolute lg:top-2 lg:left-0 lg:-mt-5">
|
||||||
<button
|
<button
|
||||||
className="border-2 border-[#bb8f70] w-25 h-10 rounded-3xl text-[#402e32] hover:bg-[#7f4629] hover:text-white transition-all duration-300 hover:border-none">
|
onClick={() => navigate('/cafe-management')}
|
||||||
|
className="border-2 border-[#bb8f70] w-20 lg:w-25 h-10 rounded-3xl text-sm lg:text-base text-[#402e32] hover:bg-[#7f4629] hover:text-white transition-all duration-300 hover:border-none">
|
||||||
انصراف
|
انصراف
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="border-2 border-[#bb8f70] bg-[#7f4629] text-white w-25 h-10 rounded-3xl mr-4 hover:bg-[#5f494f] transition-all duration-300 hover:border-none">
|
className="border-2 border-[#bb8f70] bg-[#7f4629] text-white w-20 lg:w-25 h-10 rounded-3xl text-sm lg:text-base hover:bg-[#5f494f] transition-all duration-300 hover:border-none">
|
||||||
تایید
|
تایید
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<BiEdit className="w-4.5 h-4.5 -mt-1"/>
|
|
||||||
<h3 className="font-bold text-base">کافه ترنج</h3>
|
<BiEdit className="w-5 h-5 mt-0 lg:-mt-1"/>
|
||||||
<hr className="w-38 -mt-3 border-1 text-[#80931e]"/>
|
<h3 className="font-bold text-base">{cafeData.Name}</h3>
|
||||||
|
<hr className="w-full lg:w-38 -mt-3 border-1 text-[#80931e]"/>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<GrLocation/>
|
<GrLocation/>
|
||||||
<span className="text-base">اصفهان - خیابان آذر </span>
|
<span className="text-sm lg:text-base">{cafeData.address || "آدرس موجود نیست"}</span>
|
||||||
</div>
|
</div>
|
||||||
<hr className="w-38 -mt-3 border-1 text-[#80931e]"/>
|
<hr className="w-full lg:w-38 -mt-3 border-1 text-[#80931e]"/>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaRegStar/>
|
<FaRegStar/>
|
||||||
<span className="text-base">3.9</span>
|
<span className="text-sm lg:text-base">{cafeData.rating || 0}</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-bold text-base">درباره کافه</h3>
|
|
||||||
<span className="text-base">
|
|
||||||
کافه ترنج، یک کافی شاپ با محیطی دنج و دلچسب در شهر اصفهان و یکی از
|
|
||||||
ممتازترین کافی شاپهای ابن شهر است. از جمله خدمات این کافه میتوان
|
|
||||||
به اینترنت رایگان و ارائه کتابهایی برای مطالعه در داخل کافه اشاره
|
|
||||||
کرد.
|
|
||||||
</span>
|
|
||||||
<hr className="w-[104%] -mt-3 border-1 text-[#80931e]"/>
|
|
||||||
|
|
||||||
<h3 className="text-[#402E32] font-bold mt-10 relative -right-64">
|
<h3 className="font-bold text-base">درباره کافه</h3>
|
||||||
|
<span className="text-sm lg:text-base">
|
||||||
|
{cafeData.description || "توضیحاتی برای این کافه وجود ندارد."}
|
||||||
|
</span>
|
||||||
|
<hr className="w-full lg:w-[104%] -mt-3 border-1 text-[#80931e]"/>
|
||||||
|
|
||||||
|
<h3 className="text-[#402E32] font-bold mt-6 lg:mt-10 lg:relative lg:-right-64">
|
||||||
ویژگی ها
|
ویژگی ها
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div className="relative -mr-71 -ml-7 mt-5 flex gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:flex lg:relative lg:-mr-71 lg:-ml-7 mt-5 gap-3">
|
||||||
<div
|
<div
|
||||||
className="bg-[#e1d5c2] w-[140px] h-[137.6px] flex flex-col items-center gap-8 text-center rounded-4xl transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="bg-[#e1d5c2] w-full lg:w-[140px] h-[137.6px] flex flex-col items-center gap-4 lg:gap-8 text-center rounded-2xl lg:rounded-4xl transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Coffee3} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Coffee3} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span className="text-[#402E32] font-medium whitespace-nowrap">
|
<span className="text-[#402E32] font-medium text-sm lg:text-base whitespace-nowrap px-2">
|
||||||
منو کافه:
|
منو کافه:
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-4 text-[#402E32] font-medium w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-4xl pr-3 transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex flex-col gap-3 lg:gap-4 text-[#402E32] font-medium w-full lg:w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-2xl lg:rounded-4xl pr-3 text-sm lg:text-base transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector15} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Vector15} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span>ساعت کاری:</span>
|
<span>ساعت کاری:</span>
|
||||||
<span> 23 - 8</span>
|
<span> 23 - 8</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-4 text-[#402E32] font-medium w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-4xl pr-3 transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex flex-col gap-3 lg:gap-4 text-[#402E32] font-medium w-full lg:w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-2xl lg:rounded-4xl pr-3 text-sm lg:text-base transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector14} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Vector14} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span>رزرو :</span>
|
<span>رزرو :</span>
|
||||||
<span>رزرو آنلاین</span>
|
<span>رزرو آنلاین</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-4 text-[#402E32] font-medium w-[170.5px] h-[137.6px] bg-[#e1d5c2] rounded-4xl pr-3 transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex flex-col gap-3 lg:gap-4 text-[#402E32] font-medium w-full lg:w-[170.5px] h-[137.6px] bg-[#e1d5c2] rounded-2xl lg:rounded-4xl pr-3 text-sm lg:text-base transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector11} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Vector11} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span>موسیقی :</span>
|
<span>موسیقی :</span>
|
||||||
<span>موسیقی زنده آخر هفته</span>
|
<span>موسیقی زنده آخر هفته</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-4 text-[#402E32] font-medium w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-4xl pr-3 transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex flex-col gap-3 lg:gap-4 text-[#402E32] font-medium w-full lg:w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-2xl lg:rounded-4xl pr-3 text-sm lg:text-base transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector13} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Vector13} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span>پارکینگ :</span>
|
<span>پارکینگ :</span>
|
||||||
<span>عمومی</span>
|
<span>عمومی</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-4 text-[#402E32] font-medium w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-4xl pr-3 transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex flex-col gap-3 lg:gap-4 text-[#402E32] font-medium w-full lg:w-[161.5px] h-[137.6px] bg-[#e1d5c2] rounded-2xl lg:rounded-4xl pr-3 text-sm lg:text-base transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector12} className="w-6 h-6 text-[#402E32] mt-5"/>
|
<img src={Vector12} className="w-6 h-6 text-[#402E32] mt-5"/>
|
||||||
<span>دسترسی آسان :</span>
|
<span>دسترسی آسان :</span>
|
||||||
<span>مناسب افراد ناتوان</span>
|
<span>مناسب افراد ناتوان</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex justify-center items-center w-[150.5px] h-[137.6px] bg-[#5e5450] rounded-4xl transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="flex justify-center items-center w-full lg:w-[150.5px] h-[137.6px] bg-[#5e5450] rounded-2xl lg:rounded-4xl transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<img src={Vector9} className="w-6 h-6 text-[#402E32]"/>
|
<img src={Vector9} className="w-6 h-6 text-[#402E32]"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className="mt-10 -mr-64 text-[#402E32] font-medium w-[132%]">
|
<div className="mt-10 lg:-mr-64 text-[#402E32] font-medium w-full lg:w-[132%]">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||||
<div className="max-w-[930px] overflow-hidden flex-1">
|
<div className="w-full sm:max-w-[930px] overflow-hidden flex-1">
|
||||||
<div className="categories-scroll flex gap-10 overflow-x-auto scrollbar-hide">
|
<div className="categories-scroll flex gap-6 lg:gap-10 overflow-x-auto scrollbar-hide">
|
||||||
<div className="flex items-center gap-2 justify-center flex-shrink-0">
|
<div className="flex items-center gap-2 justify-center flex-shrink-0">
|
||||||
<img
|
<img
|
||||||
src={Vector16}
|
src={Vector16}
|
||||||
|
|
@ -223,23 +273,20 @@ const EditCafe = () => {
|
||||||
onClick={() => setIsEditMode(!isEditMode)}
|
onClick={() => setIsEditMode(!isEditMode)}
|
||||||
title={isEditMode ? "خروج از حالت ویرایش" : "ویرایش عنوانها"}
|
title={isEditMode ? "خروج از حالت ویرایش" : "ویرایش عنوانها"}
|
||||||
/>
|
/>
|
||||||
<span className="whitespace-nowrap">عنوان</span>
|
<span className="whitespace-nowrap text-sm lg:text-base">عنوان</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isEditMode ? (
|
{!isEditMode ? (
|
||||||
// حالت عادی - فقط نمایش عنوانها
|
|
||||||
<>
|
<>
|
||||||
{categories.map((category, index) => (
|
{categories.map((category, index) => (
|
||||||
<span key={index} className="whitespace-nowrap flex-shrink-0">{category}</span>
|
<span key={index} className="whitespace-nowrap flex-shrink-0 text-sm lg:text-base">{category}</span>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// حالت ویرایش - نمایش دکمههای ویرایش و حذف بالای عنوان
|
|
||||||
<>
|
<>
|
||||||
{categories.map((category, index) => (
|
{categories.map((category, index) => (
|
||||||
<div key={index} className="flex flex-col items-center gap-1 flex-shrink-0">
|
<div key={index} className="flex flex-col items-center gap-1 flex-shrink-0">
|
||||||
{editingIndex === index ? (
|
{editingIndex === index ? (
|
||||||
// حالت ویرایش
|
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center gap-1 mb-1">
|
<div className="flex items-center gap-1 mb-1">
|
||||||
<IoMdCheckmark
|
<IoMdCheckmark
|
||||||
|
|
@ -262,21 +309,20 @@ const EditCafe = () => {
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// حالت عادی - آیکنها بالای عنوان
|
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center gap-1 mb-1">
|
<div className="flex items-center gap-2">
|
||||||
<BiEdit
|
<BiEdit
|
||||||
className="text-[#7f4629] cursor-pointer hover:text-[#5f494f] w-4 h-4 flex-shrink-0"
|
className="text-[#7f4629] cursor-pointer hover:text-[#5f494f] w-5 h-5 flex-shrink-0"
|
||||||
onClick={() => handleStartEdit(index)}
|
onClick={() => handleStartEdit(index)}
|
||||||
title="ویرایش"
|
title="ویرایش"
|
||||||
/>
|
/>
|
||||||
<MdDelete
|
<span className="whitespace-nowrap text-sm lg:text-base">{category}</span>
|
||||||
className="text-red-600 cursor-pointer hover:text-red-800 w-4 h-4 flex-shrink-0"
|
<IoMdClose
|
||||||
|
className="text-white bg-[#a79fa1] rounded-md cursor-pointer size-5 flex-shrink-0"
|
||||||
onClick={() => handleDeleteCategory(index)}
|
onClick={() => handleDeleteCategory(index)}
|
||||||
title="حذف"
|
title="حذف"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="whitespace-nowrap">{category}</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -286,13 +332,12 @@ const EditCafe = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* دکمه اضافه کردن عنوان جدید - بیرون از container اسکرول */}
|
|
||||||
{isEditMode && (
|
{isEditMode && (
|
||||||
<div className="flex-shrink-0" style={{minWidth: '120px'}}>
|
<div className="flex-shrink-0 w-full sm:w-auto" style={{minWidth: '120px'}}>
|
||||||
{!isAdding ? (
|
{!isAdding ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsAdding(true)}
|
onClick={() => setIsAdding(true)}
|
||||||
className="text-[#7f4629] hover:text-[#5f494f] font-bold transition-colors whitespace-nowrap w-full"
|
className="text-[#7f4629] hover:text-[#5f494f] font-bold transition-colors whitespace-nowrap w-full text-sm lg:text-base"
|
||||||
title="اضافه کردن عنوان جدید"
|
title="اضافه کردن عنوان جدید"
|
||||||
>
|
>
|
||||||
+ افزودن
|
+ افزودن
|
||||||
|
|
@ -306,7 +351,7 @@ const EditCafe = () => {
|
||||||
title="ذخیره"
|
title="ذخیره"
|
||||||
/>
|
/>
|
||||||
<IoMdClose
|
<IoMdClose
|
||||||
className="text-red-600 cursor-pointer hover:text-red-800 w-4 h-4 flex-shrink-0"
|
className="text-white bg-[#a79fa1] rounded-md cursor-pointer w-4 h-4 flex-shrink-0"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsAdding(false);
|
setIsAdding(false);
|
||||||
setNewCategory("");
|
setNewCategory("");
|
||||||
|
|
@ -328,35 +373,35 @@ const EditCafe = () => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className="w-[132%] -mr-66 mt-3 border-2 rounded-3xl text-[#939393]"/>
|
<hr className="w-full lg:w-[132%] lg:-mr-66 mt-3 border-2 rounded-3xl text-[#939393]"/>
|
||||||
|
|
||||||
<div className="mt-9 flex items-center gap-2 -mr-64 text-[#a79fa1] font-bold">
|
<div className="mt-9 flex items-center gap-2 lg:-mr-64 text-[#a79fa1] font-bold text-sm lg:text-base">
|
||||||
<img src={Vector16} alt="Logo"/>
|
<img src={Vector16} alt="Logo"/>
|
||||||
<h3>افزودن زیر عنوان</h3>
|
<h3>افزودن زیر عنوان</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-9 flex items-center gap-2 -mr-64 text-[#66585b] font-bold">
|
<div className="mt-9 flex items-center gap-2 lg:-mr-64 text-[#66585b] font-bold text-sm lg:text-base">
|
||||||
<img className="w-5.5 h-5.5" src={Edit} alt="Logo"/>
|
<img className="w-5.5 h-5.5" src={Edit} alt="Logo"/>
|
||||||
<img className="w-6 h-6" src={Coffee3} alt="Logo"/>
|
<img className="w-6 h-6" src={Coffee3} alt="Logo"/>
|
||||||
<h3>قهوه ها</h3>
|
<h3>قهوه ها</h3>
|
||||||
<hr className="mt-9 -mr-15 w-[5%] border-1 text-[#80931e]"/>
|
<hr className="mt-9 -mr-15 w-[5%] border-1 text-[#80931e] hidden lg:block"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-9 flex items-center gap-2 -mr-64 text-[#66585b] font-bold">
|
<div className="mt-9 flex items-center gap-2 lg:-mr-64 text-[#66585b] font-bold text-sm lg:text-base">
|
||||||
<img src={Vector16} alt="Logo"/>
|
<img src={Vector16} alt="Logo"/>
|
||||||
<h3>آیتم</h3>
|
<h3>آیتم</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-5 -mr-64">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 lg:-mr-64">
|
||||||
<div
|
<div
|
||||||
className="mt-13 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="mt-8 lg:mt-13 flex items-center flex-col justify-center w-full lg:w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<h1 className="text-[#402E32] font-bold -mr-50">اسپرسو100%</h1>
|
<h1 className="text-[#402E32] font-bold text-sm lg:text-base lg:-mr-50">اسپرسو100%</h1>
|
||||||
<img src={Sperso} alt="Logo" className="mt-5"/>
|
<img src={Sperso} alt="Logo" className="mt-5"/>
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
<div className="flex justify-between gap-20 lg:gap-50 mt-3 text-[#66585b] font-medium text-sm lg:text-base">
|
||||||
<span>قیمت</span>
|
<span>قیمت</span>
|
||||||
<span>118.000</span>
|
<span>118.000</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="font-light text-[#66585b] mt-2 break-words mr-4 text-[14.90px]">
|
<span className="font-light text-[#66585b] mt-2 break-words px-4 lg:mr-4 text-xs lg:text-[14.90px]">
|
||||||
45 میلی لیتر، قهوه، 100% عربیکا، دم شده با دستگاه اسپرسو ساز،
|
45 میلی لیتر، قهوه، 100% عربیکا، دم شده با دستگاه اسپرسو ساز،
|
||||||
به همراه یک عدد آب معدنی مینی
|
به همراه یک عدد آب معدنی مینی
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -364,16 +409,16 @@ const EditCafe = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="mt-10 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="mt-8 lg:mt-10 flex items-center flex-col justify-center w-full lg:w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<h1 className="text-[#402E32] font-bold -mr-50">
|
<h1 className="text-[#402E32] font-bold text-sm lg:text-base lg:-mr-50">
|
||||||
کارامل ماکیاتو
|
کارامل ماکیاتو
|
||||||
</h1>
|
</h1>
|
||||||
<img src={Coffee1} alt="Logo" className="mt-5"/>
|
<img src={Coffee1} alt="Logo" className="mt-5"/>
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
<div className="flex justify-between gap-20 lg:gap-50 mt-3 text-[#66585b] font-medium text-sm lg:text-base">
|
||||||
<span>قیمت</span>
|
<span>قیمت</span>
|
||||||
<span>149.000</span>
|
<span>149.000</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="font-light text-[#66585b] mt-2 break-words mr-4 text-[14.90px]">
|
<span className="font-light text-[#66585b] mt-2 break-words px-4 lg:mr-4 text-xs lg:text-[14.90px]">
|
||||||
220 میلی لیتر، 2 شات اسپرسو 30% روبوستا، 70% عربیکا، یک لکه
|
220 میلی لیتر، 2 شات اسپرسو 30% روبوستا، 70% عربیکا، یک لکه
|
||||||
فوم شیر، سیروپ کارامل
|
فوم شیر، سیروپ کارامل
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -381,72 +426,20 @@ const EditCafe = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="mt-10 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
className="mt-8 lg:mt-10 flex items-center flex-col justify-center w-full lg:w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
||||||
<h1 className="text-[#402E32] font-bold -mr-47">
|
<h1 className="text-[#402E32] font-bold text-sm lg:text-base lg:-mr-47">
|
||||||
اسپرسو آفوگاتو
|
اسپرسو آفوگاتو
|
||||||
</h1>
|
</h1>
|
||||||
<img src={Coffee2} alt="Logo" className="mt-5"/>
|
<img src={Coffee2} alt="Logo" className="mt-5"/>
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
<div className="flex justify-between gap-20 lg:gap-50 mt-3 text-[#66585b] font-medium text-sm lg:text-base">
|
||||||
<span>قیمت</span>
|
<span>قیمت</span>
|
||||||
<span>118.000</span>
|
<span>118.000</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
className="font-light text-[#66585b] mt-2 mb-10 break-words -mr-23 text-[14.90px]">
|
className="font-light text-[#66585b] mt-2 mb-10 break-words px-4 lg:-mr-23 text-xs lg:text-[14.90px]">
|
||||||
اسپرسو، یک اسکوپ بستنی وانیلی
|
اسپرسو، یک اسکوپ بستنی وانیلی
|
||||||
</span>
|
</span>
|
||||||
<hr className=" mt- w-[90%] border-3 rounded-4xl text-[#e6e2de]"/>
|
<hr className="w-[90%] border-3 rounded-4xl text-[#e6e2de]"/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="mt-10 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
|
||||||
<h1 className="text-[#402E32] font-bold -mr-47">
|
|
||||||
اسپرسو آفوگاتو
|
|
||||||
</h1>
|
|
||||||
<img src={Coffee2} alt="Logo" className="mt-5"/>
|
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
|
||||||
<span>قیمت</span>
|
|
||||||
<span>118.000</span>
|
|
||||||
</div>
|
|
||||||
<span
|
|
||||||
className="font-light text-[#66585b] mt-2 mb-10 break-words -mr-23 text-[14.90px]">
|
|
||||||
اسپرسو، یک اسکوپ بستنی وانیلی
|
|
||||||
</span>
|
|
||||||
<hr className=" mt- w-[90%] border-3 rounded-4xl text-[#e6e2de]"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="mt-10 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
|
||||||
<h1 className="text-[#402E32] font-bold -mr-47">
|
|
||||||
اسپرسو آفوگاتو
|
|
||||||
</h1>
|
|
||||||
<img src={Coffee2} alt="Logo" className="mt-5"/>
|
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
|
||||||
<span>قیمت</span>
|
|
||||||
<span>118.000</span>
|
|
||||||
</div>
|
|
||||||
<span
|
|
||||||
className="font-light text-[#66585b] mt-2 mb-10 break-words -mr-23 text-[14.90px]">
|
|
||||||
اسپرسو، یک اسکوپ بستنی وانیلی
|
|
||||||
</span>
|
|
||||||
<hr className=" mt- w-[90%] border-3 rounded-4xl text-[#e6e2de]"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="mt-10 flex items-center flex-col justify-center w-[320px] h-[391px] transform hover:-translate-y-1 transition-all duration-300 hover:shadow-md">
|
|
||||||
<h1 className="text-[#402E32] font-bold -mr-47">
|
|
||||||
اسپرسو آفوگاتو
|
|
||||||
</h1>
|
|
||||||
<img src={Coffee2} alt="Logo" className="mt-5"/>
|
|
||||||
<div className="flex justify-between gap-50 mt-3 text-[#66585b] font-medium">
|
|
||||||
<span>قیمت</span>
|
|
||||||
<span>118.000</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="font-light text-[#66585b] mt-2 mb-10 break-words -mr-23 text-[14.90px]">
|
|
||||||
اسپرسو، یک اسکوپ بستنی وانیلی
|
|
||||||
</span>
|
|
||||||
<hr className=" mt- w-[90%] border-3 rounded-4xl text-[#e6e2de]"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,81 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import Loginpic from '../../assets/image/loginpic.jpg';
|
import Loginpic from '../../assets/image/loginpic.jpg';
|
||||||
import { FiLock } from 'react-icons/fi';
|
import { FiLock } from 'react-icons/fi';
|
||||||
import { HiOutlineDevicePhoneMobile } from "react-icons/hi2";
|
import { FaRegUser } from "react-icons/fa6";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import LogoDM from "../../assets/icons/LogoDM.svg";
|
import LogoDM from "../../assets/icons/LogoDM.svg";
|
||||||
|
import { useNavigate, Navigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
// تنظیم base URL برای axios
|
||||||
|
axios.defaults.baseURL = 'https://cafeju.maksiran.ir';
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const [phoneNumber, setPhoneNumber] = useState('');
|
const [userName, setUserName] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handlePhoneChange = (e) => {
|
// چک کردن token موقع لود شدن صفحه
|
||||||
const value = e.target.value;
|
useEffect(() => {
|
||||||
// فقط اجازه ورود اعداد
|
const token = localStorage.getItem('token');
|
||||||
if (value === '' || /^[0-9\b]+$/.test(value)) {
|
// اگر قبلاً لاگین کرده، به داشبورد هدایت میشه
|
||||||
// محدود کردن به 11 رقم
|
if (token) {
|
||||||
if (value.length <= 11) {
|
navigate('/dashboard');
|
||||||
setPhoneNumber(value);
|
|
||||||
}
|
}
|
||||||
}
|
}, [navigate]);
|
||||||
};
|
|
||||||
|
|
||||||
const handleLogin = (e) => {
|
const handleLogin = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setError('');
|
setError('');
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// آمادهسازی داده برای ارسال
|
|
||||||
const loginData = {
|
const loginData = {
|
||||||
userName: phoneNumber,
|
userName: userName,
|
||||||
password: password
|
password: password
|
||||||
};
|
};
|
||||||
|
|
||||||
// ارسال درخواست به API
|
console.log('Sending login request with:', loginData);
|
||||||
|
|
||||||
axios.post('/api/admin/v1/login', loginData)
|
axios.post('/api/admin/v1/login', loginData)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
console.log('Login successful:', response.data);
|
console.log('✅ Login successful!');
|
||||||
|
console.log('Response:', response.data);
|
||||||
|
|
||||||
// ذخیره توکن در localStorage
|
if (response.data.success && response.data.data && response.data.data.tokens) {
|
||||||
if (response.data.token) {
|
const accessToken = response.data.data.tokens.accessToken;
|
||||||
localStorage.setItem('token', response.data.token);
|
const refreshToken = response.data.data.tokens.refreshToken;
|
||||||
|
|
||||||
|
localStorage.setItem('accessToken', accessToken);
|
||||||
|
localStorage.setItem('refreshToken', refreshToken);
|
||||||
|
localStorage.setItem('token', accessToken);
|
||||||
|
|
||||||
|
localStorage.setItem('adminInfo', JSON.stringify(response.data.data.admin));
|
||||||
|
|
||||||
|
console.log('Tokens saved to localStorage');
|
||||||
|
console.log('Admin info:', response.data.data.admin);
|
||||||
|
|
||||||
|
console.log('Navigating to dashboard...');
|
||||||
|
navigate('/dashboard');
|
||||||
|
} else {
|
||||||
|
console.error('❌ Invalid response format');
|
||||||
|
setError('پاسخ سرور معتبر نیست');
|
||||||
}
|
}
|
||||||
|
|
||||||
// هدایت به صفحه داشبورد یا صفحه اصلی
|
|
||||||
// window.location.href = '/dashboard';
|
|
||||||
alert('ورود موفقیتآمیز بود!');
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
console.error('Login error:', error);
|
console.error('❌ Login error:', error);
|
||||||
|
|
||||||
// مدیریت خطاها
|
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
// سرور پاسخ داد اما با خطا
|
console.error('Response status:', error.response.status);
|
||||||
setError(error.response.data.message || 'نام کاربری یا رمز عبور اشتباه است');
|
console.error('Response data:', error.response.data);
|
||||||
|
setError(error.response.data.message || error.response.data.en_message || 'نام کاربری یا رمز عبور اشتباه است');
|
||||||
} else if (error.request) {
|
} else if (error.request) {
|
||||||
// درخواست ارسال شد اما پاسخی دریافت نشد
|
console.error('No response received from server');
|
||||||
setError('خطا در برقراری ارتباط با سرور');
|
setError('خطا در برقراری ارتباط با سرور');
|
||||||
} else {
|
} else {
|
||||||
|
console.error('Error setting up request');
|
||||||
setError('خطای نامشخص رخ داده است');
|
setError('خطای نامشخص رخ داده است');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -134,7 +150,6 @@ const Login = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleLogin} className="space-y-6">
|
<form onSubmit={handleLogin} className="space-y-6">
|
||||||
{/* نمایش پیغام خطا */}
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="bg-red-50 border-2 border-red-300 text-red-700 px-4 py-3 rounded-xl text-sm">
|
<div className="bg-red-50 border-2 border-red-300 text-red-700 px-4 py-3 rounded-xl text-sm">
|
||||||
{error}
|
{error}
|
||||||
|
|
@ -143,21 +158,18 @@ const Login = () => {
|
||||||
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<label className="absolute -top-2.5 right-4 bg-[#f5f0e8] px-2 text-sm text-gray-600 z-10">
|
<label className="absolute -top-2.5 right-4 bg-[#f5f0e8] px-2 text-sm text-gray-600 z-10">
|
||||||
شماره موبایل
|
نام کاربری
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={phoneNumber}
|
value={userName}
|
||||||
onChange={handlePhoneChange}
|
onChange={(e) => setUserName(e.target.value)}
|
||||||
placeholder="09132659856"
|
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-14 pr-6 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
maxLength={11}
|
|
||||||
inputMode="numeric"
|
|
||||||
pattern="[0-9]*"
|
|
||||||
/>
|
/>
|
||||||
<HiOutlineDevicePhoneMobile className="absolute left-5 top-1/2 -translate-y-1/2 text-gray-400 w-6 h-10" />
|
<FaRegUser className="absolute left-5 top-1/2 -translate-y-1/2 text-gray-400 w-6 h-5" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -170,7 +182,7 @@ const Login = () => {
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
placeholder="2569876nb*"
|
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-14 pr-6 py-3 border-2 border-gray-300 rounded-xl focus:outline-none focus:border-[#7f4629] transition-colors"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
/>
|
/>
|
||||||
|
|
@ -189,7 +201,7 @@ const Login = () => {
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading || !phoneNumber || !password}
|
disabled={loading || !userName || !password}
|
||||||
className="w-full bg-[#7f4629] text-white py-3 rounded-full font-bold hover:bg-[#5f494f] transition-all duration-300 shadow-lg hover:shadow-xl disabled:bg-gray-400 disabled:cursor-not-allowed"
|
className="w-full bg-[#7f4629] text-white py-3 rounded-full font-bold hover:bg-[#5f494f] transition-all duration-300 shadow-lg hover:shadow-xl disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{loading ? 'در حال ورود...' : 'ورود'}
|
{loading ? 'در حال ورود...' : 'ورود'}
|
||||||
|
|
@ -210,4 +222,18 @@ const Login = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ProtectedRoute = ({ children }) => {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
|
||||||
|
console.log('ProtectedRoute - Token check:', token ? 'Token exists' : 'No token');
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
console.log('ProtectedRoute - Redirecting to login');
|
||||||
|
return <Navigate to="/login" replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('ProtectedRoute - Rendering protected content');
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
||||||
export default Login;
|
export default Login;
|
||||||
|
|
@ -1,42 +1,112 @@
|
||||||
/* #root {
|
@tailwind utilities;
|
||||||
max-width: 1280px;
|
|
||||||
|
/* Custom Breakpoints for Mobile-First Design */
|
||||||
|
@layer base {
|
||||||
|
/* Base styles - Mobile First (320px+) */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Responsive Classes */
|
||||||
|
@layer utilities {
|
||||||
|
/* Hide scrollbar globally */
|
||||||
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-hide {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent horizontal scroll */
|
||||||
|
.no-scroll-x {
|
||||||
|
overflow-x: hidden;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Container Sizes */
|
||||||
|
@layer components {
|
||||||
|
.container-responsive {
|
||||||
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2rem;
|
padding-left: 1rem;
|
||||||
text-align: center;
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
/* iPhone SE and smaller (320px - 374px) */
|
||||||
height: 6em;
|
@media (min-width: 320px) {
|
||||||
padding: 1.5em;
|
.container-responsive {
|
||||||
will-change: filter;
|
max-width: 320px;
|
||||||
transition: filter 300ms;
|
|
||||||
}
|
|
||||||
.logo:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #646cffaa);
|
|
||||||
}
|
|
||||||
.logo.react:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
/* iPhone 12/13 Mini (375px - 389px) */
|
||||||
a:nth-of-type(2) .logo {
|
@media (min-width: 375px) {
|
||||||
animation: logo-spin infinite 20s linear;
|
.container-responsive {
|
||||||
|
max-width: 375px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
/* iPhone 14 (390px - 429px) */
|
||||||
padding: 2em;
|
@media (min-width: 390px) {
|
||||||
|
.container-responsive {
|
||||||
|
max-width: 390px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.read-the-docs {
|
/* iPhone 14 Pro Max (430px - 639px) */
|
||||||
color: #888;
|
@media (min-width: 430px) {
|
||||||
} */
|
.container-responsive {
|
||||||
|
max-width: 430px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small devices (640px - 767px) - Tailwind sm */
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.container-responsive {
|
||||||
|
max-width: 640px;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Medium devices (768px - 1023px) - Tailwind md */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.container-responsive {
|
||||||
|
max-width: 768px;
|
||||||
|
padding-left: 2rem;
|
||||||
|
padding-right: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Large devices (1024px+) - Tailwind lg */
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.container-responsive {
|
||||||
|
max-width: 1024px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra Large devices (1280px+) - Tailwind xl */
|
||||||
|
@media (min-width: 1280px) {
|
||||||
|
.container-responsive {
|
||||||
|
max-width: 1280px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue