Create cache flow

parent f555737a
......@@ -1170,14 +1170,6 @@
"@types/yargs": "^13.0.0"
}
},
"@react-native-community/async-storage": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.10.3.tgz",
"integrity": "sha512-f3G3dX5aoFZZC1G7alnaFmlTpXn8HPfpR8H3Hf7wbbQrQvZmW7mW2fXHv/oj99FNPd228bneL3GOnjGe2Epkww==",
"requires": {
"deep-assign": "^3.0.0"
}
},
"@react-native-community/cli-debugger-ui": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-3.0.0.tgz",
......@@ -1414,7 +1406,6 @@
"version": "0.60.31",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.60.31.tgz",
"integrity": "sha512-Y0Q+nv50KHnLL+jM0UH68gQQv7Wt6v2KuNepiHKwK1DoWGVd1oYun/GJCnvUje+/V8pMQQWW6QuBvHZz1pV7tQ==",
"dev": true,
"requires": {
"@types/prop-types": "*",
"@types/react": "*"
......@@ -1427,16 +1418,6 @@
"requires": {
"@types/react": "*",
"@types/react-native": "*"
},
"dependencies": {
"@types/react-native": {
"version": "0.62.7",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.7.tgz",
"integrity": "sha512-FGFEt9GcFVl//XxWmxkeBxAx0YnzyEhJpR8hOJrjfaFKZm0KjHzzyCmCksBAP2qHSTrcJCiBkIvYCX/kGiOgww==",
"requires": {
"@types/react": "*"
}
}
}
},
"@types/react-redux": {
......@@ -6629,9 +6610,9 @@
}
},
"react-native-elements": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/react-native-elements/-/react-native-elements-1.2.7.tgz",
"integrity": "sha512-0S+0R1cbItl15i64qrkWnyMztwpw60d0SUsZGVDKRAMf0Jvq9Clgyh/MzxJx2sr42mbedQP1sg5Et4fZM7Fp1w==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-native-elements/-/react-native-elements-2.0.0.tgz",
"integrity": "sha512-xViTU/JlabYX94fDL2iu17gvMtgEOq2lFAToYlU3RBkwb/J13cdwSr8Ti9z6v6Iui4f8S3FjkpRJnFaOsZrK7w==",
"requires": {
"@types/react-native-vector-icons": "^6.4.4",
"color": "^3.1.0",
......@@ -6639,7 +6620,7 @@
"hoist-non-react-statics": "^3.1.0",
"opencollective-postinstall": "^2.0.0",
"prop-types": "^15.7.2",
"react-native-ratings": "^6.3.0",
"react-native-ratings": "^6.5.0",
"react-native-status-bar-height": "^2.2.0"
}
},
......
import React from 'react';
import { Icon } from 'react-native-elements';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
import { useSelector } from 'react-redux';
import DiscoverScreen from './screens/DiscoverScreen';
import MessageCreateScreen from './screens/MessageCreateScreen';
import SavedMessagesScreen from './screens/SavedMessagesScreen';
import SignInScreen from './screens/SignInScreen';
import RootNavigator from './navigation/RootNavigator';
import theme from './theme';
import BootScreen from './screens/BootScreen';
import { getAuthLoading, getAuthToken } from './store/auth/AuthSelectors';
const NavTheme = {
...DefaultTheme,
......@@ -20,74 +11,6 @@ const NavTheme = {
},
};
const TabIcon: React.FC<{ name: string}> = ({ name }) => (
<Icon
name={name}
type={'font-awesome'}
color={theme.colors.green}
/>
);
const Tab = createBottomTabNavigator();
const AppNavigator = () => (
<Tab.Navigator
initialRouteName={'Saved'}
tabBarOptions={{
activeTintColor: theme.colors.green,
}}
>
<Tab.Screen
name={'Discover'}
component={DiscoverScreen}
options={{
tabBarIcon: () => <TabIcon name={'compass'} />,
}}
/>
<Tab.Screen
name={'Saved'}
component={SavedMessagesScreen}
options={{
tabBarIcon: () => <TabIcon name={'bookmark'} />,
}}
/>
<Tab.Screen
name={'Create'}
component={MessageCreateScreen}
options={{
tabBarIcon: () => <TabIcon name={'pencil'} />,
}}
/>
</Tab.Navigator>
);
const Stack = createStackNavigator();
const RootNavigator = () => {
const loading = useSelector(getAuthLoading);
const token = useSelector(getAuthToken);
if (loading) {
return <BootScreen />;
}
return (
<Stack.Navigator headerMode={'none'}>
{token
? (
<Stack.Screen component={AppNavigator} name={'AppNavigator'} />
)
: (
<Stack.Screen
name={'SignIn'}
component={SignInScreen}
options={{
animationTypeForReplace: 'pop',
}}
/>
)}
</Stack.Navigator>
);
};
const AppContainer = () => (
<NavigationContainer theme={NavTheme}>
<RootNavigator />
......
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Overlay, Button } from 'react-native-elements';
import { Overlay } from 'react-native-elements';
import theme from '../theme';
import GeoText from './GeoText';
import { Cache } from '../store/caches/CachesState';
import GeoButton from './GeoButton';
const styles = StyleSheet.create({
......@@ -17,12 +18,6 @@ const styles = StyleSheet.create({
width: '75%',
height: '40%',
},
buttonContainer: {
flex: 1,
},
button: {
borderRadius: 0,
},
});
interface Props {
......@@ -48,19 +43,16 @@ const MessageFoundModal: React.FC<Props> = ({
<GeoText text={cache.message} style={{ marginTop: theme.spacing.medium }} />
</View>
<View style={{ flexDirection: 'row' }}>
<Button
<GeoButton
title={'Report'}
type={'outline'}
containerStyle={[styles.buttonContainer, { marginRight: theme.spacing.small }]}
buttonStyle={styles.button}
onPress={onReport}
style={{ flex: 1, marginRight: theme.spacing.small }}
type={'clear'}
/>
<Button
<GeoButton
title={'Save'}
type={'solid'}
containerStyle={styles.buttonContainer}
buttonStyle={styles.button}
onPress={onSave}
style={{ flex: 1 }}
/>
</View>
</View>
......
import React, { useCallback } from 'react';
import { StyleSheet, View } from 'react-native';
import { Overlay, Button } from 'react-native-elements';
import { Overlay } from 'react-native-elements';
import { useDispatch, useSelector } from 'react-redux';
import { geoSearch } from '../store/caches/CachesActions';
import { getUserLatLng } from '../store/location/LocationSelectors';
import { signOutAsync } from '../store/auth/AuthActions';
import GeoButton from './GeoButton';
const styles = StyleSheet.create({
overlay: {
......@@ -12,9 +13,6 @@ const styles = StyleSheet.create({
justifyContent: 'center',
alignItems: 'center',
},
button: {
width: '100%',
},
});
interface Props {
......@@ -37,23 +35,17 @@ const DevModal: React.FC<Props> = ({ isOpen, onClose }) => {
return (
<Overlay isVisible={isOpen} fullScreen>
<View style={styles.overlay}>
<Button
<GeoButton
title={'geosearch'}
onPress={geosearch}
type={'solid'}
containerStyle={styles.button}
/>
<Button
<GeoButton
title={'sign out'}
onPress={signout}
type={'solid'}
containerStyle={styles.button}
/>
<Button
<GeoButton
title={'Close'}
onPress={onClose}
type={'outline'}
containerStyle={styles.button}
/>
</View>
</Overlay>
......
import React from 'react';
import { StyleSheet, ViewStyle } from 'react-native';
import { Button } from 'react-native-elements';
import theme from '../theme';
const styles = StyleSheet.create({
container: {
width: '100%',
borderRadius: theme.spacing.large,
},
button: {},
});
interface Props {
disabled?: boolean;
onPress: () => void;
style?: ViewStyle;
title: string;
type?: 'solid' | 'clear' | 'outline';
}
const GeoButton: React.FC<Props> = ({
disabled = false,
style,
title, onPress,
type = 'solid',
}) => (
<Button
containerStyle={[styles.container, style]}
disabled={disabled}
onPress={onPress}
style={styles.button}
title={title}
type={type}
/>
);
export default GeoButton;
import React, { useCallback } from 'react';
import React from 'react';
import { Callout, Marker } from 'react-native-maps';
import { Cache } from '../store/caches/CachesState';
import GeoText from './GeoText';
import theme from '../theme';
interface Props {
cache: Cache;
onPress: (cache: Cache) => void;
lat: number;
lng: number;
message?: string;
onPress?: () => void;
}
const GeoMarker: React.FC<Props> = ({ cache, onPress }) => {
const handlePress = useCallback(() => onPress(cache), [onPress, cache]);
return (
<Marker
key={cache.id}
coordinate={{ latitude: cache.lat, longitude: cache.lng }}
>
const GeoMarker: React.FC<Props> = ({
lat, lng, message, onPress,
}) => (
<Marker
coordinate={{ latitude: lat, longitude: lng }}
>
{ message && onPress && (
<Callout
onPress={handlePress}
onPress={onPress}
tooltip={false}
style={{ width: 200, padding: theme.spacing.small }}
>
<GeoText
text={cache.message}
text={message}
variant={'text'}
style={{ flex: 1, flexWrap: 'wrap' }}
numberOfLines={3}
/>
</Callout>
</Marker>
);
};
)}
</Marker>
);
export default GeoMarker;
......@@ -2,7 +2,7 @@ import React from 'react';
import {
Text, TextStyle, StyleSheet, TextProps,
} from 'react-native';
import theme, { Color } from '../theme';
import { Color, COLOR_MAP } from '../theme';
type Variant = 'header' | 'formHeader' | 'textBold' | 'text' | 'textWeak';
......@@ -48,10 +48,10 @@ interface Props {
}
const GeoText: React.FC<Props & TextProps> = ({
text, variant = 'text', color = theme.colors.black, style, ...textProps
text, variant = 'text', color = 'black', style, ...textProps
}) => (
<Text
style={[styles[variant], style, { color }]}
style={[styles[variant], style, { color: COLOR_MAP[color] }]}
{...textProps}
>
{text}
......
import React from 'react';
import { View, StyleSheet, ViewStyle } from 'react-native';
import { Icon } from 'react-native-elements';
import { TouchableOpacity } from 'react-native-gesture-handler';
import theme from '../theme';
const SIZE = 34;
const styles = StyleSheet.create({
background: {
backgroundColor: theme.colors.green,
borderRadius: SIZE,
},
icon: {
padding: SIZE / 2,
},
});
interface Props {
onPress: () => void;
style?: ViewStyle;
}
const NewCacheButton: React.FC<Props> = ({ onPress, style }) => (
<View style={[styles.background, style]}>
<TouchableOpacity onPress={onPress} style={{ flex: 1 }}>
<Icon
name={'feather-alt'}
type={'font-awesome-5'}
color={theme.colors.white}
style={styles.icon}
size={SIZE}
/>
</TouchableOpacity>
</View>
);
export default NewCacheButton;
......@@ -11,6 +11,7 @@ interface Props {
const ScreenHeader: React.FC<Props> = ({ title }) => {
const [devModalOpen, setDevModalOpen] = useState(false);
return (
<>
<Header
......
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import HomeNavigator from './HomeNavigator';
import CreateCacheNavigator from './CreateCacheNavigator';
const Stack = createStackNavigator();
const AppNavigator = () => (
<Stack.Navigator mode={'modal'} headerMode={'none'}>
<Stack.Screen
name={'Main'}
component={HomeNavigator}
/>
<Stack.Screen
name={'Create'}
component={CreateCacheNavigator}
/>
</Stack.Navigator>
);
export default AppNavigator;
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { Icon } from 'react-native-elements';
import { TouchableOpacity } from 'react-native-gesture-handler';
import CacheMessageScreen from '../screens/create/CacheMessageScreen';
import CacheDurationScreen from '../screens/create/CacheDurationScreen';
import CacheSubmitScreen from '../screens/create/CacheSubmitScreen';
import theme from '../theme';
interface BackButtonProps {
close: boolean;
onPress: () => void;
}
const BackButton: React.FC<BackButtonProps> = ({ close, onPress }) => (
<TouchableOpacity
onPress={onPress}
style={{ marginLeft: theme.spacing.screenPadding }}
>
<Icon
name={close ? 'times' : 'chevron-left'}
type={'font-awesome-5'}
/>
</TouchableOpacity>
);
const Stack = createStackNavigator();
const CreateCacheNavigator = () => (
<Stack.Navigator
screenOptions={
({ navigation, route }) => ({
headerLeft: () => (
<BackButton
close={route.name === 'CacheContent'}
onPress={() => navigation.goBack()}
/>
),
headerTitleStyle: { fontSize: 24 },
})
}
>
<Stack.Screen
name={'CacheContent'}
component={CacheMessageScreen}
options={{ title: 'Message' }}
/>
<Stack.Screen
name={'CacheDuration'}
component={CacheDurationScreen}
options={{ title: 'Hide Time' }}
/>
<Stack.Screen
name={'CacheSubmit'}
component={CacheSubmitScreen}
options={{ title: 'Submit' }}
/>
</Stack.Navigator>
);
export default CreateCacheNavigator;
import React from 'react';
import { Icon } from 'react-native-elements';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import DiscoverScreen from '../screens/DiscoverScreen';
import ActivityScreen from '../screens/ActivityScreen';
import SavedMessagesScreen from '../screens/SavedMessagesScreen';
import theme from '../theme';
const TabIcon: React.FC<{ name: string}> = ({ name }) => (
<Icon
name={name}
type={'font-awesome'}
color={theme.colors.green}
/>
);
const Tab = createBottomTabNavigator();
const HomeNavigator = () => (
<Tab.Navigator
initialRouteName={'Discover'}
tabBarOptions={{
activeTintColor: theme.colors.green,
}}
>
<Tab.Screen
name={'Discover'}
component={DiscoverScreen}
options={{
tabBarIcon: () => <TabIcon name={'compass'} />,
}}
/>
<Tab.Screen
name={'Activity'}
component={ActivityScreen}
options={{
tabBarIcon: () => <TabIcon name={'heart'} />,
}}
/>
<Tab.Screen
name={'Saved'}
component={SavedMessagesScreen}
options={{
tabBarIcon: () => <TabIcon name={'bookmark'} />,
}}
/>
</Tab.Navigator>
);
export default HomeNavigator;
import React from 'react';
import { useSelector } from 'react-redux';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import BootScreen from '../screens/BootScreen';
import { getAuthLoading, getAuthToken } from '../store/auth/AuthSelectors';
import AppNavigator from './AppNavigator';
const Stack = createStackNavigator();
const RootNavigator = () => {
const loading = useSelector(getAuthLoading);
const token = useSelector(getAuthToken);
if (loading) {
return <BootScreen />;
}
return (
<Stack.Navigator headerMode={'none'}>
{token
? (
<Stack.Screen component={AppNavigator} name={'AppNavigator'} />
)
: (
<Stack.Screen
name={'SignIn'}
component={SignInScreen}
options={{
animationTypeForReplace: 'pop',
}}
/>
)}
</Stack.Navigator>
);
};
export default RootNavigator;
import React from 'react';
import { View, Text } from 'react-native';
const ActivityScreen = () => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Activity Screen</Text>
</View>
);
export default ActivityScreen;
......@@ -2,6 +2,7 @@ import React, { useState, useCallback, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { StyleSheet, View } from 'react-native';
import MapView from 'react-native-maps';
import { useNavigation } from '@react-navigation/native';
import CacheFoundModal from '../components/CacheFoundModal';
import { Cache } from '../store/caches/CachesState';
import { getDiscoveredCaches } from '../store/caches/CachesSelectors';
......@@ -10,6 +11,7 @@ import { saveCache, reportCache, geoSearch } from '../store/caches/CachesActions
import ScreenHeader from '../components/ScreenHeader';
import GeoMarker from '../components/GeoMarker';
import { sampleCaches } from '../SampleCaches';
import NewCacheButton from '../components/NewCacheButton';
const styles = StyleSheet.create({
background: {
......@@ -19,10 +21,16 @@ const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
newCacheButton: {
position: 'absolute',
bottom: 20,
right: 20,
},
});
const DiscoverScreen: React.FC = () => {
const dispatch = useDispatch();
const { navigate } = useNavigation();
const discoveredCaches: Cache[] = useSelector(getDiscoveredCaches);
const [isCacheModalOpen, setCacheModalOpen] = useState(false);
const [openCache, setOpenCache] = useState<Cache | null>(sampleCaches[0]);
......@@ -82,9 +90,16 @@ const DiscoverScreen: React.FC = () => {
// followsUserLocation={true}
>
{discoveredCaches.map((cache) => (
<GeoMarker key={cache.id} cache={cache} onPress={onCalloutPress} />
<GeoMarker
key={cache.id}
lat={cache.lat}
lng={cache.lng}
message={cache.message}
onPress={() => onCalloutPress(cache)}
/>
))}
</MapView>
<NewCacheButton onPress={() => navigate('Create')} style={styles.newCacheButton} />
</View>
</>
);
......
import React, { useState, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import {
Picker,
StyleSheet,
Switch,
Text,
View,