feat(storefront): add payment/carrier assets, CustomerConfidenceBooster, and footer enhancements
- Add payment method SVGs (Visa, Mastercard, Apple Pay, Google Pay, Klarna, Link, Revolut Pay, Billie, Cartes, Discover) - Add carrier images (DPD, Evri) - Add CustomerConfidenceBooster section component - Enhance Footer with payment methods and carrier display - Wire CustomerConfidenceBooster into shop pages (PetCategory, RecentlyAdded, ShopIndex, SubCategory, Tag, TopCategory) and home page - Update tsconfig.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import { RecentlyAddedSection } from "../components/sections/hompepage/products-
|
||||
import { SpecialOffersSection } from "../components/sections/hompepage/products-sections/special-offers/SpecialOffersSection";
|
||||
import { TopPicksSection } from "../components/sections/hompepage/products-sections/top-picks/TopPicsSection";
|
||||
import { WishlistSection } from "../components/sections/hompepage/wishlist/WishlistSection";
|
||||
import { CustomerConfidenceBooster } from "../components/sections/CustomerConfidenceBooster";
|
||||
import { Toast } from "@heroui/react";
|
||||
|
||||
export default function HomePage() {
|
||||
@@ -20,6 +21,7 @@ export default function HomePage() {
|
||||
<RecentlyAddedSection />
|
||||
<SpecialOffersSection />
|
||||
<TopPicksSection />
|
||||
<CustomerConfidenceBooster />
|
||||
<NewsletterSection />
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
import Image from "next/image";
|
||||
import { BrandLogo } from "@/components/layout/BrandLogo";
|
||||
|
||||
const carriers = [
|
||||
{ name: "DPD", src: "/images/carriers/dpd.png", width: 30, height: 15 },
|
||||
{ name: "Evri", src: "/images/carriers/evri.png", width: 30, height: 15 },
|
||||
];
|
||||
|
||||
const paymentMethods = [
|
||||
{ name: "Visa", src: "/images/payment-methods/visa_card.svg" },
|
||||
{ name: "Mastercard", src: "/images/payment-methods/master_card.svg" },
|
||||
{ name: "Discover", src: "/images/payment-methods/discovery_card.svg" },
|
||||
{ name: "Apple Pay", src: "/images/payment-methods/apple_pay.svg" },
|
||||
{ name: "Google Pay", src: "/images/payment-methods/google_pay.svg" },
|
||||
{ name: "Link", src: "/images/payment-methods/link.svg" },
|
||||
{ name: "Revolut Pay", src: "/images/payment-methods/revoult_pay.svg" },
|
||||
{ name: "Billie", src: "/images/payment-methods/billie.svg" },
|
||||
{ name: "Cartes", src: "/images/payment-methods/cartes.svg" },
|
||||
{ name: "Klarna", src: "/images/payment-methods/klarna.svg" },
|
||||
];
|
||||
|
||||
const linkClasses =
|
||||
"text-sm text-[#3d5554] transition-colors hover:text-[#38a99f]";
|
||||
|
||||
@@ -217,6 +236,61 @@ export function Footer() {
|
||||
{/* Column 4 — Utility */}
|
||||
<FooterColumn groups={utilityGroups} />
|
||||
</div>
|
||||
|
||||
{/* Carrier partners + Payment methods */}
|
||||
<section
|
||||
className="border-t border-[#e8f7f6] px-4 py-6 lg:px-6"
|
||||
aria-label="Delivery and payment options"
|
||||
>
|
||||
<div className="mx-auto flex min-w-0 max-w-[1400px] flex-col gap-6 md:flex-row md:items-center md:justify-between">
|
||||
{/* Delivery partners — left */}
|
||||
<div className="flex flex-col items-center gap-3 sm:flex-row sm:justify-center sm:gap-6 md:justify-start">
|
||||
<p className="text-xs font-medium text-[#3d5554]">
|
||||
DELIVERY PARTNERS
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center justify-center gap-6 md:justify-start">
|
||||
{carriers.map((carrier) => (
|
||||
<span
|
||||
key={carrier.name}
|
||||
className="flex items-center justify-center rounded px-3 py-2"
|
||||
title={carrier.name}
|
||||
>
|
||||
<Image
|
||||
src={carrier.src}
|
||||
alt={carrier.name}
|
||||
width={carrier.width}
|
||||
height={carrier.height}
|
||||
className="h-5 w-auto object-contain md:h-6"
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* Payment methods — right */}
|
||||
<div className="flex flex-col items-center gap-3 sm:flex-row sm:justify-center sm:gap-4 md:justify-end">
|
||||
<p className="text-xs font-medium text-[#3d5554]">
|
||||
PAYMENT METHODS
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center justify-center gap-3 md:justify-end">
|
||||
{paymentMethods.map((method) => (
|
||||
<span
|
||||
key={method.name}
|
||||
className="flex items-center justify-center px-2 "
|
||||
title={method.name}
|
||||
>
|
||||
<Image
|
||||
src={method.src}
|
||||
alt={method.name}
|
||||
width={30}
|
||||
height={15}
|
||||
className="h-6 w-auto max-w-10 object-contain md:h-7"
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{/* Copyright bar */}
|
||||
@@ -239,10 +313,10 @@ export function Footer() {
|
||||
Privacy Policy
|
||||
</a>
|
||||
<a
|
||||
href="/sitemap"
|
||||
href="/data-protection"
|
||||
className="text-xs text-white/80 transition-colors hover:text-white"
|
||||
>
|
||||
Site Map
|
||||
Data Protection
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* Customer confidence booster: trust badges (Free Shipping, Easy Returns, Secure Checkout).
|
||||
* Rendered below product grids on shop pages and homepage. PetPaws theme, mobile-first.
|
||||
*/
|
||||
export function CustomerConfidenceBooster() {
|
||||
const items: { title: string; subheading: string; icon: React.ReactNode }[] = [
|
||||
{
|
||||
title: "Free Shipping",
|
||||
subheading: "No extra costs (T&C apply)",
|
||||
icon: (
|
||||
<svg
|
||||
className="size-8 shrink-0"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden
|
||||
>
|
||||
<path d="M5 18H3c-.6 0-1-.4-1-1V7c0-.6.4-1 1-1h10c.6 0 1 .4 1 1v2" />
|
||||
<path d="M19 10h2l-1.5 4.5L18 10h2" />
|
||||
<path d="M14 10h4" />
|
||||
<path d="M2 14h15.5" />
|
||||
<circle cx="7" cy="18" r="2" />
|
||||
<path d="M9 18h6" />
|
||||
<circle cx="17" cy="18" r="2" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Easy Returns",
|
||||
subheading: "Return with ease",
|
||||
icon: (
|
||||
<svg
|
||||
className="size-8 shrink-0"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden
|
||||
>
|
||||
<path d="M16 3h5v5" />
|
||||
<path d="M8 3H3v5" />
|
||||
<path d="M12 22v-8.3a4 4 0 0 0-1.2-2.9L3 7" />
|
||||
<path d="m3 7 7.8 7.8a4 4 0 0 1 1.2 2.9V22" />
|
||||
<path d="M21 7l-7.8 7.8a4 4 0 0 1-1.2 2.9V12" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Secure Checkout",
|
||||
subheading: "Secure payment",
|
||||
icon: (
|
||||
<svg
|
||||
className="size-8 shrink-0"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden
|
||||
>
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section
|
||||
aria-label="Why shop with us"
|
||||
className="w-full border border-[#d9e8e7] bg-gradient-to-r from-[#e8f7f6] to-[#f0f8f7] px-4 py-6 md:px-6 md:py-8 m-16 max-w-7xl mx-auto rounded-xl"
|
||||
>
|
||||
<div className="mx-auto grid w-full max-w-4xl grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 md:gap-8">
|
||||
{items.map(({ title, subheading, icon }) => (
|
||||
<div
|
||||
key={title}
|
||||
className="flex flex-col items-center gap-3 text-center"
|
||||
>
|
||||
<div
|
||||
className="flex size-12 items-center justify-center rounded-full bg-white text-[#236f6b] shadow-sm ring-1 ring-[#d9e8e7]"
|
||||
aria-hidden
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span
|
||||
className="block font-[family-name:var(--font-fraunces)] text-base font-semibold text-[#1a2e2d] md:text-lg"
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
<span className="block text-sm text-[#3d5554]">
|
||||
{subheading}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
|
||||
const SORT_OPTIONS: SortOption[] = [
|
||||
{ value: "newest", label: "Newest" },
|
||||
@@ -192,6 +193,9 @@ export function PetCategoryPage({ slug }: { slug: PetCategorySlug }) {
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
import {
|
||||
filterStateFromSearchParams,
|
||||
mergeFilterStateIntoSearchParams,
|
||||
@@ -162,6 +163,9 @@ export function RecentlyAddedPage() {
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
import {
|
||||
filterStateFromSearchParams,
|
||||
filterStateToSearchParams,
|
||||
@@ -162,6 +163,9 @@ export function ShopIndexContent() {
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
import {
|
||||
filterStateFromSearchParams,
|
||||
filterStateToSearchParams,
|
||||
@@ -209,6 +210,9 @@ export function SubCategoryPageContent({
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
import {
|
||||
filterStateFromSearchParams,
|
||||
mergeFilterStateIntoSearchParams,
|
||||
@@ -168,6 +169,9 @@ export function TagShopPage({
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar";
|
||||
import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState";
|
||||
import { ShopErrorState } from "@/components/shop/state/ShopErrorState";
|
||||
import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton";
|
||||
import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster";
|
||||
import {
|
||||
PET_CATEGORY_SLUGS,
|
||||
TOP_CATEGORY_SLUGS,
|
||||
@@ -247,6 +248,9 @@ export function TopCategoryPage({ slug }: { slug: TopCategorySlug }) {
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
<CustomerConfidenceBooster />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user