134 lines
3.4 KiB
TypeScript
134 lines
3.4 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, 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,
|
|
)
|
|
}
|
|
} |