feat: adding more information warranty, part number, sku, speciall offers

Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
Chloe
2024-04-25 14:14:20 +07:00
parent e3f564ca77
commit 59c3f07beb
14 changed files with 215 additions and 85 deletions

View File

@@ -39,29 +39,33 @@ export function Gallery({ images }: { images: { src: string; altText: string }[]
priority={true}
/>
)}
{images.length > 1 ? (
<div className="absolute bottom-[15%] flex w-full justify-center">
<div className="mx-auto flex h-11 items-center rounded-full border border-white bg-neutral-50/80 text-neutral-500 backdrop-blur dark:border-black dark:bg-neutral-900/80">
<Link
aria-label="Previous product image"
href={previousUrl}
className={buttonClassName}
scroll={false}
>
<ArrowLeftIcon className="h-5" />
</Link>
<div className="mx-1 h-6 w-px bg-neutral-500"></div>
<Link
aria-label="Next product image"
href={nextUrl}
className={buttonClassName}
scroll={false}
>
<ArrowRightIcon className="h-5" />
</Link>
<>
<div className="absolute bottom-[15%] flex w-full justify-center">
<div className="mx-auto mb-3 flex h-11 items-center rounded-full border border-white bg-neutral-50/80 text-neutral-500 backdrop-blur dark:border-black dark:bg-neutral-900/80">
<Link
aria-label="Previous product image"
href={previousUrl}
className={buttonClassName}
scroll={false}
>
<ArrowLeftIcon className="h-5" />
</Link>
<div className="mx-1 h-6 w-px bg-neutral-500"></div>
<Link
aria-label="Next product image"
href={nextUrl}
className={buttonClassName}
scroll={false}
>
<ArrowRightIcon className="h-5" />
</Link>
</div>
</div>
</div>
<p className="absolute bottom-[5%] flex w-full justify-center text-sm text-neutral-500">
Representative Image
</p>
</>
) : null}
</div>

View File

@@ -1,10 +1,7 @@
'use client';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import { Checkbox } from 'components/checkbox';
import CoreCharge from 'components/core-charge';
import Price from 'components/price';
import Tooltip from 'components/tooltip';
import { Money, ProductVariant } from 'lib/shopify/types';
import { useSearchParams } from 'next/navigation';
@@ -20,32 +17,28 @@ const PriceWithCoreCharge = ({ variants, defaultPrice }: PriceWithCoreChargeProp
(option) => option.value === searchParams.get(option.name.toLowerCase())
)
);
console.log({ variant });
const price = variant?.price.amount || defaultPrice.amount;
return (
<div className="mr-auto flex w-auto flex-row flex-wrap items-center gap-3 text-sm">
<Price
amount={variant?.price.amount || defaultPrice.amount}
currencyCode={variant?.price.currencyCode || defaultPrice.currencyCode}
className="text-lg font-semibold"
/>
<CoreCharge variant={variant} />
{variant?.coreCharge?.amount && variant.waiverAvailable ? (
<div className="mt-1 flex w-full items-center space-x-3">
<Checkbox id="payCoreCharge" />
<label htmlFor="payCoreCharge" className="text-md flex items-center gap-1 leading-none">
Pay a core charge of
<Price
amount={variant.coreCharge.amount}
currencyCode={variant.coreCharge.currencyCode}
/>
<span data-tooltip-id="payCoreCharge">
<InformationCircleIcon className="ml-1 h-4 w-4 text-gray-500" />
</span>
</label>
<Tooltip id="payCoreCharge">Select this if you do not have a core to return</Tooltip>
</div>
) : null}
</div>
<>
<div className="mb-4">
{variant && (
<div className="flex flex-row items-center space-x-3 text-sm text-neutral-700">
{variant.sku && <span>SKU: {variant.sku}</span>}
{variant.barcode && <span>Part Number: {variant.barcode}</span>}
</div>
)}
</div>
<div className="mr-auto flex w-auto flex-row flex-wrap items-center gap-3 text-sm">
<Price
amount={price}
currencyCode={variant?.price.currencyCode || defaultPrice.currencyCode}
className="text-2xl font-semibold"
/>
<CoreCharge variant={variant} />
</div>
</>
);
};

View File

@@ -3,13 +3,15 @@ import Prose from 'components/prose';
import { Product } from 'lib/shopify/types';
import { Suspense } from 'react';
import PriceWithCoreCharge from './price-with-core-charge';
import SpecialOffer from './special-offer';
import { VariantSelector } from './variant-selector';
import Warranty from './warranty';
export function ProductDescription({ product }: { product: Product }) {
return (
<>
<div className="mb-6 flex flex-col border-b pb-6 dark:border-neutral-700">
<h1 className="mb-3 text-4xl font-bold">{product.title}</h1>
<div className="mb-5 flex flex-col dark:border-neutral-700">
<h1 className="mb-3 text-2xl font-bold">{product.title}</h1>
<PriceWithCoreCharge
variants={product.variants}
defaultPrice={product.priceRange.minVariantPrice}
@@ -21,14 +23,21 @@ export function ProductDescription({ product }: { product: Product }) {
{product.descriptionHtml ? (
<Prose
className="mb-6 text-sm leading-tight dark:text-white/[60%]"
className="mb-4 text-sm leading-tight dark:text-white/[60%]"
html={product.descriptionHtml}
/>
) : null}
<div className="mb-4 border-t py-6 dark:border-neutral-700">
<Warranty productType={product.productType} />
</div>
<Suspense fallback={null}>
<AddToCart variants={product.variants} availableForSale={product.availableForSale} />
</Suspense>
<div className="mt-4 border-t pt-4">
<SpecialOffer />
</div>
</>
);
}

View File

@@ -0,0 +1,27 @@
import { CurrencyDollarIcon, ShieldCheckIcon, UsersIcon } from '@heroicons/react/24/outline';
import { TruckIcon } from '@heroicons/react/24/solid';
const SpecialOffer = () => {
return (
<>
<div className="mb-3 text-base font-medium tracking-tight">Special Offers</div>
<div className="flex flex-col space-y-2 pl-2 tracking-normal text-neutral-800">
<p className="flex items-center gap-3">
<TruckIcon className="h-5 w-5 text-secondary" /> Flat Rate Shipping (Commercial Address)
</p>
<p className="flex items-center gap-3">
<ShieldCheckIcon className="h-5 w-5 text-secondary" /> Up to 5 Years Unlimited Miles
Warranty
</p>
<p className="flex items-center gap-3">
<UsersIcon className="h-5 w-5 text-secondary" /> Excellent Customer Support
</p>
<p className="flex items-center gap-3">
<CurrencyDollarIcon className="h-5 w-5 text-secondary" /> No Core Charge for 30 days
</p>
</div>
</>
);
};
export default SpecialOffer;

View File

@@ -39,8 +39,8 @@ export function VariantSelector({
}));
return options.map((option) => (
<dl className="mb-8" key={option.id}>
<dt className="mb-4 text-sm uppercase tracking-wide">{option.name}</dt>
<dl className="mb-6" key={option.id}>
<dt className="mb-4 text-sm font-medium tracking-wide">{option.name}</dt>
<dd className="flex flex-wrap gap-3">
{option.values.map((value) => {
const optionNameLowerCase = option.name.toLowerCase();

View File

@@ -0,0 +1,57 @@
'use client';
import Price from 'components/price';
import { cn } from 'lib/utils';
import { ReactNode, useState } from 'react';
const options = ['Included', 'Premium Labor', '+1 Year'] as const;
type Option = (typeof options)[number];
const plans: Array<{
key: Option;
template: ReactNode;
price: number;
}> = [
{
template: (
<>
<span>Included</span>
<span>3-Year Warranty</span>
</>
),
price: 0,
key: 'Included'
},
{
template: <span>Premium Labor</span>,
price: 150,
key: 'Premium Labor'
},
{
template: <span>+1 Year</span>,
price: 100,
key: '+1 Year'
}
];
const WarrantySelector = () => {
const [selectedOptions, setSelectedOptions] = useState<Option>('Included');
return (
<ul className="flex min-h-16 flex-row space-x-4 pt-2">
{plans.map((plan) => (
<li
key={plan.key}
onClick={() => setSelectedOptions(plan.key)}
className={cn(
'flex w-32 cursor-pointer flex-col items-center justify-center space-y-2 rounded-md border p-2 text-xs font-medium',
{ 'ring-2 ring-secondary': plan.key === selectedOptions }
)}
>
{plan.template}
<Price amount={String(plan.price)} currencyCode="USD" />
</li>
))}
</ul>
);
};
export default WarrantySelector;

View File

@@ -0,0 +1,30 @@
import { ShieldCheckIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import WarrantySelector from './warranty-selector';
type WarrantyProps = {
productType: string | null;
};
const Warranty = ({ productType }: WarrantyProps) => {
return (
<div className="flex flex-col text-sm">
<div className="mb-3 flex flex-row items-center space-x-2 text-base font-medium">
<ShieldCheckIcon className="h-7 w-7" />
<span> Protect your {productType ?? 'product'}</span>
</div>
<div className="mb-1 flex flex-row items-center space-x-3 divide-x divide-gray-400 leading-none">
<span>Extended Warranty</span>
<Link href="#" className="pl-2 text-blue-800 hover:underline">
What&apos;s Included
</Link>
<Link href="#" className="pl-2 text-blue-800 hover:underline">
Terms & Conditions
</Link>
</div>
<WarrantySelector />
</div>
);
};
export default Warranty;