mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 04:37:51 +00:00
polish order confirmation in orders list and order details pages
This commit is contained in:
parent
f4f6edcd9a
commit
64a666f34a
@ -62,7 +62,7 @@ export default async function AccountPage() {
|
|||||||
<span className="sr-only">{order.normalizedId}</span>
|
<span className="sr-only">{order.normalizedId}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{!isBeforeToday(order?.warrantyActivationDeadline) && (
|
{!isBeforeToday(order?.warrantyActivationDeadline?.value) && (
|
||||||
<ActivateWarranty order={order} />
|
<ActivateWarranty order={order} />
|
||||||
)}
|
)}
|
||||||
{!order.orderConfirmation && <OrderConfirmation order={order} />}
|
{!order.orderConfirmation && <OrderConfirmation order={order} />}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { getMenu, getMetaobjects } from 'lib/shopify';
|
import { getAllMetaobjects, getMenu } from 'lib/shopify';
|
||||||
import FiltersList from './filters-list';
|
import FiltersList from './filters-list';
|
||||||
|
|
||||||
const HomePageFilters = async () => {
|
const HomePageFilters = async () => {
|
||||||
const yearsData = getMetaobjects('make_model_year_composite');
|
const yearsData = getAllMetaobjects('make_model_year_composite');
|
||||||
const modelsData = getMetaobjects('make_model_composite');
|
const modelsData = getAllMetaobjects('make_model_composite');
|
||||||
const makesData = getMetaobjects('make');
|
const makesData = getAllMetaobjects('make');
|
||||||
|
|
||||||
const [years, models, makes] = await Promise.all([yearsData, modelsData, makesData]);
|
const [years, models, makes] = await Promise.all([yearsData, modelsData, makesData]);
|
||||||
const menu = await getMenu('main-menu');
|
const menu = await getMenu('main-menu');
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
'use server';
|
|
||||||
|
|
||||||
import { handleUploadFile } from 'components/form/file-input/actions';
|
|
||||||
import { TAGS } from 'lib/constants';
|
|
||||||
import { updateOrderMetafields } from 'lib/shopify';
|
|
||||||
import { ShopifyOrderMetafield, UpdateOrderMetafieldInput } from 'lib/shopify/types';
|
|
||||||
import { revalidateTag } from 'next/cache';
|
|
||||||
|
|
||||||
const getMetafieldValue = (
|
|
||||||
key: keyof ShopifyOrderMetafield,
|
|
||||||
newValue: { value?: string | null; type: string; key: string },
|
|
||||||
orderMetafields?: ShopifyOrderMetafield
|
|
||||||
): UpdateOrderMetafieldInput => {
|
|
||||||
return orderMetafields?.[key]?.id
|
|
||||||
? { id: orderMetafields[key]?.id!, value: newValue.value, key: newValue.key }
|
|
||||||
: { ...newValue, namespace: 'custom' };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const activateWarranty = async (
|
|
||||||
orderId: string,
|
|
||||||
formData: FormData,
|
|
||||||
orderMetafields?: ShopifyOrderMetafield
|
|
||||||
) => {
|
|
||||||
let odometerFileId = null;
|
|
||||||
let installationFileId = null;
|
|
||||||
const odometerFile = formData.get('warranty_activation_odometer');
|
|
||||||
const installationFile = formData.get('warranty_activation_installation');
|
|
||||||
if (odometerFile) {
|
|
||||||
odometerFileId = await handleUploadFile({ file: odometerFile as File });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installationFile) {
|
|
||||||
installationFileId = await handleUploadFile({ file: installationFile as File });
|
|
||||||
}
|
|
||||||
console.log(formData.get('warranty_activation_self_install'));
|
|
||||||
// https://shopify.dev/docs/api/admin-graphql/2024-01/mutations/orderUpdate
|
|
||||||
const rawFormData = [
|
|
||||||
getMetafieldValue(
|
|
||||||
'warrantyActivationOdometer',
|
|
||||||
{
|
|
||||||
key: 'warranty_activation_odometer',
|
|
||||||
value: odometerFileId,
|
|
||||||
type: 'file_reference'
|
|
||||||
},
|
|
||||||
orderMetafields
|
|
||||||
),
|
|
||||||
getMetafieldValue(
|
|
||||||
'warrantyActivationInstallation',
|
|
||||||
{
|
|
||||||
key: 'warranty_activation_installation',
|
|
||||||
value: installationFileId,
|
|
||||||
type: 'file_reference'
|
|
||||||
},
|
|
||||||
orderMetafields
|
|
||||||
),
|
|
||||||
getMetafieldValue(
|
|
||||||
'warrantyActivationSelfInstall',
|
|
||||||
{
|
|
||||||
key: 'warranty_activation_self_install',
|
|
||||||
value: formData.get('warranty_activation_self_install') === 'on' ? 'true' : 'false',
|
|
||||||
type: 'boolean'
|
|
||||||
},
|
|
||||||
orderMetafields
|
|
||||||
),
|
|
||||||
getMetafieldValue(
|
|
||||||
'warrantyActivationMileage',
|
|
||||||
{
|
|
||||||
key: 'warranty_activation_mileage',
|
|
||||||
value: formData.get('warranty_activation_mileage') as string | null,
|
|
||||||
type: 'number_integer'
|
|
||||||
},
|
|
||||||
orderMetafields
|
|
||||||
),
|
|
||||||
getMetafieldValue(
|
|
||||||
'warrantyActivationVIN',
|
|
||||||
{
|
|
||||||
key: 'warranty_activation_vin',
|
|
||||||
value: formData.get('warranty_activation_vin') as string | null,
|
|
||||||
type: 'single_line_text_field'
|
|
||||||
},
|
|
||||||
orderMetafields
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateOrderMetafields({
|
|
||||||
orderId,
|
|
||||||
metafields: rawFormData
|
|
||||||
});
|
|
||||||
|
|
||||||
revalidateTag(TAGS.orderMetafields);
|
|
||||||
} catch (error) {
|
|
||||||
console.log('activateWarranty action', error);
|
|
||||||
}
|
|
||||||
};
|
|
@ -5,10 +5,25 @@ import OrderConfirmationPdf from 'components/orders/order-confirmation-pdf';
|
|||||||
import { handleUploadFile } from 'components/form/file-input/actions';
|
import { handleUploadFile } from 'components/form/file-input/actions';
|
||||||
import { TAGS } from 'lib/constants';
|
import { TAGS } from 'lib/constants';
|
||||||
import { updateOrderMetafields } from 'lib/shopify';
|
import { updateOrderMetafields } from 'lib/shopify';
|
||||||
import { Order, OrderConfirmationContent } from 'lib/shopify/types';
|
import {
|
||||||
|
Order,
|
||||||
|
OrderConfirmationContent,
|
||||||
|
ShopifyOrderMetafield,
|
||||||
|
UpdateOrderMetafieldInput
|
||||||
|
} from 'lib/shopify/types';
|
||||||
import { revalidateTag } from 'next/cache';
|
import { revalidateTag } from 'next/cache';
|
||||||
|
|
||||||
export const activateWarranty = async (orderId: string, formData: FormData) => {
|
const getMetafieldValue = (
|
||||||
|
key: keyof ShopifyOrderMetafield,
|
||||||
|
newValue: { value?: string | null; type: string; key: string },
|
||||||
|
orderMetafields?: ShopifyOrderMetafield
|
||||||
|
): UpdateOrderMetafieldInput => {
|
||||||
|
return orderMetafields?.[key]?.id
|
||||||
|
? { id: orderMetafields[key]?.id!, value: newValue.value, key: newValue.key }
|
||||||
|
: { ...newValue, namespace: 'custom' };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const activateWarranty = async (order: Order, formData: FormData) => {
|
||||||
let odometerFileId = null;
|
let odometerFileId = null;
|
||||||
let installationFileId = null;
|
let installationFileId = null;
|
||||||
const odometerFile = formData.get('warranty_activation_odometer');
|
const odometerFile = formData.get('warranty_activation_odometer');
|
||||||
@ -21,24 +36,58 @@ export const activateWarranty = async (orderId: string, formData: FormData) => {
|
|||||||
installationFileId = await handleUploadFile({ file: installationFile as File });
|
installationFileId = await handleUploadFile({ file: installationFile as File });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://shopify.dev/docs/api/admin-graphql/2024-01/mutations/orderUpdate
|
||||||
const rawFormData = [
|
const rawFormData = [
|
||||||
{ key: 'warranty_activation_odometer', value: odometerFileId, type: 'file_reference' },
|
getMetafieldValue(
|
||||||
{ key: 'warranty_activation_installation', value: installationFileId, type: 'file_reference' },
|
'warrantyActivationOdometer',
|
||||||
{
|
{
|
||||||
key: 'warranty_activation_mileage',
|
key: 'warranty_activation_odometer',
|
||||||
value: formData.get('warranty_activation_mileage') as string | null,
|
value: odometerFileId,
|
||||||
type: 'number_integer'
|
type: 'file_reference'
|
||||||
},
|
},
|
||||||
{
|
order
|
||||||
key: 'warranty_activation_vin',
|
),
|
||||||
value: formData.get('warranty_activation_vin') as string | null,
|
getMetafieldValue(
|
||||||
type: 'single_line_text_field'
|
'warrantyActivationInstallation',
|
||||||
}
|
{
|
||||||
|
key: 'warranty_activation_installation',
|
||||||
|
value: installationFileId,
|
||||||
|
type: 'file_reference'
|
||||||
|
},
|
||||||
|
order
|
||||||
|
),
|
||||||
|
getMetafieldValue(
|
||||||
|
'warrantyActivationSelfInstall',
|
||||||
|
{
|
||||||
|
key: 'warranty_activation_self_install',
|
||||||
|
value: formData.get('warranty_activation_self_install') === 'on' ? 'true' : 'false',
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
order
|
||||||
|
),
|
||||||
|
getMetafieldValue(
|
||||||
|
'warrantyActivationMileage',
|
||||||
|
{
|
||||||
|
key: 'warranty_activation_mileage',
|
||||||
|
value: formData.get('warranty_activation_mileage') as string | null,
|
||||||
|
type: 'number_integer'
|
||||||
|
},
|
||||||
|
order
|
||||||
|
),
|
||||||
|
getMetafieldValue(
|
||||||
|
'warrantyActivationVIN',
|
||||||
|
{
|
||||||
|
key: 'warranty_activation_vin',
|
||||||
|
value: formData.get('warranty_activation_vin') as string | null,
|
||||||
|
type: 'single_line_text_field'
|
||||||
|
},
|
||||||
|
order
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateOrderMetafields({
|
await updateOrderMetafields({
|
||||||
orderId,
|
orderId: order.id,
|
||||||
metafields: rawFormData
|
metafields: rawFormData
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -91,7 +140,12 @@ export const confirmOrder = async ({ order, content, formData }: ConfirmOrderOpt
|
|||||||
const confirmationPDFId = await handleUploadFile({ file });
|
const confirmationPDFId = await handleUploadFile({ file });
|
||||||
|
|
||||||
const rawFormData = [
|
const rawFormData = [
|
||||||
{ key: 'customer_confirmation', value: confirmationPDFId, type: 'file_reference' }
|
{
|
||||||
|
key: 'customer_confirmation',
|
||||||
|
value: confirmationPDFId,
|
||||||
|
type: 'file_reference',
|
||||||
|
namespace: 'custom'
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -6,23 +6,17 @@ import CheckboxField from 'components/form/checkbox-field';
|
|||||||
import FileInput from 'components/form/file-input';
|
import FileInput from 'components/form/file-input';
|
||||||
import Input from 'components/form/input-field';
|
import Input from 'components/form/input-field';
|
||||||
import LoadingDots from 'components/loading-dots';
|
import LoadingDots from 'components/loading-dots';
|
||||||
import { ShopifyOrderMetafield } from 'lib/shopify/types';
|
import { Order } from 'lib/shopify/types';
|
||||||
import { FormEventHandler, useRef, useTransition } from 'react';
|
import { FormEventHandler, useRef, useTransition } from 'react';
|
||||||
import { activateWarranty } from './actions';
|
import { activateWarranty } from './actions';
|
||||||
|
|
||||||
type ActivateWarrantyModalProps = {
|
type ActivateWarrantyModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
orderId: string;
|
order: Order;
|
||||||
orderMetafields?: ShopifyOrderMetafield;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ActivateWarrantyModal({
|
function ActivateWarrantyModal({ onClose, isOpen, order }: ActivateWarrantyModalProps) {
|
||||||
onClose,
|
|
||||||
isOpen,
|
|
||||||
orderId,
|
|
||||||
orderMetafields
|
|
||||||
}: ActivateWarrantyModalProps) {
|
|
||||||
const [pending, startTransition] = useTransition();
|
const [pending, startTransition] = useTransition();
|
||||||
const formRef = useRef<HTMLFormElement>(null);
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
|
|
||||||
@ -33,7 +27,7 @@ function ActivateWarrantyModal({
|
|||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
|
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
await activateWarranty(orderId, formData, orderMetafields);
|
await activateWarranty(order, formData);
|
||||||
form.reset();
|
form.reset();
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
@ -59,28 +53,28 @@ function ActivateWarrantyModal({
|
|||||||
<FileInput
|
<FileInput
|
||||||
label="Odometer"
|
label="Odometer"
|
||||||
name="warranty_activation_odometer"
|
name="warranty_activation_odometer"
|
||||||
fileId={orderMetafields?.warrantyActivationOdometer?.value}
|
fileId={order?.warrantyActivationOdometer?.value}
|
||||||
/>
|
/>
|
||||||
<FileInput
|
<FileInput
|
||||||
label="Installation Receipt"
|
label="Installation Receipt"
|
||||||
name="warranty_activation_installation"
|
name="warranty_activation_installation"
|
||||||
fileId={orderMetafields?.warrantyActivationInstallation?.value}
|
fileId={order?.warrantyActivationInstallation?.value}
|
||||||
/>
|
/>
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
label="Self Installed"
|
label="Self Installed"
|
||||||
name="warranty_activation_self_install"
|
name="warranty_activation_self_install"
|
||||||
defaultChecked={orderMetafields?.warrantyActivationSelfInstall?.value === 'true'}
|
defaultChecked={order?.warrantyActivationSelfInstall?.value === 'true'}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="Customer Mileage"
|
label="Customer Mileage"
|
||||||
name="warranty_activation_mileage"
|
name="warranty_activation_mileage"
|
||||||
type="number"
|
type="number"
|
||||||
defaultValue={orderMetafields?.warrantyActivationMileage?.value}
|
defaultValue={order?.warrantyActivationMileage?.value}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="Customer VIN"
|
label="Customer VIN"
|
||||||
name="warranty_activation_vin"
|
name="warranty_activation_vin"
|
||||||
defaultValue={orderMetafields?.warrantyActivationVIN?.value}
|
defaultValue={order?.warrantyActivationVIN?.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex w-full justify-end gap-4">
|
<div className="mt-4 flex w-full justify-end gap-4">
|
||||||
|
@ -5,6 +5,7 @@ import { isBeforeToday } from 'lib/utils';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import ActivateWarrantyModal from './activate-warranty-modal';
|
import ActivateWarrantyModal from './activate-warranty-modal';
|
||||||
import WarrantyActivatedBadge from './warranty-activated-badge';
|
import WarrantyActivatedBadge from './warranty-activated-badge';
|
||||||
|
import { Button } from 'components/ui';
|
||||||
|
|
||||||
type ActivateWarrantyModalProps = {
|
type ActivateWarrantyModalProps = {
|
||||||
order: Order;
|
order: Order;
|
||||||
@ -12,7 +13,7 @@ type ActivateWarrantyModalProps = {
|
|||||||
|
|
||||||
const ActivateWarranty = ({ order }: ActivateWarrantyModalProps) => {
|
const ActivateWarranty = ({ order }: ActivateWarrantyModalProps) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const isWarrantyActivated = order?.warrantyStatus === WarrantyStatus.Activated;
|
const isWarrantyActivated = order?.warrantyStatus?.value === WarrantyStatus.Activated;
|
||||||
const isPassDeadline = isBeforeToday(order?.warrantyActivationDeadline?.value);
|
const isPassDeadline = isBeforeToday(order?.warrantyActivationDeadline?.value);
|
||||||
|
|
||||||
if (isWarrantyActivated) {
|
if (isWarrantyActivated) {
|
||||||
@ -25,13 +26,8 @@ const ActivateWarranty = ({ order }: ActivateWarrantyModalProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<Button onClick={() => setIsOpen(true)}>Activate Warranty</Button>
|
||||||
className="flex h-fit 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"
|
<ActivateWarrantyModal isOpen={isOpen} onClose={() => setIsOpen(false)} order={order} />
|
||||||
onClick={() => setIsOpen(true)}
|
|
||||||
>
|
|
||||||
Activate Warranty
|
|
||||||
</button>
|
|
||||||
<ActivateWarrantyModal isOpen={isOpen} onClose={() => setIsOpen(false)} orderId={order.id} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -16,9 +16,9 @@ const MobileOrderActions = ({ order }: { order: Order }) => {
|
|||||||
const [isWarrantyOpen, setIsWarrantyOpen] = useState(false);
|
const [isWarrantyOpen, setIsWarrantyOpen] = useState(false);
|
||||||
const [isOrderConfirmaionOpen, setIsOrderConfirmationOpen] = useState(false);
|
const [isOrderConfirmaionOpen, setIsOrderConfirmationOpen] = useState(false);
|
||||||
|
|
||||||
const isWarrantyActivated = order?.warrantyStatus === WarrantyStatus.Activated;
|
const isWarrantyActivated = order?.warrantyStatus?.value === WarrantyStatus.Activated;
|
||||||
const isPassDeadline = isBeforeToday(order?.warrantyActivationDeadline);
|
const isPassDeadline = isBeforeToday(order?.warrantyActivationDeadline?.value);
|
||||||
const isOrderConfirmed = order?.orderConfirmation;
|
const isOrderConfirmed = order?.orderConfirmation?.value;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -84,7 +84,7 @@ const MobileOrderActions = ({ order }: { order: Order }) => {
|
|||||||
<ActivateWarrantyModal
|
<ActivateWarrantyModal
|
||||||
isOpen={isWarrantyOpen}
|
isOpen={isWarrantyOpen}
|
||||||
onClose={() => setIsWarrantyOpen(false)}
|
onClose={() => setIsWarrantyOpen(false)}
|
||||||
orderId={order.id}
|
order={order}
|
||||||
/>
|
/>
|
||||||
{!isOrderConfirmed && (
|
{!isOrderConfirmed && (
|
||||||
<OrderConfirmationModal
|
<OrderConfirmationModal
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
|
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
|
||||||
import Text from 'components/ui/text';
|
|
||||||
import { Input } from 'components/ui/input';
|
|
||||||
import { InputLabel } from 'components/ui/input-label';
|
|
||||||
import Skeleton from 'components/ui/skeleton';
|
|
||||||
import { toPrintDate } from 'lib/utils';
|
import { toPrintDate } from 'lib/utils';
|
||||||
import Label from 'components/ui/label';
|
|
||||||
import Heading from 'components/ui/heading';
|
|
||||||
import PaymentsDetails from './payment-details';
|
import PaymentsDetails from './payment-details';
|
||||||
import Price from 'components/price';
|
import Price from 'components/price';
|
||||||
import Divider from 'components/divider';
|
import Divider from 'components/divider';
|
||||||
@ -14,7 +8,7 @@ import Markdown from 'markdown-to-jsx';
|
|||||||
import { Order, OrderConfirmationContent } from 'lib/shopify/types';
|
import { Order, OrderConfirmationContent } from 'lib/shopify/types';
|
||||||
import { FormEventHandler, useEffect, useRef, useState, useTransition } from 'react';
|
import { FormEventHandler, useEffect, useRef, useState, useTransition } from 'react';
|
||||||
import { confirmOrder } from 'components/orders/actions';
|
import { confirmOrder } from 'components/orders/actions';
|
||||||
import { Button } from 'components/ui';
|
import { Button, Heading, Text, Label, Skeleton, InputLabel, Input } from 'components/ui';
|
||||||
|
|
||||||
function OrderConfirmationDetails({
|
function OrderConfirmationDetails({
|
||||||
content,
|
content,
|
||||||
@ -218,6 +212,7 @@ export default function OrderConfirmationModal({
|
|||||||
|
|
||||||
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
setLoading(true);
|
||||||
const form = formRef.current;
|
const form = formRef.current;
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
@ -276,11 +271,15 @@ export default function OrderConfirmationModal({
|
|||||||
</InputLabel>
|
</InputLabel>
|
||||||
<Input id="signature2" name="signature2" required />
|
<Input id="signature2" name="signature2" required />
|
||||||
</div>
|
</div>
|
||||||
<div className="space-x-2">
|
<div className="flex justify-end gap-2">
|
||||||
<Button variant="outlined" color="content">
|
<Button variant="text">Cancel</Button>
|
||||||
Cancel
|
<Button
|
||||||
</Button>
|
type="submit"
|
||||||
<Button type="submit" disabled={loading}>
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
disabled={loading}
|
||||||
|
isLoading={loading}
|
||||||
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,6 @@ const buttonVariants = tv({
|
|||||||
'transition-all duration-100 ease-in-out',
|
'transition-all duration-100 ease-in-out',
|
||||||
// disabled
|
// disabled
|
||||||
'disabled:pointer-events-none disabled:shadow-none',
|
'disabled:pointer-events-none disabled:shadow-none',
|
||||||
'shadow-sm',
|
|
||||||
focusInput
|
focusInput
|
||||||
],
|
],
|
||||||
loading: 'pointer-events-none flex shrink-0 items-center justify-center gap-1.5'
|
loading: 'pointer-events-none flex shrink-0 items-center justify-center gap-1.5'
|
||||||
@ -40,12 +39,14 @@ const buttonVariants = tv({
|
|||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
solid: {
|
solid: {
|
||||||
root: 'border border-transparent'
|
root: 'border border-transparent shadow-sm'
|
||||||
},
|
},
|
||||||
outlined: {
|
outlined: {
|
||||||
root: 'border bg-white'
|
root: 'border bg-white shadow-sm'
|
||||||
},
|
},
|
||||||
text: {}
|
text: {
|
||||||
|
root: 'border border-transparent'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
compoundVariants: [
|
compoundVariants: [
|
||||||
@ -118,6 +119,22 @@ const buttonVariants = tv({
|
|||||||
'disabled:border-content-muted disabled:text-content-muted'
|
'disabled:border-content-muted disabled:text-content-muted'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: 'content',
|
||||||
|
variant: 'text',
|
||||||
|
class: {
|
||||||
|
root: [
|
||||||
|
// text color
|
||||||
|
'text-content-emphasis',
|
||||||
|
// background color
|
||||||
|
'bg-transparent',
|
||||||
|
// hover color
|
||||||
|
'hover:bg-content/5',
|
||||||
|
// disabled
|
||||||
|
'disabled:text-content-muted'
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
@ -25,4 +25,4 @@ const Checkbox = forwardRef<
|
|||||||
|
|
||||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Checkbox };
|
export default Checkbox;
|
||||||
|
@ -5,7 +5,6 @@ export * from './button';
|
|||||||
export { default as Card } from './card';
|
export { default as Card } from './card';
|
||||||
export * from './card';
|
export * from './card';
|
||||||
export { default as Checkbox } from './checkbox';
|
export { default as Checkbox } from './checkbox';
|
||||||
export * from './checkbox';
|
|
||||||
export { default as Heading } from './heading';
|
export { default as Heading } from './heading';
|
||||||
export { default as InputLabel } from './input-label';
|
export { default as InputLabel } from './input-label';
|
||||||
export * from './input-label';
|
export * from './input-label';
|
||||||
|
@ -3,7 +3,8 @@ import * as LabelPrimitives from '@radix-ui/react-label';
|
|||||||
|
|
||||||
import { cx } from 'lib/utils';
|
import { cx } from 'lib/utils';
|
||||||
|
|
||||||
interface InputLabelProps extends React.ComponentPropsWithoutRef<typeof LabelPrimitives.Root> {
|
export interface InputLabelProps
|
||||||
|
extends React.ComponentPropsWithoutRef<typeof LabelPrimitives.Root> {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,4 +30,4 @@ const InputLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitives.Root
|
|||||||
);
|
);
|
||||||
InputLabel.displayName = 'InputLabel';
|
InputLabel.displayName = 'InputLabel';
|
||||||
|
|
||||||
export { InputLabel };
|
export default InputLabel;
|
||||||
|
@ -41,7 +41,7 @@ const inputStyles = tv({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface InputProps
|
export interface InputProps
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement>,
|
extends React.InputHTMLAttributes<HTMLInputElement>,
|
||||||
VariantProps<typeof inputStyles> {
|
VariantProps<typeof inputStyles> {
|
||||||
inputClassName?: string;
|
inputClassName?: string;
|
||||||
@ -67,4 +67,4 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
|
|
||||||
Input.displayName = 'Input';
|
Input.displayName = 'Input';
|
||||||
|
|
||||||
export { Input, inputStyles, type InputProps };
|
export default Input;
|
||||||
|
0
lib/shopify/fragments/order-card.ts
Normal file
0
lib/shopify/fragments/order-card.ts
Normal file
@ -37,7 +37,7 @@ import {
|
|||||||
import { getCustomerQuery } from './queries/customer';
|
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 { getFileQuery, getImageQuery, getMetaobjectsByIdsQuery } from './queries/node';
|
||||||
import { getCustomerOrdersQuery } from './queries/orders';
|
import { getCustomerOrdersQuery } from './queries/orders';
|
||||||
import { getPageQuery, getPagesQuery } from './queries/page';
|
import { getPageQuery, getPagesQuery } from './queries/page';
|
||||||
import {
|
import {
|
||||||
@ -52,6 +52,7 @@ import {
|
|||||||
Collection,
|
Collection,
|
||||||
Connection,
|
Connection,
|
||||||
Customer,
|
Customer,
|
||||||
|
File,
|
||||||
FileCreateInput,
|
FileCreateInput,
|
||||||
Filter,
|
Filter,
|
||||||
Fulfillment,
|
Fulfillment,
|
||||||
@ -313,7 +314,7 @@ export async function shopifyCustomerFetch<T>({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeEdgesAndNodes = (array: Connection<any>) => {
|
const removeEdgesAndNodes = <T = any>(array: Connection<T>) => {
|
||||||
return array.edges.map((edge) => edge?.node);
|
return array.edges.map((edge) => edge?.node);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -439,7 +440,7 @@ const reshapeImages = (images: Connection<Image>, productTitle: string) => {
|
|||||||
const flattened = removeEdgesAndNodes(images);
|
const flattened = removeEdgesAndNodes(images);
|
||||||
|
|
||||||
return flattened.map((image) => {
|
return flattened.map((image) => {
|
||||||
const filename = image.url.match(/.*\/(.*)\..*/)[1];
|
const filename = (image.url.match(/.*\/(.*)\..*/) || [])[1];
|
||||||
return {
|
return {
|
||||||
...image,
|
...image,
|
||||||
altText: image.altText || `${productTitle} - ${filename}`
|
altText: image.altText || `${productTitle} - ${filename}`
|
||||||
@ -621,25 +622,21 @@ function reshapeOrder(shopifyOrder: ShopifyOrder): Order {
|
|||||||
shippingMethod: {
|
shippingMethod: {
|
||||||
name: shopifyOrder.shippingLine?.title,
|
name: shopifyOrder.shippingLine?.title,
|
||||||
price: reshapeMoney(shopifyOrder.shippingLine.originalPrice)!
|
price: reshapeMoney(shopifyOrder.shippingLine.originalPrice)!
|
||||||
}
|
},
|
||||||
|
warrantyActivationDeadline: shopifyOrder.warrantyActivationDeadline,
|
||||||
|
warrantyStatus: shopifyOrder.warrantyStatus,
|
||||||
|
warrantyActivationInstallation: shopifyOrder.warrantyActivationInstallation,
|
||||||
|
warrantyActivationMileage: shopifyOrder.warrantyActivationMileage,
|
||||||
|
warrantyActivationOdometer: shopifyOrder.warrantyActivationOdometer,
|
||||||
|
warrantyActivationSelfInstall: shopifyOrder.warrantyActivationSelfInstall,
|
||||||
|
warrantyActivationVIN: shopifyOrder.warrantyActivationVIN,
|
||||||
|
orderConfirmation: shopifyOrder.orderConfirmation
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shopifyOrder.customer) {
|
if (shopifyOrder.customer) {
|
||||||
order.customer = reshapeCustomer(shopifyOrder.customer);
|
order.customer = reshapeCustomer(shopifyOrder.customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shopifyOrder.warrantyStatus) {
|
|
||||||
order.warrantyStatus = shopifyOrder.warrantyStatus.value as WarrantyStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shopifyOrder.warrantyActivationDeadline) {
|
|
||||||
order.warrantyActivationDeadline = new Date(shopifyOrder.warrantyActivationDeadline.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shopifyOrder.orderConfirmation) {
|
|
||||||
order.orderConfirmation = shopifyOrder.orderConfirmation.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,6 +888,31 @@ export async function getMetaobjects(type: string) {
|
|||||||
return reshapeMetaobjects(removeEdgesAndNodes(res.body.data.metaobjects));
|
return reshapeMetaobjects(removeEdgesAndNodes(res.body.data.metaobjects));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAllMetaobjects(type: string) {
|
||||||
|
const allMetaobjects: Metaobject[] = [];
|
||||||
|
let hasNextPage = true;
|
||||||
|
let after: string | undefined;
|
||||||
|
|
||||||
|
while (hasNextPage) {
|
||||||
|
const res = await shopifyFetch<ShopifyMetaobjectsOperation>({
|
||||||
|
query: getMetaobjectsQuery,
|
||||||
|
tags: [TAGS.collections, TAGS.products],
|
||||||
|
variables: { type, after }
|
||||||
|
});
|
||||||
|
|
||||||
|
const metaobjects = reshapeMetaobjects(removeEdgesAndNodes(res.body.data.metaobjects));
|
||||||
|
|
||||||
|
for (const metaobject of metaobjects) {
|
||||||
|
allMetaobjects.push(metaobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNextPage = res.body.data.metaobjects.pageInfo?.hasNextPage || false;
|
||||||
|
after = res.body.data.metaobjects.pageInfo?.endCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allMetaobjects;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getMetaobjectsByIds(ids: string[]) {
|
export async function getMetaobjectsByIds(ids: string[]) {
|
||||||
if (!ids.length) return [];
|
if (!ids.length) return [];
|
||||||
|
|
||||||
@ -1147,3 +1169,19 @@ export const updateOrderMetafields = async ({
|
|||||||
|
|
||||||
return response.body.data.orderUpdate.order.id;
|
return response.body.data.orderUpdate.order.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFile = async (id: string) => {
|
||||||
|
const res = await shopifyFetch<{
|
||||||
|
data: {
|
||||||
|
node: File;
|
||||||
|
};
|
||||||
|
variables: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
}>({
|
||||||
|
query: getFileQuery,
|
||||||
|
variables: { id }
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.body.data.node;
|
||||||
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export const getMetaobjectsQuery = /* GraphQL */ `
|
export const getMetaobjectsQuery = /* GraphQL */ `
|
||||||
query getMetaobjects($type: String!) {
|
query getMetaobjects($type: String!, $after: String) {
|
||||||
metaobjects(type: $type, first: 200) {
|
metaobjects(type: $type, first: 200, after: $after) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@ -16,6 +16,10 @@ export const getMetaobjectsQuery = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -3,6 +3,7 @@ export type Maybe<T> = T | null;
|
|||||||
|
|
||||||
export type Connection<T> = {
|
export type Connection<T> = {
|
||||||
edges: Array<Edge<T>>;
|
edges: Array<Edge<T>>;
|
||||||
|
pageInfo?: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Edge<T> = {
|
export type Edge<T> = {
|
||||||
@ -152,10 +153,7 @@ export type Order = {
|
|||||||
name: string;
|
name: string;
|
||||||
price: Money;
|
price: Money;
|
||||||
};
|
};
|
||||||
warrantyStatus?: WarrantyStatus | null;
|
} & ShopifyOrderMetafield;
|
||||||
warrantyActivationDeadline?: Date | null;
|
|
||||||
orderConfirmation?: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ShopifyOrder = {
|
export type ShopifyOrder = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -184,10 +182,7 @@ export type ShopifyOrder = {
|
|||||||
requiresShipping: boolean;
|
requiresShipping: boolean;
|
||||||
shippingLine: ShopifyShippingLine;
|
shippingLine: ShopifyShippingLine;
|
||||||
note: string | null;
|
note: string | null;
|
||||||
warrantyStatus?: ShopifyMetafield;
|
} & ShopifyOrderMetafield;
|
||||||
warrantyActivationDeadline?: ShopifyMetafield;
|
|
||||||
orderConfirmation?: ShopifyMetafield;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ShopifyShippingLine = {
|
type ShopifyShippingLine = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -685,7 +680,7 @@ export type ShopifyImageOperation = {
|
|||||||
|
|
||||||
export type ShopifyMetaobjectsOperation = {
|
export type ShopifyMetaobjectsOperation = {
|
||||||
data: { metaobjects: Connection<ShopifyMetaobject> };
|
data: { metaobjects: Connection<ShopifyMetaobject> };
|
||||||
variables: { type: string };
|
variables: { type: string; after?: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ShopifyPagesOperation = {
|
export type ShopifyPagesOperation = {
|
||||||
@ -878,20 +873,15 @@ export enum WarrantyStatus {
|
|||||||
LimitedActivated = 'Limited Activation'
|
LimitedActivated = 'Limited Activation'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrderMetafieldValue<T = string> = {
|
|
||||||
value: T;
|
|
||||||
id: string;
|
|
||||||
key: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ShopifyOrderMetafield = {
|
export type ShopifyOrderMetafield = {
|
||||||
warrantyStatus: OrderMetafieldValue | null;
|
orderConfirmation: ShopifyMetafield | null;
|
||||||
warrantyActivationDeadline: OrderMetafieldValue | null;
|
warrantyStatus: ShopifyMetafield | null;
|
||||||
warrantyActivationOdometer: OrderMetafieldValue | null;
|
warrantyActivationDeadline: ShopifyMetafield | null;
|
||||||
warrantyActivationInstallation: OrderMetafieldValue | null;
|
warrantyActivationOdometer: ShopifyMetafield | null;
|
||||||
warrantyActivationSelfInstall: OrderMetafieldValue | null;
|
warrantyActivationInstallation: ShopifyMetafield | null;
|
||||||
warrantyActivationVIN: OrderMetafieldValue | null;
|
warrantyActivationSelfInstall: ShopifyMetafield | null;
|
||||||
warrantyActivationMileage: OrderMetafieldValue | null;
|
warrantyActivationVIN: ShopifyMetafield | null;
|
||||||
|
warrantyActivationMileage: ShopifyMetafield | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type File = {
|
export type File = {
|
||||||
|
@ -124,12 +124,13 @@ export function toPrintDate(date: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isBeforeToday = (date?: Date | null) => {
|
export const isBeforeToday = (date?: string | null) => {
|
||||||
if (!date) return false;
|
if (!date) return false;
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
const compareDate = new Date(date);
|
||||||
|
|
||||||
today.setHours(0, 0, 0, 0);
|
today.setHours(0, 0, 0, 0);
|
||||||
date.setHours(0, 0, 0, 0);
|
compareDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
return date <= today;
|
return compareDate <= today;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user