This commit is contained in:
Maarten 2024-08-08 13:13:58 +02:00
parent fe82b69997
commit 3287b9a3b7
10 changed files with 813 additions and 813 deletions

View file

@ -1,65 +1,65 @@
import {
SafeAreaView,
ScrollView,
StyleSheet,
Dimensions
SafeAreaView,
ScrollView,
StyleSheet,
Dimensions
} from 'react-native';
import {useEffect, useState} from 'react';
import { useEffect, useState } from 'react';
import RenderHtml from 'react-native-render-html';
import {useNavigation} from '@react-navigation/native';
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';
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('');
const colorScheme = useColorScheme() ?? 'light';
const navigation = useNavigation();
const [ description, setDescription ] = useState( '' );
// Load item from storage
useEffect(() => {
AsyncStorage.getItem('activeCategory').then((data) => {
const itemData: any = JSON.parse(data ?? '{}');
// Load item from storage
useEffect( () => {
AsyncStorage.getItem( 'activeCategory' ).then( (data) => {
const itemData: any = JSON.parse( data ?? '{}' );
if (itemData != null) {
const {name, description} = itemData;
if (itemData != null) {
const { name, description } = itemData;
// Set description
// @ts-ignore
setDescription(description);
// Set description
// @ts-ignore
setDescription( description );
// Set page title
navigation.setOptions({title: name});
}
});
}, []);
// Set page title
navigation.setOptions( { title: name } );
}
} );
}, [] );
// HTML render props
const source = {html: description};
const width = Dimensions.get('window').width;
// 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>
);
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,
},
})
const styles = StyleSheet.create( {
container: {
padding: 25,
},
htmlContainer: {
paddingBottom: 50,
},
} )

View file

@ -1,128 +1,128 @@
import {Stack} from 'expo-router';
import {StyleSheet, TextInput, TouchableOpacity} from 'react-native';
import { Stack } from 'expo-router';
import { StyleSheet, TextInput, TouchableOpacity } from 'react-native';
import {ThemedText} from '@/components/ThemedText';
import {ThemedView} from '@/components/ThemedView';
import {useToken} from '@/context/AppProvider';
import {Colors} from '@/constants/Colors';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { useToken } from '@/context/AppProvider';
import { Colors } from '@/constants/Colors';
import React from 'react';
import {useColorScheme} from '@/hooks/useColorScheme';
import {Message} from '@/services/message';
import {Request} from '@/services/request';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Message } from '@/services/message';
import { Request } from '@/services/request';
import { router } from 'expo-router';
export default function OnboardStartScreen() {
const colorScheme = useColorScheme() ?? 'light';
const {setToken} = useToken();
const [name, setName] = React.useState('Maarten');
const [zipcode, setZipcode] = React.useState('6715GA');
const [houseNumber, setHouseNumber] = React.useState('3');
const colorScheme = useColorScheme() ?? 'light';
const { setToken } = useToken();
const [ name, setName ] = React.useState( 'Maarten' );
const [ zipcode, setZipcode ] = React.useState( '6715GA' );
const [ houseNumber, setHouseNumber ] = React.useState( '3' );
const start = () => {
if (name === '' || zipcode === '' || houseNumber === '') {
Message.error('Niet alle gegevens zijn ingevuld!');
const start = () => {
if (name === '' || zipcode === '' || houseNumber === '') {
Message.error( 'Niet alle gegevens zijn ingevuld!' );
return;
return;
}
// TODO: Get device name
const deviceName = 'Test';
Request
.post( 'sessions/create', {
name: name,
zipcode: zipcode,
houseNumber: houseNumber,
device: deviceName,
} )
.then( (response) => {
if (!response.success) {
Message.error( response.message );
} else {
const token = response.token;
setToken( token );
router.replace( "/(tabs)" );
Message.success( response.message );
}
} );
}
// TODO: Get device name
const deviceName = 'Test';
return (
<>
<Stack.Screen options={{ title: 'Welkom' }}/>
<ThemedView style={styles.container}>
<ThemedView style={styles.heading}>
<ThemedText type="title">Welkom bij </ThemedText>
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>Kliko</ThemedText>
</ThemedView>
Request
.post('sessions/create', {
name: name,
zipcode: zipcode,
houseNumber: houseNumber,
device: deviceName,
})
.then((response) => {
if (!response.success) {
Message.error(response.message);
} else {
const token = response.token;
<ThemedView style={styles.inputContainer}>
<ThemedText>Wat is je naam?</ThemedText>
<TextInput
style={styles.input}
onChangeText={setName}
placeholder={'Je naam'}
value={name}
/>
</ThemedView>
setToken(token);
router.replace("/(tabs)");
Message.success(response.message);
}
});
}
return (
<>
<Stack.Screen options={{title: 'Welkom'}}/>
<ThemedView style={styles.container}>
<ThemedView style={styles.heading}>
<ThemedText type="title">Welkom bij </ThemedText>
<ThemedText type="title" style={{color: Colors[colorScheme].tint}}>Kliko</ThemedText>
</ThemedView>
<ThemedView style={styles.inputContainer}>
<ThemedText>Wat is je naam?</ThemedText>
<TextInput
style={styles.input}
onChangeText={setName}
placeholder={'Je naam'}
value={name}
/>
</ThemedView>
<ThemedView style={styles.inputContainer}>
<ThemedText>Wat is je postcode en huisnummer?</ThemedText>
<TextInput
style={styles.input}
onChangeText={setZipcode}
placeholder={'Postcode'}
value={zipcode}
/>
<TextInput
style={styles.input}
onChangeText={setHouseNumber}
placeholder={'Huisnummer'}
value={houseNumber}
keyboardType="numeric"
/>
</ThemedView>
<ThemedView style={styles.inputContainer}>
<ThemedText>Wat is je postcode en huisnummer?</ThemedText>
<TextInput
style={styles.input}
onChangeText={setZipcode}
placeholder={'Postcode'}
value={zipcode}
/>
<TextInput
style={styles.input}
onChangeText={setHouseNumber}
placeholder={'Huisnummer'}
value={houseNumber}
keyboardType="numeric"
/>
</ThemedView>
<TouchableOpacity style={{...styles.button, backgroundColor: Colors[colorScheme].tint}} onPress={start}>
<ThemedText style={{color: '#fff'}}>Start</ThemedText>
</TouchableOpacity>
</ThemedView>
</>
);
<TouchableOpacity style={{ ...styles.button, backgroundColor: Colors[ colorScheme ].tint }} onPress={start}>
<ThemedText style={{ color: '#fff' }}>Start</ThemedText>
</TouchableOpacity>
</ThemedView>
</>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
heading: {
marginBottom: 30,
alignItems: 'center',
justifyContent: 'center',
},
inputContainer: {
paddingTop: 20,
},
input: {
width: 250,
borderWidth: 1,
padding: 10,
paddingLeft: 20,
borderRadius: 3,
marginBottom: 10,
},
button: {
borderRadius: 5,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 40,
paddingRight: 40,
marginTop: 30,
},
});
const styles = StyleSheet.create( {
container: {
padding: 20,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
heading: {
marginBottom: 30,
alignItems: 'center',
justifyContent: 'center',
},
inputContainer: {
paddingTop: 20,
},
input: {
width: 250,
borderWidth: 1,
padding: 10,
paddingLeft: 20,
borderRadius: 3,
marginBottom: 10,
},
button: {
borderRadius: 5,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 40,
paddingRight: 40,
marginTop: 30,
},
} );

View file

@ -6,55 +6,55 @@ import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
export default function TabLayout() {
const colorScheme = useColorScheme();
const colorScheme = useColorScheme();
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
tabBarShowLabel: false,
headerShown: false,
tabBarStyle: {
height: 70,
elevation: 0,
}
}}>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'calendar' : 'calendar-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="map"
options={{
title: 'Map',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'map' : 'map-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="explore"
options={{
title: 'Explore',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'trash' : 'trash-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="settings"
options={{
title: 'Settings',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'settings' : 'settings-outline'} color={color} />
),
}}
/>
</Tabs>
);
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[ colorScheme ?? 'light' ].tint,
tabBarShowLabel: false,
headerShown: false,
tabBarStyle: {
height: 70,
elevation: 0,
}
}}>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'calendar' : 'calendar-outline'} color={color}/>
),
}}
/>
<Tabs.Screen
name="map"
options={{
title: 'Map',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'map' : 'map-outline'} color={color}/>
),
}}
/>
<Tabs.Screen
name="explore"
options={{
title: 'Explore',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'trash' : 'trash-outline'} color={color}/>
),
}}
/>
<Tabs.Screen
name="settings"
options={{
title: 'Settings',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'settings' : 'settings-outline'} color={color}/>
),
}}
/>
</Tabs>
);
}

View file

@ -1,220 +1,220 @@
import {
StyleSheet,
ScrollView,
SafeAreaView,
StatusBar,
Image,
TouchableOpacity,
View,
StyleSheet,
ScrollView,
SafeAreaView,
StatusBar,
Image,
TouchableOpacity,
View,
} from 'react-native';
import React, {useState, useEffect, useRef} from 'react';
import {router} from 'expo-router';
import type {AutocompleteDropdownRef} from 'react-native-autocomplete-dropdown'
import {AutocompleteDropdown} from 'react-native-autocomplete-dropdown';
import React, { useState, useEffect, useRef } from 'react';
import { router } from 'expo-router';
import type { AutocompleteDropdownRef } from 'react-native-autocomplete-dropdown'
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
import Modal from "react-native-modal";
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 {Request} from '@/services/request';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Request } from '@/services/request';
import List from '@/components/List';
export default function ExploreScreen() {
const colorScheme = useColorScheme() ?? 'light';
const [categories, setCategories] = useState([]);
const [types, setTypes] = useState([]);
const [activeCategory, setActiveCategory] = useState<any | null>(null);
const searchRef = useRef(null);
const dropdownController = useRef<AutocompleteDropdownRef | null>(null)
const colorScheme = useColorScheme() ?? 'light';
const [ categories, setCategories ] = useState( [] );
const [ types, setTypes ] = useState( [] );
const [ activeCategory, setActiveCategory ] = useState<any | null>( null );
const searchRef = useRef( null );
const dropdownController = useRef<AutocompleteDropdownRef | null>( null )
useEffect(() => {
// Load categories
Request.get('categories').then((response) => {
const list: any = [];
useEffect( () => {
// Load categories
Request.get( 'categories' ).then( (response) => {
const list: any = [];
response.forEach((category: any, index: any) => {
list.push({
id: index,
title: category.name,
category: category,
})
});
response.forEach( (category: any, index: any) => {
list.push( {
id: index,
title: category.name,
category: category,
} )
} );
setCategories(list);
})
setCategories( list );
} )
// Load waste types
Request.get('waste-types').then((response) => {
setTypes(response);
});
}, []);
// Load waste types
Request.get( 'waste-types' ).then( (response) => {
setTypes( response );
} );
}, [] );
// View selected item in modal
const selectItem = (item: any | null) => {
if (item == null) {
return;
// View selected item in modal
const selectItem = (item: any | null) => {
if (item == null) {
return;
}
// Clear select
dropdownController.current?.clear()
const { category } = item;
setActiveCategory( category );
}
// Clear select
dropdownController.current?.clear()
// View item in sub screen
const viewItem = async (item: any) => {
await AsyncStorage.setItem( 'activeCategory', JSON.stringify( item ) );
const {category} = item;
setActiveCategory(category);
}
router.push( '/(explore)/category' );
};
// View item in sub screen
const viewItem = async (item: any) => {
await AsyncStorage.setItem('activeCategory', JSON.stringify(item));
return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedView>
<ScrollView style={styles.container}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Wat moet waar?</ThemedText>
</ThemedView>
router.push('/(explore)/category');
};
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>en waarom?</ThemedText>
</ThemedView>
return (
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background}}>
<ThemedView>
<ScrollView style={styles.container}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Wat moet waar?</ThemedText>
</ThemedView>
<ThemedView style={styles.searchContainer}>
<ThemedText type="defaultSemiBold">Wat wilt u scheiden?</ThemedText>
<AutocompleteDropdown
ref={searchRef}
controller={controller => {
dropdownController.current = controller
}}
textInputProps={{
placeholder: 'Wat wilt u scheiden?',
autoCorrect: false,
autoCapitalize: 'none',
}}
clearOnFocus={false}
closeOnBlur={false}
closeOnSubmit={false}
emptyResultText={'Niks gevonden'}
onSelectItem={selectItem}
dataSet={categories}
showClear={false}
/>
</ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{color: Colors[colorScheme].tint}}>en waarom?</ThemedText>
</ThemedView>
<ThemedView style={styles.categoriesContainer}>
<ThemedText type="defaultSemiBold">Of kies een categorie:</ThemedText>
</ThemedView>
<ThemedView style={styles.searchContainer}>
<ThemedText type="defaultSemiBold">Wat wilt u scheiden?</ThemedText>
<AutocompleteDropdown
ref={searchRef}
controller={controller => {
dropdownController.current = controller
}}
textInputProps={{
placeholder: 'Wat wilt u scheiden?',
autoCorrect: false,
autoCapitalize: 'none',
}}
clearOnFocus={false}
closeOnBlur={false}
closeOnSubmit={false}
emptyResultText={'Niks gevonden'}
onSelectItem={selectItem}
dataSet={categories}
showClear={false}
/>
</ThemedView>
<ThemedView style={styles.listContainer}>
<List
data={types}
renderItem={(item: any, index: any) => (
<TouchableOpacity style={styles.listItem} key={index} onPress={() => viewItem( item )}>
<Image source={{ uri: item.image }} style={styles.listImage}/>
<ThemedText type="default">{item.name}</ThemedText>
</TouchableOpacity>
)}
/>
</ThemedView>
</ScrollView>
</ThemedView>
<ThemedView style={styles.categoriesContainer}>
<ThemedText type="defaultSemiBold">Of kies een categorie:</ThemedText>
</ThemedView>
<Modal isVisible={activeCategory !== null}>
<ThemedView style={{ ...styles.modalView, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedText type="subtitle" style={{ marginBottom: 30, textAlign: 'center' }}>{activeCategory?.name}</ThemedText>
<ThemedView style={styles.listContainer}>
<List
data={types}
renderItem={(item: any, index: any) => (
<TouchableOpacity style={styles.listItem} key={index} onPress={() => viewItem(item)}>
<Image source={{uri: item.image}} style={styles.listImage}/>
<ThemedText type="default">{item.name}</ThemedText>
</TouchableOpacity>
)}
/>
</ThemedView>
</ScrollView>
</ThemedView>
<View style={styles.modalType}>
<Image source={{ uri: activeCategory?.type.image }} style={styles.modalTypeImage}/>
<ThemedText>{activeCategory?.type?.name}</ThemedText>
</View>
<Modal isVisible={activeCategory !== null}>
<ThemedView style={{...styles.modalView, backgroundColor: Colors[colorScheme].background}}>
<ThemedText type="subtitle" style={{marginBottom: 30, textAlign: 'center'}}>{activeCategory?.name}</ThemedText>
<View style={{ alignItems: 'center' }}>
<ThemedText type="defaultSemiBold">Opmerking:</ThemedText>
<ThemedText>{activeCategory?.description}</ThemedText>
</View>
<View style={styles.modalType}>
<Image source={{uri: activeCategory?.type.image}} style={styles.modalTypeImage}/>
<ThemedText>{activeCategory?.type?.name}</ThemedText>
</View>
<View style={{alignItems: 'center'}}>
<ThemedText type="defaultSemiBold">Opmerking:</ThemedText>
<ThemedText>{activeCategory?.description}</ThemedText>
</View>
<TouchableOpacity
onPress={() => setActiveCategory(null)}
style={{...styles.modalClose, backgroundColor: Colors[colorScheme].tint}}>
<ThemedText style={{color: '#fff'}}>Sluiten</ThemedText>
</TouchableOpacity>
</ThemedView>
</Modal>
</SafeAreaView>
);
<TouchableOpacity
onPress={() => setActiveCategory( null )}
style={{ ...styles.modalClose, backgroundColor: Colors[ colorScheme ].tint }}>
<ThemedText style={{ color: '#fff' }}>Sluiten</ThemedText>
</TouchableOpacity>
</ThemedView>
</Modal>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
marginTop: StatusBar.currentHeight,
padding: 25,
},
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
searchContainer: {
marginTop: 10,
},
categoriesContainer: {
marginTop: 25,
},
listContainer: {
marginTop: 10,
paddingBottom: 50
},
listItem: {
flex: 1,
display: 'flex',
gap: 8,
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
},
listImage: {
width: 30,
height: 30,
borderRadius: 5,
marginRight: 8,
},
modalView: {
margin: 20,
borderRadius: 5,
padding: 35,
alignItems: 'center',
textAlign: 'center',
},
modalType: {
flex: 1,
display: 'flex',
gap: 8,
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 30,
},
modalTypeImage: {
width: 40,
height: 40,
borderRadius: 5,
marginRight: 8,
},
modalClose: {
borderRadius: 5,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 40,
paddingRight: 40,
marginTop: 30,
},
});
const styles = StyleSheet.create( {
container: {
marginTop: StatusBar.currentHeight,
padding: 25,
},
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
searchContainer: {
marginTop: 10,
},
categoriesContainer: {
marginTop: 25,
},
listContainer: {
marginTop: 10,
paddingBottom: 50
},
listItem: {
flex: 1,
display: 'flex',
gap: 8,
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
},
listImage: {
width: 30,
height: 30,
borderRadius: 5,
marginRight: 8,
},
modalView: {
margin: 20,
borderRadius: 5,
padding: 35,
alignItems: 'center',
textAlign: 'center',
},
modalType: {
flex: 1,
display: 'flex',
gap: 8,
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 30,
},
modalTypeImage: {
width: 40,
height: 40,
borderRadius: 5,
marginRight: 8,
},
modalClose: {
borderRadius: 5,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 40,
paddingRight: 40,
marginTop: 30,
},
} );

View file

@ -1,171 +1,171 @@
import React, {useEffect, useState} from 'react';
import {StyleSheet, ScrollView, SafeAreaView, View, StatusBar, TouchableOpacity, Image} from 'react-native';
import React, { useEffect, useState } from 'react';
import { StyleSheet, ScrollView, SafeAreaView, View, StatusBar, TouchableOpacity, Image } from 'react-native';
// @ts-ignore
import CalendarPicker from 'react-native-calendar-picker';
import Ionicons from '@expo/vector-icons/Ionicons';
import {ThemedText} from '@/components/ThemedText';
import {ThemedView} from '@/components/ThemedView';
import {Colors} from '@/constants/Colors';
import {useColorScheme} from '@/hooks/useColorScheme';
import {useToken} from '@/context/AppProvider';
import {Request} from '@/services/request';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useToken } from '@/context/AppProvider';
import { Request } from '@/services/request';
import List from '@/components/List';
import { useIsFocused } from '@react-navigation/core';
export default function HomeScreen() {
const colorScheme = useColorScheme() ?? 'light';
const isFocused = useIsFocused();
const {token, isLoading} = useToken();
const [name, setName] = useState(' '); // Default empty space to prevent layout shifting
const [dates, setDates] = useState<any | null>([]);
const [types, setTypes] = useState<any | null>([]);
const colorScheme = useColorScheme() ?? 'light';
const isFocused = useIsFocused();
const { token, isLoading } = useToken();
const [ name, setName ] = useState( ' ' ); // Default empty space to prevent layout shifting
const [ dates, setDates ] = useState<any | null>( [] );
const [ types, setTypes ] = useState<any | null>( [] );
useEffect(() => {
if (token) {
Request.post('calendar', {token: token}).then((response) => {
if (response.success) {
// Set name
setName(response.name);
useEffect( () => {
if (token) {
Request.post( 'calendar', { token: token } ).then( (response) => {
if (response.success) {
// Set name
setName( response.name );
// Set dates
let calendarDates: any[] = [];
response.dates.forEach((date: any) => {
calendarDates.push({
date: new Date(date.date),
style: {backgroundColor: date.color},
textStyle: {color: Colors.white},
allowDisabled: true,
})
})
setDates(calendarDates);
// Set dates
let calendarDates: any[] = [];
response.dates.forEach( (date: any) => {
calendarDates.push( {
date: new Date( date.date ),
style: { backgroundColor: date.color },
textStyle: { color: Colors.white },
allowDisabled: true,
} )
} )
setDates( calendarDates );
// Set types
setTypes(response.types);
// Set types
setTypes( response.types );
}
} )
}
})
}
}, [isFocused]);
}, [ isFocused ] );
return (
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
<ThemedView style={styles.container}>
<ScrollView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">{getGreeting()},</ThemedText>
</ThemedView>
return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background, }}>
<ThemedView style={styles.container}>
<ScrollView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">{getGreeting()},</ThemedText>
</ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{color: Colors[colorScheme].tint}}>{name}</ThemedText>
</ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>{name}</ThemedText>
</ThemedView>
<ThemedView style={styles.calendarContainer}>
<CalendarPicker
showDayStragglers={true}
enableDateChange={false}
customDatesStyles={dates}
todayTextStyle={styles.today}
previousComponent={
<Ionicons size={28} name="chevron-back"/>
}
nextComponent={
<Ionicons size={28} name="chevron-forward"/>
}
weekdays={["Zo", "Ma", "Di", "Woe", "Do", "Vrij", "Zat"]}
months={[
"Januari",
"Februari",
"Maart",
"April",
"Mei",
"Juni",
"Juli",
"Augustus",
"September",
"Oktober",
"November",
"December",
]}
/>
</ThemedView>
<ThemedView style={styles.calendarContainer}>
<CalendarPicker
showDayStragglers={true}
enableDateChange={false}
customDatesStyles={dates}
todayTextStyle={styles.today}
previousComponent={
<Ionicons size={28} name="chevron-back"/>
}
nextComponent={
<Ionicons size={28} name="chevron-forward"/>
}
weekdays={[ "Zo", "Ma", "Di", "Woe", "Do", "Vrij", "Zat" ]}
months={[
"Januari",
"Februari",
"Maart",
"April",
"Mei",
"Juni",
"Juli",
"Augustus",
"September",
"Oktober",
"November",
"December",
]}
/>
</ThemedView>
<ThemedView style={styles.legendaContainer}>
<ThemedText type='subtitle'>Legenda:</ThemedText>
<List
data={types}
viewStyle={styles.legendaList}
renderItem={(type: any, index: any) => (
<View style={styles.legendaItem} key={index}>
<View style={{...styles.circle, backgroundColor: type.color}}/>
<ThemedText type="default">{ type.name }</ThemedText>
</View>
)}
/>
</ThemedView>
</ScrollView>
</ThemedView>
</SafeAreaView>
);
<ThemedView style={styles.legendaContainer}>
<ThemedText type='subtitle'>Legenda:</ThemedText>
<List
data={types}
viewStyle={styles.legendaList}
renderItem={(type: any, index: any) => (
<View style={styles.legendaItem} key={index}>
<View style={{ ...styles.circle, backgroundColor: type.color }}/>
<ThemedText type="default">{type.name}</ThemedText>
</View>
)}
/>
</ThemedView>
</ScrollView>
</ThemedView>
</SafeAreaView>
);
}
function getGreeting() {
const myDate = new Date();
const hours = myDate.getHours();
const myDate = new Date();
const hours = myDate.getHours();
if (hours < 12) {
return 'Goedemorgen';
} else if (hours >= 12 && hours <= 17) {
return 'Goedemiddag';
} else if (hours >= 17 && hours <= 24) {
return 'Goedenavond';
}
if (hours < 12) {
return 'Goedemorgen';
} else if (hours >= 12 && hours <= 17) {
return 'Goedemiddag';
} else if (hours >= 17 && hours <= 24) {
return 'Goedenavond';
}
return 'Hallo';
return 'Hallo';
}
const styles = StyleSheet.create({
container: {
padding: 25,
marginTop: StatusBar.currentHeight,
},
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
calendarContainer: {
marginTop: 15,
},
legendaContainer: {
marginTop: 40,
},
legendaList: {
marginTop: 15,
flex: 1,
flexDirection: 'column',
alignContent: 'center',
gap: 15,
},
legendaItem: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
flexGrow: 1,
},
circle: {
width: 25,
height: 25,
borderRadius: 50,
},
today: {
borderWidth: 3,
borderColor: Colors.dark.grey,
borderRadius: 25,
textAlign: 'center',
paddingTop: 8,
width: 40,
height: 40,
},
});
const styles = StyleSheet.create( {
container: {
padding: 25,
marginTop: StatusBar.currentHeight,
},
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
calendarContainer: {
marginTop: 15,
},
legendaContainer: {
marginTop: 40,
},
legendaList: {
marginTop: 15,
flex: 1,
flexDirection: 'column',
alignContent: 'center',
gap: 15,
},
legendaItem: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
flexGrow: 1,
},
circle: {
width: 25,
height: 25,
borderRadius: 50,
},
today: {
borderWidth: 3,
borderColor: Colors.dark.grey,
borderRadius: 25,
textAlign: 'center',
paddingTop: 8,
width: 40,
height: 40,
},
} );

View file

@ -1,194 +1,194 @@
import React, {useEffect, useState} from 'react';
import {Image, SafeAreaView, ScrollView, StatusBar, StyleSheet, Switch, View, Dimensions} from 'react-native';
import Mapbox, {Callout, Camera, MapView, PointAnnotation} from "@rnmapbox/maps";
import React, { useEffect, useState } from 'react';
import { Image, SafeAreaView, ScrollView, StatusBar, StyleSheet, Switch, View, Dimensions } from 'react-native';
import Mapbox, { Callout, Camera, MapView, PointAnnotation } from "@rnmapbox/maps";
Mapbox.setAccessToken("pk.eyJ1IjoibWFhcnRlbnZyOTgiLCJhIjoiY2x6ZDFqMGp1MGVyejJrczhqcXpvYm9iYiJ9.XvYcL62dWiJQiFmG6mOoug");
Mapbox.setAccessToken( "pk.eyJ1IjoibWFhcnRlbnZyOTgiLCJhIjoiY2x6ZDFqMGp1MGVyejJrczhqcXpvYm9iYiJ9.XvYcL62dWiJQiFmG6mOoug" );
import {ThemedText} from '@/components/ThemedText';
import {ThemedView} from '@/components/ThemedView';
import {Colors} from '@/constants/Colors';
import {useColorScheme} from '@/hooks/useColorScheme';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import List from '@/components/List';
import {Request} from '@/services/request';
import { Request } from '@/services/request';
export default function MapScreen() {
const colorScheme = useColorScheme() ?? 'light';
const colorScheme = useColorScheme() ?? 'light';
const [types, setTypes] = useState<any>([]);
const [markers, setMarkers] = useState<any>([]);
const [ types, setTypes ] = useState<any>( [] );
const [ markers, setMarkers ] = useState<any>( [] );
// Load markers and types
useEffect(() => {
Mapbox.setTelemetryEnabled(false);
// Load markers and types
useEffect( () => {
Mapbox.setTelemetryEnabled( false );
Request.get('locations').then((response) => {
const {locations, types} = response;
Request.get( 'locations' ).then( (response) => {
const { locations, types } = response;
// Set types
const typesList: any[] = [];
types.forEach((type: any) => {
typesList.push({
name: type.name,
image: type.image,
isEnabled: false,
type: type.config_name,
});
})
setTypes(typesList);
// Set types
const typesList: any[] = [];
types.forEach( (type: any) => {
typesList.push( {
name: type.name,
image: type.image,
isEnabled: false,
type: type.config_name,
} );
} )
setTypes( typesList );
// Set markers
setMarkers(locations);
})
}, []);
// Set markers
setMarkers( locations );
} )
}, [] );
// Enable/disable type
const toggleSwitch = (index: any) => {
const newData = types.map((item: any, key: any) =>
key === index ? {...item, isEnabled: !item.isEnabled} : item
);
// Enable/disable type
const toggleSwitch = (index: any) => {
const newData = types.map( (item: any, key: any) =>
key === index ? { ...item, isEnabled: !item.isEnabled } : item
);
setTypes(newData);
};
setTypes( newData );
};
// Get all types that are active
const getActiveTypes = (): Array<String> => {
const list: any[] = [];
// Get all types that are active
const getActiveTypes = (): Array<String> => {
const list: any[] = [];
types.forEach((type: any) => {
if (type.isEnabled) {
list.push(type.type);
}
});
types.forEach( (type: any) => {
if (type.isEnabled) {
list.push( type.type );
}
} );
return list;
}
return list;
}
// Get all markers that needs to be visible
const activeMarkers = () => {
return markers.filter((marker: any) => {
return getActiveTypes().includes(marker.waste_type);
});
}
// Get all markers that needs to be visible
const activeMarkers = () => {
return markers.filter( (marker: any) => {
return getActiveTypes().includes( marker.waste_type );
} );
}
return (
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background}}>
<ThemedView style={styles.container}>
<ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Afvalcontainers</ThemedText>
</ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{color: Colors[colorScheme].tint}}>in de buurt</ThemedText>
</ThemedView>
<ThemedView style={styles.mapContainer}>
<MapView
style={styles.map}
logoEnabled={false}
scaleBarEnabled={false}
attributionEnabled={false}
>
<Camera
centerCoordinate={[5.630960, 52.043420]}
zoomLevel={13}
animationMode={'none'}
/>
{activeMarkers().map((marker: any, index: any) => (
<PointAnnotation
key={marker.id.toString()}
id={marker.id.toString()}
coordinate={marker.coordinate}
>
<Callout title={marker.number}>
<ThemedView style={styles.callout}>
<ThemedText>{marker.description + ' - ' + marker.street}</ThemedText>
return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedView style={styles.container}>
<ThemedView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Afvalcontainers</ThemedText>
</ThemedView>
</Callout>
</PointAnnotation>
))}
</MapView>
</ThemedView>
</ThemedView>
<ScrollView style={styles.listContainer}>
<List
data={types}
renderItem={(item: any, index: any) => (
<ThemedView style={styles.listItem} key={index}>
<View style={styles.listItemTitle}>
<Image source={{uri: item.image}} style={styles.listImage}/>
<ThemedText type="default">{item.name}</ThemedText>
</View>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title" style={{ color: Colors[ colorScheme ].tint }}>in de buurt</ThemedText>
</ThemedView>
<Switch
trackColor={{false: '#767577', true: Colors[colorScheme].tint}}
thumbColor={'#fff'}
value={item.isEnabled}
onValueChange={() => toggleSwitch(index)}
/>
</ThemedView>
)}/>
</ScrollView>
</ThemedView>
</SafeAreaView>
);
<ThemedView style={styles.mapContainer}>
<MapView
style={styles.map}
logoEnabled={false}
scaleBarEnabled={false}
attributionEnabled={false}
>
<Camera
centerCoordinate={[ 5.630960, 52.043420 ]}
zoomLevel={13}
animationMode={'none'}
/>
{activeMarkers().map( (marker: any, index: any) => (
<PointAnnotation
key={marker.id.toString()}
id={marker.id.toString()}
coordinate={marker.coordinate}
>
<Callout title={marker.number}>
<ThemedView style={styles.callout}>
<ThemedText>{marker.description + ' - ' + marker.street}</ThemedText>
</ThemedView>
</Callout>
</PointAnnotation>
) )}
</MapView>
</ThemedView>
</ThemedView>
<ScrollView style={styles.listContainer}>
<List
data={types}
renderItem={(item: any, index: any) => (
<ThemedView style={styles.listItem} key={index}>
<View style={styles.listItemTitle}>
<Image source={{ uri: item.image }} style={styles.listImage}/>
<ThemedText type="default">{item.name}</ThemedText>
</View>
<Switch
trackColor={{ false: '#767577', true: Colors[ colorScheme ].tint }}
thumbColor={'#fff'}
value={item.isEnabled}
onValueChange={() => toggleSwitch( index )}
/>
</ThemedView>
)}/>
</ScrollView>
</ThemedView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
marginTop: StatusBar.currentHeight,
paddingTop: 25,
flex: 1,
},
titleContainer: {
paddingLeft: 25,
paddingRight: 25,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
mapContainer: {
marginTop: 15,
height: 400,
},
map: {
width: Dimensions.get('window').width,
height: 400,
flex: 1,
},
listContainer: {
flex: 1,
paddingTop: 20,
paddingLeft: 25,
paddingRight: 25,
},
listItem: {
flex: 1,
display: 'flex',
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
},
listItemTitle: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
listImage: {
width: 30,
height: 30,
borderRadius: 5,
marginRight: 8,
},
callout: {
width: 200,
padding: 5,
},
});
const styles = StyleSheet.create( {
container: {
marginTop: StatusBar.currentHeight,
paddingTop: 25,
flex: 1,
},
titleContainer: {
paddingLeft: 25,
paddingRight: 25,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingBottom: 8,
},
mapContainer: {
marginTop: 15,
height: 400,
},
map: {
width: Dimensions.get( 'window' ).width,
height: 400,
flex: 1,
},
listContainer: {
flex: 1,
paddingTop: 20,
paddingLeft: 25,
paddingRight: 25,
},
listItem: {
flex: 1,
display: 'flex',
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 10,
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
},
listItemTitle: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
listImage: {
width: 30,
height: 30,
borderRadius: 5,
marginRight: 8,
},
callout: {
width: 200,
padding: 5,
},
} );

View file

@ -64,7 +64,7 @@ export default function SettingsScreen() {
// Handle
const handleSave = (inputValues: Record<string, string>) => {
let postData: any = {token: token};
let postData: any = { token: token };
if (inputValues.name) {
postData[ 'name' ] = inputValues.name;
@ -80,7 +80,7 @@ export default function SettingsScreen() {
Request.post( 'sessions/update', postData )
.then( (response) => {
console.log('save', response);
console.log( 'save', response );
if (response.success) {
setSessionData( response.session );
@ -90,9 +90,9 @@ export default function SettingsScreen() {
Message.error( response.message );
}
} )
.catch((error) => {
console.log('error', error);
})
.catch( (error) => {
console.log( 'error', error );
} )
};
const logout = () => {

View file

@ -6,26 +6,26 @@ import { type PropsWithChildren } from 'react';
* The contents of this function only run in Node.js environments and do not have access to the DOM or browser APIs.
*/
export default function Root({ children }: PropsWithChildren) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
return (
<html lang="en">
<head>
<meta charSet="utf-8"/>
<meta httpEquiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
{/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
<ScrollViewStyleReset />
{/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
<ScrollViewStyleReset/>
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }}/>
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
}
const responsiveBackground = `

View file

@ -1,47 +1,47 @@
import {useFonts} from 'expo-font';
import {Slot, Stack} from 'expo-router';
import { useFonts } from 'expo-font';
import { Slot, Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import {useEffect} from 'react';
import { useEffect } from 'react';
import 'react-native-reanimated';
import {AppProvider} from '@/context/AppProvider';
import {DarkTheme, DefaultTheme, ThemeProvider} from '@react-navigation/native';
import { AppProvider } from '@/context/AppProvider';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import Toast from 'react-native-toast-message';
import {AutocompleteDropdownContextProvider} from 'react-native-autocomplete-dropdown';
import {useColorScheme} from '@/hooks/useColorScheme';
import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown';
import { useColorScheme } from '@/hooks/useColorScheme';
// Prevent the splash screen from auto-hiding before asset loading is complete.
// SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const colorScheme = useColorScheme();
const colorScheme = useColorScheme();
const [loaded] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
});
const [ loaded ] = useFonts( {
SpaceMono: require( '../assets/fonts/SpaceMono-Regular.ttf' ),
} );
useEffect(() => {
if (loaded) {
// SplashScreen.hideAsync();
useEffect( () => {
if (loaded) {
// SplashScreen.hideAsync();
}
}, [ loaded ] );
if (!loaded) {
return null;
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<AppProvider>
<AutocompleteDropdownContextProvider>
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{headerShown: false}}/>
<Stack.Screen name="(onboarding)/start" options={{headerShown: false}}/>
<Stack.Screen name="index" options={{headerShown: false}}/>
</Stack>
<Toast/>
</ThemeProvider>
</AutocompleteDropdownContextProvider>
</AppProvider>
);
return (
<AppProvider>
<AutocompleteDropdownContextProvider>
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }}/>
<Stack.Screen name="(onboarding)/start" options={{ headerShown: false }}/>
<Stack.Screen name="index" options={{ headerShown: false }}/>
</Stack>
<Toast/>
</ThemeProvider>
</AutocompleteDropdownContextProvider>
</AppProvider>
);
}

View file

@ -1,45 +1,45 @@
import React, {useEffect} from 'react';
import {Redirect, router, useRouter} from 'expo-router';
import React, { useEffect } from 'react';
import { Redirect, router, useRouter } from 'expo-router';
import {ThemedText} from '@/components/ThemedText';
import {ThemedView} from '@/components/ThemedView';
import {useToken} from '@/context/AppProvider';
import {Request} from '@/services/request';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { useToken } from '@/context/AppProvider';
import { Request } from '@/services/request';
export default function OnboardStartScreen() {
const { token, isLoading } = useToken();
const router = useRouter();
const { token, isLoading } = useToken();
const router = useRouter();
const loadingScreen = () => (
<ThemedView>
<ThemedText>Laden...</ThemedText>
</ThemedView>
);
const loadingScreen = () => (
<ThemedView>
<ThemedText>Laden...</ThemedText>
</ThemedView>
);
useEffect(() => {
const fetchData = async () => {
const response = await Request.post('sessions/get', { token: token });
if (response.success) {
// @ts-ignore
router.replace('/(tabs)/settings');
} else {
router.replace('/(onboarding)/start');
}
};
useEffect( () => {
const fetchData = async () => {
const response = await Request.post( 'sessions/get', { token: token } );
if (response.success) {
// @ts-ignore
router.replace( '/(tabs)/settings' );
} else {
router.replace( '/(onboarding)/start' );
}
};
if (!isLoading && token) {
fetchData();
if (!isLoading && token) {
fetchData();
}
}, [ isLoading, token, router ] );
if (isLoading) {
return loadingScreen();
}
if (!token) {
return <Redirect href="/(onboarding)/start"/>;
}
}, [isLoading, token, router]);
if (isLoading) {
return loadingScreen();
}
if (!token) {
return <Redirect href="/(onboarding)/start" />;
}
return loadingScreen();
}