mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 12:47:50 +00:00
feat: add activate warranty form
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
parent
b1782a4a28
commit
b2efb59f5c
@ -1,3 +0,0 @@
|
|||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
||||||
return <div className="mx-auto max-w-screen-2xl">{children}</div>;
|
|
||||||
}
|
|
@ -1,32 +1,14 @@
|
|||||||
import Divider from 'components/divider';
|
import OrdersHeader from 'components/orders/orders-header';
|
||||||
import Heading from 'components/ui/heading';
|
|
||||||
import Skeleton from 'components/ui/skeleton';
|
|
||||||
|
|
||||||
export default function Loading() {
|
export default function OrdersLoadingPage() {
|
||||||
return (
|
return (
|
||||||
<div className="p-6">
|
<div className="py-5 sm:py-10">
|
||||||
<Heading className="pb-4" as="h1">
|
<OrdersHeader />
|
||||||
Orders
|
<div className="mx-auto mt-10 max-w-7xl sm:px-2 lg:px-8">
|
||||||
</Heading>
|
<div className="mx-auto max-w-2xl animate-pulse space-y-8 sm:px-4 lg:max-w-4xl lg:px-0">
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
|
||||||
<div className="flex w-full flex-col rounded border bg-white p-6">
|
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
|
||||||
<div className="flex flex-col gap-4">
|
<div className="h-[200px] border-b border-t border-gray-200 bg-gray-100 shadow-sm sm:rounded-lg sm:border" />
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,17 +10,10 @@ import Label from 'components/ui/label';
|
|||||||
import Text from 'components/ui/text';
|
import Text from 'components/ui/text';
|
||||||
import { getCustomerOrder } from 'lib/shopify';
|
import { getCustomerOrder } from 'lib/shopify';
|
||||||
import { Fulfillment, Order } from 'lib/shopify/types';
|
import { Fulfillment, Order } from 'lib/shopify/types';
|
||||||
|
import { toPrintDate } from 'lib/utils';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
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 }) {
|
function Unfulfilled({ order }: { order: Order }) {
|
||||||
// Build a map of line item IDs to quantities fulfilled
|
// Build a map of line item IDs to quantities fulfilled
|
||||||
const fulfilledLineItems = order.fulfillments.reduce<Map<string, number>>((acc, fulfillment) => {
|
const fulfilledLineItems = order.fulfillments.reduce<Map<string, number>>((acc, fulfillment) => {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { Button } from 'components/button';
|
import { InformationCircleIcon } from '@heroicons/react/24/outline';
|
||||||
import Divider from 'components/divider';
|
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 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 { getCustomerOrders } from 'lib/shopify';
|
||||||
|
import { toPrintDate } from 'lib/utils';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
@ -14,55 +12,99 @@ export default async function AccountPage() {
|
|||||||
const orders = await getCustomerOrders();
|
const orders = await getCustomerOrders();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6">
|
<div className="py-5 sm:py-10">
|
||||||
<Heading className="pb-4" as="h1">
|
<OrdersHeader />
|
||||||
Orders
|
<div className="mt-10">
|
||||||
</Heading>
|
<h2 className="sr-only">Recent orders</h2>
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
<div className="mx-auto max-w-7xl sm:px-2 lg:px-8">
|
||||||
{orders.map((order, index) => (
|
<div className="mx-auto max-w-2xl space-y-8 sm:px-4 lg:max-w-4xl lg:px-0">
|
||||||
<div className="relative" key={index}>
|
{orders.map((order) => (
|
||||||
<Link
|
<div
|
||||||
className="peer absolute left-0 top-0 h-full w-full"
|
className="border-b border-t border-gray-200 bg-white shadow-sm sm:rounded-lg sm:border"
|
||||||
href={`/account/orders/${order.id}`}
|
key={order.normalizedId}
|
||||||
/>
|
>
|
||||||
<Card className="flex h-full flex-col transition-shadow peer-hover:shadow-lg peer-active:shadow-lg">
|
<h3 className="sr-only">
|
||||||
<div className="flex flex-col gap-4">
|
Order placed on <time dateTime={order.createdAt}>{order.createdAt}</time>
|
||||||
{order.lineItems.map((lineItem, index) => (
|
</h3>
|
||||||
<div key={index}>
|
<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">
|
||||||
<div className="flex items-center gap-2">
|
<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">
|
||||||
<Badge content={lineItem.quantity!}>
|
<div>
|
||||||
<Image
|
<dt className="font-medium text-gray-900">Order</dt>
|
||||||
src={lineItem?.image?.url}
|
<dd className="mt-1 text-gray-500">{order.name}</dd>
|
||||||
alt={lineItem?.image?.altText}
|
|
||||||
width={80}
|
|
||||||
height={80}
|
|
||||||
className="rounded border"
|
|
||||||
/>
|
|
||||||
</Badge>
|
|
||||||
<Text>{lineItem.title}</Text>
|
|
||||||
</div>
|
</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>
|
||||||
))}
|
|
||||||
</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>
|
</div>
|
||||||
<Price
|
|
||||||
amount={order.totalPrice!.amount}
|
<h4 className="sr-only">Items</h4>
|
||||||
currencyCode={order.totalPrice!.currencyCode}
|
<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>
|
</div>
|
||||||
<Button size="lg" className="mt-4">
|
))}
|
||||||
Activate Warranty
|
|
||||||
</Button>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
33
components/form/file-input.tsx
Normal file
33
components/form/file-input.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { PhotoIcon } from '@heroicons/react/24/outline';
|
||||||
|
import { useId } from 'react';
|
||||||
|
|
||||||
|
type FileInputProps = {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FileInput = ({ name, label }: FileInputProps) => {
|
||||||
|
const id = useId();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium leading-6 text-gray-900">{label}</label>
|
||||||
|
<div className="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 px-6 py-5">
|
||||||
|
<div className="text-center">
|
||||||
|
<PhotoIcon className="mx-auto h-12 w-12 text-gray-300" aria-hidden="true" />
|
||||||
|
<div className="mt-2 flex text-sm leading-6 text-gray-600">
|
||||||
|
<label
|
||||||
|
htmlFor={id}
|
||||||
|
className="relative cursor-pointer rounded-md bg-white font-semibold text-primary focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2"
|
||||||
|
>
|
||||||
|
<span>Upload a file</span>
|
||||||
|
<input id={id} name={name} type="file" className="sr-only" />
|
||||||
|
</label>
|
||||||
|
<p className="pl-1">or drag and drop</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FileInput;
|
20
components/form/input.tsx
Normal file
20
components/form/input.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Field, Input as HeadlessInput, Label } from '@headlessui/react';
|
||||||
|
import { InputHTMLAttributes } from 'react';
|
||||||
|
|
||||||
|
type InputProps = InputHTMLAttributes<HTMLInputElement> & {
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Input = ({ label, ...props }: InputProps) => {
|
||||||
|
return (
|
||||||
|
<Field>
|
||||||
|
<Label className="block text-sm font-medium leading-6 text-gray-900">{label}</Label>
|
||||||
|
<HeadlessInput
|
||||||
|
className="mt-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary/70 sm:text-sm sm:leading-6"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Input;
|
57
components/orders/activate-warranty-modal.tsx
Normal file
57
components/orders/activate-warranty-modal.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react';
|
||||||
|
import FileInput from 'components/form/file-input';
|
||||||
|
import Input from 'components/form/input';
|
||||||
|
|
||||||
|
type ActivateWarrantyModalProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ActivateWarrantyModal({ onClose, isOpen }: ActivateWarrantyModalProps) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
transition
|
||||||
|
className="fixed inset-0 z-50 flex w-screen items-center justify-center bg-black/30 p-4 transition duration-300 ease-out data-[closed]:opacity-0"
|
||||||
|
>
|
||||||
|
{/* The backdrop, rendered as a fixed sibling to the panel container */}
|
||||||
|
<DialogBackdrop className="fixed inset-0 bg-black/30" />
|
||||||
|
|
||||||
|
{/* Full-screen container to center the panel */}
|
||||||
|
<div className="fixed inset-0 flex w-screen items-center justify-center p-4">
|
||||||
|
{/* The actual dialog panel */}
|
||||||
|
<DialogPanel className="w-full max-w-lg bg-white p-5 sm:w-[500px]">
|
||||||
|
<DialogTitle className="mb-2 font-bold">Activate Warranty</DialogTitle>
|
||||||
|
<form>
|
||||||
|
<div className="flex w-full flex-col gap-4">
|
||||||
|
<FileInput label="Odometer" name="odometer" />
|
||||||
|
<FileInput label="Installation Receipt" name="installation-receipt" />
|
||||||
|
<Input label="Customer Mileage" name="customer-mileage" type="number" />
|
||||||
|
<Input label="Customer VIN" name="customer-vin" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div className="mt-4 flex w-full justify-end gap-4">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm font-semibold leading-6 text-gray-900"
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="rounded-md bg-primary px-3 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||||
|
>
|
||||||
|
Activate
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</DialogPanel>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActivateWarrantyModal;
|
25
components/orders/activate-warranty.tsx
Normal file
25
components/orders/activate-warranty.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import ActivateWarrantyModal from './activate-warranty-modal';
|
||||||
|
|
||||||
|
type ActivateWarrantyModalProps = {
|
||||||
|
orderId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ActivateWarranty = ({ orderId }: ActivateWarrantyModalProps) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
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"
|
||||||
|
onClick={() => setIsOpen(true)}
|
||||||
|
>
|
||||||
|
Activate Warranty
|
||||||
|
</button>
|
||||||
|
<ActivateWarrantyModal isOpen={isOpen} onClose={() => setIsOpen(false)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActivateWarranty;
|
62
components/orders/mobile-order-actions.tsx
Normal file
62
components/orders/mobile-order-actions.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Button, Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react';
|
||||||
|
import { EllipsisVerticalIcon } from '@heroicons/react/24/solid';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Order } from 'lib/shopify/types';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import ActivateWarrantyModal from './activate-warranty-modal';
|
||||||
|
|
||||||
|
const MobileOrderActions = ({ order }: { order: Order }) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Menu as="div" className="relative flex justify-end lg:hidden">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<MenuButton className="-m-2 flex items-center p-2 text-gray-400 hover:text-gray-500">
|
||||||
|
<span className="sr-only">Options for order {order.name}</span>
|
||||||
|
<EllipsisVerticalIcon className="h-6 w-6" aria-hidden="true" />
|
||||||
|
</MenuButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<MenuItems
|
||||||
|
transition
|
||||||
|
className="absolute right-0 z-10 mt-2 w-40 origin-bottom-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in"
|
||||||
|
>
|
||||||
|
<div className="py-1">
|
||||||
|
<MenuItem>
|
||||||
|
{({ focus }) => (
|
||||||
|
<Link
|
||||||
|
href={`/account/orders/${order.normalizedId}`}
|
||||||
|
className={clsx(
|
||||||
|
focus ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
|
||||||
|
'block px-4 py-2 text-sm'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem>
|
||||||
|
{({ focus }) => (
|
||||||
|
<Button
|
||||||
|
className={clsx(
|
||||||
|
focus ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
|
||||||
|
'block px-4 py-2 text-sm'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
Activate Warranty
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</MenuItem>
|
||||||
|
</div>
|
||||||
|
</MenuItems>
|
||||||
|
</Menu>
|
||||||
|
<ActivateWarrantyModal isOpen={isOpen} onClose={() => setIsOpen(false)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MobileOrderActions;
|
@ -1,10 +1,11 @@
|
|||||||
import Image from 'next/image';
|
import { InformationCircleIcon } from '@heroicons/react/24/outline';
|
||||||
import Price from 'components/price';
|
import Price from 'components/price';
|
||||||
import Badge from 'components/ui/badge';
|
import Badge from 'components/ui/badge';
|
||||||
import Heading from 'components/ui/heading';
|
import Heading from 'components/ui/heading';
|
||||||
import Label from 'components/ui/label';
|
import Label from 'components/ui/label';
|
||||||
import Text from 'components/ui/text';
|
import Text from 'components/ui/text';
|
||||||
import { Order } from 'lib/shopify/types';
|
import { Order } from 'lib/shopify/types';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
export default function OrderSummary({ order }: { order: Order }) {
|
export default function OrderSummary({ order }: { order: Order }) {
|
||||||
return (
|
return (
|
||||||
@ -12,19 +13,32 @@ export default function OrderSummary({ order }: { order: Order }) {
|
|||||||
<Heading size="sm">Order Summary</Heading>
|
<Heading size="sm">Order Summary</Heading>
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
{order.lineItems.map((lineItem, index) => (
|
{order.lineItems.map((lineItem, index) => (
|
||||||
<div key={index} className="flex items-center gap-4">
|
<div key={index} className="flex items-start justify-between">
|
||||||
<Badge content={lineItem.quantity!}>
|
<div className="flex items-start gap-4">
|
||||||
<Image
|
<Badge content={lineItem.quantity!}>
|
||||||
src={lineItem.image.url}
|
<div className="h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg bg-gray-100">
|
||||||
alt={lineItem.image.altText}
|
{lineItem.image ? (
|
||||||
width={lineItem.image.width}
|
<Image
|
||||||
height={lineItem.image.height}
|
src={lineItem.image.url}
|
||||||
className="rounded border"
|
alt={lineItem.image.altText}
|
||||||
/>
|
width={lineItem.image.width}
|
||||||
</Badge>
|
height={lineItem.image.height}
|
||||||
<div className="flex flex-col gap-2">
|
className="h-full w-full object-cover object-center"
|
||||||
<Text>{lineItem.title}</Text>
|
/>
|
||||||
<Label>{lineItem.sku}</Label>
|
) : (
|
||||||
|
<div
|
||||||
|
className="flex h-full w-full items-center justify-center"
|
||||||
|
title="Missing Product Image"
|
||||||
|
>
|
||||||
|
<InformationCircleIcon className="size-8 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Text>{lineItem.title}</Text>
|
||||||
|
<Label>{lineItem.sku}</Label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Price
|
<Price
|
||||||
className="text-sm"
|
className="text-sm"
|
||||||
|
16
components/orders/orders-header.tsx
Normal file
16
components/orders/orders-header.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const OrdersHeader = () => {
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-7xl sm:px-2 lg:px-8">
|
||||||
|
<div className="mx-auto max-w-2xl px-4 lg:max-w-4xl lg:px-0">
|
||||||
|
<h1 className="text-2xl font-bold tracking-tight text-gray-900 sm:text-3xl">
|
||||||
|
Order history
|
||||||
|
</h1>
|
||||||
|
<p className="mt-2 text-sm text-gray-500">
|
||||||
|
Check the status of recent orders, manage returns, and discover similar products.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrdersHeader;
|
@ -1,16 +1,17 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { JSXElementConstructor } from 'react';
|
||||||
|
|
||||||
const Price = ({
|
const Price = ({
|
||||||
amount,
|
amount,
|
||||||
className,
|
className,
|
||||||
as,
|
as: Component = 'p',
|
||||||
currencyCode = 'USD',
|
currencyCode = 'USD',
|
||||||
currencyCodeClassName,
|
currencyCodeClassName,
|
||||||
showCurrency = false,
|
showCurrency = false,
|
||||||
prefix
|
prefix
|
||||||
}: {
|
}: {
|
||||||
amount: string;
|
amount: string;
|
||||||
as?: 'p' | 'span';
|
as?: keyof JSX.IntrinsicElements | JSXElementConstructor<any>;
|
||||||
className?: string;
|
className?: string;
|
||||||
currencyCode: string;
|
currencyCode: string;
|
||||||
currencyCodeClassName?: string;
|
currencyCodeClassName?: string;
|
||||||
@ -25,7 +26,6 @@ const Price = ({
|
|||||||
return <p className={className}>Included</p>;
|
return <p className={className}>Included</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Component = as || 'p';
|
|
||||||
// Otherwise, format and display the price
|
// Otherwise, format and display the price
|
||||||
return (
|
return (
|
||||||
<Component suppressHydrationWarning={true} className={className}>
|
<Component suppressHydrationWarning={true} className={className}>
|
||||||
|
@ -35,6 +35,7 @@ export const TAGS = {
|
|||||||
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
|
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
|
||||||
export const DEFAULT_OPTION = 'Default Title';
|
export const DEFAULT_OPTION = 'Default Title';
|
||||||
export const SHOPIFY_GRAPHQL_API_ENDPOINT = '/api/2024-04/graphql.json';
|
export const SHOPIFY_GRAPHQL_API_ENDPOINT = '/api/2024-04/graphql.json';
|
||||||
|
export const SHOPIFY_GRAPHQL_CUSTOMER_API_ENDPOINT = '/account/customer/api/2024-07/graphql';
|
||||||
|
|
||||||
export const CORE_WAIVER = 'core-waiver';
|
export const CORE_WAIVER = 'core-waiver';
|
||||||
export const CORE_VARIANT_ID_KEY = 'coreVariantId';
|
export const CORE_VARIANT_ID_KEY = 'coreVariantId';
|
||||||
|
25
lib/shopify/fragments/line-item.ts
Normal file
25
lib/shopify/fragments/line-item.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const lineItemFragment = /* GraphQL */ `
|
||||||
|
fragment LineItem on LineItem {
|
||||||
|
title
|
||||||
|
image {
|
||||||
|
altText
|
||||||
|
height
|
||||||
|
url
|
||||||
|
width
|
||||||
|
}
|
||||||
|
price {
|
||||||
|
amount
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
quantity
|
||||||
|
sku
|
||||||
|
totalPrice {
|
||||||
|
amount
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
variantTitle
|
||||||
|
id
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default lineItemFragment;
|
@ -1,9 +1,12 @@
|
|||||||
|
import lineItemFragment from './line-item';
|
||||||
|
|
||||||
const orderCard = /* GraphQL */ `
|
const orderCard = /* GraphQL */ `
|
||||||
fragment OrderCard on Order {
|
fragment OrderCard on Order {
|
||||||
id
|
id
|
||||||
number
|
number
|
||||||
name
|
name
|
||||||
processedAt
|
processedAt
|
||||||
|
createdAt
|
||||||
financialStatus
|
financialStatus
|
||||||
fulfillments(first: 1) {
|
fulfillments(first: 1) {
|
||||||
edges {
|
edges {
|
||||||
@ -17,20 +20,12 @@ const orderCard = /* GraphQL */ `
|
|||||||
currencyCode
|
currencyCode
|
||||||
}
|
}
|
||||||
lineItems(first: 20) {
|
lineItems(first: 20) {
|
||||||
edges {
|
nodes {
|
||||||
node {
|
...LineItem
|
||||||
title
|
|
||||||
quantity
|
|
||||||
image {
|
|
||||||
altText
|
|
||||||
height
|
|
||||||
url
|
|
||||||
width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
${lineItemFragment}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default orderCard;
|
export default orderCard;
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
PRICE_FILTER_ID,
|
PRICE_FILTER_ID,
|
||||||
PRODUCT_METAFIELD_PREFIX,
|
PRODUCT_METAFIELD_PREFIX,
|
||||||
SHOPIFY_GRAPHQL_API_ENDPOINT,
|
SHOPIFY_GRAPHQL_API_ENDPOINT,
|
||||||
|
SHOPIFY_GRAPHQL_CUSTOMER_API_ENDPOINT,
|
||||||
TAGS,
|
TAGS,
|
||||||
VARIANT_METAFIELD_PREFIX,
|
VARIANT_METAFIELD_PREFIX,
|
||||||
YEAR_FILTER_ID
|
YEAR_FILTER_ID
|
||||||
@ -29,9 +30,12 @@ import {
|
|||||||
getCollectionQuery,
|
getCollectionQuery,
|
||||||
getCollectionsQuery
|
getCollectionsQuery
|
||||||
} from './queries/collection';
|
} from './queries/collection';
|
||||||
|
import { getCustomerQuery } from './queries/customer';
|
||||||
import { getMenuQuery } from './queries/menu';
|
import { getMenuQuery } from './queries/menu';
|
||||||
import { getMetaobjectQuery, getMetaobjectsQuery } from './queries/metaobject';
|
import { getMetaobjectQuery, getMetaobjectsQuery } from './queries/metaobject';
|
||||||
import { getImageQuery, getMetaobjectsByIdsQuery } from './queries/node';
|
import { getImageQuery, getMetaobjectsByIdsQuery } from './queries/node';
|
||||||
|
import { getCustomerOrderQuery } from './queries/order';
|
||||||
|
import { getCustomerOrdersQuery } from './queries/orders';
|
||||||
import { getPageQuery, getPagesQuery } from './queries/page';
|
import { getPageQuery, getPagesQuery } from './queries/page';
|
||||||
import {
|
import {
|
||||||
getProductQuery,
|
getProductQuery,
|
||||||
@ -46,18 +50,19 @@ import {
|
|||||||
Connection,
|
Connection,
|
||||||
Customer,
|
Customer,
|
||||||
Filter,
|
Filter,
|
||||||
|
Fulfillment,
|
||||||
Image,
|
Image,
|
||||||
|
LineItem,
|
||||||
Menu,
|
Menu,
|
||||||
Metaobject,
|
Metaobject,
|
||||||
Money,
|
Money,
|
||||||
Order,
|
Order,
|
||||||
Fulfillment,
|
|
||||||
Transaction,
|
|
||||||
Page,
|
Page,
|
||||||
PageInfo,
|
PageInfo,
|
||||||
Product,
|
Product,
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
ShopifyAddToCartOperation,
|
ShopifyAddToCartOperation,
|
||||||
|
ShopifyAddress,
|
||||||
ShopifyCart,
|
ShopifyCart,
|
||||||
ShopifyCartOperation,
|
ShopifyCartOperation,
|
||||||
ShopifyCollection,
|
ShopifyCollection,
|
||||||
@ -65,6 +70,7 @@ import {
|
|||||||
ShopifyCollectionProductsOperation,
|
ShopifyCollectionProductsOperation,
|
||||||
ShopifyCollectionsOperation,
|
ShopifyCollectionsOperation,
|
||||||
ShopifyCreateCartOperation,
|
ShopifyCreateCartOperation,
|
||||||
|
ShopifyCustomer,
|
||||||
ShopifyCustomerOperation,
|
ShopifyCustomerOperation,
|
||||||
ShopifyCustomerOrderOperation,
|
ShopifyCustomerOrderOperation,
|
||||||
ShopifyCustomerOrdersOperation,
|
ShopifyCustomerOrdersOperation,
|
||||||
@ -73,6 +79,8 @@ import {
|
|||||||
ShopifyMenuOperation,
|
ShopifyMenuOperation,
|
||||||
ShopifyMetaobject,
|
ShopifyMetaobject,
|
||||||
ShopifyMetaobjectsOperation,
|
ShopifyMetaobjectsOperation,
|
||||||
|
ShopifyMoneyV2,
|
||||||
|
ShopifyOrder,
|
||||||
ShopifyPage,
|
ShopifyPage,
|
||||||
ShopifyPageOperation,
|
ShopifyPageOperation,
|
||||||
ShopifyPagesOperation,
|
ShopifyPagesOperation,
|
||||||
@ -84,26 +92,18 @@ import {
|
|||||||
ShopifyRemoveFromCartOperation,
|
ShopifyRemoveFromCartOperation,
|
||||||
ShopifySetCartAttributesOperation,
|
ShopifySetCartAttributesOperation,
|
||||||
ShopifyUpdateCartOperation,
|
ShopifyUpdateCartOperation,
|
||||||
TransmissionType,
|
Transaction,
|
||||||
ShopifyCustomer,
|
TransmissionType
|
||||||
ShopifyOrder,
|
|
||||||
ShopifyAddress,
|
|
||||||
ShopifyMoneyV2,
|
|
||||||
LineItem
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import { getCustomerQuery } from './queries/customer';
|
|
||||||
import { getCustomerOrdersQuery } from './queries/orders';
|
|
||||||
import { getCustomerOrderQuery } from './queries/order';
|
|
||||||
|
|
||||||
const domain = process.env.SHOPIFY_STORE_DOMAIN
|
const domain = process.env.SHOPIFY_STORE_DOMAIN
|
||||||
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
|
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const customerApiUrl = process.env.SHOPIFY_CUSTOMER_ACCOUNT_API_URL;
|
const customerApiUrl = process.env.SHOPIFY_CUSTOMER_ACCOUNT_API_URL;
|
||||||
const customerApiVersion = process.env.SHOPIFY_CUSTOMER_API_VERSION;
|
|
||||||
|
|
||||||
const storefrontEndpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
|
const storefrontEndpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
|
||||||
const customerEndpoint = `${customerApiUrl}/account/customer/api/${customerApiVersion}/graphql`;
|
const customerEndpoint = `${customerApiUrl}/${SHOPIFY_GRAPHQL_CUSTOMER_API_ENDPOINT}`;
|
||||||
|
|
||||||
const userAgent = '*';
|
const userAgent = '*';
|
||||||
const placeholderProductImage =
|
const placeholderProductImage =
|
||||||
@ -528,24 +528,15 @@ function reshapeOrder(shopifyOrder: ShopifyOrder): Order {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const orderLineItems: LineItem[] =
|
const orderLineItems: LineItem[] =
|
||||||
shopifyOrder.lineItems?.edges.map((edge) => ({
|
shopifyOrder.lineItems?.nodes?.map((item) => ({
|
||||||
id: edge.node.id,
|
...item,
|
||||||
title: edge.node.title,
|
price: reshapeMoney(item.price),
|
||||||
quantity: edge.node.quantity,
|
totalPrice: reshapeMoney(item.totalPrice)
|
||||||
image: {
|
|
||||||
url: edge.node.image?.url || placeholderProductImage,
|
|
||||||
altText: edge.node.image?.altText || edge.node.title,
|
|
||||||
width: 62,
|
|
||||||
height: 62
|
|
||||||
},
|
|
||||||
price: reshapeMoney(edge.node.price),
|
|
||||||
totalPrice: reshapeMoney(edge.node.totalPrice),
|
|
||||||
variantTitle: edge.node.variantTitle,
|
|
||||||
sku: edge.node.sku
|
|
||||||
})) || [];
|
})) || [];
|
||||||
|
|
||||||
const order: Order = {
|
const order: Order = {
|
||||||
id: shopifyOrder.id.replace('gid://shopify/Order/', ''),
|
id: shopifyOrder.id,
|
||||||
|
normalizedId: shopifyOrder.id.replace('gid://shopify/Order/', ''),
|
||||||
name: shopifyOrder.name,
|
name: shopifyOrder.name,
|
||||||
processedAt: shopifyOrder.processedAt,
|
processedAt: shopifyOrder.processedAt,
|
||||||
fulfillments: orderFulfillments,
|
fulfillments: orderFulfillments,
|
||||||
@ -556,7 +547,8 @@ function reshapeOrder(shopifyOrder: ShopifyOrder): Order {
|
|||||||
subtotal: reshapeMoney(shopifyOrder.subtotal),
|
subtotal: reshapeMoney(shopifyOrder.subtotal),
|
||||||
totalShipping: reshapeMoney(shopifyOrder.totalShipping),
|
totalShipping: reshapeMoney(shopifyOrder.totalShipping),
|
||||||
totalTax: reshapeMoney(shopifyOrder.totalTax),
|
totalTax: reshapeMoney(shopifyOrder.totalTax),
|
||||||
totalPrice: reshapeMoney(shopifyOrder.totalPrice)
|
totalPrice: reshapeMoney(shopifyOrder.totalPrice),
|
||||||
|
createdAt: shopifyOrder.createdAt
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shopifyOrder.customer) {
|
if (shopifyOrder.customer) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import lineItemFragment from '../fragments/line-item';
|
||||||
|
|
||||||
// NOTE: https://shopify.dev/docs/api/customer/latest/queries/customer
|
// NOTE: https://shopify.dev/docs/api/customer/latest/queries/customer
|
||||||
export const getCustomerOrderQuery = /* GraphQL */ `
|
export const getCustomerOrderQuery = /* GraphQL */ `
|
||||||
query getCustomerOrderQuery($orderId: ID!) {
|
query getCustomerOrderQuery($orderId: ID!) {
|
||||||
@ -55,11 +57,9 @@ export const getCustomerOrderQuery = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lineItems(first: 50) {
|
lineItems(first: 50) {
|
||||||
edges {
|
nodes {
|
||||||
node {
|
id
|
||||||
id
|
...LineItem
|
||||||
...LineItem
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalPrice {
|
totalPrice {
|
||||||
@ -194,25 +194,6 @@ export const getCustomerOrderQuery = /* GraphQL */ `
|
|||||||
happenedAt
|
happenedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment LineItem on LineItem {
|
|
||||||
title
|
|
||||||
image {
|
|
||||||
altText
|
|
||||||
height
|
|
||||||
url
|
|
||||||
width
|
|
||||||
}
|
|
||||||
price {
|
|
||||||
...Price
|
|
||||||
}
|
|
||||||
quantity
|
|
||||||
sku
|
|
||||||
totalPrice {
|
|
||||||
...Price
|
|
||||||
}
|
|
||||||
variantTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment OrderPaymentInformation on OrderPaymentInformation {
|
fragment OrderPaymentInformation on OrderPaymentInformation {
|
||||||
paymentStatus
|
paymentStatus
|
||||||
totalPaidAmount {
|
totalPaidAmount {
|
||||||
@ -237,4 +218,5 @@ export const getCustomerOrderQuery = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
${lineItemFragment}
|
||||||
`;
|
`;
|
||||||
|
@ -121,7 +121,7 @@ export type Address = {
|
|||||||
export type LineItem = {
|
export type LineItem = {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
image: Image;
|
image: Image | null;
|
||||||
price?: Money;
|
price?: Money;
|
||||||
quantity?: number;
|
quantity?: number;
|
||||||
sku?: string;
|
sku?: string;
|
||||||
@ -131,9 +131,11 @@ export type LineItem = {
|
|||||||
|
|
||||||
export type Order = {
|
export type Order = {
|
||||||
id: string;
|
id: string;
|
||||||
|
normalizedId: string;
|
||||||
name: string;
|
name: string;
|
||||||
customer?: Customer;
|
customer?: Customer;
|
||||||
processedAt: string;
|
processedAt: string;
|
||||||
|
createdAt: string;
|
||||||
fulfillments: Fulfillment[];
|
fulfillments: Fulfillment[];
|
||||||
transactions: Transaction[];
|
transactions: Transaction[];
|
||||||
lineItems: LineItem[];
|
lineItems: LineItem[];
|
||||||
@ -156,13 +158,16 @@ export type ShopifyOrder = {
|
|||||||
confirmationNumber: string;
|
confirmationNumber: string;
|
||||||
customer: ShopifyCustomer;
|
customer: ShopifyCustomer;
|
||||||
processedAt: string;
|
processedAt: string;
|
||||||
|
createdAt: string;
|
||||||
cancelledAt: string | null;
|
cancelledAt: string | null;
|
||||||
currencyCode: string;
|
currencyCode: string;
|
||||||
transactions: ShopifyOrderTransaction[];
|
transactions: ShopifyOrderTransaction[];
|
||||||
billingAddress: ShopifyAddress;
|
billingAddress: ShopifyAddress;
|
||||||
shippingAddress: ShopifyAddress;
|
shippingAddress: ShopifyAddress;
|
||||||
fulfillments: Connection<ShopifyFulfillment>;
|
fulfillments: Connection<ShopifyFulfillment>;
|
||||||
lineItems: Connection<ShopifyLineItem>;
|
lineItems: {
|
||||||
|
nodes: ShopifyLineItem[];
|
||||||
|
};
|
||||||
totalPrice: ShopifyMoneyV2;
|
totalPrice: ShopifyMoneyV2;
|
||||||
subtotal: ShopifyMoneyV2;
|
subtotal: ShopifyMoneyV2;
|
||||||
totalShipping: ShopifyMoneyV2;
|
totalShipping: ShopifyMoneyV2;
|
||||||
@ -269,7 +274,7 @@ type ShopifyFulfillmentLineItem = {
|
|||||||
type ShopifyLineItem = {
|
type ShopifyLineItem = {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
image: ShopifyImage;
|
image: Image | null;
|
||||||
price: ShopifyMoneyV2;
|
price: ShopifyMoneyV2;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
sku: string;
|
sku: string;
|
||||||
@ -277,13 +282,6 @@ type ShopifyLineItem = {
|
|||||||
variantTitle: string;
|
variantTitle: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ShopifyImage = {
|
|
||||||
altText: string;
|
|
||||||
height: number;
|
|
||||||
url: string;
|
|
||||||
width: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ShopifyFulfillmentEvent = {
|
type ShopifyFulfillmentEvent = {
|
||||||
status: string;
|
status: string;
|
||||||
happenedAt: string;
|
happenedAt: string;
|
||||||
|
@ -87,3 +87,11 @@ export function parseJSON(json: any) {
|
|||||||
function noproto(k: string, v: string) {
|
function noproto(k: string, v: string) {
|
||||||
if (k !== '__proto__') return v;
|
if (k !== '__proto__') return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toPrintDate(date: string) {
|
||||||
|
return new Date(date).toLocaleDateString('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"*": "prettier --write --ignore-unknown"
|
"*": "prettier --write --ignore-unknown"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^2.0.1",
|
"@headlessui/react": "^2.1.0",
|
||||||
"@heroicons/react": "^2.1.3",
|
"@heroicons/react": "^2.1.3",
|
||||||
"@hookform/resolvers": "^3.6.0",
|
"@hookform/resolvers": "^3.6.0",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
|
101
pnpm-lock.yaml
generated
101
pnpm-lock.yaml
generated
@ -9,8 +9,8 @@ importers:
|
|||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@headlessui/react':
|
'@headlessui/react':
|
||||||
specifier: ^2.0.1
|
specifier: ^2.1.0
|
||||||
version: 2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
version: 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
'@heroicons/react':
|
'@heroicons/react':
|
||||||
specifier: ^2.1.3
|
specifier: ^2.1.3
|
||||||
version: 2.1.3(react@18.2.0)
|
version: 2.1.3(react@18.2.0)
|
||||||
@ -180,14 +180,14 @@ packages:
|
|||||||
'@floating-ui/dom@1.6.3':
|
'@floating-ui/dom@1.6.3':
|
||||||
resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
|
resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
|
||||||
|
|
||||||
'@floating-ui/react-dom@2.0.9':
|
'@floating-ui/react-dom@2.1.0':
|
||||||
resolution: {integrity: sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==}
|
resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16.8.0'
|
react: '>=16.8.0'
|
||||||
react-dom: '>=16.8.0'
|
react-dom: '>=16.8.0'
|
||||||
|
|
||||||
'@floating-ui/react@0.26.13':
|
'@floating-ui/react@0.26.17':
|
||||||
resolution: {integrity: sha512-kBa9wntpugzrZ8t/4yWelvSmEKZdeTXTJzrxqyrLmcU/n1SM4nvse8yQh2e1b37rJGvtu0EplV9+IkBrCJ1vkw==}
|
resolution: {integrity: sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16.8.0'
|
react: '>=16.8.0'
|
||||||
react-dom: '>=16.8.0'
|
react-dom: '>=16.8.0'
|
||||||
@ -195,8 +195,8 @@ packages:
|
|||||||
'@floating-ui/utils@0.2.1':
|
'@floating-ui/utils@0.2.1':
|
||||||
resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
|
resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
|
||||||
|
|
||||||
'@headlessui/react@2.0.1':
|
'@headlessui/react@2.1.0':
|
||||||
resolution: {integrity: sha512-GxFvHHk27AYELf0WIMa0LgSeVqJ0SOvIwg7USTptMFbtLz31jNGQoolHiQPnvsI/IMmEeJ4ybzQlqV69/uvQ8A==}
|
resolution: {integrity: sha512-/MizQk2xqR5ELkmCI1xWy3VgJULvR8gcAXtZhcK7sY53TNRCPeMdeODEXKSv9LPSSRlEAyzW1+NGJiaXq6dLRw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18
|
react: ^18
|
||||||
@ -435,34 +435,34 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@react-aria/focus@3.17.0':
|
'@react-aria/focus@3.17.1':
|
||||||
resolution: {integrity: sha512-aRzBw1WTUkcIV3xFrqPA6aB8ZVt3XyGpTaSHAypU0Pgoy2wRq9YeJYpbunsKj9CJmskuffvTqXwAjTcaQish1Q==}
|
resolution: {integrity: sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
'@react-aria/interactions@3.21.2':
|
'@react-aria/interactions@3.21.3':
|
||||||
resolution: {integrity: sha512-Ju706DtoEmI/2vsfu9DCEIjDqsRBVLm/wmt2fr0xKbBca7PtmK8daajxFWz+eTq+EJakvYfLr7gWgLau9HyWXg==}
|
resolution: {integrity: sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
'@react-aria/ssr@3.9.3':
|
'@react-aria/ssr@3.9.4':
|
||||||
resolution: {integrity: sha512-5bUZ93dmvHFcmfUcEN7qzYe8yQQ8JY+nHN6m9/iSDCQ/QmCiE0kWXYwhurjw5ch6I8WokQzx66xKIMHBAa4NNA==}
|
resolution: {integrity: sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
'@react-aria/utils@3.24.0':
|
'@react-aria/utils@3.24.1':
|
||||||
resolution: {integrity: sha512-JAxkPhK5fCvFVNY2YG3TW3m1nTzwRcbz7iyTSkUzLFat4N4LZ7Kzh7NMHsgeE/oMOxd8zLY+XsUxMu/E/2GujA==}
|
resolution: {integrity: sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
'@react-stately/utils@3.10.0':
|
'@react-stately/utils@3.10.1':
|
||||||
resolution: {integrity: sha512-nji2i9fTYg65ZWx/3r11zR1F2tGya+mBubRCbMTwHyRnsSLFZaeq/W6lmrOyIy1uMJKBNKLJpqfmpT4x7rw6pg==}
|
resolution: {integrity: sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
'@react-types/shared@3.23.0':
|
'@react-types/shared@3.23.1':
|
||||||
resolution: {integrity: sha512-GQm/iPiii3ikcaMNR4WdVkJ4w0mKtV3mLqeSfSqzdqbPr6vONkqXbh3RhPlPmAJs1b4QHnexd/wZQP3U9DHOwQ==}
|
resolution: {integrity: sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||||
|
|
||||||
@ -472,9 +472,6 @@ packages:
|
|||||||
'@swc/counter@0.1.3':
|
'@swc/counter@0.1.3':
|
||||||
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
|
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
|
||||||
|
|
||||||
'@swc/helpers@0.5.2':
|
|
||||||
resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
|
|
||||||
|
|
||||||
'@swc/helpers@0.5.5':
|
'@swc/helpers@0.5.5':
|
||||||
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
||||||
|
|
||||||
@ -2344,15 +2341,15 @@ snapshots:
|
|||||||
'@floating-ui/core': 1.6.0
|
'@floating-ui/core': 1.6.0
|
||||||
'@floating-ui/utils': 0.2.1
|
'@floating-ui/utils': 0.2.1
|
||||||
|
|
||||||
'@floating-ui/react-dom@2.0.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
'@floating-ui/react-dom@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@floating-ui/dom': 1.6.3
|
'@floating-ui/dom': 1.6.3
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
|
||||||
'@floating-ui/react@0.26.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
'@floating-ui/react@0.26.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@floating-ui/react-dom': 2.0.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
'@floating-ui/react-dom': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
'@floating-ui/utils': 0.2.1
|
'@floating-ui/utils': 0.2.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
@ -2360,11 +2357,11 @@ snapshots:
|
|||||||
|
|
||||||
'@floating-ui/utils@0.2.1': {}
|
'@floating-ui/utils@0.2.1': {}
|
||||||
|
|
||||||
'@headlessui/react@2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
'@headlessui/react@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@floating-ui/react': 0.26.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
'@floating-ui/react': 0.26.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
'@react-aria/focus': 3.17.0(react@18.2.0)
|
'@react-aria/focus': 3.17.1(react@18.2.0)
|
||||||
'@react-aria/interactions': 3.21.2(react@18.2.0)
|
'@react-aria/interactions': 3.21.3(react@18.2.0)
|
||||||
'@tanstack/react-virtual': 3.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
'@tanstack/react-virtual': 3.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
@ -2564,43 +2561,43 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 18.2.72
|
'@types/react': 18.2.72
|
||||||
|
|
||||||
'@react-aria/focus@3.17.0(react@18.2.0)':
|
'@react-aria/focus@3.17.1(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@react-aria/interactions': 3.21.2(react@18.2.0)
|
'@react-aria/interactions': 3.21.3(react@18.2.0)
|
||||||
'@react-aria/utils': 3.24.0(react@18.2.0)
|
'@react-aria/utils': 3.24.1(react@18.2.0)
|
||||||
'@react-types/shared': 3.23.0(react@18.2.0)
|
'@react-types/shared': 3.23.1(react@18.2.0)
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.5
|
||||||
clsx: 2.1.0
|
clsx: 2.1.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
'@react-aria/interactions@3.21.2(react@18.2.0)':
|
'@react-aria/interactions@3.21.3(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@react-aria/ssr': 3.9.3(react@18.2.0)
|
'@react-aria/ssr': 3.9.4(react@18.2.0)
|
||||||
'@react-aria/utils': 3.24.0(react@18.2.0)
|
'@react-aria/utils': 3.24.1(react@18.2.0)
|
||||||
'@react-types/shared': 3.23.0(react@18.2.0)
|
'@react-types/shared': 3.23.1(react@18.2.0)
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.5
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
'@react-aria/ssr@3.9.3(react@18.2.0)':
|
'@react-aria/ssr@3.9.4(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.5
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
'@react-aria/utils@3.24.0(react@18.2.0)':
|
'@react-aria/utils@3.24.1(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@react-aria/ssr': 3.9.3(react@18.2.0)
|
'@react-aria/ssr': 3.9.4(react@18.2.0)
|
||||||
'@react-stately/utils': 3.10.0(react@18.2.0)
|
'@react-stately/utils': 3.10.1(react@18.2.0)
|
||||||
'@react-types/shared': 3.23.0(react@18.2.0)
|
'@react-types/shared': 3.23.1(react@18.2.0)
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.5
|
||||||
clsx: 2.1.0
|
clsx: 2.1.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
'@react-stately/utils@3.10.0(react@18.2.0)':
|
'@react-stately/utils@3.10.1(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.5
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
'@react-types/shared@3.23.0(react@18.2.0)':
|
'@react-types/shared@3.23.1(react@18.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
@ -2608,10 +2605,6 @@ snapshots:
|
|||||||
|
|
||||||
'@swc/counter@0.1.3': {}
|
'@swc/counter@0.1.3': {}
|
||||||
|
|
||||||
'@swc/helpers@0.5.2':
|
|
||||||
dependencies:
|
|
||||||
tslib: 2.6.2
|
|
||||||
|
|
||||||
'@swc/helpers@0.5.5':
|
'@swc/helpers@0.5.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user