updata
This commit is contained in:
@@ -10,6 +10,7 @@ import Rate from "rc-rate";
|
||||
import "rc-rate/assets/index.css";
|
||||
import { useUser } from "@/hooks/useUser";
|
||||
import { Course } from "@/types/types";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
export interface Comments {
|
||||
_id: string;
|
||||
@@ -60,6 +61,7 @@ function CommentsModal({
|
||||
const { request } = useAxios();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const currentUser = useUser();
|
||||
const requireAuth = useRequireAuth();
|
||||
const [hasRatedCourse, setHasRatedCourse] = useState(false);
|
||||
|
||||
// تابع دریافت اطلاعات کاربر با caching
|
||||
@@ -215,6 +217,7 @@ function CommentsModal({
|
||||
|
||||
// ارسال کامنت جدید
|
||||
const sendMessageHandler = async () => {
|
||||
if (!requireAuth()) return;
|
||||
if (!newMessage.trim()) {
|
||||
toast.error("ثبت نظر الزامی است.");
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { useUserById } from "@/hooks/getUserById";
|
||||
import { AxiosError } from "axios";
|
||||
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
function MainModelCardActions({ postData }: { postData: Course }) {
|
||||
const { _id, user_id, likes } = postData;
|
||||
@@ -35,6 +36,7 @@ function MainModelCardActions({ postData }: { postData: Course }) {
|
||||
|
||||
const { request, loading } = useAxios();
|
||||
const router = useRouter();
|
||||
const requireAuth = useRequireAuth();
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
@@ -56,6 +58,7 @@ function MainModelCardActions({ postData }: { postData: Course }) {
|
||||
}, []);
|
||||
|
||||
const toggleLike = async () => {
|
||||
if (!requireAuth()) return;
|
||||
if (loading) return;
|
||||
|
||||
if (liked === false) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import VerificationBadge from "@/components/main/VerificationBadge";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import RoundedInput from "@/components/elements/RoundedInput";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
export interface Comments {
|
||||
_id: string;
|
||||
@@ -46,7 +47,9 @@ function BillboardCommentsModal({
|
||||
});
|
||||
const [newMessage, setNewMessage] = useState("");
|
||||
const { request } = useAxios();
|
||||
const requireAuth = useRequireAuth();
|
||||
const sendMessageHandler = async () => {
|
||||
if (!requireAuth()) return;
|
||||
try {
|
||||
const data = {
|
||||
text: newMessage,
|
||||
|
||||
@@ -8,6 +8,7 @@ import Rate from "rc-rate";
|
||||
import "rc-rate/assets/index.css";
|
||||
import BoldIcon from "@/components/ui/BoldIcon";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
export interface Comments {
|
||||
_id: string;
|
||||
@@ -40,6 +41,7 @@ function CommentsModal({ isOpen, onClose, userId, postId }: CommentsModalProps)
|
||||
const [newMessage, setNewMessage] = useState("");
|
||||
const [rating, setRating] = useState<number>(0);
|
||||
const { request } = useAxios();
|
||||
const requireAuth = useRequireAuth();
|
||||
|
||||
const { data, containerRef, isFetchingNextPage, refetch } = useInfiniteScroll({
|
||||
endpoint: "/users/comments",
|
||||
@@ -66,6 +68,7 @@ function CommentsModal({ isOpen, onClose, userId, postId }: CommentsModalProps)
|
||||
: allComments;
|
||||
|
||||
const sendMessageHandler = async () => {
|
||||
if (!requireAuth()) return;
|
||||
if (!newMessage.trim()) {
|
||||
toast.error("ثبت نظر الزامی است.");
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { useUserById } from "@/hooks/getUserById";
|
||||
import { AxiosError } from "axios";
|
||||
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
|
||||
import SharePostModal from "@/components/main/SharePostModal";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
function MainModelCardActions({ postData }: { postData: Post }) {
|
||||
const {
|
||||
@@ -41,8 +42,10 @@ function MainModelCardActions({ postData }: { postData: Post }) {
|
||||
const [likesCountState, setLikesCount] = useState<number>(likesCount || 0);
|
||||
|
||||
const { request, loading } = useAxios();
|
||||
const requireAuth = useRequireAuth();
|
||||
|
||||
const toggleLike = async () => {
|
||||
if (!requireAuth()) return;
|
||||
if (!user_id || !postId) {
|
||||
toast.error("لطفاً وارد حساب کاربری خود شوید یا ثبتنام کنید");
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import Cookies from "js-cookie";
|
||||
import { useRouter } from "next/navigation";
|
||||
import toast from "react-hot-toast";
|
||||
import { debounce } from "lodash";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
|
||||
const LocationModal = dynamic(() => import("./LocationModal"), {
|
||||
@@ -52,7 +53,9 @@ function ModelContent({ user, searchParams }: ModelContentProps) {
|
||||
}, []);
|
||||
|
||||
const router = useRouter();
|
||||
const requireAuth = useRequireAuth();
|
||||
const sendMsgHandler = () => {
|
||||
if (!requireAuth()) return;
|
||||
if (user?.offer_status) {
|
||||
if (usertype) {
|
||||
router.push(`/settings/chats/${user?.user_name}/${user?._id}`);
|
||||
@@ -87,6 +90,11 @@ function ModelContent({ user, searchParams }: ModelContentProps) {
|
||||
fetchData();
|
||||
}, [searchParams]);
|
||||
|
||||
const openCollaboration = () => {
|
||||
if (!requireAuth()) return;
|
||||
setShowModelDetailModal((prev) => !prev);
|
||||
};
|
||||
|
||||
// Debounce برای جلوگیری از باز شدن سریع مودال
|
||||
const openLocationModal = debounce(() => {
|
||||
if (user?.show_location) {
|
||||
@@ -189,7 +197,7 @@ function ModelContent({ user, searchParams }: ModelContentProps) {
|
||||
) : user?.user_type == "user" ? (
|
||||
<div className={`grid gap-1 md:gap-4 mt-2 md:mt-4 ${!user?.show_location? "grid-cols-2" : "grid-cols-3"}`}>
|
||||
<RoundedButton
|
||||
onClick={() => setShowModelDetailModal(!showModelDetailModal)}
|
||||
onClick={openCollaboration}
|
||||
className="text-xs h-7 md:h-8 max-w-full max-sm:text-[8px]"
|
||||
>
|
||||
درخواست همکاری
|
||||
@@ -211,7 +219,7 @@ function ModelContent({ user, searchParams }: ModelContentProps) {
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-1 md:gap-2 mt-2 mx-auto justify-center max-w-xl">
|
||||
<RoundedButton
|
||||
onClick={() => setShowModelDetailModal(!showModelDetailModal)}
|
||||
onClick={openCollaboration}
|
||||
className="text-xs h-7 md:h-8 max-w-full max-sm:text-[8px]"
|
||||
>
|
||||
دعوت به همکاری
|
||||
|
||||
@@ -17,6 +17,7 @@ import SharePostModal from "@/components/main/SharePostModal";
|
||||
import BoldIcon from "@/components/ui/BoldIcon";
|
||||
import Cookies from "js-cookie";
|
||||
import { trackExploreInteraction } from "@/api/trackExploreInteraction";
|
||||
import { useRequireAuth } from "@/lib/auth/useRequireAuth";
|
||||
|
||||
interface ReelsPostActionsProps {
|
||||
postData: Post;
|
||||
@@ -50,8 +51,10 @@ export default function ReelsPostActions({ postData }: ReelsPostActionsProps) {
|
||||
const [likesCountState, setLikesCount] = useState<number>(likesCount || 0);
|
||||
|
||||
const { request, loading } = useAxios();
|
||||
const requireAuth = useRequireAuth();
|
||||
|
||||
const toggleLike = async () => {
|
||||
if (!requireAuth()) return;
|
||||
if (!user_id || !postId) {
|
||||
toast.error("لطفاً وارد حساب کاربری خود شوید یا ثبتنام کنید");
|
||||
return;
|
||||
|
||||
@@ -117,6 +117,11 @@ axiosInstance.interceptors.response.use(
|
||||
const handleUnauthorized = (): void => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// مهمان (بدون توکن) نباید به صفحه ورود هدایت شود؛ فقط آزادانه صفحات را میبیند
|
||||
// و درخواستهای محافظتشده بیسروصدا رد میشوند. عملیاتها خودشان کاربر را به ورود میبرند.
|
||||
const hasToken = Boolean(Cookies.get("token"));
|
||||
if (!hasToken) return;
|
||||
|
||||
const path = window.location.pathname;
|
||||
if (
|
||||
path.startsWith("/login") ||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { User } from "@/types/types";
|
||||
import useAxios from "./useAxios";
|
||||
import { getStoredUserId } from "@/lib/auth/session";
|
||||
import { getStoredUserId, isAuthenticated } from "@/lib/auth/session";
|
||||
|
||||
function readStoredUser(): User | undefined {
|
||||
const id = getStoredUserId();
|
||||
@@ -23,6 +23,8 @@ export const useUser = () => {
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
// مهمان پروفایل شخصی ندارد؛ از فچ بیمورد /profile جلوگیری میشود
|
||||
if (!isAuthenticated()) return;
|
||||
fetchUser();
|
||||
}, []);
|
||||
|
||||
|
||||
34
src/lib/auth/useRequireAuth.ts
Normal file
34
src/lib/auth/useRequireAuth.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import toast from "react-hot-toast";
|
||||
import { isAuthenticated } from "@/lib/auth/session";
|
||||
|
||||
/**
|
||||
* گارد احراز هویت برای عملیاتها (لایک، کامنت، فالو، ارسال پیام، درخواست همکاری و ...).
|
||||
*
|
||||
* کاربر مهمان میتواند آزادانه صفحات را ببیند؛ فقط زمانی که بخواهد عملیاتی انجام دهد،
|
||||
* پیام کوتاهی نمایش داده و به صفحه ورود با آدرس بازگشت (redirect) هدایت میشود.
|
||||
*
|
||||
* خروجی `true` یعنی کاربر وارد شده و میتوان عملیات را ادامه داد.
|
||||
*/
|
||||
export function useRequireAuth() {
|
||||
const router = useRouter();
|
||||
|
||||
return useCallback(
|
||||
(message: string | null = "برای انجام این کار وارد حساب کاربری خود شوید"): boolean => {
|
||||
if (isAuthenticated()) return true;
|
||||
|
||||
if (message) toast.error(message);
|
||||
|
||||
const current =
|
||||
typeof window !== "undefined"
|
||||
? window.location.pathname + window.location.search
|
||||
: "/";
|
||||
router.push(`/login?redirect=${encodeURIComponent(current)}`);
|
||||
return false;
|
||||
},
|
||||
[router]
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,14 @@ export function middleware(req: NextRequest) {
|
||||
|
||||
const token = req.cookies.get("token")?.value?.trim();
|
||||
|
||||
if (req.nextUrl.pathname.startsWith("/settings") && !token) {
|
||||
// صفحاتی که ذاتاً نیازمند ورود هستند (حساب کاربری و ساخت محتوا)
|
||||
// بقیه صفحات برای مهمان آزاد است و فقط هنگام انجام عملیات به ورود هدایت میشود.
|
||||
const protectedPaths = ["/settings", "/new-post", "/new-project"];
|
||||
const needsAuth = protectedPaths.some((p) =>
|
||||
req.nextUrl.pathname.startsWith(p)
|
||||
);
|
||||
|
||||
if (needsAuth && !token) {
|
||||
const loginUrl = new URL("/login", req.url);
|
||||
loginUrl.searchParams.set("redirect", req.nextUrl.pathname);
|
||||
return NextResponse.redirect(loginUrl);
|
||||
@@ -22,6 +29,6 @@ export function middleware(req: NextRequest) {
|
||||
}
|
||||
//
|
||||
export const config = {
|
||||
matcher: ["/settings/:path*"],
|
||||
matcher: ["/settings/:path*", "/new-post/:path*", "/new-project/:path*"],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user