PliWould/components/ProductCalculatorSelector.tsx

205 lines
5.1 KiB
TypeScript

import { Product, productPriceFor } from "@/lib/product";
import { dimensions_t } from "@/lib/dimensions";
import { useState, useEffect } from "react";
import { View, Text, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import PriceDisplay from "./Price";
import { AreaInput } from "./AreaInput";
import ProductList from "./ProductList";
import convert, { Length } from "convert";
import PercentDamage from "./PercentDamange";
import MeasurementUnitInput from "./MeasurementUnitInput";
import UnitChooser from "./UnitChooser";
export default function ProductCalculatorSelector() {
const [activeProduct, setActiveProduct] = useState(null as Product | null);
const [price, setPrice] = useState(0);
const [measurement, setMeasurement] = useState({
l: 0,
w: 0,
u: "ft",
} as dimensions_t);
const [percentDamage, setPercentDamange] = useState(0.0);
useEffect(
function () {
const iv = setInterval(function () {
if (!(activeProduct && measurement)) return;
setPrice(productPriceFor(activeProduct, measurement, percentDamage));
}, 50);
return function () {
clearInterval(iv);
};
},
[activeProduct, measurement, percentDamage]
);
function onMeasurementSet(dimensions: dimensions_t) {
setMeasurement(dimensions);
activeProduct &&
setPrice(productPriceFor(activeProduct, measurement, percentDamage));
}
function onLengthSet(l: number) {
setMeasurement({ ...measurement, l });
onMeasurementSet && onMeasurementSet({ ...measurement, l });
}
function onUnitChosen(unit: Length) {
setMeasurement({
...measurement,
u: unit,
});
}
function onSetPercentDamage(pct: number) {
setPercentDamange(pct);
}
function onProductSelected(product: Product) {
setActiveProduct(product);
setMeasurement({
l: convert(product.dimensions.l, product.dimensions.u).to(measurement.u),
u: measurement.u,
...("w" in measurement && "w" in product.dimensions
? {
w: convert(product.dimensions.w, product.dimensions.u).to(
measurement.u
),
u: measurement.u,
}
: {}),
});
}
return (
<SafeAreaView style={styles.wrapper}>
<PriceDisplay price={price} />
<View style={styles.inputAndUnitWrapper}>
<View style={styles.inputWrapper}>
{activeProduct ? (
"w" in activeProduct.dimensions ? (
<View style={{flex: 1, flexDirection: "row"}}>
<AreaInput
defaultValue={activeProduct.dimensions}
onMeasurementSet={onMeasurementSet}
widthLabel="enter width"
lengthLabel="enter length"
units={measurement.u}
/>
<UnitChooser
choices={["in", "ft"]}
onUnitSet={onUnitChosen}
defaultUnit={activeProduct.dimensions.u}
/>
</View>
) : (
<MeasurementUnitInput
defaultValue={activeProduct.dimensions.l}
onValueSet={onLengthSet}
onUnitSet={onUnitChosen}
defaultUnit={activeProduct.dimensions.u}
unitChoices={["ft", "in"]}
/>
)
) : (
<Text>Please select a product</Text>
)}
</View>
</View>
{activeProduct && (
<View style={styles.damageWrapper}>
<PercentDamage onSetPercentage={onSetPercentDamage} />
</View>
)}
<ProductList onProductSelected={onProductSelected} productType="lumber" />
</SafeAreaView>
);
}
export const styles = StyleSheet.create({
wrapper: {
overflow: "scroll",
},
bigPriceWrapper: {
alignContent: "center",
},
bigPrice: {
alignSelf: "center",
fontSize: 40,
marginTop: 100,
marginBottom: 100,
},
inputWrapper: {
flexDirection: "row",
alignItems: "flex-start",
verticalAlign: "middle",
},
unitSelector: {},
inputAndUnitWrapper: {
flexDirection: "row",
alignSelf: "center",
},
widthInput: {
width: 200,
borderWidth: 1,
borderRadius: 4,
borderColor: "grey",
padding: 4,
margin: 4,
fontSize: 30,
},
activeProduct: {
borderWidth: 2,
borderColor: "black",
borderStyle: "solid",
},
inactiveProduct: {},
titleContainer: {
flexDirection: "row",
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
},
productTileTouchable: {
margin: 10,
padding: 20,
backgroundColor: "grey",
},
productTileTouchableActive: {
borderWidth: 2,
borderStyle: "solid",
borderColor: "black",
margin: 10,
padding: 20,
},
productTileText: {
textAlign: "center",
color: "white",
},
productTileTextActive: {
textAlign: "center",
color: "black",
},
productTileCover: {
padding: 4,
},
damageWrapper: {
paddingVertical: 10,
paddingHorizontal: 10,
},
});