Skip to content

Commit

Permalink
draft: hi fi about screen (#17)
Browse files Browse the repository at this point in the history
* Updated Directory, Tree Search & Filter

* Styled Filter component.

* Added functional checkboxes and filtering.

* Fixed SVG typing.

---------

Co-authored-by: Chris Torres <[email protected]>
Co-authored-by: Chris Torres <[email protected]>
  • Loading branch information
3 people authored Jan 2, 2025
1 parent f461657 commit aa3fa6d
Show file tree
Hide file tree
Showing 48 changed files with 4,973 additions and 622 deletions.
1 change: 1 addition & 0 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import { Text } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
Expand Down
1 change: 0 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"orientation": "portrait",
"icon": "./assets/bp-icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"plugins": [
[
"expo-camera",
Expand Down
Binary file added assets/OCF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3,935 changes: 3,619 additions & 316 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@
"body-parser": "^1.20.3",
"cookie": "^1.0.2",
"cross-spawn": "^7.0.6",
"dotenv": "^16.4.5",
"expo": "~52.0.18",
"expo": "~52.0.20",
"expo-auth-session": "~6.0.1",
"expo-camera": "~16.0.9",
"expo-camera": "~16.0.10",
"expo-constants": "~17.0.3",
"expo-crypto": "~14.0.1",
"expo-dev-client": "~5.0.6",
"expo-dev-launcher": "^5.0.14",
"expo-dev-client": "~5.0.8",
"expo-device": "~7.0.1",
"expo-font": "^13.0.1",
"expo-linking": "~7.0.3",
Expand All @@ -54,9 +52,10 @@
"react-native-element-dropdown": "^2.12.2",
"react-native-elements": "^3.4.3",
"react-native-gesture-handler": "~2.20.2",
"react-native-paper": "^5.12.5",
"react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "^4.12.0",
"react-native-screens": "~4.1.0",
"react-native-screens": "~4.4.0",
"react-native-svg": "15.8.0",
"react-native-toast-message": "^2.2.1",
"react-native-url-polyfill": "^2.0.0",
Expand All @@ -66,15 +65,16 @@
"send": "^1.1.0",
"uuid": "^11.0.3",
"xml2js": "^0.6.2",
"zod": "^3.23.8",
"zustand": "^5.0.0-rc.2"
"zod": "^3.23.8"
},
"devDependencies": {
"@babel/core": "^7.24.0",
"@eslint/config-array": "^0.19.0",
"@eslint/js": "^9.9.0",
"@eslint/object-schema": "^2.1.4",
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
"@react-native-community/cli": "latest",
"@svgr/cli": "^8.1.0",
"@types/react": "~18.3.12",
"@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.18.0",
Expand Down
21 changes: 21 additions & 0 deletions src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { TouchableOpacity, View } from 'react-native';
import { styles } from './styles';

type CheckboxProps = {
value: boolean;
onValueChange: () => void;
};

const Checkbox: React.FC<CheckboxProps> = ({ value, onValueChange }) => {
return (
<TouchableOpacity
onPress={onValueChange}
style={[styles.checkbox, value && styles.checkboxChecked]}
>
{value && <View style={styles.checkmark} />}
</TouchableOpacity>
);
};

export default Checkbox;
29 changes: 29 additions & 0 deletions src/components/Checkbox/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { StyleSheet } from 'react-native';
import colors from '@/styles/colors';

export const styles = StyleSheet.create({
checkbox: {
width: 20,
height: 20,
backgroundColor: colors.gray5,
borderRadius: 5,
borderWidth: 0,
justifyContent: 'center',
alignItems: 'center',
},

checkboxChecked: {
backgroundColor: colors.secondary,
borderColor: colors.primary,
borderWidth: 1,
},

checkmark: {
width: 12,
height: 6,
borderLeftWidth: 2,
borderBottomWidth: 2,
borderColor: colors.primary,
transform: [{ rotate: '315deg' }],
},
});
5 changes: 2 additions & 3 deletions src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import styles from './styles';

type DropdownProps<T extends string[]> = {
options: T;
setValue: (value: T[number]) => any;
setValue: (value: T[number]) => unknown;
value: string;
displayValue?: (s: string) => string;
};
Expand All @@ -31,7 +31,7 @@ function Dropdown<T extends string[]>({
placeholderStyle={[styles.text, styles.textContainer]}
selectedTextStyle={[styles.text, styles.textContainer]}
inputSearchStyle={styles.text}
itemTextStyle={[styles.text, styles.gray4]}
itemTextStyle={styles.text}
containerStyle={styles.dropdownContainer}
dropdownPosition="bottom"
iconStyle={styles.iconStyle}
Expand All @@ -48,7 +48,6 @@ function Dropdown<T extends string[]>({
<Text
style={[
styles.text,
styles.gray4,
styles.itemContainer,
selected && styles.selectedBar,
{ borderBottomLeftRadius: 0, borderTopLeftRadius: 0 },
Expand Down
8 changes: 0 additions & 8 deletions src/components/Dropdown/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ import colors from '@/styles/colors';
import typography from '@/styles/typography';

export default StyleSheet.create({
gray4: {
color: colors.gray4,
},

black3: {
color: colors.gray3,
},

textContainer: {
paddingHorizontal: 20,
},
Expand Down
23 changes: 0 additions & 23 deletions src/components/SearchBar.tsx

This file was deleted.

66 changes: 66 additions & 0 deletions src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import { TextInput, TouchableOpacity, View } from 'react-native';
import TreeFilterModal from '@/components/TreeFilter/TreeFilter';
import Search from '@/icons/Search';
import Filter from '@/icons/Sort';
import { styles } from './styles';

type SearchBarProps = {
value: string;
onChange: (text: string) => void;
filters: {
height: string[];
shape: string;
fruit: string[];
water: string[];
other: string[];
};
setFilters: React.Dispatch<
React.SetStateAction<{
height: string[];
shape: string;
fruit: string[];
water: string[];
other: string[];
}>
>;
};

const SearchBar: React.FC<SearchBarProps> = ({
value,
onChange,
filters,
setFilters,
}) => {
const [modalVisible, setModalVisible] = useState(false);

const openModal = () => setModalVisible(true);
const closeModal = () => setModalVisible(false);

return (
<View style={styles.searchContainer}>
<View style={styles.inputContainer}>
<Search />
<TextInput
style={styles.searchBarInput}
placeholder="Find a species..."
value={value}
onChangeText={onChange}
/>
<TouchableOpacity onPress={openModal}>
<View style={styles.filterIconContainer}>
<Filter />
</View>
</TouchableOpacity>
<TreeFilterModal
visible={modalVisible}
onClose={closeModal}
filters={filters}
setFilters={setFilters}
/>
</View>
</View>
);
};

export default SearchBar;
53 changes: 53 additions & 0 deletions src/components/SearchBar/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { StyleSheet } from 'react-native';
import colors from '@/styles/colors';
import typography from '@/styles/typography';

export const styles = StyleSheet.create({
searchContainer: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: colors.gray5,
paddingTop: 5,
paddingBottom: 20,
paddingHorizontal: 24,
},

searchBarInput: {
...typography.normalRegular,
color: colors.gray3,
flex: 1,
height: 42,
borderWidth: 1,
borderRadius: 30,
paddingHorizontal: 10,
borderColor: colors.gray6,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'transparent',
},

inputContainer: {
flex: 1,
height: 42,
flexDirection: 'row',
alignItems: 'center',
width: '100%',
position: 'relative',
borderColor: colors.gray6,
backgroundColor: colors.gray6,
borderRadius: 30,
paddingHorizontal: 10,
},

filterIconContainer: {
width: 32,
height: 32,
borderRadius: 16,
backgroundColor: colors.white,
justifyContent: 'center',
alignItems: 'center',
},
});

export default styles;
13 changes: 10 additions & 3 deletions src/components/SpeciesDisplay/SpeciesDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export default function SpeciesDisplay({
speciesData,
treeData,
}: SpeciesDisplayProps) {
const uniqueLocations = treeData.filter(
(tree, index, self) =>
index === self.findIndex(t => t.bank === tree.bank && t.row === tree.row),
);
return (
<View style={styles.main}>
<Text style={styles.text}>{speciesData.description}</Text>
Expand Down Expand Up @@ -93,7 +97,7 @@ export default function SpeciesDisplay({
</View>
)}

{speciesData.evegreen && (
{speciesData.evergreen && (
<View style={styles.property}>
<SvgLeaf />
<Text style={styles.propertyText}>Evegreen</Text>
Expand All @@ -112,8 +116,11 @@ export default function SpeciesDisplay({
<>
<Text style={styles.header}>Location</Text>
<View style={styles.locations}>
{treeData?.map(tree => (
<View style={styles.locationEntry} key={tree.tree_id}>
{uniqueLocations?.map((tree, index) => (
<View
style={styles.locationEntry}
key={`${tree.bank}-${tree.row}-${index}`}
>
<SvgLocationPin />
<Text style={styles.propertyText}>
Bank #{tree.bank ?? 0} {' '}|{' '} Row #{tree.row ?? 0}
Expand Down
39 changes: 21 additions & 18 deletions src/components/ToggleSwitch/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import {
Animated,
LayoutRectangle,
Expand Down Expand Up @@ -38,27 +38,30 @@ export default function ToggleSwitch({
const translateAnimation = useRef(new Animated.Value(40)).current;
const scaleAnimation = useRef(new Animated.Value(0)).current;

const runAnimations = (newValue: boolean) => {
if (!trueLabelLayout || !falseLabelLayout) return;
const runAnimations = useCallback(
(newValue: boolean) => {
if (!trueLabelLayout || !falseLabelLayout) return;

Animated.timing(translateAnimation, {
duration: 100,
toValue: newValue
? trueLabelLayout.x + trueLabelLayout.width / 2 - 2
: falseLabelLayout.x + falseLabelLayout.width / 2 + 2,
useNativeDriver: true,
}).start();

Animated.timing(scaleAnimation, {
duration: 100,
toValue: (newValue ? trueLabelLayout.width : falseLabelLayout.width) ?? 0,
useNativeDriver: true,
}).start();
};
Animated.timing(translateAnimation, {
duration: 100,
toValue: newValue
? trueLabelLayout.x + trueLabelLayout.width / 2 - 2
: falseLabelLayout.x + falseLabelLayout.width / 2 + 2,
useNativeDriver: true,
}).start();

Animated.timing(scaleAnimation, {
duration: 100,
toValue:
(newValue ? trueLabelLayout.width : falseLabelLayout.width) ?? 0,
useNativeDriver: true,
}).start();
},
[trueLabelLayout, falseLabelLayout, translateAnimation, scaleAnimation],
);
useEffect(() => {
runAnimations(value);
}, [trueLabelLayout, falseLabelLayout]);
}, [trueLabelLayout, falseLabelLayout, value, runAnimations]);

const handlePress = (newValue: boolean) => {
runAnimations(newValue);
Expand Down
Loading

0 comments on commit aa3fa6d

Please sign in to comment.