fix layout of carpet roll calculator. todo: reinstate unit buttons for plywood calculator.

This commit is contained in:
Jordan
2024-08-19 07:08:54 -07:00
parent dc7f4b25a9
commit 257642a251
12 changed files with 396 additions and 297 deletions

View File

@ -36,7 +36,6 @@ const BIG_FONT_SIZE = 30;
const styles = StyleSheet.create({
component: {
paddingVertical: 100,
alignItems: "center",
},
dimensions: {

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { View, Text, StyleSheet } from "react-native";
import { View, Text, StyleSheet, StatusBar, Dimensions, useWindowDimensions } from "react-native";
import { Product } from "@/lib/product";
import { selectProducts } from "@/features/product/productSlice";
import { area_t, diameterToLength, length_t } from "@/lib/dimensions";
@ -9,10 +9,14 @@ import convert, { Length } from "convert";
import ProductList from "@/components/ProductList";
import { HelpfulMeasurementUnitInput } from "./HelpfulMeasurementInput";
import { ScrollView } from "react-native-gesture-handler";
import { SafeAreaView } from "react-native-safe-area-context";
const DEFAULT_DIAMETER_UNIT: Length = "in";
const DEFAULT_LENGTH_UNIT: Length = "ft";
const screenDimensions = Dimensions.get('screen');
const windowDimensions = Dimensions.get('window');
export const CarpetRollCalculator = () => {
const products = useAppSelector(selectProducts);
@ -61,85 +65,93 @@ export const CarpetRollCalculator = () => {
}, [outerDiameter, innerDiameter, width, numRings, selectedProduct, units]);
return (
<View style={styles.container}>
<View>
{selectedProduct ? (
<AreaRugTag dimensions={rugDimensions} product={selectedProduct} />
) : (
<Text style={styles.placeholder}>Please Select a Product</Text>
)}
</View>
<View style={{ flex: 1, }}>
<ScrollView>
<View style={styles.inputFields}>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Length"
svgUri="/assets/images/icons/carpet-roll-length-raw.svg"
onUnitSet={setUnits}
onValueSet={setWidth}
defaultValue={width}
defaultUnit={units}
unitChoices={["ft", "in"]}
/>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Inner diameter"
svgUri="/assets/images/icons/carpet-roll-length-inner-diameter-raw.svg"
onUnitSet={(u) => setInnerDiameter({ ...innerDiameter, u })}
defaultValue={innerDiameter.l}
defaultUnit={innerDiameter.u}
unitChoices={["ft", "in"]}
onValueSet={(l) => setInnerDiameter({ ...innerDiameter, l })}
/>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Outer diameter"
svgUri="/assets/images/icons/carpet-roll-length-outer-diameter-raw.svg"
onUnitSet={(u) => setOuterDiameter({ ...outerDiameter, u })}
defaultValue={innerDiameter.l}
defaultUnit={innerDiameter.u}
unitChoices={["ft", "in"]}
onValueSet={(l) => setOuterDiameter({ ...outerDiameter, l })}
/>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Number of rings"
svgUri="/assets/images/icons/carpet-roll-length-number-of-rings-raw.svg"
defaultValue={0}
onValueSet={setNumRings}
/>
</View>
</View>
<View style={styles.container}>
<ProductList
onProductSelected={setSelectedProduct}
productType="area_rug"
<SafeAreaView style={styles.container}>
<View style={styles.placeholder}>
{selectedProduct ? (
<AreaRugTag dimensions={rugDimensions} product={selectedProduct} />
) : (
<Text style={styles.placeholderText}>Please Select a Product</Text>
)}
</View>
<ScrollView style={styles.scrollView}>
<View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Length"
svgUri="/assets/images/icons/carpet-roll-length-raw.svg"
onUnitSet={setUnits}
onValueSet={setWidth}
defaultValue={width}
defaultUnit={units}
unitChoices={["ft", "in"]}
/>
</View>
</ScrollView>
</View>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Inner diameter"
svgUri="/assets/images/icons/carpet-roll-length-inner-diameter-raw.svg"
onUnitSet={(u) => setInnerDiameter({ ...innerDiameter, u })}
defaultValue={innerDiameter.l}
defaultUnit={innerDiameter.u}
unitChoices={["ft", "in"]}
onValueSet={(l) => setInnerDiameter({ ...innerDiameter, l })}
/>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Outer diameter"
svgUri="/assets/images/icons/carpet-roll-length-outer-diameter-raw.svg"
onUnitSet={(u) => setOuterDiameter({ ...outerDiameter, u })}
defaultValue={innerDiameter.l}
defaultUnit={innerDiameter.u}
unitChoices={["ft", "in"]}
onValueSet={(l) => setOuterDiameter({ ...outerDiameter, l })}
/>
</View>
<View style={styles.inputFieldWrapper}>
<HelpfulMeasurementUnitInput
label="Number of rings"
svgUri="/assets/images/icons/carpet-roll-length-number-of-rings-raw.svg"
defaultValue={0}
onValueSet={setNumRings}
/>
</View>
</View>
<View>
<ProductList
onProductSelected={setSelectedProduct}
productType="area_rug"
/>
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flexGrow: 1,
flex: 1,
paddingTop: StatusBar.currentHeight,
},
scrollView: {
marginHorizontal: 20,
height: windowDimensions.height - 50,
},
placeholder: {
alignContent: "center",
alignSelf: "center",
paddingTop: 50,
paddingBottom: 50,
height: 300,
paddingTop: 40,
paddingBottom: 40,
fontSize: 30,
position: "static",
},
placeholderText: {
fontSize: 30,
paddingVertical: 70,
},
inputFieldWrapper: {
padding: 10,
// padding: 10,
},
inputFields: {},
label: {

View File

@ -5,13 +5,12 @@ 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 convert, { Length } from "convert";
import PercentDamage from "./PercentDamange";
import MeasurementUnitInput from "./MeasurementUnitInput";
export default function ProductCalculatorSelector() {
const [activeProduct, setActiveProduct] = useState(null as Product | null);
const [price, setPrice] = useState(0);

View File

@ -1,10 +1,12 @@
import { ScrollView, StyleSheet } from "react-native";
import { Dimensions, ScrollView, StyleSheet } from "react-native";
import { ProductTile } from "./ProductTile";
import { Product, product_type_t } from "@/lib/product";
import { useState } from "react";
import { selectProducts } from "@/features/product/productSlice";
import { useAppSelector } from "@/app/store";
const windowDimensions = Dimensions.get('window');
export type ProductSelectionProps = {
onProductSelected?: (product: Product) => any;
productType?: product_type_t;
@ -28,7 +30,7 @@ export default function ProductList({
}
return (
<ScrollView scrollToOverflowEnabled={true} aria-label="product list">
<ScrollView style={styles.productSelectorFlatList} contentContainerStyle={styles.content} aria-label="product list">
{products.map((product) => {
return (
<ProductTile
@ -47,5 +49,12 @@ const styles = StyleSheet.create({
productSelectorFlatList: {
padding: 10,
margin: 10,
height: windowDimensions.height - 200,
width: windowDimensions.width,
},
content: {
alignItems: "flex-start",
flexWrap: "wrap",
flexDirection: "row",
}
});

View File

@ -1,58 +1,84 @@
import { Product, priceDisplay, pricePerUnitDisplay } from "@/lib/product"
import { ImageBackground, StyleProp, StyleSheet, Text, TouchableHighlight, View, ViewStyle } from "react-native";
import { Product, priceDisplay, pricePerUnitDisplay } from "@/lib/product";
import { LinearGradient } from "expo-linear-gradient";
import {
ImageBackground,
Pressable,
StyleProp,
StyleSheet,
Text,
TouchableHighlight,
View,
ViewStyle,
} from "react-native";
import { AnimatedStyle } from "react-native-reanimated";
export type OnProductSelectedFunc = (product : Product) => any;
export type OnProductSelectedFunc = (product: Product) => any;
type MyStyle = StyleProp<AnimatedStyle<StyleProp<ViewStyle>>>;
type StyleSpec = {
highlight?: MyStyle,
text?: MyStyle,
image?: MyStyle,
}
highlight?: MyStyle;
text?: MyStyle;
image?: MyStyle;
};
export type ProductTileProps = {
product: (Product),
onProductSelected?: OnProductSelectedFunc,
isActive: boolean,
}
product: Product;
onProductSelected?: OnProductSelectedFunc;
isActive: boolean;
};
const FALLBACK_IMAGE = "";
export function ProductTile ({product, onProductSelected, isActive} : ProductTileProps) {
const k = isActive ? "active" : "default";
export function ProductTile({
product,
onProductSelected,
isActive,
}: ProductTileProps) {
const k = isActive ? "active" : "default";
const priceDisplay = pricePerUnitDisplay(product);
return (
const BLUE_HILIGHT = "#caceff";
const BLUE = "#8b9cff";
const GRAY_HILIGHT = "#ffffff";
const GRAY = "#b1b1b1";
<TouchableHighlight
aria-label={`product ${product.id}`}
style={styles[k].highlight}
onPress={() => onProductSelected && onProductSelected(product)}>
<Text style={styles[k].text}>{product.attributes?.name || `Product ${product.id}`} ({priceDisplay})</Text>
</TouchableHighlight>
);
const activeColors = [BLUE_HILIGHT, BLUE, BLUE, BLUE];
const inactiveColors = [GRAY_HILIGHT, GRAY, GRAY, GRAY];
const priceDisplay = pricePerUnitDisplay(product);
return (
<LinearGradient
colors={isActive ? activeColors : inactiveColors}
style={styles.gradientButton}
>
<Pressable
style={styles.button}
aria-label={`product ${product.id}`}
onPress={() => onProductSelected && onProductSelected(product)}
>
<Text style={styles.text}>
{product.attributes?.name || `Product ${product.id}`} ({priceDisplay})
</Text>
</Pressable>
</LinearGradient>
);
}
const styles = {
active: StyleSheet.create({
highlight: {
padding: 10,
margin: 2,
color: "lightblue",
},
text: {
}
}),
default: StyleSheet.create({
highlight: {
padding: 10,
margin: 2,
backgroundColor: "lightgrey",
},
text: {
}
}),
}
const styles = StyleSheet.create({
gradientButton: {
borderRadius: 10,
borderWidth: 1,
borderColor: "gray",
borderStyle: "solid",
margin: 1,
width: 300,
marginVertical: 10,
marginHorizontal: 10,
},
button: {
},
text: {
paddingVertical: 30,
paddingHorizontal: 40,
}
});

View File

@ -38,8 +38,13 @@ export default function UnitChooser({
onUnitSet && onUnitSet(choice);
}
const activeColors = ['#a7caff', '#5588ff', '#5588ff', '#5588ff'];
const inactiveColors = ['#d0d0d0', '#828282', '#828282', '#828282'];
const BLUE_HILIGHT = "#caceff";
const BLUE = "#8b9cff";
const GRAY_HILIGHT = "#ffffff";
const GRAY = "#b1b1b1";
const activeColors = [BLUE_HILIGHT, BLUE, BLUE, BLUE];
const inactiveColors = [GRAY_HILIGHT, GRAY, GRAY, GRAY];
return (
<View style={styles.unitChooser}>
@ -49,7 +54,7 @@ export default function UnitChooser({
colors={ci === value ? activeColors : inactiveColors}
style={styles.gradientButton}
>
<TouchableHighlight style={{padding: 5, borderRadius: 5, }} onPress={() => doChoiceClicked(ci)} key={ci}>
<TouchableHighlight style={{padding: 5, }} onPress={() => doChoiceClicked(ci)} key={ci}>
<Text style={{padding: 5, fontSize: 16}}>{ci}</Text>
</TouchableHighlight>
</LinearGradient>
@ -60,7 +65,13 @@ export default function UnitChooser({
}
const styles = StyleSheet.create({
gradientButton: {},
gradientButton: {
borderRadius: 10,
borderWidth: 1,
borderColor: "gray",
borderStyle: "solid",
margin: 1,
},
unitChooser: {
flexDirection: "row",
verticalAlign: "middle",