James Ketrenos 7377c316db Use useReducer to forceUpdate the view when Whiskies deep object changes
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
2021-08-16 18:44:00 -07:00

236 lines
5.4 KiB
TypeScript

import { StatusBar } from 'expo-status-bar';
import React, { useState, useReducer } from 'react';
import { StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { request, GraphQLClient, gql } from 'graphql-request';
import moment from 'moment';
import { buildExecutionContext } from 'graphql/execution/execute';
const client = new GraphQLClient("http://localhost:4000/graphql", { headers: {} });
const Whisky = (props : { active?: boolean, whisky: any, style: any }) => {
const whisky = props.whisky;
let quantity = 0,
time = moment.unix(0);
const locations: any[] = [];
if (whisky.inventories) {
whisky.inventories.forEach((item : { location: any, quantity: number, updated: string }) => {
quantity += item.quantity;
const updated = moment(item.updated, 'YYYY-MM-DD');
if (time < updated) {
time = updated;
}
locations.push(
<View key={item.location.code} style={[styles.horizontal,styles.container]}>
<Text style={whiskyStyles.address}>{item.location.address}</Text>
<Text style={whiskyStyles.phone}>{item.location.phone}</Text>
<Text style={whiskyStyles.quantity}>{item.quantity}</Text>
</View>
)
});
}
const date = (time.unix() == 0) ? "" : time.format("YYYY-MM-DD");
return (
<View style={[...props.style, whiskyStyles.container]}>
<View style={[styles.container, styles.horizontal, {width: "100%"}]}>
<View style={whiskyStyles.code}><Text>{whisky.code}</Text></View>
<View style={whiskyStyles.description}><Text>{whisky.description}</Text></View>
<View style={whiskyStyles.date}><Text>{date}</Text></View>
<View style={whiskyStyles.quantity}><Text>{whisky.quantity}</Text></View>
</View>
{ props.active && <View style={styles.vertical}>
{ locations }
</View> }
</View>
);
};
const textStyle = {
paddingTop: 5,
paddingRight: 10,
paddingBottom: 5,
paddingLeft: 10
};
const whiskyStyles = StyleSheet.create({
container: {
flex: 1,
minHeight: 25,
},
code: {
...textStyle
},
description: {
flexGrow: 10,
...textStyle
},
date: {
...textStyle
},
address: {
flex: 1,
flexGrow: 1,
...textStyle
},
phone: {
...textStyle
},
quantity: {
flexShrink: 10,
minWidth: 50,
...textStyle
}
});
export default function App() {
const [whiskies, setWhiskies] = useState<any>(null),
[search, setSearch] = useState<string>(""),
[lastSearch, setLastSearch] = useState<string>(""),
[activeWhisky, setActiveWhisky] = useState<string>("");
const [, forceUpdate] = useReducer(x => x + 1, 0);
const updateWhisky = (code : string) => {
const query = gql` {
Whisky(code: "${code}") {
inventories {
location {
code
address
city
phone
longitude
latitude
}
quantity
updated
}
code
size
description
updated
quantity
}
}`;
client.request(query)
.then(data => {
for (let i = 0; i < whiskies.length; i++) {
if (whiskies[i].code == data.Whisky.code) {
whiskies[i] = data.Whisky;
break;
}
}
setWhiskies(whiskies);
forceUpdate();
})
.catch (error => {
console.error(error);
});
};
const onPress = (code : string) => {
if (code == activeWhisky) {
setActiveWhisky("");
} else {
setActiveWhisky(code);
updateWhisky(code);
}
};
const items = whiskies ? whiskies
.filter((item : any) => item.size == 750)
.sort((a : any, b : any) => a.description.localeCompare(b.description))
.map((whisky : any) => {
const active = whisky.code == activeWhisky;
return (
<TouchableOpacity key={whisky.code} onPress={() => onPress(whisky.code)}>
<Whisky
active={active}
style={[styles.container, styles.whisky]}
whisky={whisky}/>
</TouchableOpacity>
);
}) : [];
const submitSearch = () => {
if (search.trim() == "") {
setWhiskies([]);
return;
}
if (lastSearch == search) {
return;
}
const _query = gql` {
Whiskies(code:"${search}") {
code
description
price
size
lastSeen
quantity
updated
}
}`;
setLastSearch(search);
client.request(_query)
.then(data => {
setWhiskies(data.Whiskies);
})
.catch (error => {
console.error(error);
});
};
const keyPress = (event : KeyboardEvent) => {
if (event.code == "\n") {
submitSearch();
}
};
return (
<View style={[styles.container]}>
<TextInput style={[{borderWidth: 1 }]}
onBlur={submitSearch}
onKeyPress={(event : any) => keyPress(event)}
onChange={(value) => setSearch(value.target.value)}></TextInput>
<View style={[styles.container]}>
{ items }
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
horizontal: {
flex: 1,
display: "flex",
flexGrow: 1,
flexDirection: "row",
},
vertical: {
flex: 1,
display: "flex",
flexGrow: 1,
flexDirection: "column",
},
whisky: {
width: 500,
borderWidth: 1,
borderColor: "black",
margin: 2
}
});