♻ Refactor MembershipScreen
This commit is contained in:
1 parent
311117669d
commit
8733f331bb
10 files changed
+192
-169
No files matched your search
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user