This commit is contained in:
Mohammadreza 2025-12-28 15:18:05 +03:30
commit 4e4f9685a4
8 changed files with 375 additions and 184 deletions

View File

@ -23,6 +23,12 @@ const SIDEBAR = {
icon: PiCoffee, icon: PiCoffee,
label: 'مدیریت کافه ها', label: 'مدیریت کافه ها',
}, },
{
id: 'users-management',
path: '/users-management',
icon: PiCoffee,
label: 'مدیریت کاربران',
},
{ {
id: 'stats', id: 'stats',
path: '/stats', path: '/stats',

View File

@ -7,11 +7,14 @@ import toggleTheme from "../ToggleTheme";
import { CgDarkMode } from "react-icons/cg"; import { CgDarkMode } from "react-icons/cg";
const HEADER_PATHS = [ const HEADER_PATHS = [
{ route: "/cafe-management", title: "مدیریت کافه ها" }, "/management",
{ route: "/dashboard", title: "داشبورد" }, "/management/",
{ route: "/stats", title: "آمار و تحلیل" }, "/management/cafes",
{ route: "/edit-cafe/", title: "ویرایش کافه" }, "/edit-cafe",
"/edit-cafe/",
"/cafe",
"/cafes",
"/admin",
]; ];
export default function Layout() { export default function Layout() {

View File

@ -68,82 +68,65 @@ const CafeManagement = () => {
); );
} }
return ( return (
<> <>
{/* جدول دسکتاپ */} {/* جدول دسکتاپ */}
<div className="hidden lg:block mt-10 overflow-x-auto"> <div className="hidden lg:block mt-10 overflow-x-auto">
<table className="w-full border-collapse"> <table className="w-full border-collapse">
<thead> <thead>
<tr className="bg-thead"> <tr className="bg-thead">
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> <th className="px-4 py-3 text-right text-text2 font-medium text-sm">لوگو</th>
لوگو <th className="px-4 py-3 text-right text-text2 font-medium text-sm">اسم</th>
</th> <th className="px-4 py-3 text-right text-text2 font-medium text-sm">آدرس</th>
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> <th className="px-4 py-3 text-right text-text2 font-medium text-sm">ریتینگ</th>
اسم <th className="px-4 py-3 text-right text-text2 font-medium text-sm">ساعت کاری</th>
</th> <th className="px-4 py-3 text-right text-text2 font-medium text-sm">ادیت</th>
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> </tr>
آدرس </thead>
</th> <tbody>
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> {cafes.map((cafe) => (
ریتینگ <tr key={cafe._id} className="border-b border-[#EFEEEE] hover:bg-hover transition-colors">
</th> <td className="px-4 py-4 text-right">
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> <img
ساعت کاری src={cafe.photo || Pic1}
</th> alt={cafe.Name}
<th className="px-4 py-3 text-right text-text2 font-medium text-sm"> className="w-10 h-10 rounded-full object-cover"
ادیت />
</th> </td>
</tr> <td className="px-4 py-4 text-right text-[#402E32] font-medium text-sm whitespace-nowrap">
</thead> {cafe.Name}
<tbody> </td>
{cafes.map((cafe) => ( <td className="px-4 py-4 text-right text-[#402E32] text-sm max-w-xs overflow-hidden text-ellipsis">
<tr {cafe.address}
key={cafe._id} </td>
className="border-b border-[#EFEEEE] hover:bg-hover transition-colors" <td className="px-4 py-4 text-right">
> <div className="flex items-center gap-2">
<td className="px-4 py-4 text-right"> <img src={Star1} alt="rating" className="w-5 h-5" />
<img <span className="text-[#402E32] text-sm">{cafe.rating || 0}</span>
src={cafe.photo || Pic1} </div>
alt={cafe.Name} </td>
className="w-10 h-10 rounded-full object-cover" <td className="px-4 py-4 text-right">
/> <div className="flex items-center gap-2">
</td> <img src={Group} alt="time" className="w-5 h-5" />
<td className="px-4 py-4 text-right text-[#402E32] font-medium text-sm whitespace-nowrap"> <span className="text-[#402E32] text-sm whitespace-nowrap">
{cafe.Name} {cafe.openinghour || "نامشخص"}
</td> </span>
<td className="px-4 py-4 text-right text-[#402E32] text-sm max-w-xs overflow-hidden text-ellipsis"> </div>
{cafe.address} </td>
</td> <td className="px-4 py-4 text-center">
<td className="px-4 py-4 text-right"> <Link
<div className="flex items-center gap-2"> to={`/edit-cafe/${cafe._id}`}
<img src={Star1} alt="rating" className="w-5 h-5" /> className="inline-flex items-center justify-center gap-2 border-2 border-[#BB8F70] px-6 py-2 rounded-3xl text-sm font-light text-text1 hover:bg-button1 hover:border-button1 transition-all duration-300"
<span className="text-[#402E32] text-sm"> >
{cafe.rating || 0} <span>ادیت</span>
</span> <BiEdit className="w-4 h-4" />
</div> </Link>
</td> </td>
<td className="px-4 py-4 text-right"> </tr>
<div className="flex items-center gap-2"> ))}
<img src={Group} alt="time" className="w-5 h-5" /> </tbody>
<span className="text-[#402E32] text-sm whitespace-nowrap"> </table>
{cafe.openinghour || "نامشخص"} </div>
</span>
</div>
</td>
<td className="px-4 py-4 text-center">
<Link
to={`/edit-cafe/${cafe._id}`}
className="inline-flex items-center justify-center gap-2 border-2 border-[#BB8F70] px-6 py-2 rounded-3xl text-sm font-light text-text1 hover:bg-button1 hover:border-button1 transition-all duration-300"
>
<span>ادیت</span>
<BiEdit className="w-4 h-4" />
</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* کارت موبایل */} {/* کارت موبایل */}
<div className="lg:hidden mt-6 space-y-4"> <div className="lg:hidden mt-6 space-y-4">
@ -181,29 +164,29 @@ const CafeManagement = () => {
</div> </div>
</div> </div>
<Link <Link
to={`/edit-cafe/${cafe._id}`} to={`/edit-cafe/${cafe._id}`}
className="flex justify-center items-center gap-2 w-full border-2 border-[#BB8F70] py-2 rounded-full text-sm font-medium text-text1 hover:bg-button1 hover:border-button1 transition-all duration-300" className="flex justify-center items-center gap-2 w-full border-2 border-[#BB8F70] py-2 rounded-full text-sm font-medium text-text1 hover:bg-button1 hover:border-button1 transition-all duration-300"
> >
<span className="">ادیت کافه</span> <span className="">ادیت کافه</span>
<BiEdit className="w-4 h-4" /> <BiEdit className="w-4 h-4" />
</Link> </Link>
</div> </div>
))} ))}
</div> </div>
</> </>
); );
}; };
return ( return (
<section dir="rtl" className="w-full pt-24 max-w-full overflow-x-hidden"> <section dir="rtl" className="w-full pt-24 max-w-full overflow-x-hidden">
{/* بخش دکمه اضافه کردن */} {/* بخش دکمه اضافه کردن */}
<div className="flex items-center justify-between mb-8"> <div className="flex items-center justify-between mb-8">
<button className="flex items-center justify-center gap-3 px-6 py-3 bg-button1 text-white rounded-3xl text-sm lg:text-base font-medium hover:bg-hover2 transition-all duration-300 cursor-pointer"> <button className="flex items-center justify-center gap-3 px-6 py-3 bg-button1 text-white rounded-3xl text-sm lg:text-base font-medium hover:bg-hover2 transition-all duration-300 cursor-pointer">
<span>افزودن شعبه جدید</span> <span>افزودن شعبه جدید</span>
<img src={Vector9} alt="افزودن" className="w-5 h-5" /> <img src={Vector9} alt="افزودن" className="w-5 h-5" />
</button> </button>
</div> </div>
{/* عنوان */} {/* عنوان */}
<h1 className="text-[#402E32] font-bold text-lg lg:text-xl mb-6"> <h1 className="text-[#402E32] font-bold text-lg lg:text-xl mb-6">

View File

@ -1,58 +1,106 @@
import React from "react"; import React from "react";
import VisitorsChart from "./components/viewstats"; import VisitorsChart from "./components/viewstats";
import CafePopularity from "./components/popular";
import CafeVisitPie from "./components/mostView";
import { RiArrowLeftSLine } from "react-icons/ri";
import { RiArrowDownSLine } from "react-icons/ri";
import { useState } from "react";
export default function Stats() { export default function Stats() {
const [dropDownOpen, setDropdownOpen] = useState(false);
return ( return (
<section dir="rtl" className="w-full h-full flex flex-col gap-6"> <section dir="rtl" className="w-full h-full flex flex-col gap-6">
<div className="flex flex-col gap-2 border-2 border-border rounded-2xl p-6 md:p-8"> <div className="flex flex-col gap-2 border-2 border-border rounded-2xl p-6 md:p-8">
<div className="flex gap-5"> <div className="flex gap-5">
<h4 className="font-bold text-md">آمار بازدید کننده ها</h4> <h4 className="font-bold text-md">آمار بازدید کننده ها</h4>
<button className="ps-5 pe-10 bg-hover text-text1 rounded-lg text-sm lg:text-base font-medium hover:bg-hover2 transition-all duration-300 cursor-pointer"> <div className="relative">
آبان <button
</button> onClick={() => setDropdownOpen(prev => !prev)}
className=" flex gap-2 justify-between items-center py-1 pe-5 ps-3 w-40 bg-hover text-text1 rounded-lg text-sm lg:text-base font-medium hover:bg-hover2 cursor-pointer">
<span>این هفته</span>
<RiArrowDownSLine size={20} className={`${dropDownOpen ? 'rotate-180' : ''} transition-all duration-200`} />
</button>
{dropDownOpen && (
<div className="absolute mt-2 bg-background text-text1 hover:text-text1 border-2 border-border rounded-lg shadow-lg w-40 z-10">
<ul className="flex flex-col">
<li className="px-4 py-2 hover:bg-hover2 cursor-pointer">امروز</li>
<li className="px-4 py-2 hover:bg-hover2 cursor-pointer">این هفته</li>
<li className="px-4 py-2 hover:bg-hover2 cursor-pointer">این ماه</li>
<li className="px-4 py-2 hover:bg-hover2 cursor-pointer">این سال</li>
</ul>
</div>
)
}
</div>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-col lg:flex-row gap-2">
<div className="self-end"> <div className="self-end lg:pb-10 lg:me-10 flex lg:flex-col gap-2 justify-center items-start">
مجموع فروش: 0 تومان <div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-red-500 rounded-sm" />
<span>راهنما</span>
</div>
<div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-blue-500 rounded-sm" />
<span>راهنما</span>
</div>
</div> </div>
<div className="flex-1"> <div className="flex-1">
<VisitorsChart /> <VisitorsChart />
</div> </div>
</div> </div>
</div> </div>
<div className="flex gap-5 rounded-2xl"> <div className="flex flex-col lg:flex-row gap-5 rounded-2xl">
<div className="flex flex-col w-1/2 gap-2 border-2 border-border rounded-2xl p-6 md:p-8"> <div className="flex flex-col w-full lg:w-1/2 gap-2 border-2 border-border rounded-2xl p-6 md:p-8">
<div className="flex gap-5"> <div className="flex justify-between gap-5">
<h4 className="font-bold text-md">آمار بازدید کننده ها</h4> <h4 className="font-bold text-md">آمار بازدید کننده ها</h4>
<button className="ps-5 pe-10 bg-hover text-text1 rounded-lg text-sm lg:text-base font-medium hover:bg-hover2 transition-all duration-300 cursor-pointer"> <span className="flex gap-2 justify-center items-center px-2 text-text1 rounded-lg text-sm lg:text-base font-medium transition-all duration-300 cursor-pointer">
آبان <span>همه</span>
</button> <RiArrowLeftSLine />
</span>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-col lg:flex-row gap-2">
<div className="self-end"> <div className="self-end lg:pb-10 lg:me-10 flex lg:flex-col gap-2 justify-center items-start">
مجموع فروش: 0 تومان <div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-red-500 rounded-sm" />
<span>راهنما</span>
</div>
<div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-blue-500 rounded-sm" />
<span>راهنما</span>
</div>
</div> </div>
<div className="flex-1"> <div className="flex-1">
<VisitorsChart /> <CafeVisitPie />
</div> </div>
</div> </div>
</div> </div>
<div className="flex flex-col gap-2 w-1/2 border-2 border-border rounded-2xl p-6 md:p-8"> <div className="flex flex-col gap-2 w-full lg:w-1/2 border-2 border-border rounded-2xl p-6 md:p-8">
<div className="flex gap-5"> <div className="flex justify-between gap-5">
<h4 className="font-bold text-md">آمار بازدید کننده ها</h4> <h4 className="font-bold text-md">آمار بازدید کننده ها</h4>
<button className="ps-5 pe-10 bg-hover text-text1 rounded-lg text-sm lg:text-base font-medium hover:bg-hover2 transition-all duration-300 cursor-pointer"> <span className="flex gap-2 justify-center items-center px-2 text-text1 rounded-lg text-sm lg:text-base font-medium transition-all duration-300 cursor-pointer">
آبان <span>همه</span>
</button> <RiArrowLeftSLine />
</span>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-col lg:flex-row gap-2">
<div className="self-end"> <div className="self-end lg:pb-10 lg:me-10 flex lg:flex-col gap-2 justify-center items-start">
مجموع فروش: 0 تومان <div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-red-500 rounded-sm" />
<span>راهنما</span>
</div>
<div className="flex gap-2 justify-center items-center">
<span className="w-4 h-4 bg-blue-500 rounded-sm" />
<span>راهنما</span>
</div>
</div> </div>
<div className="flex-1"> <div className="flex-1">
<VisitorsChart /> <CafePopularity />
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,48 @@
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
} from "recharts";
const data = [
{ name: "دان", value: 48, color: "#b52424" },
{ name: "وی", value: 38, color: "#C0BCBC" },
{ name: "آنی", value: 19, color: "#7f7376" },
];
export default function CafeVisitPie() {
return (
<div dir="ltr" className="w-full h-62 p-6 pb-0 pl-0">
{/* <p className="text-sm font-medium mb-3 text-right">پربازدیدترین کافه‌ها</p> */}
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Tooltip
contentStyle={{
background: "var(--bg-primary)",
border: "1px solid var(--border-color)",
color: "var(--text-primary)",
}}
/>
<Pie
data={data}
dataKey="value"
cx="50%"
cy="50%"
// innerRadius={50}
outerRadius={80}
label={({ value }) => `${value}%`}
>
{data.map((item, i) => (
<Cell key={i} fill={item.color} />
))}
</Pie>
</PieChart>
</ResponsiveContainer>
</div>
);
}

View File

@ -0,0 +1,50 @@
import {
BarChart,
Bar,
XAxis,
Tooltip,
ResponsiveContainer,
Cell,
} from "recharts";
const data = [
{ name: "وی", value: 120 },
{ name: "پل", value: 90 },
{ name: "دولت", value: 60 },
{ name: "و", value: 180 },
{ name: "تریح", value: 100 },
{ name: "دان", value: 110 },
];
const colors = ["#efecec", "#efecec", "#efecec", "#7f7376", "#efecec", "#efecec"];
export default function CafePopularity() {
return (
<div className="w-full h-72 p-6">
{/* <p className="text-sm font-medium mb-3 text-right">محبوب‌ترین کافه‌ها</p> */}
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data}>
<XAxis dataKey="name" />
<Tooltip
contentStyle={{
background: "none",
border: "none",
color: "var(--color-text1)",
}}
/>
<Bar
dataKey="value"
radius={[20, 20, 20, 20]}
cursor="default"
>
{data.map((entry, i) => (
<Cell key={i} fill={colors[i]} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
);
}

View File

@ -1,65 +1,88 @@
import { import {
LineChart, ComposedChart,
Line, Line,
XAxis, XAxis,
YAxis, YAxis,
Tooltip, Tooltip,
ResponsiveContainer, ResponsiveContainer,
Area
} from "recharts"; } from "recharts";
const data = [ const data = [
{ name: "هفته اول", a: 200000, b: 250000 }, { name: "هفته اول", a: 200000, b: 250000 },
{ name: "هفته دوم", a: 450000, b: 380000 }, { name: "هفته دوم", a: 450000, b: 380000 },
{ name: "هفته سوم", a: 350000, b: 600000 }, { name: "هفته سوم", a: 350000, b: 600000 },
{ name: "هفته چهارم", a: 150000, b: 500000 }, { name: "هفته چهارم", a: 150000, b: 500000 },
{ name: "هفته پنجم", a: 500000, b: 700000 }, { name: "هفته پنجم", a: 500000, b: 700000 },
{ name: "هفته ششم", a: 600000, b: 800000 }, { name: "هفته ششم", a: 600000, b: 800000 },
{ name: "هفته هفتم", a: 700000, b: 900000 }, { name: "هفته هفتم", a: 700000, b: 900000 },
{ name: "هفته هشتم", a: 800000, b: 950000 }, { name: "هفته هشتم", a: 800000, b: 950000 },
{ name: "هفته نهم", a: 900000, b: 1000000 }, { name: "هفته نهم", a: 900000, b: 1000000 },
]; ];
export default function VisitorsChart() { export default function VisitorsChart() {
return ( return (
<div dir="ltr" className="w-full h-72 rounded-xl bg-white shadow-sm p-6"> <div dir="ltr" className="w-full h-96 p-6 pb-0 pl-0">
<p className="text-sm font-medium mb-3 text-right">آمار بازدید کنندهها</p> <ResponsiveContainer width="100%" height="90%">
<ComposedChart data={data}>
<ResponsiveContainer width="100%" height="90%"> <defs>
<LineChart data={data}> <linearGradient id="gradA" x1="0" y1="0" x2="0" y2="1">
{/* گرادیانت‌ها */} <stop offset="0%" stopColor="#b52424" stopOpacity={0.4} />
<defs> <stop offset="100%" stopColor="#b52424" stopOpacity={0} />
<linearGradient id="gradA" x1="0" y1="0" x2="0" y2="1"> </linearGradient>
<stop offset="0%" stopColor="#C2574E" stopOpacity={0.4} />
<stop offset="100%" stopColor="#C2574E" stopOpacity={0} />
</linearGradient>
<linearGradient id="gradB" x1="0" y1="0" x2="0" y2="1"> <linearGradient id="gradB" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#6B432B" stopOpacity={0.4} /> <stop offset="0%" stopColor="#7f7376" stopOpacity={0.4} />
<stop offset="100%" stopColor="#6B432B" stopOpacity={0} /> <stop offset="100%" stopColor="#7f7376" stopOpacity={0} />
</linearGradient> </linearGradient>
</defs> </defs>
<XAxis dataKey="name" tick={{ fontSize: 12 }} /> <Area
<YAxis tick={{ fontSize: 12 }} /> type="monotone"
<Tooltip /> dataKey="a"
<Line stroke="none"
type="monotone" fill="url(#gradA)"
dataKey="a" fillOpacity={1}
stroke="#C2574E" />
strokeWidth={3} <Area
fill="url(#gradA)" type="monotone"
dot={false} dataKey="b"
/> stroke="none"
<Line fill="url(#gradB)"
type="monotone" fillOpacity={1}
dataKey="b" />
stroke="#6B432B"
strokeWidth={3} <XAxis dataKey="name" tick={{ fontSize: 12 }} />
fill="url(#gradB)" <YAxis tick={{ fontSize: 12 }} />
dot={false}
/> <Tooltip
</LineChart> contentStyle={{
</ResponsiveContainer> background: "var(--bg-primary)",
</div> border: "1px solid var(--border-color)",
); color: "var(--text-primary)",
}}
/>
<Line
type="monotone"
dataKey="a"
stroke="#b52424"
strokeWidth={3}
fill="url(#gradA)"
dot={false}
/>
<Line
type="monotone"
dataKey="b"
stroke="#7f7376"
strokeWidth={3}
fill="url(#gradB)"
dot={false}
/>
</ComposedChart>
</ResponsiveContainer>
</div>
);
} }

View File

@ -72,6 +72,10 @@ select:-webkit-autofill {
-webkit-text-fill-color: inherit !important; -webkit-text-fill-color: inherit !important;
} }
.primary {
color: var(--color-primary);
background-color: var(--color-primary);
}
h1, h1,
h2, h2,
@ -104,7 +108,7 @@ div:hover
} }
.dark div:hover { .dark div:hover {
color: var(--color-text2) !important; color: var(--color-text1);
} }
@ -179,4 +183,30 @@ svg {
/* بک‌گراند انتخاب */ /* بک‌گراند انتخاب */
color: var(--color-text1); color: var(--color-text1);
/* رنگ متن انتخاب */ /* رنگ متن انتخاب */
} }
/* جلوگیری کامل از رینگ / بوردر فوکوس در Recharts */
.recharts-wrapper:focus,
.recharts-wrapper:focus-visible,
.recharts-surface:focus,
.recharts-surface:focus-visible,
.recharts-responsive-container:focus,
.recharts-responsive-container:focus-visible,
.recharts-layer:focus,
.recharts-layer:focus-visible,
svg:focus,
svg:focus-visible,
g:focus,
g:focus-visible {
outline: none !important;
border: none !important;
box-shadow: none !important;
}
/* برای اطمینان بیشتر روی کل پروژه */
*:focus,
*:focus-visible {
outline: none !important;
box-shadow: none !important;
}