polish order confirmation in orders list and order details pages

This commit is contained in:
tedraykov 2024-07-01 22:42:02 +03:00
parent f4f6edcd9a
commit 64a666f34a
18 changed files with 206 additions and 208 deletions

View File

@ -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} />}

View File

@ -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');

View File

@ -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);
}
};

View File

@ -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 {

View File

@ -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">

View File

@ -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} />
</> </>
); );
}; };

View File

@ -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

View File

@ -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>

View File

@ -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: {

View File

@ -25,4 +25,4 @@ const Checkbox = forwardRef<
Checkbox.displayName = CheckboxPrimitive.Root.displayName; Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox }; export default Checkbox;

View File

@ -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';

View File

@ -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;

View File

@ -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;

View File

View 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;
};

View File

@ -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
}
} }
} }
`; `;

View File

@ -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 = {

View 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;
}; };