Add Pinterest product tag: discover filter, Reels badge, and images-step checkbox
- Pinterest filter toggle on the Shop discover page, alongside "All", backed by the backend's new ?pinterest=true param on /shop-products/discover - Pinterest badge shown above the favorite button in ShopReelsView's action rail for products tagged is_pinterest - "Pinterest product" checkbox at the bottom of the product images step (create wizard and edit flow share the same route) - New pinterest bold-icon SVG under public/images/icons/vuesax/bold Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
3
public/images/icons/vuesax/bold/pinterest.svg
Normal file
3
public/images/icons/vuesax/bold/pinterest.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12C2 16.25 4.67 19.9 8.44 21.34C8.35 20.56 8.28 19.36 8.47 18.5C8.65 17.72 9.63 13.6 9.63 13.6C9.63 13.6 9.33 13 9.33 12.09C9.33 10.66 10.16 9.6 11.2 9.6C12.08 9.6 12.5 10.26 12.5 11.05C12.5 11.93 11.93 13.26 11.63 14.5C11.39 15.53 12.15 16.38 13.16 16.38C14.99 16.38 16.4 14.45 16.4 11.66C16.4 9.19 14.62 7.46 12.08 7.46C9.14 7.46 7.42 9.66 7.42 11.94C7.42 12.82 7.76 13.77 8.19 14.29C8.27 14.39 8.28 14.48 8.26 14.58C8.19 14.86 8.04 15.46 8.01 15.59C7.97 15.77 7.87 15.81 7.68 15.72C6.44 15.14 5.67 13.34 5.67 11.9C5.67 8.75 7.95 5.86 12.24 5.86C15.68 5.86 18.36 8.31 18.36 11.62C18.36 15.07 16.19 17.85 13.16 17.85C12.13 17.85 11.16 17.31 10.83 16.68C10.83 16.68 10.32 18.65 10.2 19.1C9.97 19.97 9.35 21.07 8.94 21.74C9.9 22.04 10.93 22.2 12 22.2C17.52 22.2 22 17.72 22 12.2C22 6.68 17.52 2 12 2Z" fill="#292D32"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 952 B |
@@ -36,16 +36,21 @@ function ProductImagesPage() {
|
||||
|
||||
const [images, setImages] = useState<PickedImage[]>([]);
|
||||
const [primaryIndex, setPrimaryIndex] = useState(0);
|
||||
const [isPinterest, setIsPinterest] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!listingId) return;
|
||||
request<{ listing: { images: string[]; primaryImageIndex: number } }>(
|
||||
"GET",
|
||||
`/shop-products/${listingId}`
|
||||
).then((res) => {
|
||||
request<{
|
||||
listing: {
|
||||
images: string[];
|
||||
primaryImageIndex: number;
|
||||
is_pinterest?: boolean;
|
||||
};
|
||||
}>("GET", `/shop-products/${listingId}`).then((res) => {
|
||||
if (!res?.listing) return;
|
||||
setImages((res.listing.images || []).map((path) => ({ type: "existing", path })));
|
||||
setPrimaryIndex(res.listing.primaryImageIndex || 0);
|
||||
setIsPinterest(Boolean(res.listing.is_pinterest));
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [listingId]);
|
||||
@@ -83,6 +88,7 @@ function ProductImagesPage() {
|
||||
newFiles.forEach((img) => formData.append("images", img.file, img.file.name));
|
||||
formData.append("existing_images", JSON.stringify(existingImages));
|
||||
formData.append("primaryImageIndex", String(primaryIndex));
|
||||
formData.append("is_pinterest", String(isPinterest));
|
||||
|
||||
try {
|
||||
await request("PATCH", `/shop-products/${listingId}`, formData);
|
||||
@@ -172,6 +178,34 @@ function ProductImagesPage() {
|
||||
onChange={handleSelect}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsPinterest((v) => !v)}
|
||||
className="mt-4 flex w-full max-w-sm items-center gap-2.5 rounded-2xl border border-neutral-200 bg-neutral-50 px-3.5 py-3 text-right dark:border-neutral-700 dark:bg-neutral-900"
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"flex h-5 w-5 shrink-0 items-center justify-center rounded-md border-2",
|
||||
isPinterest
|
||||
? "border-[#E60023] bg-[#E60023]"
|
||||
: "border-neutral-300 dark:border-neutral-600"
|
||||
)}
|
||||
>
|
||||
{isPinterest ? (
|
||||
<BoldIcon name="tick-square" size={12} tinted className="text-white" />
|
||||
) : null}
|
||||
</span>
|
||||
<BoldIcon name="pinterest" size={18} tinted className="text-[#E60023]" />
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block text-sm font-medium">
|
||||
{t("shops.pinterestProductLabel")}
|
||||
</span>
|
||||
<span className="block text-[11px] text-neutral-500">
|
||||
{t("shops.pinterestProductHint")}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</AuthPageContent>
|
||||
<AuthFormFooter onSkip={goNext} skipDisabled={loading}>
|
||||
<AuthNextButton
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Container from "@/components/elements/Container";
|
||||
import LocalePageShell from "@/components/i18n/LocalePageShell";
|
||||
import PageTitle from "@/components/settings/PageTitle";
|
||||
import Header from "@/components/main/Header";
|
||||
import TabNavigation from "@/components/TabNavigation";
|
||||
import ShopProductGrid from "@/components/shops/ShopProductGrid";
|
||||
import BoldIcon from "@/components/ui/BoldIcon";
|
||||
import { cn } from "@/lib/utils";
|
||||
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
|
||||
import { IShopProductListing } from "@/types/types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function ShopDiscoverPage() {
|
||||
const { t } = useTranslation("common");
|
||||
const [pinterestOnly, setPinterestOnly] = useState(false);
|
||||
|
||||
const { data, isLoading } = useInfiniteScroll({
|
||||
endpoint: "/shop-products/discover",
|
||||
queryKey: ["shop-products-discover"],
|
||||
queryKey: ["shop-products-discover", String(pinterestOnly)],
|
||||
params: pinterestOnly ? { pinterest: "true" } : {},
|
||||
});
|
||||
|
||||
const listings: IShopProductListing[] =
|
||||
@@ -27,6 +32,35 @@ export default function ShopDiscoverPage() {
|
||||
<LocalePageShell>
|
||||
<Container className="pb-28">
|
||||
<PageTitle>{t("shops.discoverTitle")}</PageTitle>
|
||||
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPinterestOnly(false)}
|
||||
className={cn(
|
||||
"rounded-2xl border px-3.5 py-2 text-sm font-medium transition",
|
||||
!pinterestOnly
|
||||
? "border-pink-400 bg-pink-50 text-pink-600 dark:bg-pink-950/30"
|
||||
: "border-neutral-200 text-neutral-700 dark:border-neutral-700 dark:text-neutral-300"
|
||||
)}
|
||||
>
|
||||
{t("common.all")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPinterestOnly(true)}
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 rounded-2xl border px-3.5 py-2 text-sm font-medium transition",
|
||||
pinterestOnly
|
||||
? "border-[#E60023] bg-[#E60023]/10 text-[#E60023]"
|
||||
: "border-neutral-200 text-neutral-700 dark:border-neutral-700 dark:text-neutral-300"
|
||||
)}
|
||||
>
|
||||
<BoldIcon name="pinterest" size={14} tinted />
|
||||
{t("shops.pinterestFilter")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ShopProductGrid
|
||||
listings={listings}
|
||||
isLoading={isLoading}
|
||||
|
||||
@@ -301,6 +301,19 @@ export default function ShopReelsView({
|
||||
className="text-white brightness-125 drop-shadow-lg"
|
||||
/>
|
||||
</button>
|
||||
{listing.is_pinterest && (
|
||||
<span
|
||||
aria-hidden
|
||||
className="flex flex-col items-center gap-1"
|
||||
>
|
||||
<BoldIcon
|
||||
name="pinterest"
|
||||
size={26}
|
||||
tinted
|
||||
className="text-[#E60023] drop-shadow-lg"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleToggleFavorite(listing._id)}
|
||||
|
||||
@@ -3000,6 +3000,9 @@
|
||||
"comparisonTitle": "Compare shop prices",
|
||||
"noListingsForProduct": "No shops found for this product",
|
||||
"discoverTitle": "Shops",
|
||||
"pinterestFilter": "Pinterest",
|
||||
"pinterestProductLabel": "Pinterest product",
|
||||
"pinterestProductHint": "This product will show up under the shop's Pinterest filter",
|
||||
"quantityLabel": "Quantity",
|
||||
"buyNow": "Continue purchase",
|
||||
"addressRequiredHint": "You need to set your address and location to place an order",
|
||||
|
||||
@@ -2999,6 +2999,9 @@
|
||||
"comparisonTitle": "مقایسه قیمت فروشگاهها",
|
||||
"noListingsForProduct": "فروشگاهی برای این کالا یافت نشد",
|
||||
"discoverTitle": "فروشگاهها",
|
||||
"pinterestFilter": "پینترستی",
|
||||
"pinterestProductLabel": "محصول پینترستی",
|
||||
"pinterestProductHint": "این کالا در فیلتر پینترستی فروشگاه نمایش داده میشود",
|
||||
"quantityLabel": "تعداد",
|
||||
"buyNow": "ادامه خرید",
|
||||
"addressRequiredHint": "برای ثبت سفارش نیاز به ثبت آدرس و لوکیشن میباشید",
|
||||
|
||||
@@ -139,6 +139,7 @@ export interface IShopProductListing {
|
||||
isTaggedPost?: boolean;
|
||||
postId?: string;
|
||||
postCaption?: string | null;
|
||||
is_pinterest?: boolean;
|
||||
}
|
||||
export interface LastPost {
|
||||
_id: string;
|
||||
|
||||
Reference in New Issue
Block a user