Category view + detail
This commit is contained in:
parent
5ebd10cd3a
commit
aaedcec4a6
8 changed files with 3360 additions and 1599 deletions
|
@ -4,23 +4,43 @@ import {
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
Image,
|
Image,
|
||||||
TouchableOpacity
|
TouchableOpacity,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
|
||||||
|
import React, {useState} from 'react';
|
||||||
|
import {router} from 'expo-router';
|
||||||
import {AutocompleteDropdown} from 'react-native-autocomplete-dropdown';
|
import {AutocompleteDropdown} from 'react-native-autocomplete-dropdown';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
import {ThemedText} from '@/components/ThemedText';
|
import {ThemedText} from '@/components/ThemedText';
|
||||||
import {ThemedView} from '@/components/ThemedView';
|
import {ThemedView} from '@/components/ThemedView';
|
||||||
import {Colors} from '@/constants/Colors';
|
import {Colors} from '@/constants/Colors';
|
||||||
import {useColorScheme} from '@/hooks/useColorScheme';
|
import {useColorScheme} from '@/hooks/useColorScheme';
|
||||||
import React from 'react';
|
import {Request} from '@/services/request';
|
||||||
|
import List from '@/components/List';
|
||||||
|
|
||||||
export default function ExploreScreen() {
|
export default function ExploreScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
|
const [types, setTypes] = useState([]);
|
||||||
|
|
||||||
|
// Load waste types
|
||||||
|
Request.get('waste-types').then((responseData) => {
|
||||||
|
const response = responseData.data;
|
||||||
|
|
||||||
|
setTypes(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
// View item in sub screen
|
||||||
|
const viewItem = async (item: any) => {
|
||||||
|
await AsyncStorage.setItem('activeCategory', JSON.stringify(item));
|
||||||
|
|
||||||
|
router.push('/explore/category');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
|
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
|
||||||
<ThemedView style={styles.container}>
|
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
|
<ThemedView style={styles.container}>
|
||||||
<ThemedView style={styles.titleContainer}>
|
<ThemedView style={styles.titleContainer}>
|
||||||
<ThemedText type="title">Wat moet waar?</ThemedText>
|
<ThemedText type="title">Wat moet waar?</ThemedText>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
@ -49,21 +69,18 @@ export default function ExploreScreen() {
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.listContainer}>
|
<ThemedView style={styles.listContainer}>
|
||||||
<TouchableOpacity style={styles.listItem}>
|
<List
|
||||||
|
data={types}
|
||||||
|
renderItem={(item: any, index: any) => (
|
||||||
|
<TouchableOpacity style={styles.listItem} key={index} onPress={() => viewItem(item)}>
|
||||||
<Image source={require('@/assets/images/paper.png')} style={styles.listImage}/>
|
<Image source={require('@/assets/images/paper.png')} style={styles.listImage}/>
|
||||||
<ThemedText type="default">Categorie 1</ThemedText>
|
<ThemedText type="default">{item.name}</ThemedText>
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={styles.listItem}>
|
|
||||||
<Image source={require('@/assets/images/paper.png')} style={styles.listImage} />
|
|
||||||
<ThemedText type="default">Categorie 2</ThemedText>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={styles.listItem}>
|
|
||||||
<Image source={require('@/assets/images/paper.png')} style={styles.listImage} />
|
|
||||||
<ThemedText type="default">Categorie 3</ThemedText>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</ThemedView>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</ThemedView>
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {ThemedView} from '@/components/ThemedView';
|
||||||
import {Colors} from '@/constants/Colors';
|
import {Colors} from '@/constants/Colors';
|
||||||
import {useColorScheme} from '@/hooks/useColorScheme';
|
import {useColorScheme} from '@/hooks/useColorScheme';
|
||||||
import MapView from '@/components/map/map';
|
import MapView from '@/components/map/map';
|
||||||
|
import List from '@/components/List';
|
||||||
|
|
||||||
export default function MapScreen() {
|
export default function MapScreen() {
|
||||||
const colorScheme = useColorScheme() ?? 'light';
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
|
@ -47,24 +48,6 @@ export default function MapScreen() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const renderListItem = (item: any, index: any) => {
|
|
||||||
return (
|
|
||||||
<ThemedView style={styles.listItem} key={index}>
|
|
||||||
<View style={styles.listItemTitle}>
|
|
||||||
<Image source={item.image} style={styles.listImage}/>
|
|
||||||
<ThemedText type="default">{item.name}</ThemedText>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
trackColor={{false: '#767577', true: Colors.light.tint}}
|
|
||||||
thumbColor={'#fff'}
|
|
||||||
value={item.isEnabled}
|
|
||||||
onValueChange={() => toggleSwitch(index)}
|
|
||||||
/>
|
|
||||||
</ThemedView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleSwitch = (index: any) => {
|
const toggleSwitch = (index: any) => {
|
||||||
const newData = types.map((item, key) =>
|
const newData = types.map((item, key) =>
|
||||||
key === index ? {...item, isEnabled: !item.isEnabled} : item
|
key === index ? {...item, isEnabled: !item.isEnabled} : item
|
||||||
|
@ -73,18 +56,6 @@ export default function MapScreen() {
|
||||||
setTypes(newData);
|
setTypes(newData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderList = () => {
|
|
||||||
let list: any[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < types.length; i++) {
|
|
||||||
const type = types[i];
|
|
||||||
|
|
||||||
list[i] = renderListItem(type, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background}}>
|
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background}}>
|
||||||
<ThemedView style={styles.container}>
|
<ThemedView style={styles.container}>
|
||||||
|
@ -110,7 +81,23 @@ export default function MapScreen() {
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
<ThemedView style={styles.listContainer}>
|
<ThemedView style={styles.listContainer}>
|
||||||
{ renderList() }
|
<List
|
||||||
|
data={types}
|
||||||
|
renderItem={(item: any, index: any) => (
|
||||||
|
<ThemedView style={styles.listItem} key={index}>
|
||||||
|
<View style={styles.listItemTitle}>
|
||||||
|
<Image source={item.image} style={styles.listImage}/>
|
||||||
|
<ThemedText type="default">{item.name}</ThemedText>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
trackColor={{false: '#767577', true: Colors.light.tint}}
|
||||||
|
thumbColor={'#fff'}
|
||||||
|
value={item.isEnabled}
|
||||||
|
onValueChange={() => toggleSwitch(index)}
|
||||||
|
/>
|
||||||
|
</ThemedView>
|
||||||
|
)}/>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
@ -140,6 +127,8 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
listContainer: {
|
listContainer: {
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
|
paddingLeft: 25,
|
||||||
|
paddingRight: 25,
|
||||||
},
|
},
|
||||||
listItem: {
|
listItem: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -147,8 +136,6 @@ const styles = StyleSheet.create({
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: 25,
|
|
||||||
paddingRight: 25,
|
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
|
|
63
app/explore/category.tsx
Normal file
63
app/explore/category.tsx
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import {
|
||||||
|
SafeAreaView,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Dimensions
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import {useState} from 'react';
|
||||||
|
import RenderHtml from 'react-native-render-html';
|
||||||
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
import {Colors} from '@/constants/Colors';
|
||||||
|
import {useColorScheme} from '@/hooks/useColorScheme';
|
||||||
|
import {ThemedView} from '@/components/ThemedView';
|
||||||
|
|
||||||
|
export default function CategoryScreen() {
|
||||||
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
|
const navigation = useNavigation();
|
||||||
|
const [description, setDescription] = useState('');
|
||||||
|
|
||||||
|
// Load item from storage
|
||||||
|
AsyncStorage.getItem('activeCategory').then((data) => {
|
||||||
|
const itemData: any = JSON.parse(data ?? '{}');
|
||||||
|
|
||||||
|
if (itemData != null) {
|
||||||
|
const {name, description} = itemData;
|
||||||
|
|
||||||
|
// Set description
|
||||||
|
// @ts-ignore
|
||||||
|
setDescription(description);
|
||||||
|
|
||||||
|
// Set page title
|
||||||
|
navigation.setOptions({title: name});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// HTML render props
|
||||||
|
const source = {html: description};
|
||||||
|
const width = Dimensions.get('window').width;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
|
||||||
|
<ScrollView style={styles.container}>
|
||||||
|
<ThemedView style={styles.htmlContainer}>
|
||||||
|
<RenderHtml
|
||||||
|
contentWidth={width}
|
||||||
|
source={source}
|
||||||
|
/>
|
||||||
|
</ThemedView>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
padding: 25,
|
||||||
|
},
|
||||||
|
htmlContainer: {
|
||||||
|
paddingBottom: 50,
|
||||||
|
},
|
||||||
|
})
|
29
components/List.tsx
Normal file
29
components/List.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {StyleSheet, View} from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface ListProps {
|
||||||
|
data: any;
|
||||||
|
renderItem: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomList: React.FC<ListProps> = ({ data, renderItem }) => {
|
||||||
|
const renderList = () => {
|
||||||
|
let list: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const item = data[i];
|
||||||
|
|
||||||
|
list[i] = renderItem(item, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{renderList()}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomList;
|
955
package-lock.json
generated
955
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -16,9 +16,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.0.2",
|
"@expo/vector-icons": "^14.0.2",
|
||||||
|
"@react-native-async-storage/async-storage": "^1.24.0",
|
||||||
"@react-navigation/native": "^6.0.2",
|
"@react-navigation/native": "^6.0.2",
|
||||||
"@teovilla/react-native-web-maps": "^0.9.5",
|
"@teovilla/react-native-web-maps": "^0.9.5",
|
||||||
"@uiw/react-color-circle": "^2.3.0",
|
"@uiw/react-color-circle": "^2.3.0",
|
||||||
|
"axios": "^1.7.2",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"deprecated-react-native-prop-types": "^5.0.0",
|
"deprecated-react-native-prop-types": "^5.0.0",
|
||||||
"expo": "~51.0.22",
|
"expo": "~51.0.22",
|
||||||
|
@ -40,6 +42,7 @@
|
||||||
"react-native-leaflet-view": "^0.1.2",
|
"react-native-leaflet-view": "^0.1.2",
|
||||||
"react-native-maps": "1.14.0",
|
"react-native-maps": "1.14.0",
|
||||||
"react-native-reanimated": "~3.10.1",
|
"react-native-reanimated": "~3.10.1",
|
||||||
|
"react-native-render-html": "^6.3.4",
|
||||||
"react-native-safe-area-context": "4.10.5",
|
"react-native-safe-area-context": "4.10.5",
|
||||||
"react-native-screens": "3.31.1",
|
"react-native-screens": "3.31.1",
|
||||||
"react-native-svg": "^15.4.0",
|
"react-native-svg": "^15.4.0",
|
||||||
|
|
53
services/request.tsx
Normal file
53
services/request.tsx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const API_URL = 'https://kliko.maartenvr98.nl/api/v1/';
|
||||||
|
const CONFIG = {
|
||||||
|
timeout: 3000,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Request {
|
||||||
|
/**
|
||||||
|
* Send GET request to API
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param headers
|
||||||
|
* @returns {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
static get(url: string, headers = {}) {
|
||||||
|
return axios.get(API_URL + url, {
|
||||||
|
...CONFIG,
|
||||||
|
...headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send POST request to API
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param body
|
||||||
|
* @param headers
|
||||||
|
* @returns {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
static post(url: string, body = {}, headers = {}) {
|
||||||
|
return axios.post(API_URL + url, body, {
|
||||||
|
...CONFIG,
|
||||||
|
...headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send PUT request to API
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param body
|
||||||
|
* @param headers
|
||||||
|
* @returns {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
static put(url: string, body = {}, headers = {}) {
|
||||||
|
return axios.put(API_URL + url, body, {
|
||||||
|
...CONFIG,
|
||||||
|
...headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue