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,
|
||||
StatusBar,
|
||||
Image,
|
||||
TouchableOpacity
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import {router} from 'expo-router';
|
||||
import {AutocompleteDropdown} from 'react-native-autocomplete-dropdown';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
import {ThemedText} from '@/components/ThemedText';
|
||||
import {ThemedView} from '@/components/ThemedView';
|
||||
import {Colors} from '@/constants/Colors';
|
||||
import {useColorScheme} from '@/hooks/useColorScheme';
|
||||
import React from 'react';
|
||||
import {Request} from '@/services/request';
|
||||
import List from '@/components/List';
|
||||
|
||||
export default function ExploreScreen() {
|
||||
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 (
|
||||
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
|
||||
<ThemedView style={styles.container}>
|
||||
<ScrollView>
|
||||
<ThemedView style={styles.container}>
|
||||
<ThemedView style={styles.titleContainer}>
|
||||
<ThemedText type="title">Wat moet waar?</ThemedText>
|
||||
</ThemedView>
|
||||
|
@ -37,9 +57,9 @@ export default function ExploreScreen() {
|
|||
closeOnSubmit={false}
|
||||
emptyResultText={'Niks gevonden'}
|
||||
dataSet={[
|
||||
{ id: '1', title: 'Alpha' },
|
||||
{ id: '2', title: 'Beta' },
|
||||
{ id: '3', title: 'Gamma' },
|
||||
{id: '1', title: 'Alpha'},
|
||||
{id: '2', title: 'Beta'},
|
||||
{id: '3', title: 'Gamma'},
|
||||
]}
|
||||
/>
|
||||
</ThemedView>
|
||||
|
@ -49,21 +69,18 @@ export default function ExploreScreen() {
|
|||
</ThemedView>
|
||||
|
||||
<ThemedView style={styles.listContainer}>
|
||||
<TouchableOpacity style={styles.listItem}>
|
||||
<Image source={require('@/assets/images/paper.png')} style={styles.listImage} />
|
||||
<ThemedText type="default">Categorie 1</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>
|
||||
<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}/>
|
||||
<ThemedText type="default">{item.name}</ThemedText>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</ThemedView>
|
||||
</ThemedView>
|
||||
</ScrollView>
|
||||
</ThemedView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import {ThemedView} from '@/components/ThemedView';
|
|||
import {Colors} from '@/constants/Colors';
|
||||
import {useColorScheme} from '@/hooks/useColorScheme';
|
||||
import MapView from '@/components/map/map';
|
||||
import List from '@/components/List';
|
||||
|
||||
export default function MapScreen() {
|
||||
const colorScheme = useColorScheme() ?? 'light';
|
||||
|
@ -47,44 +48,14 @@ 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 newData = types.map((item, key) =>
|
||||
key === index ? { ...item, isEnabled: !item.isEnabled } : item
|
||||
key === index ? {...item, isEnabled: !item.isEnabled} : item
|
||||
);
|
||||
|
||||
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 (
|
||||
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background}}>
|
||||
<ThemedView style={styles.container}>
|
||||
|
@ -110,7 +81,23 @@ export default function MapScreen() {
|
|||
</ThemedView>
|
||||
|
||||
<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>
|
||||
</ScrollView>
|
||||
</ThemedView>
|
||||
|
@ -140,6 +127,8 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
listContainer: {
|
||||
marginTop: 10,
|
||||
paddingLeft: 25,
|
||||
paddingRight: 25,
|
||||
},
|
||||
listItem: {
|
||||
flex: 1,
|
||||
|
@ -147,8 +136,6 @@ const styles = StyleSheet.create({
|
|||
justifyContent: 'space-between',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 25,
|
||||
paddingRight: 25,
|
||||
paddingBottom: 10,
|
||||
marginBottom: 10,
|
||||
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": {
|
||||
"@expo/vector-icons": "^14.0.2",
|
||||
"@react-native-async-storage/async-storage": "^1.24.0",
|
||||
"@react-navigation/native": "^6.0.2",
|
||||
"@teovilla/react-native-web-maps": "^0.9.5",
|
||||
"@uiw/react-color-circle": "^2.3.0",
|
||||
"axios": "^1.7.2",
|
||||
"date-fns": "^3.6.0",
|
||||
"deprecated-react-native-prop-types": "^5.0.0",
|
||||
"expo": "~51.0.22",
|
||||
|
@ -40,6 +42,7 @@
|
|||
"react-native-leaflet-view": "^0.1.2",
|
||||
"react-native-maps": "1.14.0",
|
||||
"react-native-reanimated": "~3.10.1",
|
||||
"react-native-render-html": "^6.3.4",
|
||||
"react-native-safe-area-context": "4.10.5",
|
||||
"react-native-screens": "3.31.1",
|
||||
"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