add membership type selection option
This commit is contained in:
4 files changed
+79
-9
No files matched your search
Generated
+19
@@ -34,6 +34,7 @@
|
||||
"react-native-render-html": "^6.3.4",
|
||||
"react-native-safe-area-context": "4.10.5",
|
||||
"react-native-screens": "^3.31.1",
|
||||
"react-native-simple-radio-button": "^2.7.4",
|
||||
"react-native-svg": "^15.2.0",
|
||||
"react-native-ui-lib": "^7.26.2",
|
||||
"react-redux": "^8.1.2",
|
||||
@@ -49,6 +50,7 @@
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/react": "18.2",
|
||||
"@types/react-native-confetti": "^0.1.4",
|
||||
"@types/react-native-simple-radio-button": "^2.7.7",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
@@ -7011,6 +7013,17 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-native-simple-radio-button": {
|
||||
"version": "2.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.7.tgz",
|
||||
"integrity": "sha512-cDDpMb+MyYDrZmQX/phRdpbW4SJynTv165MWkwjqa39jbuSkMAxuvBdiTCTBTiugikPRvQRFBG1wPRF/+0Lprw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
@@ -16205,6 +16218,12 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-simple-radio-button": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.4.tgz",
|
||||
"integrity": "sha512-QOZNmJUn0ViBGU+at7wAG/uGzd5PfXi0kMHr9lfTCLXknW/f9f2fOVjxjdHvOCdf/zA/eMJBjGjtusSDzQf1+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-svg": {
|
||||
"version": "15.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.2.0.tgz",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"react-native-render-html": "^6.3.4",
|
||||
"react-native-safe-area-context": "4.10.5",
|
||||
"react-native-screens": "^3.31.1",
|
||||
"react-native-simple-radio-button": "^2.7.4",
|
||||
"react-native-svg": "^15.2.0",
|
||||
"react-native-ui-lib": "^7.26.2",
|
||||
"react-redux": "^8.1.2",
|
||||
@@ -54,6 +55,7 @@
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/react": "18.2",
|
||||
"@types/react-native-confetti": "^0.1.4",
|
||||
"@types/react-native-simple-radio-button": "^2.7.7",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
GestureResponderEvent,
|
||||
} from 'react-native';
|
||||
import Confetti from 'react-native-confetti';
|
||||
import RadioForm from 'react-native-simple-radio-button';
|
||||
import { Button, Incubator } from 'react-native-ui-lib';
|
||||
|
||||
import theme from 'src/theme';
|
||||
@@ -76,6 +77,7 @@ interface PurchaseButtonProps {
|
||||
isLoadingMembershipType: boolean;
|
||||
membershipPrice: number;
|
||||
onPurchasePress: () => void;
|
||||
setMembershipTypeSlug: (value: string) => void;
|
||||
}
|
||||
|
||||
const PurchaseButton = ({
|
||||
@@ -84,13 +86,36 @@ const PurchaseButton = ({
|
||||
isLoadingMembershipType,
|
||||
onPurchasePress,
|
||||
membershipPrice,
|
||||
setMembershipTypeSlug,
|
||||
}: PurchaseButtonProps) => {
|
||||
if (user.is_member) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = [
|
||||
{ label: 'Student', value: 'student' },
|
||||
{ label: 'Ordinær', value: 'standard' },
|
||||
{ label: 'Støtte', value: 'support' },
|
||||
];
|
||||
|
||||
const onSelect = (value: string) => {
|
||||
setMembershipTypeSlug(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<RadioForm
|
||||
radio_props={options}
|
||||
initial={1}
|
||||
formHorizontal={true}
|
||||
labelHorizontal={false}
|
||||
buttonColor={theme.colors.neufOrange}
|
||||
// @ts-expect-error No overload matches this call. We ignore since we need to style the button
|
||||
selectedButtonColor={theme.colors.neufOrange}
|
||||
animation={false}
|
||||
onPress={onSelect}
|
||||
style={styles.radioForm}
|
||||
/>
|
||||
{paymentLoading && <ActivityIndicator color={theme.colors.neufOrange} />}
|
||||
<Button
|
||||
onPress={onPurchasePress}
|
||||
@@ -149,11 +174,18 @@ interface ProofProps {
|
||||
const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData, onDeletePress }: ProofProps) => {
|
||||
const CONFETTI_TIMEOUT = 15000;
|
||||
const confettiRef = useRef<Confetti>(null);
|
||||
const { paymentLoading, isLoadingMembershipType, onPurchasePress, membershipPrice, toast, setToast, user } = useProof(
|
||||
{
|
||||
fetchUser,
|
||||
},
|
||||
);
|
||||
const {
|
||||
paymentLoading,
|
||||
isLoadingMembershipType,
|
||||
onPurchasePress,
|
||||
membershipPrice,
|
||||
toast,
|
||||
setToast,
|
||||
user,
|
||||
setMembershipTypeSlug,
|
||||
} = useProof({
|
||||
fetchUser,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const currentRef = confettiRef.current;
|
||||
@@ -196,6 +228,7 @@ const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData, onDeletePress }:
|
||||
isLoadingMembershipType={isLoadingMembershipType}
|
||||
membershipPrice={membershipPrice}
|
||||
onPurchasePress={onPurchasePress}
|
||||
setMembershipTypeSlug={setMembershipTypeSlug}
|
||||
/>
|
||||
<MembershipValidTo user={user} />
|
||||
</View>
|
||||
@@ -273,7 +306,7 @@ const styles = StyleSheet.create({
|
||||
fontSize: 18,
|
||||
},
|
||||
purchaseButton: {
|
||||
marginTop: 16,
|
||||
marginTop: 8,
|
||||
},
|
||||
logoutButton: {
|
||||
alignSelf: 'center',
|
||||
@@ -308,4 +341,10 @@ const styles = StyleSheet.create({
|
||||
width: Dimensions.get('window').width * 0.8, // 80% of screen width
|
||||
alignSelf: 'center',
|
||||
},
|
||||
radioForm: {
|
||||
alignSelf: 'center',
|
||||
textAlign: 'center',
|
||||
marginTop: 20,
|
||||
gap: 12,
|
||||
},
|
||||
});
|
||||
@@ -9,7 +9,7 @@ import { ToastProps } from 'src/types/toast';
|
||||
|
||||
const PROOF_QUERY = gql`
|
||||
{
|
||||
membershipTypes(isDefault: true) {
|
||||
membershipTypes {
|
||||
slug
|
||||
price
|
||||
}
|
||||
@@ -26,7 +26,8 @@ const useProof = ({ fetchUser }: UseProofProps) => {
|
||||
const { data, loading } = useQuery(PROOF_QUERY);
|
||||
const { initPaymentSheet, presentPaymentSheet } = useStripe();
|
||||
const [paymentLoading, setPaymentLoading] = useState(false);
|
||||
const membershipTypeSlug = data?.membershipTypes?.[0]?.slug ?? 'standard';
|
||||
const [membershipTypeSlug, setMembershipTypeSlug] = useState('standard');
|
||||
const [membershipPrice, setMembershipPrice] = useState(25000); // WARNING: Hardcoded due to state not being loaded initially. Should probably be fixed.
|
||||
const [toast, setToast] = useState<ToastProps | null>(null);
|
||||
|
||||
const openPaymentSheet = async () => {
|
||||
@@ -77,7 +78,15 @@ const useProof = ({ fetchUser }: UseProofProps) => {
|
||||
}
|
||||
}, [fetchUser, user?.last_membership]);
|
||||
|
||||
const membershipPrice = data?.membershipTypes?.[0]?.price;
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const membershipType of data?.membershipTypes ?? []) {
|
||||
if (membershipType.slug === membershipTypeSlug) {
|
||||
setMembershipPrice(membershipType.price);
|
||||
}
|
||||
}
|
||||
}, [membershipTypeSlug, data?.membershipTypes]);
|
||||
|
||||
return {
|
||||
isLoadingMembershipType: loading,
|
||||
membershipPrice: membershipPrice ? membershipPrice / 100 : 0,
|
||||
@@ -86,6 +95,7 @@ const useProof = ({ fetchUser }: UseProofProps) => {
|
||||
toast,
|
||||
setToast,
|
||||
user,
|
||||
setMembershipTypeSlug,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user