♻ Refactor MembershipScreen
This commit is contained in:
1 parent
311117669d
commit
8733f331bb
10 files changed
+192
-169
No files matched your search
+4
-3
@@ -8,8 +8,8 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
// import EventListScreen from './screens/EventListScreen';
|
||||
// import AboutScreen from './screens/AboutScreen';
|
||||
// import EventDetailScreen from './screens/EventDetailScreen';
|
||||
import LoginScreen from './screens/LoginScreen';
|
||||
// import MembershipScreen from './screens/MembershipScreen';
|
||||
// import LoginScreen from './screens/LoginScreen';
|
||||
import MembershipScreen from './screens/MembershipScreen';
|
||||
// import UserRegisterScreen from './screens/UserRegisterScreen';
|
||||
|
||||
// const tabBarRoutes = {
|
||||
@@ -86,7 +86,8 @@ const DuskenNavigation = () => (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator>
|
||||
{/* <Stack.Screen name="About" component={AboutScreen} /> */}
|
||||
<Stack.Screen name="Login" component={LoginScreen} />
|
||||
{/* <Stack.Screen name="Login" component={LoginScreen} /> */}
|
||||
<Stack.Screen name="Membership" component={MembershipScreen} />
|
||||
{/* <Stack.Screen name="EventList" component={EventListScreen} /> */}
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
export function usePrevious(value) {
|
||||
const ref = useRef();
|
||||
|
||||
// Store current value in ref
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
}, [value]); // Only re-run if value changes
|
||||
|
||||
// Return previous value (happens before update in useEffect above)
|
||||
return ref.current;
|
||||
}
|
||||
@@ -1,48 +1,33 @@
|
||||
import React, { Component } from 'react';
|
||||
import { ScrollView, Text, View, StyleSheet } from 'react-native';
|
||||
import { Button, Text as NBText, Spinner } from 'native-base';
|
||||
import React from 'react';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import { Spinner } from 'native-base';
|
||||
|
||||
import theme from '../../theme';
|
||||
import useMembership from './useMembership';
|
||||
import MembershipInfo from './MembershipInfo';
|
||||
import Proof from './Proof';
|
||||
|
||||
export default class Membership extends Component {
|
||||
render() {
|
||||
if (this.props.isFetchingUserData) {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<Spinner color="#f58220" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const Membership = () => {
|
||||
const { isFetchingUserData, onRegisterPress, onLoginPress, onLogoutPress, user, isAuthenticated, fetchUser } =
|
||||
useMembership();
|
||||
|
||||
if (isFetchingUserData) {
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.headerTitle}>Hei 👋</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Her kan du bli medlem i Det Norske Studentersamfund - Chateau Neuf og ha medlemsbeviset ditt på telefonen
|
||||
</Text>
|
||||
<View style={styles.button}>
|
||||
<Button onPress={this.props.onRegisterPress} full>
|
||||
<NBText>Bli medlem</NBText>
|
||||
</Button>
|
||||
</View>
|
||||
<Text style={styles.header}>Hva får jeg?</Text>
|
||||
<Text style={[styles.paragraph, { textAlign: 'left', paddingLeft: 4 }]}>
|
||||
- Minst 25% rabatt på de fleste arrangement{'\n'}- Gratis inngang på enkelte arrangement{'\n'}- Store
|
||||
rabatter i barene{'\n'}- Egne medlemsarrangement og -tilbud{'\n'}- Mulighet til å delta i landets eldste
|
||||
studentdemokrati
|
||||
</Text>
|
||||
<Text style={styles.em}>Allerede medlem?</Text>
|
||||
<View style={styles.button}>
|
||||
<Button onPress={this.props.onLoginPress} full>
|
||||
<NBText>Logg inn</NBText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View style={styles.card}>
|
||||
<Spinner color="#f58220" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isAuthenticated) {
|
||||
return (
|
||||
<Proof onLogoutPress={onLogoutPress} user={user} fetchUser={fetchUser} isFetchingUserData={isFetchingUserData} />
|
||||
);
|
||||
}
|
||||
|
||||
return <MembershipInfo onRegister={onRegisterPress} onLogin={onLoginPress} />;
|
||||
};
|
||||
export default Membership;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: theme.card,
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Membership from './Membership';
|
||||
import Proof from './Proof';
|
||||
import { logout } from '../../actions';
|
||||
import { requestUserData } from '../../api';
|
||||
|
||||
class MembershipContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isFetchingUserData: props.isFetchingUserData,
|
||||
userToken: props.userToken,
|
||||
lastOrder: props.lastOrder,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.state.userToken !== nextProps.userToken) {
|
||||
this.setState({ userToken: nextProps.userToken }, () => {
|
||||
if (nextProps.userToken) {
|
||||
this.fetchUser();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.state.lastOrder !== nextProps.lastOrder) {
|
||||
this.setState({ lastOrder: nextProps.lastOrder }, () => {
|
||||
if (nextProps.userToken) {
|
||||
this.fetchUser();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchUser = () => {
|
||||
this.props.requestUserData(this.state.userToken);
|
||||
};
|
||||
|
||||
onLoginPress = () => {
|
||||
this.props.onLoginPress();
|
||||
};
|
||||
|
||||
onRegisterPress = () => {
|
||||
this.props.onRegisterPress();
|
||||
};
|
||||
|
||||
onLogoutPress = () => {
|
||||
this.props.logout();
|
||||
this.props.onLogoutPress();
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.props.user) {
|
||||
return (
|
||||
<Proof
|
||||
user={this.props.user}
|
||||
isFetchingUserData={this.props.isFetchingUserData}
|
||||
isAuthenticated={this.props.isAuthenticated}
|
||||
userToken={this.state.userToken}
|
||||
fetchUser={this.fetchUser}
|
||||
onLogoutPress={this.onLogoutPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Membership
|
||||
isFetchingUserData={this.props.isFetchingUserData}
|
||||
onLoginPress={this.onLoginPress}
|
||||
onRegisterPress={this.onRegisterPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function storeToProps(store) {
|
||||
return {
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isFetchingUserData: store.isFetchingUserData,
|
||||
userToken: store.userToken,
|
||||
user: store.user,
|
||||
lastOrder: store.lastOrder,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(storeToProps, { requestUserData, logout })(MembershipContainer);
|
||||
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
|
||||
import { ScrollView, Text, View, StyleSheet } from 'react-native';
|
||||
import { Button, Text as NBText } from 'native-base';
|
||||
import theme from '../../theme';
|
||||
|
||||
const MembershipInfo = ({ onRegister, onLogin }) => (
|
||||
<ScrollView>
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.headerTitle}>Hei 👋</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
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>
|
||||
</View>
|
||||
<Text style={styles.header}>Hva får jeg?</Text>
|
||||
<Text style={[styles.paragraph, { textAlign: 'left', paddingLeft: 4 }]}>
|
||||
- Minst 25% rabatt på de fleste arrangement{'\n'}- Gratis inngang på enkelte arrangement{'\n'}- Store rabatter i
|
||||
barene{'\n'}- Egne medlemsarrangement og -tilbud{'\n'}- Mulighet til å delta i landets eldste studentdemokrati
|
||||
</Text>
|
||||
<Text style={styles.em}>Allerede medlem?</Text>
|
||||
<View style={styles.button}>
|
||||
<Button onPress={onLogin} full>
|
||||
<NBText>Logg inn</NBText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
export default MembershipInfo;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: theme.card,
|
||||
paragraph: {
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
color: '#000',
|
||||
paddingBottom: 10,
|
||||
lineHeight: 25,
|
||||
},
|
||||
button: {
|
||||
marginTop: 6,
|
||||
marginBottom: 16,
|
||||
},
|
||||
em: {
|
||||
fontSize: 16,
|
||||
color: '#000',
|
||||
fontStyle: 'italic',
|
||||
textAlign: 'center',
|
||||
marginVertical: 10,
|
||||
},
|
||||
headerTitle: {
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20,
|
||||
color: '#000',
|
||||
paddingVertical: 10,
|
||||
lineHeight: 25,
|
||||
},
|
||||
header: {
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
color: '#000',
|
||||
lineHeight: 25,
|
||||
paddingLeft: 2,
|
||||
},
|
||||
});
|
||||
@@ -144,6 +144,15 @@ const Proof = ({ onLogoutPress, user, fetchUser, isFetchingUserData }) => {
|
||||
}, CONFETTI_TIMEOUT);
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
console.log('🔥', user);
|
||||
return (
|
||||
<View>
|
||||
<Text>No user!</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<UserConfetti user={user} confettiRef={confettiRef} />
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { logout } from '../../actions';
|
||||
import { requestUserData } from '../../api';
|
||||
import { usePrevious } from '../../hooks';
|
||||
|
||||
const useMembership = () => {
|
||||
const navigation = useNavigation();
|
||||
const dispatch = useDispatch();
|
||||
const { isAuthenticated, isFetchingUserData, userToken, user, lastOrder } = useSelector((store) => ({
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isFetchingUserData: store.isFetchingUserData,
|
||||
userToken: store.userToken,
|
||||
user: store.user,
|
||||
lastOrder: store.lastOrder,
|
||||
}));
|
||||
const prevUserToken = usePrevious(userToken);
|
||||
const prevLastOrder = usePrevious(lastOrder);
|
||||
|
||||
const onLogoutPress = () => {
|
||||
dispatch(logout());
|
||||
navigation.navigate('Membership');
|
||||
};
|
||||
const onRegisterPress = () => navigation.navigate('UserRegister');
|
||||
const onLoginPress = () => navigation.navigate('Login');
|
||||
const fetchUser = () => {
|
||||
dispatch(requestUserData(userToken));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (userToken !== prevUserToken && userToken) {
|
||||
fetchUser();
|
||||
}
|
||||
if (prevLastOrder !== lastOrder && userToken) {
|
||||
fetchUser();
|
||||
}
|
||||
}, [userToken, prevUserToken, lastOrder, prevLastOrder, fetchUser]);
|
||||
|
||||
return {
|
||||
isAuthenticated,
|
||||
isFetchingUserData,
|
||||
userToken,
|
||||
user,
|
||||
lastOrder,
|
||||
onLogoutPress,
|
||||
onRegisterPress,
|
||||
onLoginPress,
|
||||
};
|
||||
};
|
||||
export default useMembership;
|
||||
@@ -1,14 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import stripe from 'tipsi-stripe';
|
||||
// import stripe from 'tipsi-stripe';
|
||||
import Config from 'react-native-config';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
|
||||
import { requestMembershipCharge } from '../../api';
|
||||
|
||||
stripe.setOptions({
|
||||
publishableKey: Config.STRIPE_PUBLISHABLE_KEY || '',
|
||||
});
|
||||
// TODO: switch to official stripe client
|
||||
// stripe.setOptions({
|
||||
// publishableKey: Config.STRIPE_PUBLISHABLE_KEY || '',
|
||||
// });
|
||||
|
||||
const PROOF_QUERY = gql`
|
||||
{
|
||||
@@ -44,22 +45,22 @@ const useProof = ({ user, fetchUser }) => {
|
||||
smsAutofillDisabled: true,
|
||||
};
|
||||
|
||||
const membershipTypeSlug = data.membershipTypes ? data.membershipTypes[0].slug : 'standard';
|
||||
const membershipTypeSlug = data?.membershipTypes?.[0]?.slug ?? 'standard';
|
||||
|
||||
stripe.paymentRequestWithCardForm(options).then(
|
||||
(token) => {
|
||||
// returns a token.tokenId which should be saved
|
||||
dispatch(requestMembershipCharge(userToken, { id: token.tokenId, email: user.email }, membershipTypeSlug));
|
||||
},
|
||||
() => {
|
||||
/* FIXME: Happens only if card dialog is canceled? */
|
||||
}
|
||||
);
|
||||
// stripe.paymentRequestWithCardForm(options).then(
|
||||
// (token) => {
|
||||
// // returns a token.tokenId which should be saved
|
||||
// dispatch(requestMembershipCharge(userToken, { id: token.tokenId, email: user.email }, membershipTypeSlug));
|
||||
// },
|
||||
// () => {
|
||||
// /* FIXME: Happens only if card dialog is canceled? */
|
||||
// }
|
||||
// );
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const todaysDate = new Date().toISOString().substring(0, 10);
|
||||
const lastMembership = user.last_membership;
|
||||
const lastMembership = user?.last_membership;
|
||||
if (lastMembership && lastMembership.membership_type !== 'lifelong' && lastMembership.end_date < todaysDate) {
|
||||
fetchUser();
|
||||
}
|
||||
@@ -69,7 +70,7 @@ const useProof = ({ user, fetchUser }) => {
|
||||
chargeError: chargeError || '',
|
||||
isChargingMembership,
|
||||
isLoadingMembershipType: loading,
|
||||
membershipPrice: getPrice(data.membershipTypes),
|
||||
membershipPrice: getPrice(data?.membershipTypes),
|
||||
onChargePress: openStripe,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
|
||||
import Login from '../modules/login/Login';
|
||||
|
||||
// navigation.goBack onLogin works since LoginScreen is allways navigated to from MembershipScreen
|
||||
const LoginScreen = () => {
|
||||
return <Login />;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import Icon from 'react-native-vector-icons/SimpleLineIcons';
|
||||
import { StyleProvider } from 'native-base';
|
||||
import MembershipContainer from '../modules/membership/MembershipContainer';
|
||||
import getTheme from '../../native-base-theme/components';
|
||||
import Membership from '../modules/membership/Membership';
|
||||
|
||||
export default class MembershipScreen extends Component {
|
||||
static navigationOptions = {
|
||||
@@ -10,27 +8,7 @@ export default class MembershipScreen extends Component {
|
||||
tabBarIcon: ({ tintColor }) => <Icon name="user" size={16} color={tintColor} style={{ marginTop: 5 }} />,
|
||||
};
|
||||
|
||||
loginNavigate = () => {
|
||||
this.props.navigation.navigate('Login');
|
||||
};
|
||||
|
||||
logoutNavigate = () => {
|
||||
this.props.navigation.navigate('Membership');
|
||||
};
|
||||
|
||||
registerNavigate = () => {
|
||||
this.props.navigation.navigate('UserRegister');
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StyleProvider style={getTheme()}>
|
||||
<MembershipContainer
|
||||
onLoginPress={this.loginNavigate}
|
||||
onLogoutPress={this.logoutNavigate}
|
||||
onRegisterPress={this.registerNavigate}
|
||||
/>
|
||||
</StyleProvider>
|
||||
);
|
||||
return <Membership />;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user