handle dashboard access by role
This commit is contained in:
@@ -5,8 +5,14 @@ import {
|
|||||||
User, Crown, Home, ShoppingBag, Wallet, MapPin,
|
User, Crown, Home, ShoppingBag, Wallet, MapPin,
|
||||||
Headphones, Heart, IdCard, LogOut, TrendingUp,
|
Headphones, Heart, IdCard, LogOut, TrendingUp,
|
||||||
Plus, Hash, Clock, AlertCircle, Eye, Reply,
|
Plus, Hash, Clock, AlertCircle, Eye, Reply,
|
||||||
CreditCard, Gift, Edit, Trash2, CircleCheck, Info, Box, Camera, Check, Shield, ShieldAlert, Mail
|
CreditCard, Gift, Edit, Trash2, CircleCheck, Info, Box, Camera, Check, Shield, ShieldAlert, Mail, CheckCircle, ShieldX
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// === رابطها و کامپوننتهای کمکی ===
|
// === رابطها و کامپوننتهای کمکی ===
|
||||||
interface PriceDisplayProps {
|
interface PriceDisplayProps {
|
||||||
@@ -89,7 +95,22 @@ const sampleAddresses = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState('dash');
|
const [activeTab, setActiveTab] = useState('dash');
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const success = searchParams.get("success");
|
||||||
|
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
||||||
|
React.useEffect(() => {
|
||||||
|
const token = localStorage.getItem("accessToken");
|
||||||
|
const role = localStorage.getItem("role");
|
||||||
|
|
||||||
|
if (token && (role === "user" || role === "admin")) {
|
||||||
|
setAuthorized(true);
|
||||||
|
} else {
|
||||||
|
setAuthorized(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ id: 'dash', label: 'پیشخوان', icon: Home },
|
{ id: 'dash', label: 'پیشخوان', icon: Home },
|
||||||
@@ -100,9 +121,73 @@ export default function Dashboard() {
|
|||||||
{ id: 'profile', label: 'مشخصات حساب', icon: IdCard },
|
{ id: 'profile', label: 'مشخصات حساب', icon: IdCard },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// ✅ حالت در حال بررسی
|
||||||
|
if (authorized === null) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-gray-50" dir="rtl">
|
||||||
|
<p className="text-gray-600">در حال بررسی دسترسی...</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ دسترسی ندارد
|
||||||
|
if (!authorized) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4" dir="rtl">
|
||||||
|
<div className="bg-white shadow-xl rounded-2xl p-10 max-w-md w-full text-center border border-gray-100">
|
||||||
|
|
||||||
|
<div className="flex justify-center mb-6">
|
||||||
|
<div className="bg-red-100 p-4 rounded-full">
|
||||||
|
<ShieldX className="w-10 h-10 text-red-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-2xl font-bold text-gray-800 mb-2">
|
||||||
|
دسترسی غیرمجاز
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-gray-500 text-sm leading-relaxed mb-6">
|
||||||
|
شما اجازه دسترسی به این صفحه را ندارید.
|
||||||
|
برای مشاهده داشبورد باید ابتدا وارد حساب کاربری خود شوید.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button
|
||||||
|
onClick={() => router.push("/")}
|
||||||
|
className="flex cursor-pointer items-center gap-2 bg-gray-900 text-white px-4 py-2 rounded-lg text-sm hover:bg-black transition"
|
||||||
|
>
|
||||||
|
<Home className="w-4 h-4" />
|
||||||
|
بازگشت به صفحه اصلی
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 py-8" dir="rtl">
|
<div className="min-h-screen bg-gray-50 py-8" dir="rtl">
|
||||||
<div className="container mx-auto px-4 max-w-6xl">
|
<div className="container mx-auto px-4 max-w-6xl">
|
||||||
|
|
||||||
|
{success === "login" && (
|
||||||
|
<div className="mb-4 flex items-center gap-2 p-3 bg-[#d2f6dca3] text-green-700 rounded-xl text-sm">
|
||||||
|
<CheckCircle className="w-4 h-4 text-green-600" />
|
||||||
|
<span>ورود با موفقیت انجام شد</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{success === "register" && (
|
||||||
|
<div className="mb-4 flex items-center gap-2 p-3 bg-[#d2f6dca3] text-green-700 rounded-xl text-sm">
|
||||||
|
<CheckCircle className="w-4 h-4 text-green-600" />
|
||||||
|
<span>ثبت نام با موفقیت انجام شد</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col lg:flex-row gap-8">
|
<div className="flex flex-col lg:flex-row gap-8">
|
||||||
|
|
||||||
<aside className="w-full lg:w-[280px] bg-white rounded-2xl shadow-sm flex-shrink-0 h-fit">
|
<aside className="w-full lg:w-[280px] bg-white rounded-2xl shadow-sm flex-shrink-0 h-fit">
|
||||||
@@ -129,7 +214,7 @@ export default function Dashboard() {
|
|||||||
<li key={item.id}>
|
<li key={item.id}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab(item.id)}
|
onClick={() => setActiveTab(item.id)}
|
||||||
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all duration-200 ${activeTab === item.id
|
className={`w-full cursor-pointer flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all duration-200 ${activeTab === item.id
|
||||||
? 'bg-[#1a2332] text-white shadow-md'
|
? 'bg-[#1a2332] text-white shadow-md'
|
||||||
: 'text-gray-600 hover:bg-gray-50 hover:text-[#ffb900]'
|
: 'text-gray-600 hover:bg-gray-50 hover:text-[#ffb900]'
|
||||||
}`}
|
}`}
|
||||||
@@ -153,38 +238,38 @@ export default function Dashboard() {
|
|||||||
{activeTab === 'dash' && (
|
{activeTab === 'dash' && (
|
||||||
<div className="animate-in fade-in slide-in-from-bottom-4 duration-500">
|
<div className="animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||||
<h2 className="text-2xl font-bold text-gray-800 mb-6">خوش آمدید، علی عزیز</h2>
|
<h2 className="text-2xl font-bold text-gray-800 mb-6">خوش آمدید، علی عزیز</h2>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4 mb-6">
|
||||||
<div className="bg-white p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
<div className="bg-white p-5 rounded-2xl border border-gray-100 flex-col shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
||||||
<div className="w-12 h-12 rounded-xl bg-blue-50 text-blue-600 flex items-center justify-center flex-shrink-0"><Wallet size={24} /></div>
|
<div className="w-12 h-12 rounded-xl bg-blue-50 text-blue-600 flex items-center justify-center flex-shrink-0"><Wallet size={24} /></div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-xs text-gray-500 mb-1">موجودی کیف پول</h4>
|
<h4 className="text-xs text-gray-500 mb-1">موجودی کیف پول</h4>
|
||||||
<strong className="text-lg text-gray-800"><PriceDisplay amount={1500000} /></strong>
|
<strong className="text-[1em] text-gray-800"><PriceDisplay amount={1500000} /></strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
<div className="bg-white flex-col p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
||||||
<div className="w-12 h-12 rounded-xl bg-green-50 text-green-600 flex items-center justify-center flex-shrink-0"><ShoppingBag size={24} /></div>
|
<div className="w-12 h-12 rounded-xl bg-green-50 text-green-600 flex items-center justify-center flex-shrink-0"><ShoppingBag size={24} /></div>
|
||||||
<div>
|
<div className='flex flex-col items-center'>
|
||||||
<h4 className="text-xs text-gray-500 mb-1">سفارشات جاری</h4>
|
<h4 className="text-xs text-gray-500 mb-1">سفارشات جاری</h4>
|
||||||
<strong className="text-lg text-gray-800">۲ <span className="text-xs font-normal text-gray-500">مورد</span></strong>
|
<strong className="text-lg text-gray-800">۲ <span className="text-xs font-normal text-gray-500">مورد</span></strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
<div className="bg-white flex-col p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
||||||
<div className="w-12 h-12 rounded-xl bg-orange-50 text-orange-600 flex items-center justify-center flex-shrink-0"><Headphones size={24} /></div>
|
<div className="w-12 h-12 rounded-xl bg-orange-50 text-orange-600 flex items-center justify-center flex-shrink-0"><Headphones size={24} /></div>
|
||||||
<div>
|
<div className='flex flex-col items-center'>
|
||||||
<h4 className="text-xs text-gray-500 mb-1">تیکتهای باز</h4>
|
<h4 className="text-xs text-gray-500 mb-1">تیکتهای باز</h4>
|
||||||
<strong className="text-lg text-gray-800">۱ <span className="text-xs font-normal text-gray-500">مورد</span></strong>
|
<strong className="text-lg text-gray-800">۱ <span className="text-xs font-normal text-gray-500">مورد</span></strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
<div className="bg-white flex-col p-5 rounded-2xl border border-gray-100 shadow-sm flex items-center gap-4 hover:shadow-md transition-shadow">
|
||||||
<div className="w-12 h-12 rounded-xl bg-purple-50 text-purple-600 flex items-center justify-center flex-shrink-0"><TrendingUp size={24} /></div>
|
<div className="w-12 h-12 rounded-xl bg-purple-50 text-purple-600 flex items-center justify-center flex-shrink-0"><TrendingUp size={24} /></div>
|
||||||
<div>
|
<div className='flex flex-col items-center'>
|
||||||
<h4 className="text-xs text-gray-500 mb-1">امتیاز وفاداری</h4>
|
<h4 className="text-xs text-gray-500 mb-1">امتیاز وفاداری</h4>
|
||||||
<strong className="text-lg text-gray-800">۲,۳۴۰ <span className="text-xs font-normal text-gray-500">امتیاز</span></strong>
|
<strong className="text-lg text-gray-800">۲,۳۴۰ <span className="text-xs font-normal text-gray-500">امتیاز</span></strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div className="grid lg:grid-cols-2 gap-6">
|
||||||
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-6">
|
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-6">
|
||||||
<div className="flex justify-between items-center pb-4 border-b border-gray-100 mb-4">
|
<div className="flex justify-between items-center pb-4 border-b border-gray-100 mb-4">
|
||||||
<h3 className="font-bold text-gray-800">آخرین سفارشات</h3>
|
<h3 className="font-bold text-gray-800">آخرین سفارشات</h3>
|
||||||
@@ -647,3 +732,5 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
108
app/page.tsx
108
app/page.tsx
@@ -17,50 +17,6 @@ import Link from "next/link";
|
|||||||
import { useCategories } from "@/components/context/categoryprovider";
|
import { useCategories } from "@/components/context/categoryprovider";
|
||||||
|
|
||||||
|
|
||||||
const features = [
|
|
||||||
{
|
|
||||||
icon: Headphones,
|
|
||||||
title: "مشاوره فنی رایگان",
|
|
||||||
desc: "انتخاب بهترین قطعه با توجه به نیاز شما",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: FileText,
|
|
||||||
title: "فاکتور رسمی",
|
|
||||||
desc: "صدور فاکتور برای شرکتها",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: Truck,
|
|
||||||
title: "ارسال فوری",
|
|
||||||
desc: "ارسال در سریعترین زمان ممکن",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ShieldCheck,
|
|
||||||
title: "ضمانت اصالت کالا",
|
|
||||||
desc: "تضمین اورجینال بودن محصولات",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
const tabs = ["پرفروشترینها", "تخفیفدار", "جدیدترینها"];
|
|
||||||
|
|
||||||
|
|
||||||
const faqs = [
|
|
||||||
{
|
|
||||||
question: "آیا تمامی قطعات دارای ضمانت اصالت هستند؟",
|
|
||||||
answer:
|
|
||||||
"بله، تمامی محصولات ارائه شده دارای ضمانت اصالت کالا بوده و از برندهای معتبر جهانی تأمین میشوند.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "امکان صدور فاکتور رسمی برای شرکتها وجود دارد؟",
|
|
||||||
answer:
|
|
||||||
"بله، برای تمامی سفارشات امکان صدور فاکتور رسمی وجود دارد.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "سفارشها چه زمانی ارسال میشوند؟",
|
|
||||||
answer:
|
|
||||||
"سفارشها در سریعترین زمان ممکن پردازش شده و از طریق روشهای ارسال معتبر ارسال میشوند.",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@@ -69,25 +25,51 @@ export default function Home() {
|
|||||||
const latestArticles = articles.slice(-4);
|
const latestArticles = articles.slice(-4);
|
||||||
const { rootCategories } = useCategories();
|
const { rootCategories } = useCategories();
|
||||||
|
|
||||||
// const uniqueCategories = Array.from(new Set(products.map((p) => p.category)));
|
const features = [
|
||||||
// const getCategoryIcon = (categoryName: string) => {
|
{
|
||||||
// switch (categoryName) {
|
icon: Headphones,
|
||||||
// case "شیار عمیق":
|
title: "مشاوره فنی رایگان",
|
||||||
// return CircleDashed;
|
desc: "انتخاب بهترین قطعه با توجه به نیاز شما",
|
||||||
// case "مخروطی":
|
},
|
||||||
// return Disc;
|
{
|
||||||
// case "شبکه ای":
|
icon: FileText,
|
||||||
// return Hexagon;
|
title: "فاکتور رسمی",
|
||||||
// case "سوزنی":
|
desc: "صدور فاکتور برای شرکتها",
|
||||||
// return Settings;
|
},
|
||||||
// case "یاتاقان":
|
{
|
||||||
// return Wrench;
|
icon: Truck,
|
||||||
// case "گریس و روانکار":
|
title: "ارسال فوری",
|
||||||
// return Droplets;
|
desc: "ارسال در سریعترین زمان ممکن",
|
||||||
// default:
|
},
|
||||||
// return Settings; // آیکون پیشفرض
|
{
|
||||||
// }
|
icon: ShieldCheck,
|
||||||
// };
|
title: "ضمانت اصالت کالا",
|
||||||
|
desc: "تضمین اورجینال بودن محصولات",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const tabs = ["پرفروشترینها", "تخفیفدار", "جدیدترینها"];
|
||||||
|
|
||||||
|
|
||||||
|
const faqs = [
|
||||||
|
{
|
||||||
|
question: "آیا تمامی قطعات دارای ضمانت اصالت هستند؟",
|
||||||
|
answer:
|
||||||
|
"بله، تمامی محصولات ارائه شده دارای ضمانت اصالت کالا بوده و از برندهای معتبر جهانی تأمین میشوند.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "امکان صدور فاکتور رسمی برای شرکتها وجود دارد؟",
|
||||||
|
answer:
|
||||||
|
"بله، برای تمامی سفارشات امکان صدور فاکتور رسمی وجود دارد.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "سفارشها چه زمانی ارسال میشوند؟",
|
||||||
|
answer:
|
||||||
|
"سفارشها در سریعترین زمان ممکن پردازش شده و از طریق روشهای ارسال معتبر ارسال میشوند.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
const categoryIcons = [
|
const categoryIcons = [
|
||||||
CircleDashed,
|
CircleDashed,
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ export function Header() {
|
|||||||
const [registerError, setRegisterError] = useState("");
|
const [registerError, setRegisterError] = useState("");
|
||||||
const [loginError, setLoginError] = useState("");
|
const [loginError, setLoginError] = useState("");
|
||||||
const { rootCategories } = useCategories();
|
const { rootCategories } = useCategories();
|
||||||
|
const [user, setUser] = useState<{ username: string } | null>(null);
|
||||||
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [showLoginPassword, setShowLoginPassword] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [loginForm, setLoginForm] = useState({
|
const [loginForm, setLoginForm] = useState({
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
@@ -59,6 +66,17 @@ export function Header() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const token = localStorage.getItem("accessToken");
|
||||||
|
const username = localStorage.getItem("username");
|
||||||
|
|
||||||
|
if (token && username) {
|
||||||
|
setUser({ username });
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
const handleRegister = async () => {
|
const handleRegister = async () => {
|
||||||
|
|
||||||
setRegisterError("");
|
setRegisterError("");
|
||||||
@@ -84,12 +102,19 @@ export function Header() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const res = await registerUser(payload);
|
const res = await registerUser(payload);
|
||||||
|
const role = res.data?.user?.role;
|
||||||
|
|
||||||
localStorage.setItem("accessToken", res.data.accessToken);
|
localStorage.setItem("accessToken", res.data.accessToken);
|
||||||
localStorage.setItem("refreshToken", res.data.refreshToken);
|
localStorage.setItem("refreshToken", res.data.refreshToken);
|
||||||
|
localStorage.setItem("username", username);
|
||||||
|
localStorage.setItem("role", role.toLowerCase());
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
|
||||||
|
setUser({ username });
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
router.push("/dashboard");
|
router.push("/dashboard?success=register");
|
||||||
|
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
||||||
@@ -126,11 +151,16 @@ export function Header() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await loginUser({ username, password });
|
const res = await loginUser({ username, password });
|
||||||
|
const role = res.data?.user?.role;
|
||||||
|
localStorage.setItem("role", role.toLowerCase());
|
||||||
localStorage.setItem("accessToken", res.data.accessToken);
|
localStorage.setItem("accessToken", res.data.accessToken);
|
||||||
localStorage.setItem("refreshToken", res.data.refreshToken);
|
localStorage.setItem("refreshToken", res.data.refreshToken);
|
||||||
|
localStorage.setItem("username", username);
|
||||||
|
console.log(res);
|
||||||
|
setUser({ username });
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
router.push("/dashboard");
|
router.push("/dashboard?success=login");
|
||||||
|
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const msg = error?.message?.toLowerCase() || "";
|
const msg = error?.message?.toLowerCase() || "";
|
||||||
@@ -162,6 +192,16 @@ export function Header() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
localStorage.removeItem("accessToken");
|
||||||
|
localStorage.removeItem("refreshToken");
|
||||||
|
localStorage.removeItem("username");
|
||||||
|
localStorage.removeItem("role");
|
||||||
|
|
||||||
|
setUser(null);
|
||||||
|
router.push("/");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -467,15 +507,52 @@ export function Header() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
{!user ? (
|
||||||
onClick={() => setIsOpen(true)}
|
<button
|
||||||
className="flex cursor-pointer items-center gap-2 px-3 py-2.5 bg-white border border-gray-300/60 rounded-xl text-xs text-gray-700 hover:bg-gray-50 transition"
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
className="flex cursor-pointer items-center gap-2 px-3 py-2.5 bg-white border border-gray-300/60 rounded-xl text-xs text-gray-700 hover:bg-gray-50 transition"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-4 h-4 text-gray-500">
|
>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.5 20.25a7.5 7.5 0 0115 0" />
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-4 h-4 text-gray-500">
|
||||||
</svg>
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.5 20.25a7.5 7.5 0 0115 0" />
|
||||||
<span>ورود / عضویت</span>
|
</svg>
|
||||||
</button>
|
|
||||||
|
<span>ورود / عضویت</span>
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<div className="relative" onClick={() => setUserMenuOpen(!userMenuOpen)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="flex cursor-pointer items-center gap-2 px-3 py-2.5 bg-white border border-gray-300/60 rounded-xl text-xs text-gray-700 hover:bg-gray-50 transition"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="M5.121 17.804A9 9 0 1118.879 17.804M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span>{user.username}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{userMenuOpen && (
|
||||||
|
<div className="absolute left-0 mt-2 w-40 bg-white border border-gray-200 rounded-xl shadow-lg p-2 text-xs">
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => router.push("/dashboard")}
|
||||||
|
className="w-full cursor-pointer text-right px-3 py-2 rounded-lg hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
داشبورد
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleLogout}
|
||||||
|
className="w-full cursor-pointer text-right px-3 py-2 rounded-lg text-red-500 hover:bg-red-50"
|
||||||
|
>
|
||||||
|
خروج
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-[#1A2332]/40 backdrop-blur-sm transition-opacity" dir="rtl">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-[#1A2332]/40 backdrop-blur-sm transition-opacity" dir="rtl">
|
||||||
@@ -542,7 +619,7 @@ export function Header() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setFormType("password")}
|
onClick={() => setFormType("password")}
|
||||||
className="w-full text-xs text-gray-500 hover:text-[#1A2332]"
|
className="w-full cursor-pointer text-xs text-gray-500 hover:text-[#1A2332]"
|
||||||
>
|
>
|
||||||
ورود با نام کاربری و رمز عبور
|
ورود با نام کاربری و رمز عبور
|
||||||
</button>
|
</button>
|
||||||
@@ -567,18 +644,45 @@ export function Header() {
|
|||||||
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<input
|
|
||||||
type="password"
|
<div className="relative w-full">
|
||||||
value={loginForm.password}
|
<input
|
||||||
onChange={(e) =>
|
type={showLoginPassword ? "text" : "password"} // تغییر نوع بر اساس state
|
||||||
setLoginForm((prev) => ({
|
value={loginForm.password}
|
||||||
...prev,
|
onChange={(e) =>
|
||||||
password: e.target.value,
|
setLoginForm((prev) => ({
|
||||||
}))
|
...prev,
|
||||||
}
|
password: e.target.value,
|
||||||
placeholder="رمز عبور"
|
}))
|
||||||
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
}
|
||||||
/>
|
placeholder="رمز عبور"
|
||||||
|
className="w-full px-4 pl-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowLoginPassword(!showLoginPassword)}
|
||||||
|
className="absolute cursor-pointer left-4 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 p-1" // پدینگ اضافه شد تا کلیک راحتتر باشد
|
||||||
|
>
|
||||||
|
{showLoginPassword ? (
|
||||||
|
// آیکون چشم خط خورده (eye-off)
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.8">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M3 3l18 18M10.477 10.477A3 3 0 0113.5 13.5m-7.09-2.664A9.956 9.956 0 003 12s2.91-6 9-6a9.953 9.953 0 016.328 2.318M15.54 15.54A9.953 9.953 0 0112 18c-6.09 0-9-6-9-6a9.956 9.956 0 012.41-3.868" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
// آیکون چشم باز (eye)
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.8">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button onClick={handleLogin} className="w-full cursor-pointer py-3.5 bg-[#ffb900] hover:bg-[#e5a600] text-[#1A2332] font-semibold rounded-2xl text-sm">
|
<button onClick={handleLogin} className="w-full cursor-pointer py-3.5 bg-[#ffb900] hover:bg-[#e5a600] text-[#1A2332] font-semibold rounded-2xl text-sm">
|
||||||
ورود
|
ورود
|
||||||
@@ -591,7 +695,7 @@ export function Header() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setFormType("mobile")}
|
onClick={() => setFormType("mobile")}
|
||||||
className="w-full text-xs text-gray-500 hover:text-[#1A2332]"
|
className="w-full cursor-pointer text-xs text-gray-500 hover:text-[#1A2332]"
|
||||||
>
|
>
|
||||||
ورود با شماره موبایل
|
ورود با شماره موبایل
|
||||||
</button>
|
</button>
|
||||||
@@ -631,13 +735,41 @@ export function Header() {
|
|||||||
placeholder="نام کاربری"
|
placeholder="نام کاربری"
|
||||||
className='w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]'
|
className='w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]'
|
||||||
/>
|
/>
|
||||||
<input
|
<div className="relative w-full">
|
||||||
name="password"
|
<input
|
||||||
value={registerForm.password}
|
name="password"
|
||||||
onChange={handleChange} type="password"
|
value={registerForm.password}
|
||||||
placeholder="رمز عبور"
|
onChange={handleChange}
|
||||||
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
type={showPassword ? "text" : "password"}
|
||||||
/>
|
placeholder="رمز عبور"
|
||||||
|
className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
|
className="absolute cursor-pointer left-4 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700"
|
||||||
|
>
|
||||||
|
{showPassword ? (
|
||||||
|
// eye-off icon
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.8">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M3 3l18 18M10.477 10.477A3 3 0 0113.5 13.5m-7.09-2.664A9.956 9.956 0 003 12s2.91-6 9-6a9.953 9.953 0 016.328 2.318M15.54 15.54A9.953 9.953 0 0112 18c-6.09 0-9-6-9-6a9.956 9.956 0 012.41-3.868" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
// eye icon
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.8">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/* <input
|
{/* <input
|
||||||
name="confirmPassword"
|
name="confirmPassword"
|
||||||
|
|||||||
Reference in New Issue
Block a user