PliWould/lib/product.ts

133 lines
3.3 KiB
TypeScript

import uuid from "react-native-uuid";
import convert, { Area, Length } from "convert";
import { Transform } from "class-transformer";
export type Id = string;
export type Currency = "USD";
export type ProductAttributes = {
id?: string,
name?: string,
image?: string,
description?: string,
depth?: string,
currency?: Currency,
// [index:string]: any,
}
export type length_t = {
l: number, u: Length
}
export type area_t = length_t & {
w: number,
}
export type dimensions_t = area_t | length_t;
export type ProductData = {
id?: Id,
pricePerUnit: number,
dimensions: dimensions_t,
attributes?: ProductAttributes,
};
export type product_type_t = "area" | "length";
export const isArea = (d: dimensions_t) => ("width" in d);
export const isLength = (d: dimensions_t) => (!("width" in d));
export const dimensionType = (d: dimensions_t) => isArea(d) ? "area" : "length"
export function matchDimensions(d1: dimensions_t, d2: dimensions_t) {
if (!
(
(isArea(d1) && isArea(d2)) ||
(isLength(d1) && isLength(d2))
)
) {
throw new Error(`Dimension mismatch: ${JSON.stringify(d1)} / ${JSON.stringify(d1)}`);
}
return {
l: convert(d1.l, d1.u).to(d2.u),
u: d2.u,
...(
"w" in d1 ?
{ w: convert(d1.w, d1.u).to(d2.u), }
: {}
)
}
}
export function dimensionArea(d: dimensions_t) {
return "w" in d ? d.w * d.l : 0;
}
export class Product {
public id? : Id;
constructor(public pricePerUnit: number, public dimensions: dimensions_t, public attributes: ProductAttributes = {},
id?: Id,
) {
this.id = id || uuid.v4().toString();
}
public priceFor(dimensions: dimensions_t): number {
const dim = matchDimensions(dimensions, this.dimensions);
return (
dim.w ? dimensionArea(dim) / dimensionArea(this.dimensions) * this.pricePerUnit
: (dim.l / this.dimensions.l) * this.pricePerUnit
)
}
get priceDisplay() {
return this.pricePerUnit.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
}
get pricePerUnitDisplay() {
const p = this.priceDisplay;
const {l, u} = this.dimensions;
const w = (this.dimensions as area_t).w || null;
const d = w ? `${l}${u} x ${l}${u}` : `${l}${u}`;
return `$${p} per ${d}`
}
get attributesAsList() {
return Object.entries(this.attributes).map(([key, value]) => {
return { key, value }
})
}
public removeAttribute(key: string) {
this.attributes = Object.fromEntries(
Object.entries(this.attributes).filter(
([k, v]) => {
k == key;
}
)
);
}
get asObject() : ProductData {
return {
id: this.id,
pricePerUnit: this.pricePerUnit,
dimensions: this.dimensions,
attributes: this.attributes,
}
}
static fromObject({id, pricePerUnit, dimensions, attributes} : ProductData) {
return new Product(
pricePerUnit,
dimensions,
attributes,
id,
)
}
}