- Product-page chat buttons pass the product id when starting a thread, so it's shared into the conversation as a card the seller can see (and tap through). - MessageBubble renders the product card (image, title, price → product page); card-only messages no longer render an empty bubble. - Inbox preview shows 🛍 <product> instead of "بدون پیام" for product-card threads. ChatProductCard type + product on message/last-message types. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import { Button } from "~/components/ui/button";
|
|
import { ArrowRight } from "lucide-react";
|
|
import { Link, useNavigate } from "@remix-run/react";
|
|
import { ProductDetail } from "src/api/types";
|
|
import { useCreateChatThread } from "~/requestHandler/use-chat-hooks";
|
|
import { useState } from "react";
|
|
import { useRootData } from "~/hooks/use-root-data";
|
|
import { LoginRequiredDialog } from "~/components/LoginRequiredDialog";
|
|
import SellerLogo from "~/components/SellerLogo";
|
|
import { safeGoBack } from "~/utils/helpers";
|
|
interface ProductHeaderProps {
|
|
product: ProductDetail;
|
|
}
|
|
|
|
export const ProductHeader = ({ product }: ProductHeaderProps) => {
|
|
const navigate = useNavigate();
|
|
const { user } = useRootData();
|
|
const [isLoginDialogOpen, setIsLoginDialogOpen] = useState(false);
|
|
const { mutate: createChatThread, isPending: isCreatingChatThread } =
|
|
useCreateChatThread();
|
|
const handleCreateChatThread = () => {
|
|
if (!user) {
|
|
setIsLoginDialogOpen(true);
|
|
return;
|
|
}
|
|
if (!product.seller?.id) return;
|
|
createChatThread(
|
|
{ participantId: product.seller.id, productId: product.id },
|
|
{
|
|
onSuccess: (threadData) => {
|
|
navigate(`/profile/threads/${threadData.id}`);
|
|
},
|
|
}
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className="flex flex-row sticky z-30 bg-WHITE w-full items-center justify-center border-b border-inner-border"
|
|
style={
|
|
{
|
|
top: 0,
|
|
height: "calc(65px + env(safe-area-inset-top, 0px))",
|
|
paddingTop: "env(safe-area-inset-top, 0px)",
|
|
position: "sticky",
|
|
} as React.CSSProperties
|
|
}
|
|
>
|
|
<ArrowRight
|
|
onClick={() => safeGoBack(navigate)}
|
|
className="absolute right-5"
|
|
style={{ top: "calc(env(safe-area-inset-top, 0px) + 20px)" }}
|
|
/>
|
|
<Link to={`/seller/${product.seller?.username}`} className="flex gap-2">
|
|
<SellerLogo src={product.seller?.storeLogo} alt={"seller-image"} />
|
|
<div className="flex flex-col items-center justify-center">
|
|
<p className="text-B12 max-w-[100px] text-ellipsis font-bold text-overflow-ellipsis overflow-hidden whitespace-nowrap">
|
|
{product.seller?.username}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
<div
|
|
className="absolute left-5"
|
|
style={{ top: "calc(env(safe-area-inset-top, 0px) + 40px - 20px)" }}
|
|
>
|
|
<Button
|
|
variant="primary"
|
|
onClick={handleCreateChatThread}
|
|
disabled={!product.seller?.id || isCreatingChatThread}
|
|
size="lg"
|
|
className="w-full h-[28px] rounded-[8px]"
|
|
>
|
|
{isCreatingChatThread ? "در حال اتصال..." : "ارسال پیام"}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<LoginRequiredDialog
|
|
loginTitle="برای ارسال پیام به فروشنده ابتدا باید وارد حساب کاربری خود شوید."
|
|
isOpen={isLoginDialogOpen}
|
|
onOpenChange={setIsLoginDialogOpen}
|
|
/>
|
|
</>
|
|
);
|
|
};
|