Merge branch 'nikolaik/render-html' into 'main'

Migrate to react-native-render-html

See merge request edb/cnapp!1
This commit is contained in:
Leander West Furumo committed 2024-02-22 19:46:49 +00:00
commit 4585a96f60
27 files changed
+5103 -652

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
module.exports = {
root: true,
extends: [
'@react-native',
'airbnb-base',
'plugin:prettier/recommended',
'plugin:react/recommended',
'plugin:import/errors',
'plugin:import/warnings',
],
rules: {
'no-plusplus': 0,
'no-console': 0,
'no-underscore-dangle': 0,
'no-param-reassign': 0,
'react/prefer-stateless-function': 1,
'react/prop-types': 'off', // FIXME: typescript
'class-methods-use-this': 1, // FIXME: refactor
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'react/sort-comp': 0,
'max-len': 0,
'no-use-before-define': ['error', { functions: true, classes: true, variables: false }], // disable the rule for variables, but enable it for functions and classes
'react-native/no-inline-styles': 'off', // FIXME: refactor
},
plugins: ['prettier'],
parser: '@babel/eslint-parser',
settings: {
react: {
version: 'detect',
},
},
};
+1 -1
View File
@@ -29,7 +29,7 @@ yarn-error.*
*.pem
# local env files
.env*.local
.env*
# typescript
*.tsbuildinfo
+2 -2
View File
@@ -1,3 +1,3 @@
import App from './src/App'
import App from './src/App';
export default App
export default App;
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};
+5 -5
View File
@@ -1,13 +1,13 @@
// FIXME: This is never loaded by expo
import { AppRegistry } from 'react-native';
import * as Sentry from '@sentry/react-native';
import Config from 'react-native-config';
// import * as Sentry from '@sentry/react-native';
import App from './src/App';
import { name as appName } from './app.json';
if (Config.SENTRY_DSN) {
Sentry.init({ dsn: Config.SENTRY_DSN });
}
// if (Config.SENTRY_DSN) {
// Sentry.init({ dsn: Config.SENTRY_DSN });
// }
AppRegistry.registerComponent(appName, () => App);
+4872 -508
View File
File diff suppressed because it is too large. Load diff
+21 -7
View File
@@ -6,10 +6,12 @@
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
"web": "expo start --web",
"lint": "eslint ."
},
"dependencies": {
"@apollo/client": "^3.7.17",
"@expo/vector-icons": "^13.0.0",
"@react-native-async-storage/async-storage": "1.18.2",
"@react-navigation/bottom-tabs": "^6.5.8",
"@react-navigation/native": "^6.1.7",
@@ -24,23 +26,35 @@
"native-base": "^3.4.28",
"react": "18.2.0",
"react-hook-form": "^7.45.2",
"react-native": "0.72.3",
"react-native": "0.72.4",
"react-native-confetti": "^0.1.0",
"react-native-gesture-handler": "~2.12.0",
"react-native-htmlview": "^0.16.0",
"react-native-gesture-handler": "2.12.0",
"react-native-reanimated": "3.3.0",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"react-native-svg": "13.9.0",
"react-native-vector-icons": "^10.0.0",
"react-native-ui-lib": "^7.8.0",
"react-redux": "^8.1.2",
"redux": "^4.2.1",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.4.2",
"styled-components": "^6.0.6",
"styled-system": "^5.1.5"
},
"devDependencies": {
"@babel/core": "^7.20.0"
"@babel/core": "^7.20.0",
"@babel/eslint-parser": "^7.22.15",
"@react-native/eslint-config": "^0.72.2",
"@testing-library/react-native": "^12.3.0",
"eslint": "^8.49.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^3.0.3"
},
"private": true
}
+7
View File
@@ -3,6 +3,9 @@ import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { ApolloClient, HttpLink, InMemoryCache, ApolloProvider } from '@apollo/client';
import { StripeProvider } from '@stripe/stripe-react-native';
import { LogBox } from 'react-native';
import { loadTheme } from './theme';
import Dusken from './Dusken';
import { store, persistor } from './reduxStore';
@@ -11,6 +14,10 @@ const apolloClient = new ApolloClient({
link: new HttpLink({ uri: `${process.env.EXPO_PUBLIC_DUSKEN_API_URL}/api/graphql/` }),
cache: new InMemoryCache(),
});
// FIXME: Replace unmaintained native-base with https://wix.github.io/react-native-ui-lib/ which produces this warning
LogBox.ignoreLogs(['In React 18, SSRProvider is not necessary and is a noop. You can remove it from your app.']);
loadTheme();
export default function App() {
return (
+7 -4
View File
@@ -2,7 +2,7 @@ import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
import { SimpleLineIcons as Icon } from '@expo/vector-icons';
import EventList from './modules/events/EventList';
import EventDetail from './modules/events/EventDetail';
@@ -46,6 +46,9 @@ const UserStackScreen = () => (
);
const HomeTabs = createBottomTabNavigator();
const EventIcon = ({ color, size }) => <Icon name="event" size={size} color={color} style={{ marginTop: 5 }} />;
const UserIcon = ({ color, size }) => <Icon name="user" size={size} color={color} style={{ marginTop: 5 }} />;
const AboutIcon = ({ color, size }) => <Icon name="info" size={size} color={color} style={{ marginTop: 5 }} />;
const Navigation = () => (
<NavigationContainer>
<HomeTabs.Navigator initialRouteName="EventStack">
@@ -55,7 +58,7 @@ const Navigation = () => (
options={{
headerShown: false,
tabBarLabel: 'Program',
tabBarIcon: ({ color, size }) => <Icon name="event" size={size} color={color} style={{ marginTop: 5 }} />,
tabBarIcon: EventIcon,
}}
/>
<HomeTabs.Screen
@@ -64,7 +67,7 @@ const Navigation = () => (
options={{
headerShown: false,
tabBarLabel: 'Medlemskap',
tabBarIcon: ({ color, size }) => <Icon name="user" size={size} color={color} style={{ marginTop: 5 }} />,
tabBarIcon: UserIcon,
}}
/>
<HomeTabs.Screen
@@ -72,7 +75,7 @@ const Navigation = () => (
component={About}
options={{
title: 'Om oss',
tabBarIcon: ({ color, size }) => <Icon name="info" size={size} color={color} style={{ marginTop: 5 }} />,
tabBarIcon: AboutIcon,
}}
/>
</HomeTabs.Navigator>
+4 -4
View File
@@ -44,7 +44,7 @@ export function requestLogin(username, password) {
(data) => {
console.log(data);
dispatch(loginFailure(data || { non_field_errors: ['Kunne ikke logge inn, prøv igjen'] }));
}
},
);
};
}
@@ -75,7 +75,7 @@ export function requestUserData(authToken) {
},
(data) => {
dispatch(userDataFailure(data || { non_field_errors: ['Kunne ikke hente brukerdata'] }));
}
},
);
};
}
@@ -111,7 +111,7 @@ export function requestRegisterUser({ firstName, lastName, email, phoneNumber, p
},
(data) => {
dispatch(registerUserFailure(data || { non_field_errors: ['Kunne ikke registrere bruker, prøv igjen'] }));
}
},
);
};
}
@@ -146,7 +146,7 @@ export function requestMembershipCharge(authToken, stripeToken, membershipType)
},
(data) => {
dispatch(membershipChargeFailure(data.detail || 'Kunne ikke belaste bankkortet, prøv igjen'));
}
},
);
};
}
+2 -1
View File
@@ -1,5 +1,6 @@
import React from 'react';
import { Alert, HStack, Text } from 'native-base';
import { Text } from 'react-native';
import { Alert, HStack } from 'native-base';
const FormErrors = ({ errors }) => {
if (!Object.keys(errors).length || !['non_field_errors', 'detail'].some((errorField) => errorField in errors)) {
+16 -20
View File
@@ -1,9 +1,8 @@
import React from 'react';
import { Text, View, Platform, StyleSheet, Image, Linking, TouchableOpacity, ScrollView } from 'react-native';
import { Button, Text as NBText } from 'native-base';
import FAIcon from 'react-native-vector-icons/FontAwesome5';
import SimpleIcon from 'react-native-vector-icons/SimpleLineIcons';
import { SimpleLineIcons as SimpleIcon, FontAwesome5 as FAIcon } from '@expo/vector-icons';
import { Button } from 'react-native-ui-lib';
import theme from '../../theme';
const CHATEAU_NEUF_ADDRESS = 'Det Norske Studentersamfund, Slemdalsveien 15, 0369 Oslo';
@@ -71,11 +70,11 @@ const About = () => (
<View style={[styles.section, { flex: 1, flexDirection: 'row' }]}>
<TouchableOpacity style={styles.someBtn} onPress={openFacebook}>
<FAIcon name="facebook" size={40} color="black" />
<NBText>Facebook</NBText>
<Text>Facebook</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.someBtn} onPress={openInstagram}>
<FAIcon name="instagram" size={40} color="black" />
<NBText>Instagram</NBText>
<Text>Instagram</Text>
</TouchableOpacity>
</View>
@@ -84,37 +83,33 @@ const About = () => (
Det Norske Studentersamfund{'\n'}Slemdalsveien 15, 0369 Oslo
</Text>
<View style={styles.section}>
<Button leftIcon={<SimpleIcon name="map" style={styles.icon} />} onPress={openMap}>
<NBText> Vis i kart</NBText>
<Button onPress={openMap}>
<SimpleIcon name="map" style={styles.icon} />
<Text> Vis i kart</Text>
</Button>
</View>
<Text style={styles.header}>Åpningstider</Text>
<View style={styles.section}>
<Button
leftIcon={<SimpleIcon name="clock" style={styles.icon} />}
onPress={() => Linking.openURL('https://studentersamfundet.no/aapningstider/')}
>
<NBText>Vis åpningstider</NBText>
<Button onPress={() => Linking.openURL('https://studentersamfundet.no/aapningstider/')}>
<SimpleIcon name="clock" style={styles.icon} />
<Text>Vis åpningstider</Text>
</Button>
</View>
<Text style={styles.header}>Ta kontakt</Text>
<View style={[styles.section, { flex: 1, flexDirection: 'row' }]}>
<View>
<Button
leftIcon={<SimpleIcon name="phone" style={styles.icon} />}
onPress={() => Linking.openURL('tel:+4794430002')}
style={{ marginHorizontal: 10 }}
>
<NBText>Ring</NBText>
<Button onPress={() => Linking.openURL('tel:+4794430002')} style={{ marginHorizontal: 10 }}>
<SimpleIcon name="phone" style={styles.icon} />
<Text>Ring</Text>
</Button>
</View>
<View>
<Button
leftIcon={<SimpleIcon name="envelope" style={styles.icon} />}
onPress={() => Linking.openURL('mailto:ledelsen@studentersamfundet.no')}
style={{ marginHorizontal: 10 }}
>
<NBText>Send e-post</NBText>
<SimpleIcon name="envelope" style={styles.icon} />
<Text>Send e-post</Text>
</Button>
</View>
</View>
@@ -173,6 +168,7 @@ const styles = StyleSheet.create({
},
icon: {
fontSize: 16,
marginRight: 4,
},
largeIcon: {
fontSize: 40,
+64 -66
View File
@@ -1,8 +1,18 @@
import React from 'react';
import { Linking, StyleSheet, ScrollView, Text, Platform, View, Image, TouchableOpacity } from 'react-native';
import HTMLView from 'react-native-htmlview';
import {
Linking,
StyleSheet,
ScrollView,
Text,
Platform,
View,
Image,
TouchableOpacity,
useWindowDimensions,
} from 'react-native';
import RenderHtml from 'react-native-render-html';
import moment from 'moment';
import { Icon } from 'native-base';
import { FontAwesome } from '@expo/vector-icons';
import theme from '../../theme';
@@ -90,7 +100,7 @@ const PriceAndTicket = ({ event }) => {
return (
<TouchableOpacity style={styles.metaInner} onPress={() => Linking.openURL(event.ticket_url)}>
<View style={styles.metaIcon}>
<Icon name="card" style={styles.icons} />
<FontAwesome name="credit-card" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{text}</Text>
@@ -103,7 +113,7 @@ const PriceAndTicket = ({ event }) => {
return (
<View style={styles.metaInner}>
<View style={styles.metaIcon}>
<Icon name="card" style={styles.icons} />
<FontAwesome name="credit-card" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{text}</Text>
@@ -121,7 +131,7 @@ const FaceButton = ({ event }) => {
return (
<TouchableOpacity onPress={() => onFacebookUrlPress(event.facebook_url)} style={styles.metaInner}>
<View style={[styles.metaIcon, { marginTop: 0 }]}>
<Icon name="logo-facebook" style={styles.icons} />
<FontAwesome name="facebook-square" style={styles.icons} />
</View>
<View>
<Text style={[styles.metaText, { paddingTop: 2 }]}>På Facebook</Text>
@@ -147,53 +157,56 @@ const EventDetail = ({
route: {
params: { event },
},
}) => (
<ScrollView>
{event.thumbnail.medium_large && <Image source={{ uri: event.thumbnail.medium_large }} style={styles.image} />}
<View style={styles.card}>
{/* Date and title */}
<View style={styles.dateAndTitle}>
<View style={styles.dateContainer}>
<View style={[styles.card, styles.dateCard]}>
<Text style={styles.day}>{format(event.start_time, FORMAT_DAY)}</Text>
<Text style={styles.month}>{format(event.start_time, FORMAT_MONTH)}</Text>
<Year startTime={event.start_time} />
}) => {
const { width } = useWindowDimensions();
return (
<ScrollView>
{event.thumbnail.medium_large && <Image source={{ uri: event.thumbnail.medium_large }} style={styles.image} />}
<View style={styles.card}>
{/* Date and title */}
<View style={styles.dateAndTitle}>
<View style={styles.dateContainer}>
<View style={[styles.card, styles.dateCard]}>
<Text style={styles.day}>{format(event.start_time, FORMAT_DAY)}</Text>
<Text style={styles.month}>{format(event.start_time, FORMAT_MONTH)}</Text>
<Year startTime={event.start_time} />
</View>
</View>
<View style={styles.titleContainer}>
<Text style={styles.title} numberOfLines={2}>
{event.title.decoded}
</Text>
</View>
</View>
<View style={styles.titleContainer}>
<Text style={styles.title} numberOfLines={2}>
{event.title.decoded}
</Text>
</View>
{/* Time and calendar */}
<TouchableOpacity style={styles.metaInner}>
<View style={styles.metaIcon}>
<FontAwesome name="clock-o" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{formatTimeFull(event)}</Text>
<Text style={styles.metaSubtitle}>{formatRelative(event.start_time)}</Text>
</View>
</TouchableOpacity>
{/* Location and maps */}
<TouchableOpacity style={styles.metaInner} onPress={() => onLocationPress(event.venue)}>
<View style={[styles.metaIcon, { paddingLeft: 1 }]}>
<FontAwesome name="map-pin" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{event.venue}</Text>
<Text style={styles.metaSubtitle} numberOfLines={1}>
<VenueLocation venue={event.venue} />
</Text>
</View>
</TouchableOpacity>
<PriceAndTicket event={event} />
<FaceButton event={event} />
<RenderHtml contentWidth={width} source={{ html: event.content.rendered }} />
</View>
{/* Time and calendar */}
<TouchableOpacity style={styles.metaInner}>
<View style={styles.metaIcon}>
<Icon name="time" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{formatTimeFull(event)}</Text>
<Text style={styles.metaSubtitle}>{formatRelative(event.start_time)}</Text>
</View>
</TouchableOpacity>
{/* Location and maps */}
<TouchableOpacity style={styles.metaInner} onPress={() => onLocationPress(event.venue)}>
<View style={[styles.metaIcon, { paddingLeft: 1 }]}>
<Icon name="pin" style={styles.icons} />
</View>
<View style={{ flexDirection: 'column' }}>
<Text style={styles.metaText}>{event.venue}</Text>
<Text style={styles.metaSubtitle} numberOfLines={1}>
<VenueLocation venue={event.venue} />
</Text>
</View>
</TouchableOpacity>
<PriceAndTicket event={event} />
<FaceButton event={event} />
<HTMLView style={styles.content} stylesheet={HTMLStyles} value={event.content.rendered} />
</View>
</ScrollView>
);
</ScrollView>
);
};
export default EventDetail;
@@ -274,21 +287,6 @@ const styles = StyleSheet.create({
paddingTop: 3,
},
icons: {
fontSize: 16,
},
});
// FIXME: Ninja margin
const HTMLStyles = StyleSheet.create({
p: {
fontSize: 16,
marginBottom: -30,
color: '#000',
},
ul: {
fontSize: 16,
color: '#000',
marginTop: -20,
marginBottom: -30,
fontSize: 15,
},
});
+7 -4
View File
@@ -1,5 +1,7 @@
import { StyleSheet, View, Platform, SectionList, TouchableOpacity } from 'react-native';
import { Card, Text, Button, Spinner, ArrowForwardIcon, HStack } from 'native-base';
import { Card, Text, Spinner, ArrowForwardIcon, HStack } from 'native-base';
import { Button } from 'react-native-ui-lib';
import React from 'react';
import moment from 'moment';
import 'moment/locale/nb';
@@ -18,6 +20,7 @@ const renderSectionHeader = ({ section }) => (
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
);
const Header = () => <View style={styles.listHeader} />;
const EventList = () => {
const { eventsSectioned, refreshing, handleRefresh, handleLoadMore, showEvent, error, loading } = useEventList();
@@ -43,6 +46,8 @@ const EventList = () => {
</TouchableOpacity>
);
// FIXME: Hoist component definition
// eslint-disable-next-line react/no-unstable-nested-components
const Footer = () =>
!loading && (
<View style={{ paddingVertical: 20 }}>
@@ -80,9 +85,7 @@ const EventList = () => {
initialNumToRender={10}
ListFooterComponent={Footer}
style={[styles.card, styles.list]}
ListHeaderComponent={() => {
return <View style={styles.listHeader} />;
}}
ListHeaderComponent={Header}
/>
);
};
+1
View File
@@ -77,6 +77,7 @@ const useEventList = () => {
useEffect(() => {
fetchEvents();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return {
+5 -4
View File
@@ -1,6 +1,7 @@
import React from 'react';
import { Linking, StyleSheet, View } from 'react-native';
import { ScrollView, Spinner, Button, Text } from 'native-base';
import { ActivityIndicator, Linking, StyleSheet, View, Text } from 'react-native';
import { ScrollView } from 'native-base';
import { Button } from 'react-native-ui-lib';
import theme from '../../theme';
import useLogin from './useLogin';
@@ -36,7 +37,7 @@ const Login = () => {
onSubmitEditing={onSubmit}
returnKeyType="send"
/>
<Button full onPress={onSubmit} style={styles.loginButton}>
<Button fullWidth onPress={onSubmit} style={styles.loginButton}>
<Text>Logg inn</Text>
</Button>
<Button
@@ -49,7 +50,7 @@ const Login = () => {
>
<Text>Glemt passord?</Text>
</Button>
{isLoggingIn && <Spinner color="#f58220" />}
{isLoggingIn && <ActivityIndicator color="#f58220" />}
</View>
</ScrollView>
);
+2 -1
View File
@@ -2,6 +2,7 @@ import { useNavigation } from '@react-navigation/native';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useForm } from 'react-hook-form';
import { requestLogin } from '../../api';
const useLogin = () => {
@@ -31,7 +32,7 @@ const useLogin = () => {
// navigation.goBack onLogin works since LoginScreen is allways navigated to from MembershipScreen
navigation.goBack();
}
}, [isAuthenticated]);
}, [isAuthenticated, navigation]);
return { onSubmit, isLoggingIn, control, setFocus, errors: { ...errors, ...loginError } };
};
+2 -3
View File
@@ -1,6 +1,5 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { Spinner } from 'native-base';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import theme from '../../theme';
import useMembership from './useMembership';
@@ -14,7 +13,7 @@ const Membership = () => {
if (isFetchingUserData) {
return (
<View style={styles.card}>
<Spinner color="#f58220" />
<ActivityIndicator color="#f58220" />
</View>
);
}
+5 -5
View File
@@ -1,7 +1,7 @@
import React from 'react';
import { ScrollView, Text, View, StyleSheet } from 'react-native';
import { Button, Text as NBText } from 'native-base';
import { Button } from 'react-native-ui-lib';
import theme from '../../theme';
const MembershipInfo = ({ onRegister, onLogin }) => (
@@ -12,8 +12,8 @@ const MembershipInfo = ({ onRegister, onLogin }) => (
Her kan du bli medlem i Det Norske Studentersamfund - Chateau Neuf og ha medlemsbeviset ditt på telefonen
</Text>
<View style={styles.button}>
<Button onPress={onRegister} full>
<NBText>Bli medlem</NBText>
<Button onPress={onRegister} fullWidth>
<Text>Bli medlem</Text>
</Button>
</View>
<Text style={styles.header}>Hva får jeg?</Text>
@@ -23,8 +23,8 @@ const MembershipInfo = ({ onRegister, onLogin }) => (
</Text>
<Text style={styles.em}>Allerede medlem?</Text>
<View style={styles.button}>
<Button onPress={onLogin} full>
<NBText>Logg inn</NBText>
<Button onPress={onLogin} fullWidth>
<Text>Logg inn</Text>
</Button>
</View>
</View>
+18 -8
View File
@@ -1,6 +1,15 @@
import React, { useEffect, useRef } from 'react';
import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View, RefreshControl } from 'react-native';
import { Button, Text as NBText, Spinner } from 'native-base';
import {
Image,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
RefreshControl,
ActivityIndicator,
} from 'react-native';
import { Button } from 'react-native-ui-lib';
import Confetti from 'react-native-confetti';
import theme from '../../theme';
@@ -55,14 +64,14 @@ const PurchaseButton = ({ user, isChargingMembership, isLoadingMembershipType, o
return (
<View>
{isChargingMembership && <Spinner color="#f58220" />}
{isChargingMembership && <ActivityIndicator color="#f58220" />}
<Button
onPress={onChargePress}
full
fullWidth
disabled={isChargingMembership || isLoadingMembershipType}
style={styles.purchaseButton}
>
<NBText>{`Kjøp medlemskap (${membershipPrice} NOK)`}</NBText>
<Text>{`Kjøp medlemskap (${membershipPrice} NOK)`}</Text>
</Button>
<View style={styles.purchaseText}>
<Text style={styles.purchaseTextInner}>Medlemskapet er gyldig i ett år</Text>
@@ -128,9 +137,10 @@ const Proof = ({ onLogoutPress, user, fetchUser, isFetchingUserData }) => {
});
useEffect(() => {
const currentRef = confettiRef.current;
return () => {
if (confettiRef && confettiRef.current) {
confettiRef.current.stopConfetti();
if (currentRef) {
currentRef.stopConfetti();
}
};
});
@@ -172,7 +182,7 @@ const Proof = ({ onLogoutPress, user, fetchUser, isFetchingUserData }) => {
</View>
<View>
<Button onPress={onLogoutPress} style={styles.logoutButton} small>
<NBText>Logg ut</NBText>
<Text>Logg ut</Text>
</Button>
</View>
</ScrollView>
+3 -3
View File
@@ -1,5 +1,5 @@
import { useNavigation } from '@react-navigation/native';
import { useEffect } from 'react';
import { useEffect, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { logout } from '../../actions';
@@ -25,9 +25,9 @@ const useMembership = () => {
};
const onRegisterPress = () => navigation.navigate('UserRegister');
const onLoginPress = () => navigation.navigate('Login');
const fetchUser = () => {
const fetchUser = useCallback(() => {
dispatch(requestUserData(userToken));
};
}, [dispatch, userToken]);
useEffect(() => {
if (userToken !== prevUserToken && userToken) {
+3
View File
@@ -1,3 +1,5 @@
// FIXME: fix lint violations
/* eslint-disable no-unused-vars, react-hooks/exhaustive-deps */
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { gql, useQuery } from '@apollo/client';
@@ -40,6 +42,7 @@ const useProof = ({ user, fetchUser }) => {
const membershipTypeSlug = data?.membershipTypes?.[0]?.slug ?? 'standard';
// TODO: Implement stripe payment
// stripe.paymentRequestWithCardForm(options).then(
// (token) => {
// // returns a token.tokenId which should be saved
+6 -4
View File
@@ -1,6 +1,8 @@
import React from 'react';
import { Spinner, Button, Text, ScrollView } from 'native-base';
import { StyleSheet, View } from 'react-native';
import { ScrollView } from 'native-base';
import { Button } from 'react-native-ui-lib';
import { ActivityIndicator, StyleSheet, View, Text } from 'react-native';
import * as EmailValidator from 'email-validator';
import theme from '../../theme';
@@ -68,10 +70,10 @@ const UserRegister = () => {
<View style={styles.errorBox}>
<FormErrors errors={errors} />
</View>
<Button full disabled={isDisabled} onPress={onSubmit} style={styles.registerButton}>
<Button fullWidth disabled={isDisabled} onPress={onSubmit} style={styles.registerButton}>
<Text>Registrer meg</Text>
</Button>
{isRegisteringUser && <Spinner color="#f58220" />}
{isRegisteringUser && <ActivityIndicator color="#f58220" />}
</View>
</ScrollView>
);
+1 -1
View File
@@ -42,7 +42,7 @@ const useUserRegister = () => {
if (isAuthenticatedPrev !== isAuthenticated && isAuthenticated) {
navigation.goBack();
}
}, [isAuthenticatedPrev, isAuthenticated]);
}, [isAuthenticatedPrev, isAuthenticated, navigation]);
return { onSubmit, isRegisteringUser, registerError, control, setFocus, errors };
};
+1
View File
@@ -39,6 +39,7 @@ function formatErrors(errs) {
return _errs;
}
// eslint-disable-next-line default-param-last
export default function duskenApp(state = initialState, action) {
switch (action.type) {
/* Login */
+7
View File
@@ -1,6 +1,8 @@
import { Platform } from 'react-native';
import { Colors } from 'react-native-ui-lib';
const colors = {
primary: '#f58220',
danger: '#d9534f',
};
@@ -20,4 +22,9 @@ const card = {
margin: 8,
backgroundColor: '#fff',
};
export function loadTheme() {
Colors.loadDesignTokens({ primaryColor: colors.primary });
}
export default { card, colors };
+5 -1
View File
@@ -9,7 +9,11 @@ export function fetchWithTimeout(url, options, timeout = 10000) {
// FIXME: show timeout message in UI
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject(new Error('Fetch request timed out')), timeout)),
new Promise((_, reject) => {
setTimeout(() => {
reject(new Error('Fetch request timed out'));
}, timeout);
}),
]);
}