Skip to content

Commit

Permalink
variant list component
Browse files Browse the repository at this point in the history
  • Loading branch information
tobi-or-not-tobi committed Aug 1, 2024
1 parent 032021c commit 247b00b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 14 deletions.
1 change: 1 addition & 0 deletions libs/domain/product/variant-list/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './variant-list.component';
export * from './variant-list.styles';
103 changes: 89 additions & 14 deletions libs/domain/product/variant-list/variant-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,108 @@ import {
ProductListService,
ProductMixin,
} from '@oryx-frontend/product';
import { hydrate } from '@oryx-frontend/utilities';
import { LinkService, RouteType, RouterService } from '@oryx-frontend/router';
import { computed, hydrate, signalAware } from '@oryx-frontend/utilities';
import {
createSignal,
effect,
} from '@oryx-frontend/utilities/src/signals/core';
import { LitElement, TemplateResult, html } from 'lit';
import { repeat } from 'lit/directives/repeat.js';
import { variantListStyle } from './variant-list.styles';

@hydrate({ context: PRODUCT })
@signalAware()
export class ProductVariantListComponent extends ProductMixin(
LayoutMixin(LitElement)
) {
static styles = variantListStyle;

protected productListService = resolve(ProductListService);
protected productListPageService = resolve(ProductListPageService);

protected override render(): TemplateResult {
return html`
${this.renderLayout({
template: this.renderList(),
})}
`;
protected routerService = resolve(RouterService);
protected linkService = resolve(LinkService);

protected $variant = createSignal<string | undefined>(undefined);

protected $link = computed(() => {
const variantSku = this.$variant();
if (!variantSku) return;
return this.linkService.get({
type: RouteType.Product,
qualifier: { sku: variantSku },
});
});

protected route = effect(() => {
const link = this.$link();
if (link) {
this.routerService.navigate(link as any as string);
}
});

protected render(): TemplateResult | void {
const variants = this.$product()?.variants;

if (!variants || Object.keys(variants).length < 2) return;

return this.renderAttributeSelectors();
}

protected renderList(): TemplateResult {
console.log('variant list', this.$product()?.variants);
return html`
protected renderAttributeSelectors() {
const { variantDefinition, attributeNames } = this.$product() ?? {};
if (!variantDefinition) return;
const keys = Object.keys(variantDefinition);

return html` <form @change=${this.handleVariantChange}>
${repeat(
this.$product()?.variants ?? [],
(p) => p.sku,
(p) => html`<oryx-product-card .sku=${p.sku}></oryx-product-card>`
keys,
(key) =>
html`<h3>${attributeNames?.[key]}</h3>
${repeat(
variantDefinition[key],
(value) => html`
<oryx-toggle-icon>
<input
type="radio"
placeholder="make a11y happy"
.name=${key}
.value=${value}
?checked=${this.isChecked(key, value)}
/>
<span>${value}</span>
</oryx-toggle-icon>
`
)}</form>`
)}
`;
</form>`;
}

protected isChecked(key: string, value: string) {
const product = this.$product();
return product?.attributes?.[key] === value;
}

protected handleVariantChange(e: Event) {
const form = e.currentTarget as HTMLFormElement;
const formData = new FormData(form);

const selectedAttributes: Record<string, string> = {};
formData.forEach((value, key) => {
selectedAttributes[key] = value as string;
});

const { variants } = this.$product() ?? {};

if (!variants) return;
const matchingVariant = Object.keys(variants).find((sku) => {
const values = variants[sku];

return Object.keys(selectedAttributes).every(
(attrKey) => values![attrKey] === selectedAttributes[attrKey]
);
});
if (matchingVariant) this.$variant.set(matchingVariant);
}
}
8 changes: 8 additions & 0 deletions libs/domain/product/variant-list/variant-list.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { css } from 'lit';

export const variantListStyle = css`
:host {
display: grid;
gap: 8px;
}
`;

0 comments on commit 247b00b

Please sign in to comment.