Skip to content

Commit

Permalink
Adjust storefront for fashion products (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
JanChodorowski authored Nov 13, 2024
1 parent f40da3d commit c799539
Show file tree
Hide file tree
Showing 5 changed files with 468 additions and 294 deletions.
1 change: 1 addition & 0 deletions apps/storefront/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"next-auth": "5.0.0-beta.17",
"next-intl": "3.19.3",
"nextjs-routes": "2.1.0",
"nuqs": "2.1.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-error-boundary": "4.0.13",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
"use client";

import { createParser, parseAsString } from "nuqs";

import type {
Attribute,
AttributeType,
AttributeValue,
} from "@nimara/domain/objects/Attribute";
import type { Cart } from "@nimara/domain/objects/Cart";
import type {
ProductAvailability,
ProductVariant,
} from "@nimara/domain/objects/Product";
import type { User } from "@nimara/domain/objects/User";

export type AttributeDetails = {
name: string;
slug: string;
type: Attribute["type"];
values: AttributeValue[];
};

export type ChosenAttribute = { slug: string; value: string };

export type AttributePickerProps = {
availability: ProductAvailability;
cart: Cart | null;
user: (User & { accessToken: string | undefined }) | null;
variants: ProductVariant[];
};

export const getVariantSelectionAttributes = (
variantId: string,
variants: ProductVariant[],
): ChosenAttribute[] => {
const variant = variants.find(({ id }) => id === variantId);

return (
variant?.selectionAttributes
.map(({ slug, values }) => {
if (values.length) {
return {
slug,
value: values[0].slug,
};
}

return null;
})
.filter(Boolean) ?? []
);
};

export const getParserForAttributeType = (type: AttributeType) => {
switch (type) {
case "MULTISELECT":
return createParser({
parse: (value: string) => (value ? value.split(",") : []),
serialize: (values: string[]) => {
if (!Array.isArray(values)) {
return "";
}

return values.join(",");
},
}).withDefault([]);

case "DROPDOWN":
case "SWATCH":
return parseAsString.withDefault("");

default:
return parseAsString.withDefault("");
}
};

export const getAllNonSelectionAttributes = (variants: ProductVariant[]) => {
const allNonSelectionAttributes: AttributeDetails[] = [];

variants.forEach(({ nonSelectionAttributes }) => {
nonSelectionAttributes.forEach(
({
values,
type,
name,
slug,
}: {
name: string;
slug: string;
type: Attribute["type"];
values: AttributeValue[];
}) => {
if (slug && values?.length > 0) {
const attributeMatch = allNonSelectionAttributes.find(
(attribute) => attribute.slug === slug,
);

if (attributeMatch) {
const currentValuesSlug = attributeMatch.values.map(
({ slug }) => slug,
);

const newValues = values.filter(
({ slug }) => !currentValuesSlug.includes(slug),
);

attributeMatch.values.push(...newValues);
} else {
allNonSelectionAttributes.push({
slug,
values: [...values],
name,
type,
});
}
}
},
);
});

return allNonSelectionAttributes;
};

export const getAllSelectionAttributes = (variants: ProductVariant[]) => {
const allSelectionAttributes: AttributeDetails[] = [];

variants.forEach(({ selectionAttributes }) => {
selectionAttributes.forEach(
({
values,
type,
name,
slug,
}: {
name: string;
slug: string;
type: Attribute["type"];
values: AttributeValue[];
}) => {
if (slug && values?.length > 0) {
const attributeMatch = allSelectionAttributes.find(
(attribute) => attribute.slug === slug,
);

if (attributeMatch) {
const currentValuesSlug = attributeMatch.values.map(
({ slug }) => slug,
);

const newValues = values.filter(
({ slug }) => !currentValuesSlug.includes(slug),
);

attributeMatch.values.push(...newValues);
} else {
allSelectionAttributes.push({
slug,
values: [...values],
name,
type,
});
}
}
},
);
});

return allSelectionAttributes;
};

// ! currently unsued
export const isAttributeCombinationPossible = (
allVariants: ProductVariant[],
chosenAttributes: ChosenAttribute[],
) => {
if (chosenAttributes.length < 1) {
return true;
}

return allVariants.some((variant) =>
chosenAttributes.every(({ slug, value }) => {
const variantAttribute = variant.selectionAttributes.find(
(attr) => attr.slug === slug,
);

return variantAttribute?.values.some(
(attrValue) => attrValue.slug === value,
);
}),
);
};

export const validateValue = (
slug: string,
value: unknown,
allSelectionAttributes: Attribute[],
) => {
const attribute = allSelectionAttributes.find((attr) => attr.slug === slug);

if (!attribute) {
return false;
}

if (attribute.type === "MULTISELECT") {
return (
Array.isArray(value) &&
value.every((v) => attribute.values.some((av) => av.slug === v))
);
}

return value === "" || attribute.values.some((av) => av.slug === value);
};
Loading

0 comments on commit c799539

Please sign in to comment.