move away from ehemer to resolve recursive loop.
This commit is contained in:
@ -4,21 +4,20 @@ import { Product } from "../product";
|
||||
describe("Product tests", () => {
|
||||
|
||||
it(`Length product gives correct price for a shorter length`, () => {
|
||||
const standard = new Product(20, length("foot", 4));
|
||||
const comparison = standard.priceFor(length("foot", 2));
|
||||
const standard = new Product(20, { l: 4, u: "feet" });
|
||||
const comparison = standard.priceFor({ l: 2, u: "feet" });
|
||||
expect(comparison).toEqual(10);
|
||||
});
|
||||
|
||||
it(`Length product gives correct price for a longer length`, () => {
|
||||
const standard = new Product(20, length("foot", 4));
|
||||
const comparison = standard.priceFor(length("foot", 8));
|
||||
const standard = new Product(20, {l: 4, u : "feet"});
|
||||
const comparison = standard.priceFor({l : 8, u : "feet"});
|
||||
expect(comparison).toEqual(40);
|
||||
});
|
||||
|
||||
it(`Length product gives correct price if different units`, () => {
|
||||
const standard = new Product(10, length("foot", 1));
|
||||
const comparison = standard.priceFor(length("inch", 24));
|
||||
expect(comparison).toEqual(20);
|
||||
const standard = new Product(10, {l: 1, u : "feet"});
|
||||
const comparison = standard.priceFor({l : 24, u: "inch"});
|
||||
expect(comparison).toBeCloseTo(20, 4);
|
||||
});
|
||||
|
||||
});
|
103
lib/product.ts
103
lib/product.ts
@ -1,22 +1,10 @@
|
||||
import {length as en_length, area as en_area} from "enheter"
|
||||
import {Measure, LengthUnit, AreaUnit, } from "enheter"
|
||||
import uuid from "react-native-uuid";
|
||||
import convert, { Area, Length } from "convert";
|
||||
|
||||
export type Id = string;
|
||||
|
||||
export type Currency = "USD";
|
||||
|
||||
export const CURRENCY_SYMBOLS : Map<"USD", string> = {
|
||||
"USD": "$",
|
||||
};
|
||||
|
||||
export class Price {
|
||||
constructor(public currency : Currency, public value : number) {}
|
||||
public toString() {
|
||||
const sym = CURRENCY_SYMBOLS.get(this.currency);
|
||||
return `${sym} ${Math.round(this.value)}`;
|
||||
}
|
||||
}
|
||||
|
||||
export type ProductAttributes = {
|
||||
id?: string,
|
||||
name?: string,
|
||||
@ -24,35 +12,88 @@ export type ProductAttributes = {
|
||||
description?: string,
|
||||
depth?: string,
|
||||
currency?: Currency,
|
||||
[key:string]: any,
|
||||
// [index:string]: any,
|
||||
}
|
||||
|
||||
export type ProductData = {
|
||||
id?: Id,
|
||||
pricePerUnit: number,
|
||||
measurement: {
|
||||
unit: string,
|
||||
value: number,
|
||||
dimension: number,
|
||||
},
|
||||
attributes?: ProductAttributes,
|
||||
};
|
||||
|
||||
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 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 class Product {
|
||||
public id : string;
|
||||
constructor(public pricePerUnit : number, public measurement : Measure<"length" | "area">, public attributes : ProductAttributes = {}) {
|
||||
public id: string;
|
||||
public area?: area_t;
|
||||
public length?: length_t;
|
||||
public presentUnits: Length;
|
||||
|
||||
constructor(public pricePerUnit: number, dimensions: dimensions_t, public attributes: ProductAttributes = {},) {
|
||||
this.id = attributes.id || uuid.v4().toString();
|
||||
this.presentUnits = dimensions.u;
|
||||
if ("w" in dimensions) {
|
||||
this.area = {
|
||||
l: convert(dimensions.l, dimensions.u).to("meter"),
|
||||
w: convert(dimensions.w, dimensions.u).to("meter"),
|
||||
u: "meter"
|
||||
}
|
||||
} else {
|
||||
this.length = {
|
||||
l: convert(dimensions.l, dimensions.u).to("meter"),
|
||||
u: "meter"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public priceFor(measurement : Measure<"length" | "area">): number {
|
||||
const ratio = measurement.convertTo(this.measurement.unit).divideBy(this.measurement).value;
|
||||
return this.pricePerUnit * ratio
|
||||
}
|
||||
|
||||
get isArea() {
|
||||
return this.measurement.unit.dimension.length === 2;
|
||||
}
|
||||
|
||||
get isLength() {
|
||||
return this.measurement.unit.dimension.length === 1;
|
||||
public priceFor(dimensions: dimensions_t): number {
|
||||
if (this.area && "w" in dimensions) {
|
||||
const thisA = this.area.l * this.area.w;
|
||||
const otherA = convert(
|
||||
dimensions.w,
|
||||
dimensions.u
|
||||
).to("meter") * convert(
|
||||
dimensions.l,
|
||||
dimensions.u
|
||||
).to("meter");
|
||||
return (otherA / thisA) * this.pricePerUnit;
|
||||
} if (this.length) {
|
||||
const thisL = this.length.l;
|
||||
const otherL = convert(
|
||||
dimensions.l,
|
||||
dimensions.u
|
||||
).to("meter");
|
||||
return (otherL / thisL) * this.pricePerUnit;
|
||||
}
|
||||
throw new Error(`Invalid dimensions: ${dimensions}`);
|
||||
}
|
||||
|
||||
get attributesAsList() {
|
||||
return Object.entries(this.attributes).map(([key, value]) => {
|
||||
return {key, value}
|
||||
return { key, value }
|
||||
})
|
||||
}
|
||||
|
||||
public removeAttribute(key : string) {
|
||||
delete this.attributes[key]
|
||||
public removeAttribute(key: string) {
|
||||
delete this.attributes[key];
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ import { PropsWithChildren, ReactElement } from "react";
|
||||
import { Provider } from "react-redux";
|
||||
import { setupStore, RootState } from "@/app/store";
|
||||
import { Product } from "@/lib/product";
|
||||
import React from "react";
|
||||
|
||||
export interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
|
||||
preloadedState?: Partial<RootState>;
|
||||
@ -19,7 +18,7 @@ export function renderWithProviders(
|
||||
) {
|
||||
const {
|
||||
// Automatically create a store instance if no store was passed in
|
||||
store = setupStore(preloadedState as Partial<RootState>),
|
||||
store = setupStore(preloadedState),
|
||||
...renderOptions
|
||||
} = extendedRenderOptions;
|
||||
|
||||
|
Reference in New Issue
Block a user