PliWould/components/ProductEditorItem.tsx

206 lines
7.6 KiB
TypeScript

import { Id, Product, dimensions_t } from "@/lib/product"
import { useState } from "react"
import { Button, FlatList, StyleSheet, Text, 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 { Ionicons } from "@expo/vector-icons";
export type ProductAddedFunc = () => any;
export type ProductDeletedFunc = (product_id: Id) => any;
export type AttributeAddedFunc = (product_id: Id) => any;
export type AttributeKeyUpdatedFunc = (product_id: Id, oldKey: string, newKey: string) => any;
export type AttributeUpdatedFunc = (product_id: Id, attribute: string, value: string) => any;
export type AttributeDeletedFunc = (product_id: Id, attribute: string) => any;
export type PriceUpdatedFunc = (product_id: Id, price: number) => any;
export type DimensionUpdatedFunc = (product_id: Id, dimension: dimensions_t) => any;
export type ProductEditorItemProps = {
product: Product,
onProductAdded?: ProductAddedFunc,
onProductDeleted?: ProductDeletedFunc,
onAttributeAdded?: AttributeAddedFunc,
onAttributeKeyChanged?: AttributeKeyUpdatedFunc,
onAttributeUpdated?: AttributeUpdatedFunc,
onAttributeDeleted?: AttributeDeletedFunc,
onPriceUpdated?: PriceUpdatedFunc,
onDimensionsUpdated?: DimensionUpdatedFunc,
}
export const ProductEditorItem = (props: ProductEditorItemProps) => {
const [showAttributes, setShowAttributes] = useState(false);
const product = props.product;
function onAttributeChanged(key: string, newValue: string) {
props.onAttributeUpdated && props.onAttributeUpdated(product.id, key, newValue);
}
function onAttributeKeyChanged(oldKey: string, newKey: string) {
props.onAttributeKeyChanged && props.onAttributeKeyChanged(product.id, oldKey, newKey);
}
function onAttributeDelete(key: string) {
props.onAttributeDeleted && props.onAttributeDeleted(product.id, key);
}
function onPricePerUnitChange(pricePerUnit: string) {
props.onPriceUpdated && props.onPriceUpdated(product.id, parseFloat(pricePerUnit) || parseInt(pricePerUnit));
}
function onUnitsChanged(newUnits: "foot" | "inch") {
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
...((product.area || product.length) as dimensions_t),
u: newUnits,
})
}
function onChangeLength(len: string) {
const l = parseFloat(len) || parseInt(len);
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
...((product.area || product.length) as dimensions_t),
l,
})
}
function onChangeWidth(width: string) {
const w = parseFloat(width) || parseInt(width);
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
...((product.area || product.length) as dimensions_t),
w,
})
}
function onDeleteProduct() {
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";
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}
>
<Ionicons style={styles.deleteProductButton} name="trash-outline" />
</TouchableHighlight>
{showAttributes &&
(
<View>
<View style={styles.priceSpecWrapper}>
<Text style={styles.priceLabel}></Text>
<TextInput inputMode="decimal"
defaultValue={new String(product.pricePerUnit) as string}
aria-label="price per unit"
onChangeText={onPricePerUnitChange}
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")}
style={styles.unitsSelect}
aria-label="units">
<option value="foot" selected={dimension === "foot"}>feet</option>
<option value="inch" selected={dimension === "inch"}>inches</option>
</select>
<TextInput
inputMode="decimal"
defaultValue={length}
onChangeText={onChangeLength}
style={styles.lengthInput}
aria-label="length"
/>
<Text>x</Text>
<TextInput
inputMode="decimal"
defaultValue={width}
onChangeText={onChangeWidth}
style={styles.widthInput}
aria-label="width"
/>
</View>
<Button title="+ Add Attribute" onPress={() => props.onAttributeAdded && props.onAttributeAdded(product.id)} />
<FlatList
style={styles.productAttributesList}
data={Object.entries(product.attributes)}
renderItem={({ item }) => (
<ProductAttributeEditor
attributeKey={item[0] || "some key"}
attributeValue={item[1]}
onChangeAttributeKey={onAttributeKeyChanged}
onChangeAttribute={onAttributeChanged}
onDelete={onAttributeDelete}
/>
)}
keyExtractor={(item, i) => `${product.id}-${i}`}
/>
</View>
)
}
</View>
)
}
const styles = StyleSheet.create({
deleteProductHighlight: {
},
deleteProductButton: {
},
priceSpecWrapper: {
},
priceLabel: {
},
priceInput: {
},
per: {
},
unitsLabel: {
},
unitsSelect: {
},
lengthInput: {
},
widthInput: {
},
productNameText: {
paddingLeft: 10,
paddingRight: 10,
},
productItemName: {
flex: 1,
backgroundColor: "lightgrey",
padding: 4,
margin: 4,
},
productAttributesList: {
margin: 10,
padding: 10,
borderWidth: 1,
borderStyle: "solid",
borderColor: "black",
},
})