add svg icons. running into scroll issue. will upgrade packages.
This commit is contained in:
@ -1,22 +1,47 @@
|
||||
import { Product } from "../product";
|
||||
import { Id, Product, productPriceFor } from "../product";
|
||||
import uuid from "react-native-uuid"
|
||||
|
||||
describe("Product tests", () => {
|
||||
|
||||
it(`Length product gives correct price for a shorter length`, () => {
|
||||
const standard = new Product(20, { l: 4, u: "feet" });
|
||||
const comparison = standard.priceFor({ l: 2, u: "feet" });
|
||||
expect(comparison).toEqual(10);
|
||||
const standard : Product = {
|
||||
id: uuid.v4().valueOf() as Id,
|
||||
dimensions: {
|
||||
l: 5,
|
||||
u: "ft",
|
||||
},
|
||||
type: "lumber",
|
||||
pricePerUnit: 10,
|
||||
};
|
||||
const comparison = productPriceFor(standard, { l: 2, u: "feet" });
|
||||
expect(comparison).toEqual(4);
|
||||
});
|
||||
|
||||
it(`Length product gives correct price for a longer length`, () => {
|
||||
const standard = new Product(20, {l: 4, u : "feet"});
|
||||
const comparison = standard.priceFor({l : 8, u : "feet"});
|
||||
expect(comparison).toEqual(40);
|
||||
const standard : Product = {
|
||||
id: uuid.v4().valueOf() as Id,
|
||||
dimensions: {
|
||||
l: 5,
|
||||
u: "ft",
|
||||
},
|
||||
type: "lumber",
|
||||
pricePerUnit: 10,
|
||||
};
|
||||
const comparison = productPriceFor(standard, { l: 10, u: "feet" });
|
||||
expect(comparison).toEqual(20);
|
||||
});
|
||||
|
||||
it(`Length product gives correct price if different units`, () => {
|
||||
const standard = new Product(10, {l: 1, u : "feet"});
|
||||
const comparison = standard.priceFor({l : 24, u: "inch"});
|
||||
expect(comparison).toBeCloseTo(20, 4);
|
||||
const standard : Product = {
|
||||
id: uuid.v4().valueOf() as Id,
|
||||
dimensions: {
|
||||
l: 12,
|
||||
u: "in",
|
||||
},
|
||||
type: "lumber",
|
||||
pricePerUnit: 1,
|
||||
};
|
||||
const comparison = productPriceFor(standard, { l: 2, u: "feet" });
|
||||
expect(comparison).toBeCloseTo(2, 1);
|
||||
});
|
||||
});
|
@ -33,6 +33,8 @@ export const dimensionType = (d: dimensions_t) => isArea(d) ? "area" : "length";
|
||||
};
|
||||
}
|
||||
|
||||
const FACTOR = 0.1309;
|
||||
|
||||
/**
|
||||
* Gets the total length of a carpet roll based on a diameter
|
||||
* @param outerDiameter Outer diameter of the carpet roll
|
||||
@ -43,9 +45,15 @@ export function diameterToLength(outerDiameter: length_t, innerDiameter: length_
|
||||
if (outerDiameter.u !== innerDiameter.u) {
|
||||
throw new Error("diameter units must match!")
|
||||
}
|
||||
const thickness = (((outerDiameter.l - innerDiameter.l) / 2) / numRings);
|
||||
const l = FACTOR * numRings * (innerDiameter.l + outerDiameter.l);
|
||||
return {
|
||||
l: Math.PI * (Math.pow(outerDiameter.l, 2) / 4) - (Math.pow(innerDiameter.l, 2) / 4) / thickness,
|
||||
u: innerDiameter.u,
|
||||
};
|
||||
l,
|
||||
u: outerDiameter.u
|
||||
}
|
||||
}
|
||||
|
||||
export function dimensionsDisplay(d : dimensions_t) {
|
||||
if ("w" in d) {
|
||||
return `${d.w} x ${d.l} ${d.u}`
|
||||
}
|
||||
}
|
135
lib/product.ts
135
lib/product.ts
@ -1,5 +1,5 @@
|
||||
import uuid from "react-native-uuid";
|
||||
import { dimensions_t, area_t } from "./dimensions";
|
||||
import { dimensions_t, area_t, dimensionsDisplay } from "./dimensions";
|
||||
import { matchDimensions } from "./dimensions";
|
||||
import { Area, Length, Unit } from "convert";
|
||||
|
||||
@ -8,79 +8,96 @@ 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,
|
||||
}
|
||||
id?: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
description?: string;
|
||||
depth?: string;
|
||||
currency?: Currency;
|
||||
[index: string]: any;
|
||||
};
|
||||
|
||||
export function dimensionArea(d: dimensions_t) {
|
||||
return "w" in d ? d.w * d.l : 0;
|
||||
return "w" in d ? d.w * d.l : 0;
|
||||
}
|
||||
|
||||
export const PRODUCT_TYPES = [
|
||||
"lumber",
|
||||
"area_rug",
|
||||
] as const;
|
||||
|
||||
export type product_type_t = typeof PRODUCT_TYPES[number];
|
||||
export const PRODUCT_TYPES = ["lumber", "area_rug"] as const;
|
||||
|
||||
export type product_type_t = (typeof PRODUCT_TYPES)[number];
|
||||
|
||||
export type Product = {
|
||||
id?: Id;
|
||||
pricePerUnit: number;
|
||||
dimensions: dimensions_t;
|
||||
type: product_type_t;
|
||||
attributes?: ProductAttributes;
|
||||
id?: Id;
|
||||
pricePerUnit: number;
|
||||
dimensions: dimensions_t;
|
||||
type: product_type_t;
|
||||
attributes?: ProductAttributes;
|
||||
};
|
||||
|
||||
export type LumberProduct = Product & {
|
||||
type: "lumber"
|
||||
}
|
||||
type: "lumber";
|
||||
};
|
||||
|
||||
export type AreaRugProduct = Product & {
|
||||
type: "lumber"
|
||||
type: "lumber";
|
||||
};
|
||||
|
||||
export function productPriceFor(
|
||||
product: Product,
|
||||
dimensions: dimensions_t,
|
||||
damage: number = 0
|
||||
): number {
|
||||
if (Number.isNaN(damage)) damage = 0;
|
||||
const dim = matchDimensions(dimensions, product.dimensions);
|
||||
return (
|
||||
(dim.w
|
||||
? (dimensionArea(dim) / dimensionArea(product.dimensions)) *
|
||||
product.pricePerUnit
|
||||
: (dim.l / product.dimensions.l) * product.pricePerUnit) *
|
||||
(1.0 - damage)
|
||||
);
|
||||
}
|
||||
|
||||
export function productPriceFor(product : Product, dimensions: dimensions_t, damage: number = 0): number {
|
||||
if (Number.isNaN(damage)) damage = 0;
|
||||
const dim = matchDimensions(dimensions, product.dimensions);
|
||||
return (
|
||||
dim.w ? dimensionArea(dim) / dimensionArea(product.dimensions) * product.pricePerUnit
|
||||
: (dim.l / product.dimensions.l) * product.pricePerUnit
|
||||
) * (1.0 - damage);
|
||||
export function priceDisplay(price: number) {
|
||||
return price.toLocaleString(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
export function priceDisplay(price : number) {
|
||||
return price.toLocaleString(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
export function pricePerUnitDisplay(product: Product) {
|
||||
const p = priceDisplay(product.pricePerUnit);
|
||||
const { l, u } = product.dimensions;
|
||||
const w = (product.dimensions as area_t).w || null;
|
||||
const d = w ? `${l}${u} x ${w}${u}` : `${l}${u}`;
|
||||
return `$${p} per ${d}`;
|
||||
}
|
||||
|
||||
export function attributesAsList(attributes: ProductAttributes) {
|
||||
return Object.entries(attributes).map(([key, value]) => {
|
||||
return { key, value };
|
||||
});
|
||||
}
|
||||
|
||||
export function productLabel(
|
||||
product: Product,
|
||||
{ pricing }: { pricing: boolean } = { pricing: false }
|
||||
) {
|
||||
const n = product.attributes?.name || `Product ${product.id}`;
|
||||
const p = priceDisplay(product.pricePerUnit);
|
||||
const d = dimensionsDisplay(product.dimensions);
|
||||
if (!pricing) {
|
||||
return n;
|
||||
}
|
||||
return `${n} ($${p} per ${d})`;
|
||||
}
|
||||
|
||||
export function removeAttribute(
|
||||
attributes: { [key: string]: any },
|
||||
key: string
|
||||
) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(attributes).filter(([k, v]) => {
|
||||
k == key;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function pricePerUnitDisplay(product : Product) {
|
||||
const p = priceDisplay(product.pricePerUnit);
|
||||
const { l, u } = product.dimensions;
|
||||
const w = (product.dimensions as area_t).w || null;
|
||||
const d = w ? `${l}${u} x ${w}${u}` : `${l}${u}`;
|
||||
return `$${p} per ${d}`
|
||||
}
|
||||
|
||||
export function attributesAsList(attributes : {[key:string]: any}) {
|
||||
return Object.entries(attributes).map(([key, value]) => {
|
||||
return { key, value }
|
||||
})
|
||||
}
|
||||
|
||||
export function removeAttribute(attributes: {[key: string]: any}, key: string) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(attributes).filter(
|
||||
([k, v]) => {
|
||||
k == key;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
15
lib/util.ts
15
lib/util.ts
@ -0,0 +1,15 @@
|
||||
function waitForWindow(): Promise<Window> {
|
||||
return new Promise((resolve) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
resolve(window);
|
||||
} else {
|
||||
const intervalId = setInterval(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
clearInterval(intervalId);
|
||||
resolve(window);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user