feat: add activate warranty form

Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
Chloe
2024-06-24 22:28:06 +07:00
parent b1782a4a28
commit b2efb59f5c
21 changed files with 470 additions and 235 deletions

View File

@@ -1,3 +0,0 @@
export default function Layout({ children }: { children: React.ReactNode }) {
return <div className="mx-auto max-w-screen-2xl">{children}</div>;
}

View File

@@ -1,32 +1,14 @@
import Divider from 'components/divider';
import Heading from 'components/ui/heading';
import Skeleton from 'components/ui/skeleton';
import OrdersHeader from 'components/orders/orders-header';
export default function Loading() {
export default function OrdersLoadingPage() {
return (
<div className="p-6">
<Heading className="pb-4" as="h1">
Orders
</Heading>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<div className="flex w-full flex-col rounded border bg-white p-6">
<div className="flex flex-col gap-4">
<div>
<div className="flex items-center gap-2">
<Skeleton className="h-20 w-20 flex-none" />
<Skeleton />
</div>
</div>
</div>
<Divider />
<div className="flex flex-col gap-4">
<div>
<Skeleton className="mb-2 h-5 w-14" />
<Skeleton className="h-4 w-24" />
</div>
<Skeleton className="w-20" />
</div>
<Skeleton className="mt-4 h-11" />
<div className="py-5 sm:py-10">
<OrdersHeader />
<div className="mx-auto mt-10 max-w-7xl sm:px-2 lg:px-8">
<div className="mx-auto max-w-2xl animate-pulse space-y-8 sm:px-4 lg:max-w-4xl lg:px-0">
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
</div>
</div>
</div>

View File

@@ -10,17 +10,10 @@ import Label from 'components/ui/label';
import Text from 'components/ui/text';
import { getCustomerOrder } from 'lib/shopify';
import { Fulfillment, Order } from 'lib/shopify/types';
import { toPrintDate } from 'lib/utils';
import Image from 'next/image';
import Link from 'next/link';
function toPrintDate(date: string) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
function Unfulfilled({ order }: { order: Order }) {
// Build a map of line item IDs to quantities fulfilled
const fulfilledLineItems = order.fulfillments.reduce<Map<string, number>>((acc, fulfillment) => {

View File

@@ -1,12 +1,10 @@
import { Button } from 'components/button';
import Divider from 'components/divider';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import ActivateWarranty from 'components/orders/activate-warranty';
import MobileOrderActions from 'components/orders/mobile-order-actions';
import OrdersHeader from 'components/orders/orders-header';
import Price from 'components/price';
import Badge from 'components/ui/badge';
import { Card } from 'components/ui/card';
import Heading from 'components/ui/heading';
import Label from 'components/ui/label';
import Text from 'components/ui/text';
import { getCustomerOrders } from 'lib/shopify';
import { toPrintDate } from 'lib/utils';
import Image from 'next/image';
import Link from 'next/link';
@@ -14,55 +12,99 @@ export default async function AccountPage() {
const orders = await getCustomerOrders();
return (
<div className="p-6">
<Heading className="pb-4" as="h1">
Orders
</Heading>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{orders.map((order, index) => (
<div className="relative" key={index}>
<Link
className="peer absolute left-0 top-0 h-full w-full"
href={`/account/orders/${order.id}`}
/>
<Card className="flex h-full flex-col transition-shadow peer-hover:shadow-lg peer-active:shadow-lg">
<div className="flex flex-col gap-4">
{order.lineItems.map((lineItem, index) => (
<div key={index}>
<div className="flex items-center gap-2">
<Badge content={lineItem.quantity!}>
<Image
src={lineItem?.image?.url}
alt={lineItem?.image?.altText}
width={80}
height={80}
className="rounded border"
/>
</Badge>
<Text>{lineItem.title}</Text>
<div className="py-5 sm:py-10">
<OrdersHeader />
<div className="mt-10">
<h2 className="sr-only">Recent orders</h2>
<div className="mx-auto max-w-7xl sm:px-2 lg:px-8">
<div className="mx-auto max-w-2xl space-y-8 sm:px-4 lg:max-w-4xl lg:px-0">
{orders.map((order) => (
<div
className="border-b border-t border-gray-200 bg-white shadow-sm sm:rounded-lg sm:border"
key={order.normalizedId}
>
<h3 className="sr-only">
Order placed on <time dateTime={order.createdAt}>{order.createdAt}</time>
</h3>
<div className="flex items-center border-b border-gray-200 p-4 sm:grid sm:grid-cols-4 sm:gap-x-6 sm:p-6">
<dl className="grid flex-1 grid-cols-2 gap-x-6 text-sm sm:col-span-3 sm:grid-cols-3 lg:col-span-2">
<div>
<dt className="font-medium text-gray-900">Order</dt>
<dd className="mt-1 text-gray-500">{order.name}</dd>
</div>
<div className="hidden sm:block">
<dt className="font-medium text-gray-900">Date placed</dt>
<dd className="mt-1 text-gray-500">
<time dateTime={order.createdAt}>{toPrintDate(order.createdAt)}</time>
</dd>
</div>
{order.totalPrice && (
<div>
<dt className="font-medium text-gray-900">Total amount</dt>
<Price
as="dd"
className="mt-1 font-medium text-gray-900"
amount={order.totalPrice.amount}
currencyCode={order.totalPrice.currencyCode}
/>
</div>
)}
</dl>
<MobileOrderActions order={order} />
<div className="hidden lg:col-span-2 lg:flex lg:items-center lg:justify-end lg:space-x-4">
<Link
href={`/account/orders/${order.normalizedId}`}
className="flex items-center justify-center rounded-md border border-gray-300 bg-white px-2.5 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
<span>View Order</span>
<span className="sr-only">{order.normalizedId}</span>
</Link>
<ActivateWarranty orderId={order.id} />
</div>
))}
</div>
<Divider />
<div className="flex flex-1 flex-col justify-end gap-4">
<div>
<Text>
{order.lineItems.length} item{order.lineItems.length > 1 && 's'}
</Text>
<Label>Order {order.name}</Label>
</div>
<Price
amount={order.totalPrice!.amount}
currencyCode={order.totalPrice!.currencyCode}
/>
<h4 className="sr-only">Items</h4>
<ul role="list" className="divide-y divide-gray-200">
{order.lineItems.map((item) => (
<li key={item.id} className="p-4 sm:p-6">
<div className="flex items-center sm:items-start">
<div className="h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg bg-gray-100">
{item.image ? (
<Image
src={item.image.url}
width={item.image.width}
height={item.image.height}
alt={item.image.altText || item.title}
className="h-full w-full object-cover object-center"
/>
) : (
<div
className="flex h-full w-full items-center justify-center"
title="Missing Product Image"
>
<InformationCircleIcon className="size-8 text-gray-400" />
</div>
)}
</div>
<div className="ml-6 flex-1 text-sm">
<div className="font-medium text-gray-900 sm:flex sm:justify-between">
<h5>{item.title}</h5>
{item.price && <Price {...item.price} className="mt-2 sm:mt-0" />}
</div>
<p className="hidden text-gray-500 sm:mt-2 sm:block">
{item.variantTitle}
</p>
</div>
</div>
</li>
))}
</ul>
</div>
<Button size="lg" className="mt-4">
Activate Warranty
</Button>
</Card>
))}
</div>
))}
</div>
</div>
</div>
);