mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 12:47:50 +00:00
168 lines
4.6 KiB
TypeScript
168 lines
4.6 KiB
TypeScript
import clsx, { ClassValue } from 'clsx';
|
|
import { ReadonlyURLSearchParams } from 'next/navigation';
|
|
import { twMerge } from 'tailwind-merge';
|
|
import { Menu, Product, ProductVariant } from './shopify/types';
|
|
|
|
export function cx(...args: ClassValue[]) {
|
|
return twMerge(clsx(...args));
|
|
}
|
|
export const focusInput = [
|
|
// base
|
|
'focus:ring-2',
|
|
// ring color
|
|
'focus:ring-blue-200 focus:dark:ring-blue-700/30',
|
|
// border color
|
|
'focus:border-blue-500 focus:dark:border-blue-700'
|
|
];
|
|
|
|
export const hasErrorInput = [
|
|
// base
|
|
'ring-2',
|
|
// border color
|
|
'border-red-500 dark:border-red-700',
|
|
// ring color
|
|
'ring-red-200 dark:ring-red-700/30'
|
|
];
|
|
|
|
export const focusRing = [
|
|
// base
|
|
'outline outline-offset-2 outline-0 focus-visible:outline-2',
|
|
// outline color
|
|
'outline-blue-500 dark:outline-blue-500'
|
|
];
|
|
|
|
export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => {
|
|
const paramsString = params.toString();
|
|
const queryString = `${paramsString.length ? '?' : ''}${paramsString}`;
|
|
|
|
return `${pathname}${queryString}`;
|
|
};
|
|
|
|
export const ensureStartsWith = (stringToCheck: string, startsWith: string) =>
|
|
stringToCheck.startsWith(startsWith) ? stringToCheck : `${startsWith}${stringToCheck}`;
|
|
|
|
export const validateEnvironmentVariables = () => {
|
|
const requiredEnvironmentVariables = [
|
|
'SHOPIFY_STORE_DOMAIN',
|
|
'STORE_PREFIX',
|
|
'SHOPIFY_STOREFRONT_ACCESS_TOKEN',
|
|
'SHOPIFY_CUSTOMER_ACCOUNT_API_CLIENT_ID',
|
|
'SHOPIFY_CUSTOMER_ACCOUNT_API_URL',
|
|
'SHOPIFY_ORIGIN_URL',
|
|
'SHOPIFY_ADMIN_API_ACCESS_TOKEN'
|
|
];
|
|
const missingEnvironmentVariables = [] as string[];
|
|
|
|
requiredEnvironmentVariables.forEach((envVar) => {
|
|
if (!process.env[envVar]) {
|
|
missingEnvironmentVariables.push(envVar);
|
|
}
|
|
});
|
|
|
|
if (missingEnvironmentVariables.length) {
|
|
throw new Error(
|
|
`The following environment variables are missing. Your site will not work without them. Read more: https://vercel.com/docs/integrations/shopify#configure-environment-variables\n\n${missingEnvironmentVariables.join(
|
|
'\n'
|
|
)}\n`
|
|
);
|
|
}
|
|
|
|
if (
|
|
process.env.SHOPIFY_STORE_DOMAIN?.includes('[') ||
|
|
process.env.SHOPIFY_STORE_DOMAIN?.includes(']')
|
|
) {
|
|
throw new Error(
|
|
'Your `SHOPIFY_STORE_DOMAIN` environment variable includes brackets (ie. `[` and / or `]`). Your site will not work with them there. Please remove them.'
|
|
);
|
|
}
|
|
};
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
|
|
export function normalizeUrl(domain: string, url: string) {
|
|
const cleanUrl = url.replace(domain, '');
|
|
|
|
if (cleanUrl.startsWith('/collections')) {
|
|
return getCollectionUrl(cleanUrl.replace('/collections', ''), false);
|
|
}
|
|
|
|
return cleanUrl.replace('/pages', '');
|
|
}
|
|
|
|
export const parseMetaFieldValue = <T>(field: { value: string } | null): T | null => {
|
|
try {
|
|
return field?.value ? JSON.parse(field.value) : null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const findParentCollection = (menu: Menu[], collection: string): Menu | null => {
|
|
let parentCollection: Menu | null = null;
|
|
for (const item of menu) {
|
|
if (item.items.length) {
|
|
const hasParent = item.items.some((subItem) =>
|
|
subItem.path.includes(getCollectionUrl(collection))
|
|
);
|
|
if (hasParent) {
|
|
return item;
|
|
} else {
|
|
parentCollection = findParentCollection(item.items, collection);
|
|
}
|
|
}
|
|
}
|
|
return parentCollection;
|
|
};
|
|
|
|
export function parseJSON(json: any) {
|
|
if (String(json).includes('__proto__')) return JSON.parse(json, noproto);
|
|
return JSON.parse(json);
|
|
}
|
|
|
|
function noproto(k: string, v: string) {
|
|
if (k !== '__proto__') return v;
|
|
}
|
|
|
|
export function toPrintDate(date: string) {
|
|
return new Date(date).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
});
|
|
}
|
|
|
|
export const isBeforeToday = (date?: string | null) => {
|
|
if (!date) return false;
|
|
const today = new Date();
|
|
const compareDate = new Date(date);
|
|
|
|
today.setHours(0, 0, 0, 0);
|
|
compareDate.setHours(0, 0, 0, 0);
|
|
|
|
return compareDate <= today;
|
|
};
|
|
|
|
export const getCollectionUrl = (handle: string, includeSlashPrefix = true) => {
|
|
const rewriteUrl = handle.split('_').filter(Boolean).join('/').toLowerCase();
|
|
|
|
return includeSlashPrefix ? `/${rewriteUrl}` : rewriteUrl;
|
|
};
|
|
|
|
export const getSelectedProductVariant = ({
|
|
product,
|
|
searchParams
|
|
}: {
|
|
product: Product;
|
|
searchParams?: { [key: string]: string | string[] | undefined };
|
|
}) => {
|
|
const variant = product.variants.find((variant: ProductVariant) =>
|
|
variant.selectedOptions.every(
|
|
(option) => option.value === searchParams?.[option.name.toLowerCase()]
|
|
)
|
|
);
|
|
|
|
return variant || product.variants[0];
|
|
};
|