mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 23:46:58 +00:00
creating SKU generator from product.Title
This commit is contained in:
parent
e8cc4863fb
commit
decb61bee3
55
app/product/[handle]/sku/page.tsx
Normal file
55
app/product/[handle]/sku/page.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { ProductSKUs } from "components/product/sku-generator";
|
||||||
|
import { HIDDEN_PRODUCT_TAG } from "lib/constants";
|
||||||
|
import { getProduct } from "lib/shopify";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: { handle: string };
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const product = await getProduct(params.handle);
|
||||||
|
|
||||||
|
if (!product) return notFound();
|
||||||
|
|
||||||
|
const { url, width, height, altText: alt } = product.featuredImage || {};
|
||||||
|
const hide = !product.tags.includes(HIDDEN_PRODUCT_TAG);
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: product.seo.title || product.title,
|
||||||
|
description: product.seo.description || product.description,
|
||||||
|
robots: {
|
||||||
|
index: hide,
|
||||||
|
follow: hide,
|
||||||
|
googleBot: {
|
||||||
|
index: hide,
|
||||||
|
follow: hide
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openGraph: url
|
||||||
|
? {
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
alt
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ViewSKUs({ params }: { params: { handle: string } }) {
|
||||||
|
const product = await getProduct(params.handle);
|
||||||
|
|
||||||
|
if (!product) return
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ProductSKUs productTitle={product.title} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
30
components/product/sku-generator.tsx
Normal file
30
components/product/sku-generator.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { createProductSKUs } from "lib/helpers/skus";
|
||||||
|
|
||||||
|
|
||||||
|
export function ProductSKUs(productInfo: {productTitle: string}) {
|
||||||
|
const SKUs = createProductSKUs(productInfo.productTitle)
|
||||||
|
|
||||||
|
function copyText(e) {
|
||||||
|
navigator.clipboard.writeText(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mx-auto max-w-screen-2xl px-4">
|
||||||
|
<div className="rounded-lg border border-neutral-200 bg-white p-8 px-4 dark:border-neutral-800 dark:bg-black md:p-12 lg:grid lg:grid-cols-6">
|
||||||
|
<div className="lg:col-span-3">
|
||||||
|
{SKUs?.map(SKU => {
|
||||||
|
return (
|
||||||
|
<div className="my-4 w-full">
|
||||||
|
<input type="text" value={SKU} onClick={copyText} className="cursor-pointer w-full border py-2 px-2" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
69
constants/sku.tsx
Normal file
69
constants/sku.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
export const baseArtworkNumber = '000';
|
||||||
|
|
||||||
|
export const sizes = [ 'xxs', 'xs', 's', 'm', 'l', 'xl', 'xxl', 'xxxl' ];
|
||||||
|
|
||||||
|
export const garmentTypes = {
|
||||||
|
tshirt: 'tshirt',
|
||||||
|
cropT: 'cropT',
|
||||||
|
hoodie: 'hoodie',
|
||||||
|
zipHood: 'zipHood',
|
||||||
|
crew: 'crew',
|
||||||
|
cropCrew: 'cropCrew',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const garmentHandleKeys = {
|
||||||
|
'T-shirt': garmentTypes.tshirt,
|
||||||
|
'Crop T-shirt': garmentTypes.cropT,
|
||||||
|
'Hoodie': garmentTypes.hoodie,
|
||||||
|
'Zipped Hoodie': garmentTypes.zipHood,
|
||||||
|
'Crew Neck Sweatshirt': garmentTypes.crew,
|
||||||
|
'Cropped Crew Neck Sweatshirt': garmentTypes.cropCrew,
|
||||||
|
};
|
||||||
|
|
||||||
|
const xsTo2xl = sizes.slice(1, 7);
|
||||||
|
|
||||||
|
export const garmentSizes = {
|
||||||
|
[garmentTypes.tshirt]: sizes,
|
||||||
|
[garmentTypes.cropT]: xsTo2xl,
|
||||||
|
[garmentTypes.hoodie]: sizes,
|
||||||
|
[garmentTypes.zipHood]: sizes,
|
||||||
|
[garmentTypes.crew]: xsTo2xl,
|
||||||
|
[garmentTypes.cropCrew]: xsTo2xl,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const garmentSKUs = {
|
||||||
|
[garmentTypes.tshirt]: 'STTU788',
|
||||||
|
[garmentTypes.cropT]: 'STTW089',
|
||||||
|
[garmentTypes.hoodie]: 'STSU867',
|
||||||
|
[garmentTypes.zipHood]: 'STSU953',
|
||||||
|
[garmentTypes.crew]: 'STSU886',
|
||||||
|
[garmentTypes.cropCrew]: 'STSW873',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const colorSKUs = {
|
||||||
|
black: 'C002'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collectionsSKUs = {
|
||||||
|
'flower': 1,
|
||||||
|
'foliage': 2,
|
||||||
|
'nature': 3,
|
||||||
|
'sky': 4,
|
||||||
|
'urban': 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const customisationSKUs = {
|
||||||
|
printArea: 'B',
|
||||||
|
tags: 'NT'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sizeSKUs = {
|
||||||
|
xs: 'XS',
|
||||||
|
s: 'S',
|
||||||
|
m: 'M',
|
||||||
|
l: 'L',
|
||||||
|
xl: 'XL',
|
||||||
|
xxl: '2XL',
|
||||||
|
xxxl: '3XL',
|
||||||
|
};
|
||||||
|
|
54
lib/helpers/skus.tsx
Normal file
54
lib/helpers/skus.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { baseArtworkNumber, collectionsSKUs, colorSKUs, customisationSKUs, garmentHandleKeys, garmentSKUs, garmentSizes, sizeSKUs } from "constants/sku";
|
||||||
|
|
||||||
|
type TitleInfo = Awaited<ReturnType<typeof extractInfoFromTitle>>;
|
||||||
|
|
||||||
|
const artworkNumberCompiler = (artworkNumber: string) => {
|
||||||
|
const length = artworkNumber.length
|
||||||
|
const slice = baseArtworkNumber.slice(0, length + 1)
|
||||||
|
return slice + artworkNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
const garmentHandleKeyMapper = (garmentKeys: string[]) => {
|
||||||
|
const garmentTitle = garmentKeys.join(' ');
|
||||||
|
const garmentKey = garmentHandleKeys[garmentTitle as keyof typeof garmentHandleKeys]
|
||||||
|
return garmentSKUs[garmentKey as keyof typeof garmentSKUs]
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractInfoFromTitle = (productTitle: string) => {
|
||||||
|
const title = productTitle.split(' ');
|
||||||
|
const collection = title[0]?.toLowerCase();
|
||||||
|
const garmentKeys = title.slice(2)
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
collection,
|
||||||
|
garmentTitle: garmentKeys.join(' '),
|
||||||
|
artworkNumber: title[1]?.replace('No.', ''),
|
||||||
|
garmentKeys,
|
||||||
|
collectionKey: collection!.replace('scape', ''),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectionSKUMapper = (titleInfo: TitleInfo) => {
|
||||||
|
const collectionSKU = collectionsSKUs[titleInfo.collectionKey as keyof typeof collectionsSKUs];
|
||||||
|
const artworkSKU = artworkNumberCompiler(titleInfo.artworkNumber!);
|
||||||
|
const garmentSKU = garmentHandleKeyMapper(titleInfo.garmentKeys);
|
||||||
|
|
||||||
|
return `SCSQ${collectionSKU}${artworkSKU}_${garmentSKU}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customisationSKUMapper = () =>
|
||||||
|
`${colorSKUs.black}_${customisationSKUs.printArea}_${customisationSKUs.tags}`
|
||||||
|
|
||||||
|
export const createProductSKUs = (productTitle: string) => {
|
||||||
|
const titleInfo = extractInfoFromTitle(productTitle);
|
||||||
|
const garmentKey = garmentHandleKeys[titleInfo.garmentTitle as keyof typeof garmentHandleKeys]
|
||||||
|
const getGarmentSizes = garmentSizes[garmentKey]
|
||||||
|
const customisationSKUs = customisationSKUMapper();
|
||||||
|
|
||||||
|
return getGarmentSizes?.map(size => {
|
||||||
|
const currentSizeSKU = sizeSKUs[size as keyof typeof sizeSKUs]
|
||||||
|
const collectionSKU = collectionSKUMapper(titleInfo)
|
||||||
|
|
||||||
|
return `${collectionSKU}_${currentSizeSKU}_${customisationSKUs}`
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user