setShowSendModal(false)}
+ listing={listing}
+ />
>
);
}
diff --git a/src/app/shops/profile/[shopId]/ShopProfileClient.tsx b/src/app/shops/profile/[shopId]/ShopProfileClient.tsx
index 3b680a1..640f7a0 100644
--- a/src/app/shops/profile/[shopId]/ShopProfileClient.tsx
+++ b/src/app/shops/profile/[shopId]/ShopProfileClient.tsx
@@ -9,9 +9,12 @@ import { IMAGE_BASE_URL } from "@/components/main/BaseUrl";
import ProfileAvatar from "@/components/main/ProfileAvatar";
import ExpandableBio from "@/components/profile/ExpandableBio";
import ShareShopModal from "@/components/shops/ShareShopModal";
+import SendShopModal from "@/components/shops/SendShopModal";
import ShopContactInfoModal from "@/components/shops/ShopContactInfoModal";
import ShopMyOrdersModal from "@/components/shops/ShopMyOrdersModal";
-import VerificationBadge from "@/components/main/VerificationBadge";
+import VerificationBadge, {
+ resolveShopVerificationTier,
+} from "@/components/main/VerificationBadge";
import useAxios from "@/hooks/useAxios";
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
import { useUser } from "@/hooks/useUser";
@@ -96,6 +99,7 @@ export default function ShopProfileClient() {
const [showOrdersModal, setShowOrdersModal] = useState(false);
const [showLocationModal, setShowLocationModal] = useState(false);
const [showShareModal, setShowShareModal] = useState(false);
+ const [showSendModal, setShowSendModal] = useState(false);
useEffect(() => {
request<{ shop: PublicShop }>("GET", `/shops/public/${shopId}`)
@@ -244,7 +248,10 @@ export default function ShopProfileClient() {
)}
>
{shop.name}
-
+
{hasDescription ? (
)}
+
)}
+ {sharedShop && (
+
+
+
+
+ )}
+
{sharedGift && (
+
+ {logo && }
+
+
+ {data.name || t("shops.viewShop")}
+
+
+ );
+}
diff --git a/src/components/main/VerificationBadge.tsx b/src/components/main/VerificationBadge.tsx
index 4337ae0..6267d8b 100644
--- a/src/components/main/VerificationBadge.tsx
+++ b/src/components/main/VerificationBadge.tsx
@@ -34,6 +34,14 @@ export function resolveVerificationStatus(
return verifyBadge as VerifyBadgeTier;
}
+/** طبق خواستهی صریح کاربر: تیکِ وریفایِ فروشگاه (برخلافِ کاربر که چهار سطح رنگی داره)
+ * همیشه سبز باشه، مستقل از سطح واقعیِ verify_badge — فقط برای رندرِ فروشگاه استفاده بشه */
+export function resolveShopVerificationTier(
+ verifyBadge?: string | null
+): "green" | null {
+ return resolveVerificationStatus(verifyBadge) ? "green" : null;
+}
+
const VERIFICATION_ICON_SRC: Record
, string> = {
gray: "/images/icons/verify-gray.svg",
blue: "/images/icons/verify-blue.svg",
diff --git a/src/components/shops/SendShopModal.tsx b/src/components/shops/SendShopModal.tsx
new file mode 100644
index 0000000..4af8a21
--- /dev/null
+++ b/src/components/shops/SendShopModal.tsx
@@ -0,0 +1,205 @@
+"use client";
+
+import { btnPrimary } from "@/lib/ui/buttonStyles";
+import { cn } from "@/lib/utils";
+
+import { useEffect, useState } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import Image from "next/image";
+import { IMAGE_BASE_URL } from "@/components/main/BaseUrl";
+import useAxios from "@/hooks/useAxios";
+import toast from "react-hot-toast";
+import IOSSpinner from "@/components/ui/IOSSpinner";
+import { useTranslation } from "react-i18next";
+import type { ChatUserItem } from "./SendProductModal";
+
+interface SendShopModalProps {
+ open: boolean;
+ onClose: () => void;
+ shopId: string;
+ shopName: string;
+ logo?: string | null;
+}
+
+// عینِ SendProductModal.tsx، فقط برای خودِ فروشگاه (نه یه کالای خاص) — بکاند
+// shopController.js: sendShopToUsers
+export default function SendShopModal({
+ open,
+ onClose,
+ shopId,
+ shopName,
+ logo,
+}: SendShopModalProps) {
+ const { t } = useTranslation("common");
+ const { request } = useAxios();
+ const [users, setUsers] = useState([]);
+ const [selected, setSelected] = useState>(new Set());
+ const [loading, setLoading] = useState(false);
+ const [sending, setSending] = useState(false);
+
+ const loadUsers = async () => {
+ setLoading(true);
+ try {
+ const res = await request<{ filteredUsersData: ChatUserItem[] }>(
+ "GET",
+ "/messages?limit=100",
+ null,
+ { noToast: true }
+ );
+ setUsers((res?.filteredUsersData || []).filter((u) => Boolean(u.user_name)));
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ if (open) {
+ loadUsers();
+ setSelected(new Set());
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [open]);
+
+ const toggle = (id: string) => {
+ setSelected((prev) => {
+ const next = new Set(prev);
+ if (next.has(id)) next.delete(id);
+ else if (next.size < 50) next.add(id);
+ else toast.error(t("posts.maxUsers"));
+ return next;
+ });
+ };
+
+ const send = async () => {
+ if (selected.size === 0) return;
+ setSending(true);
+ try {
+ const res = await request<{ sentCount?: number }>(
+ "POST",
+ `/shops/${shopId}/send`,
+ { receiverIds: Array.from(selected) },
+ { noToast: true }
+ );
+ toast.success(
+ t("shops.sentShopToCount", { count: res?.sentCount ?? selected.size })
+ );
+ onClose();
+ setSelected(new Set());
+ } catch {
+ toast.error(t("shops.sendShopError"));
+ } finally {
+ setSending(false);
+ }
+ };
+
+ return (
+
+ {open && (
+
+ e.stopPropagation()}
+ >
+
+ {t("shops.sendShopTitle")}
+
+
+
+ {logo && (
+
+
+
+ )}
+
+ {shopName}
+
+
+
+ {loading ? (
+
+
+
+ ) : users.length === 0 ? (
+
+ {t("posts.noChatUsers")}
+
+ ) : (
+
+ {users.map((u) => {
+ const name =
+ [u.first_name, u.last_name].filter(Boolean).join(" ") ||
+ u.user_name;
+ const checked = selected.has(u._id);
+ return (
+ -
+
+
+ );
+ })}
+
+ )}
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/components/shops/ShopProductAuthor.tsx b/src/components/shops/ShopProductAuthor.tsx
index 5db7607..67695d2 100644
--- a/src/components/shops/ShopProductAuthor.tsx
+++ b/src/components/shops/ShopProductAuthor.tsx
@@ -1,7 +1,9 @@
"use client";
import { IMAGE_BASE_URL } from "@/components/main/BaseUrl";
-import VerificationBadge from "@/components/main/VerificationBadge";
+import VerificationBadge, {
+ resolveShopVerificationTier,
+} from "@/components/main/VerificationBadge";
type ShopProductAuthorProps = {
shopName: string;
@@ -28,7 +30,10 @@ export default function ShopProductAuthor({
)}
{shopName}
-
+
);
diff --git a/src/locales/en/common.json b/src/locales/en/common.json
index 92dddd0..76179a2 100644
--- a/src/locales/en/common.json
+++ b/src/locales/en/common.json
@@ -2851,6 +2851,7 @@
"editShopButton": "Edit shop",
"viewPublicProfile": "View shop page",
"viewProduct": "View product",
+ "viewShop": "View shop",
"myOrdersFromShop": "My orders from this shop",
"noOrdersFromShop": "You haven't ordered from this shop yet",
"satisfactionLabel": "Product satisfaction",
@@ -2869,6 +2870,9 @@
"sendProductTitle": "Send product",
"sentProductToCount": "Product sent to {{count}} people",
"sendProductError": "Failed to send product",
+ "sendShopTitle": "Send shop",
+ "sentShopToCount": "Shop sent to {{count}} people",
+ "sendShopError": "Failed to send shop",
"noChatMessagesYet": "No messages yet",
"performance": {
"totalRevenue": "Total revenue (Toman)",
diff --git a/src/locales/fa/common.json b/src/locales/fa/common.json
index e3c8f10..8cb749c 100644
--- a/src/locales/fa/common.json
+++ b/src/locales/fa/common.json
@@ -2856,6 +2856,7 @@
"editShopButton": "ویرایش فروشگاه",
"viewPublicProfile": "نمایش صفحه فروشگاه",
"viewProduct": "مشاهده کالا",
+ "viewShop": "مشاهده فروشگاه",
"myOrdersFromShop": "پیگیری سفارشات من",
"noOrdersFromShop": "هنوز سفارشی از این فروشگاه ثبت نکردهاید",
"satisfactionLabel": "رضایت از کالاها",
@@ -2874,6 +2875,9 @@
"sendProductTitle": "ارسال کالا",
"sentProductToCount": "کالا به {{count}} نفر ارسال شد",
"sendProductError": "خطا در ارسال کالا",
+ "sendShopTitle": "ارسال فروشگاه",
+ "sentShopToCount": "فروشگاه به {{count}} نفر ارسال شد",
+ "sendShopError": "خطا در ارسال فروشگاه",
"noChatMessagesYet": "هنوز پیامی رد و بدل نشده است",
"performance": {
"totalRevenue": "درآمد کل (تومان)",