good enough for government (or habitat) work
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import { MeasurementInput } from "./MeasurementInput";
|
||||
import { area_t, dimensions_t } from "@/lib/product";
|
||||
import { useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
|
||||
export type AreaInputProps = {
|
||||
onMeasurementSet?: (area : dimensions_t) => any,
|
||||
@ -12,7 +12,7 @@ export type AreaInputProps = {
|
||||
|
||||
export function AreaInput({onMeasurementSet, lengthLabel, widthLabel, defaultValue} : AreaInputProps) {
|
||||
|
||||
defaultValue = defaultValue || {l: 0, w: 0, u: "foot"}
|
||||
defaultValue = defaultValue || {l: 0, w: 0, u: "ft"}
|
||||
|
||||
const [area, setArea] = useState(defaultValue)
|
||||
|
||||
@ -39,19 +39,23 @@ export function AreaInput({onMeasurementSet, lengthLabel, widthLabel, defaultVal
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.areaInputWrapper}>
|
||||
<MeasurementInput
|
||||
units={area.u}
|
||||
defaultValue={area.l}
|
||||
defaultValue={{l: area.l, u: area.u}}
|
||||
onValueSet={doOnLengthSet}
|
||||
label={lengthLabel}
|
||||
/>
|
||||
<MeasurementInput
|
||||
units={area.u}
|
||||
defaultValue={area.w}
|
||||
defaultValue={{l: area.w, u: area.u}}
|
||||
onValueSet={doOnWidthSet}
|
||||
label={widthLabel}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
areaInputWrapper: {
|
||||
flexDirection: "row"
|
||||
}
|
||||
})
|
@ -1,5 +1,6 @@
|
||||
import { dimensions_t, length_t } from "@/lib/product";
|
||||
import { Length } from "convert";
|
||||
import { useState } from "react";
|
||||
import { StyleSheet, Text, TextInput, View } from "react-native";
|
||||
|
||||
export type t_length_unit = "foot" | "inch"
|
||||
@ -11,8 +12,12 @@ export type MeasurementInputProps = {
|
||||
}
|
||||
|
||||
export function MeasurementInput({onValueSet, defaultValue, label}: MeasurementInputProps) {
|
||||
1
|
||||
|
||||
const [mValue, setMValue] = useState(defaultValue)
|
||||
const defValue = Number.isNaN(defaultValue.l) ? 0 : defaultValue.l
|
||||
|
||||
function doOnValueSet(value : string) {
|
||||
setMValue(mValue);
|
||||
const iVal = parseFloat(value) || parseInt(value);
|
||||
onValueSet && onValueSet({
|
||||
...defaultValue,
|
||||
@ -20,10 +25,10 @@ export function MeasurementInput({onValueSet, defaultValue, label}: MeasurementI
|
||||
})
|
||||
}
|
||||
|
||||
const sDefValue = new String(defaultValue.l).valueOf()
|
||||
const sDefValue = new String(defValue).valueOf()
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.inputWrapper}>
|
||||
<TextInput
|
||||
clearTextOnFocus={true}
|
||||
defaultValue={sDefValue}
|
||||
@ -32,14 +37,17 @@ export function MeasurementInput({onValueSet, defaultValue, label}: MeasurementI
|
||||
style={styles.lengthInput}
|
||||
aria-label={label || "Enter measurement"}
|
||||
/>
|
||||
<Text style={styles.unitHints}>{defaultValue.u}</Text>
|
||||
<Text style={styles.unitHints}>{mValue.u}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
inputWrapper: {
|
||||
alignItems: "flex-start",
|
||||
flexDirection: "row"
|
||||
},
|
||||
unitHints: {
|
||||
fontSize: 30,
|
||||
padding: 10,
|
||||
},
|
||||
lengthInput: {
|
||||
@ -48,7 +56,7 @@ const styles = StyleSheet.create({
|
||||
borderColor: "grey",
|
||||
padding: 4,
|
||||
margin: 4,
|
||||
fontSize: 30,
|
||||
width: 200,
|
||||
fontSize: 25,
|
||||
width: 100,
|
||||
},
|
||||
})
|
44
components/PercentDamange.tsx
Normal file
44
components/PercentDamange.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { StyleSheet, Text, TextInput, View } from "react-native";
|
||||
import Slider from '@react-native-community/slider';
|
||||
import { useState } from "react";
|
||||
|
||||
type PercentDamageProps = {
|
||||
onSetPercentage: (percent: number) => any;
|
||||
}
|
||||
|
||||
export default function PercentDamage ({onSetPercentage} : PercentDamageProps) {
|
||||
const [damage, setDamage] = useState(0);
|
||||
function doOnChangeText (val : number) {
|
||||
setDamage(val);
|
||||
onSetPercentage(val / 100);
|
||||
}
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<Slider
|
||||
value={damage}
|
||||
minimumValue={0}
|
||||
maximumValue={100}
|
||||
step={5}
|
||||
onValueChange={doOnChangeText}
|
||||
/>
|
||||
<Text style={styles.label}> {damage}% Damage</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
padding: 5,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
margin: 5,
|
||||
padding: 5,
|
||||
borderWidth: 2,
|
||||
borderColor: "lightgrey",
|
||||
borderStyle: "solid",
|
||||
},
|
||||
label: {
|
||||
margin: 5,
|
||||
}
|
||||
})
|
@ -32,7 +32,7 @@ export const styles = StyleSheet.create({
|
||||
bigPrice: {
|
||||
alignSelf: "center",
|
||||
fontSize: 40,
|
||||
marginTop: 100,
|
||||
marginBottom: 100,
|
||||
marginTop: 50,
|
||||
marginBottom: 50,
|
||||
}
|
||||
});
|
@ -1,48 +1,75 @@
|
||||
import { useAppSelector } from '@/app/store';
|
||||
import { selectProducts } from '@/features/product/productSlice';
|
||||
import { Product, dimensions_t } from '@/lib/product';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { View, Text, TextInput, Button, FlatList, StyleSheet } from 'react-native';
|
||||
import { TouchableHighlight } from 'react-native-gesture-handler';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import PriceDisplay from './Price';
|
||||
import { AreaInput } from './AreaInput';
|
||||
import { MeasurementInput } from './MeasurementInput';
|
||||
import ProductList from './ProductList';
|
||||
import UnitChooser from './UnitChooser';
|
||||
import { Length } from 'convert';
|
||||
import convert, { Length } from 'convert';
|
||||
import PercentDamage from './PercentDamange';
|
||||
|
||||
|
||||
export default function ProductCalculatorSelector() {
|
||||
|
||||
const products = useAppSelector(selectProducts);
|
||||
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 [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(
|
||||
activeProduct.priceFor(measurement)
|
||||
activeProduct.priceFor(measurement, percentDamage)
|
||||
)
|
||||
}, 50);
|
||||
return function () {
|
||||
clearInterval(iv);
|
||||
};
|
||||
}, [activeProduct, measurement]);
|
||||
}, [activeProduct, measurement, percentDamage]);
|
||||
|
||||
function onMeasurementSet(dimensions: dimensions_t) {
|
||||
setMeasurement(dimensions);
|
||||
activeProduct && setPrice(
|
||||
activeProduct.priceFor(measurement, percentDamage)
|
||||
)
|
||||
}
|
||||
|
||||
function onUnitChosen(unit : Length) {
|
||||
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} />
|
||||
@ -73,7 +100,14 @@ export default function ProductCalculatorSelector() {
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
<ProductList onProductSelected={setActiveProduct} />
|
||||
{activeProduct &&
|
||||
(<View >
|
||||
<PercentDamage
|
||||
onSetPercentage={onSetPercentDamage}
|
||||
/>
|
||||
</View>)
|
||||
}
|
||||
<ProductList onProductSelected={onProductSelected} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
@ -81,6 +115,7 @@ export default function ProductCalculatorSelector() {
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
overflow: "scroll"
|
||||
},
|
||||
bigPriceWrapper: {
|
||||
alignContent: "center",
|
||||
|
@ -39,8 +39,8 @@ export const ProductEditor = ({}) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<h1 style={styles.h1}>Edit Products</h1>
|
||||
<SafeAreaView style={{overflow: "scroll"}}>
|
||||
<Text>Edit Products</Text>
|
||||
<FlatList
|
||||
data={products}
|
||||
keyExtractor={(p, i) => `product-${p.id}`}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { Id, Product, dimensions_t } from "@/lib/product"
|
||||
import { useState } from "react"
|
||||
import { Button, FlatList, StyleSheet, Text, Touchable, TouchableHighlight, View } from "react-native"
|
||||
import { Button, FlatList, StyleSheet, Text, TextInput, Touchable, TouchableHighlight, View } from "react-native"
|
||||
import { ProductAttributeEditor } from "./ProductAttributeEditor";
|
||||
import { TextInput } from "react-native-gesture-handler";
|
||||
import { useAppSelector } from "@/app/store";
|
||||
import rfdc from "rfdc";
|
||||
import SelectDropdown from "react-native-select-dropdown";
|
||||
import { Dropdown } from 'react-native-element-dropdown';
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Length } from "convert";
|
||||
|
||||
export type ProductAddedFunc = () => any;
|
||||
export type ProductDeletedFunc = (product_id: Id) => any;
|
||||
@ -50,9 +48,9 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
props.onPriceUpdated && props.onPriceUpdated(product.id, parseFloat(pricePerUnit) || parseInt(pricePerUnit));
|
||||
}
|
||||
|
||||
function onUnitsChanged(newUnits: "foot" | "inch") {
|
||||
function onUnitsChanged(newUnits: Length) {
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
...(product.dimensions as dimensions_t),
|
||||
u: newUnits,
|
||||
})
|
||||
}
|
||||
@ -60,16 +58,16 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
function onChangeLength(len: string) {
|
||||
const l = parseFloat(len) || parseInt(len);
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
...(product.dimensions as dimensions_t),
|
||||
l,
|
||||
})
|
||||
}
|
||||
|
||||
function onChangeWidth(width: string) {
|
||||
const w = parseFloat(width) || parseInt(width);
|
||||
const w = width.length == 0 ? null : parseFloat(width) || parseInt(width);
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
w,
|
||||
...(product.dimensions as dimensions_t),
|
||||
...(w ? {w} : {}),
|
||||
})
|
||||
}
|
||||
|
||||
@ -77,31 +75,36 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
props.onProductDeleted && props.onProductDeleted(product.id);
|
||||
}
|
||||
|
||||
const length = new String(product.area?.l || product.length?.l || "0") as string;
|
||||
const width = new String(product.area?.w || "") as string;
|
||||
const dimension = product.area?.u || product.length?.u || "foot";
|
||||
const length = new String(product.dimensions.l || product.dimensions.l || "0") as string;
|
||||
const width = new String(product.dimensions.w || "") as string;
|
||||
const dimension = product.dimensions.u || product.dimensions.u || "foot";
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
onPress={() => setShowAttributes(!showAttributes)}
|
||||
aria-label="Product Item"
|
||||
style={styles.productItemName}
|
||||
>
|
||||
<Text style={styles.productNameText}>{product.attributes.name || `Product ${product.id}`}</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
onPress={() => onDeleteProduct()}
|
||||
aria-label="delete product"
|
||||
style={styles.deleteProductHighlight}
|
||||
<View style={styles.productListHeader}>
|
||||
<TouchableHighlight
|
||||
onPress={() => setShowAttributes(!showAttributes)}
|
||||
aria-label="Product Item"
|
||||
style={styles.productItemName}
|
||||
>
|
||||
<Ionicons style={styles.deleteProductButton} name="trash-outline" />
|
||||
</TouchableHighlight>
|
||||
<Text style={styles.productNameText}>{product.attributes.name || `Product ${product.id}`}</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
onPress={() => onDeleteProduct()}
|
||||
aria-label="delete product"
|
||||
style={styles.deleteProductHighlight}
|
||||
>
|
||||
<Ionicons
|
||||
style={styles.deleteProductButton}
|
||||
name="trash-outline"
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
{showAttributes &&
|
||||
(
|
||||
<View>
|
||||
<View style={styles.detailsWrapper}>
|
||||
<View style={styles.priceSpecWrapper}>
|
||||
<Text style={styles.priceLabel}></Text>
|
||||
<Text style={styles.priceLabel}>$</Text>
|
||||
<TextInput inputMode="decimal"
|
||||
defaultValue={new String(product.pricePerUnit) as string}
|
||||
aria-label="price per unit"
|
||||
@ -109,14 +112,18 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
style={styles.priceInput}
|
||||
/>
|
||||
<Text style={styles.per}>per</Text>
|
||||
<Text style={styles.unitsLabel}>Units: </Text>
|
||||
<select
|
||||
onChange={(e) => onUnitsChanged(e.target.value as "foot" | "inch")}
|
||||
<Dropdown
|
||||
data={[
|
||||
{label: "feet", value: "ft"},
|
||||
{label: "inches", value: "in"},
|
||||
]}
|
||||
style={styles.unitsSelect}
|
||||
aria-label="units">
|
||||
<option value="foot" selected={dimension === "foot"}>feet</option>
|
||||
<option value="inch" selected={dimension === "inch"}>inches</option>
|
||||
</select>
|
||||
mode="modal"
|
||||
labelField="label"
|
||||
valueField="value"
|
||||
value={product.dimensions.u || "ft"}
|
||||
onChange={(item) => onUnitsChanged(item.value as Length)}
|
||||
/>
|
||||
<TextInput
|
||||
inputMode="decimal"
|
||||
defaultValue={length}
|
||||
@ -124,7 +131,7 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
style={styles.lengthInput}
|
||||
aria-label="length"
|
||||
/>
|
||||
<Text>x</Text>
|
||||
<Text style={{flex: 1,}}>x</Text>
|
||||
<TextInput
|
||||
inputMode="decimal"
|
||||
defaultValue={width}
|
||||
@ -158,33 +165,50 @@ export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
const styles = StyleSheet.create({
|
||||
deleteProductHighlight: {
|
||||
|
||||
padding: 5,
|
||||
borderWidth: 1,
|
||||
},
|
||||
deleteProductButton: {
|
||||
fontSize: 20,
|
||||
},
|
||||
detailsWrapper: {
|
||||
|
||||
},
|
||||
priceSpecWrapper: {
|
||||
|
||||
flexDirection: "row",
|
||||
},
|
||||
priceLabel: {
|
||||
|
||||
},
|
||||
priceInput: {
|
||||
|
||||
flex: 1,
|
||||
borderWidth: 2,
|
||||
borderColor: "lightgrey",
|
||||
borderStyle: "solid",
|
||||
},
|
||||
per: {
|
||||
|
||||
padding: 5,
|
||||
},
|
||||
unitsLabel: {
|
||||
|
||||
unitsLabel: {
|
||||
},
|
||||
unitsSelect: {
|
||||
|
||||
flex: 1,
|
||||
padding: 5,
|
||||
},
|
||||
lengthInput: {
|
||||
|
||||
flex: 1,
|
||||
borderWidth: 2,
|
||||
borderColor: "lightgrey",
|
||||
borderStyle: "solid",
|
||||
},
|
||||
widthInput: {
|
||||
|
||||
flex: 1,
|
||||
borderWidth: 2,
|
||||
borderColor: "lightgrey",
|
||||
borderStyle: "solid",
|
||||
},
|
||||
productListHeader: {
|
||||
flexDirection: "row",
|
||||
padding: 5,
|
||||
},
|
||||
productNameText: {
|
||||
paddingLeft: 10,
|
||||
|
@ -1,47 +1,46 @@
|
||||
import { FlatList, StyleSheet, Text, TouchableHighlight } from "react-native";
|
||||
import { FlatList, ScrollView, StyleSheet, Text, TouchableHighlight } from "react-native";
|
||||
import { ProductTile } from "./ProductTile";
|
||||
import { Product } from "@/lib/product";
|
||||
import { useState } from "react";
|
||||
import { Id, Product } from "@/lib/product";
|
||||
import { Key, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectProducts } from "@/features/product/productSlice";
|
||||
import { useAppSelector } from "@/app/store";
|
||||
|
||||
export type ProductSelectionProps = {
|
||||
onProductSelected?: (product : Product) => any;
|
||||
onProductSelected?: (product: Product) => any;
|
||||
}
|
||||
|
||||
export default function ProductList ({onProductSelected} : ProductSelectionProps) {
|
||||
export default function ProductList({ onProductSelected }: ProductSelectionProps) {
|
||||
|
||||
const products = useSelector(selectProducts);
|
||||
const [activeProduct, setActiveProduct] = useState(null as null | Product);
|
||||
const products = useAppSelector(selectProducts).filter(p => (!!p.dimensions));
|
||||
|
||||
const [activeProduct, setActiveProduct] = useState(null as null | Product);
|
||||
function doOnProductSelected(product: Product) {
|
||||
setActiveProduct(product);
|
||||
onProductSelected && onProductSelected(product);
|
||||
}
|
||||
|
||||
function doOnProductSelected(product : Product) {
|
||||
setActiveProduct(product);
|
||||
onProductSelected && onProductSelected(product);
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
data={products}
|
||||
style={styles.productSelectorFlatList}
|
||||
renderItem={({ item }) => {
|
||||
return (
|
||||
<ScrollView scrollToOverflowEnabled={true}>
|
||||
{products.map(product => {
|
||||
return (
|
||||
<ProductTile
|
||||
product={item}
|
||||
onProductSelected={doOnProductSelected}
|
||||
isActive={activeProduct === item}
|
||||
/>
|
||||
<ProductTile
|
||||
product={product}
|
||||
onProductSelected={doOnProductSelected}
|
||||
isActive={activeProduct === product}
|
||||
key={product.id}
|
||||
/>
|
||||
);
|
||||
} } />
|
||||
|
||||
)
|
||||
})}
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
productSelectorFlatList: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
},
|
||||
|
||||
|
||||
productSelectorFlatList: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
},
|
||||
|
||||
})
|
@ -6,49 +6,50 @@ export type OnProductSelectedFunc = (product : Product) => any;
|
||||
|
||||
type MyStyle = StyleProp<AnimatedStyle<StyleProp<ViewStyle>>>;
|
||||
|
||||
type StyleSpec = {
|
||||
highlight?: MyStyle,
|
||||
text?: MyStyle,
|
||||
image?: MyStyle,
|
||||
}
|
||||
|
||||
|
||||
export type ProductTileProps = {
|
||||
product: (Product),
|
||||
onProductSelected?: OnProductSelectedFunc,
|
||||
isActive: boolean,
|
||||
style?: {
|
||||
default?: {
|
||||
highlight?: MyStyle,
|
||||
text?: MyStyle,
|
||||
image?: MyStyle,
|
||||
}
|
||||
active?: {
|
||||
highlight?: MyStyle,
|
||||
text?: MyStyle,
|
||||
image?: MyStyle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FALLBACK_IMAGE = "";
|
||||
|
||||
export function ProductTile ({product, onProductSelected, isActive, style} : ProductTileProps) {
|
||||
const _style = (isActive ? style?.active : style?.default) || {};
|
||||
export function ProductTile ({product, onProductSelected, isActive} : ProductTileProps) {
|
||||
const k = isActive ? "active" : "default";
|
||||
return (
|
||||
|
||||
<TouchableHighlight
|
||||
style={_style.highlight || styles.highlight}
|
||||
style={styles[k].highlight}
|
||||
onPress={() => onProductSelected && onProductSelected(product)}>
|
||||
<Text style={_style.text || styles.text}>{product.attributes.name || `Product ${product.id}`} ({product.pricePerUnitDisplay})</Text>
|
||||
<Text style={styles[k].text}>{product.attributes.name || `Product ${product.id}`} ({product.pricePerUnitDisplay})</Text>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
highlight: {
|
||||
|
||||
},
|
||||
image: {
|
||||
|
||||
},
|
||||
text: {
|
||||
|
||||
},
|
||||
tile: {
|
||||
|
||||
},
|
||||
})
|
||||
const styles = {
|
||||
active: StyleSheet.create({
|
||||
highlight: {
|
||||
padding: 10,
|
||||
margin: 2,
|
||||
color: "lightblue",
|
||||
},
|
||||
text: {
|
||||
}
|
||||
}),
|
||||
default: StyleSheet.create({
|
||||
highlight: {
|
||||
padding: 10,
|
||||
margin: 2,
|
||||
backgroundColor: "lightgrey",
|
||||
},
|
||||
text: {
|
||||
}
|
||||
}),
|
||||
}
|
@ -13,7 +13,7 @@ export default function UnitChooser({ choices, onChoicePressed, activeColor, def
|
||||
const [value, setValue] = useState(choices[0] as Length);
|
||||
|
||||
activeColor = activeColor || "lightblue";
|
||||
defaultColor = activeColor || "lightgrey";
|
||||
defaultColor = defaultColor || "lightgrey";
|
||||
|
||||
function doChoiceClicked(choice: Length) {
|
||||
setValue(choice);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render, fireEvent, screen, act } from '@testing-library/react-native';
|
||||
import { render, fireEvent, screen, act, within } from '@testing-library/react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
import ProductCalculatorSelector from '@/components/ProductCalculatorSelector';
|
||||
import { renderWithProviders } from '@/lib/rendering';
|
||||
@ -61,10 +61,12 @@ describe('ProductCalculatorSelector', () => {
|
||||
fireEvent.changeText(widthInput, "4");
|
||||
});
|
||||
|
||||
jest.advanceTimersByTime(500);
|
||||
jest.advanceTimersByTime(3000);
|
||||
|
||||
const price = mockAreaProduct.priceFor({l: 2, w: 4, u: "ft"});
|
||||
const sPrice = price.toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 2,});
|
||||
expect(screen.getByLabelText("calculated price").find().toBeTruthy();
|
||||
const element = screen.getByLabelText("calculated price");
|
||||
const {getByText} = within(element);
|
||||
expect(getByText(sPrice)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user