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, damage : number): number { if (Number.isNaN(damage)) damage = 0; const dim = matchDimensions(dimensions, this.dimensions); return ( dim.w ? dimensionArea(dim) / dimensionArea(this.dimensions) * this.pricePerUnit : (dim.l / this.dimensions.l) * this.pricePerUnit ) * (1.0 - damage); } 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 ${w}${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, ) } }