Skip to content

Commit

Permalink
Merge pull request #1942 from coopcycle/paygreen
Browse files Browse the repository at this point in the history
Allow paying with Paygreen via redirect URL.
  • Loading branch information
r0xsh authored Feb 4, 2025
2 parents 9dd12e2 + 71dbadb commit 60cfbd0
Show file tree
Hide file tree
Showing 18 changed files with 258 additions and 58 deletions.
3 changes: 3 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ buildscript {
googlePlayServicesLocationVersion = "21.0.1"
mercadoPagoPxVersion = "4.53.2"
reactNativeVersion = "0.73.5" // https://github.com/expo/expo/issues/18129
// https://github.com/proyecto26/react-native-inappbrowser#mostly-automatic-installation
androidXAnnotation = "1.2.0"
androidXBrowser = "1.3.0"
}
repositories {
google()
Expand Down
Binary file added assets/images/Swile_black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/restoflash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,8 @@ PODS:
- RNGoogleSignin (7.0.4):
- GoogleSignIn (~> 6.0.0)
- React-Core
- RNInAppBrowser (3.7.0):
- React-Core
- RNLocalize (3.0.6):
- React-Core
- RNReanimated (3.15.5):
Expand Down Expand Up @@ -1530,6 +1532,7 @@ DEPENDENCIES:
- "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)"
- RNInAppBrowser (from `../node_modules/react-native-inappbrowser-reborn`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
Expand Down Expand Up @@ -1764,6 +1767,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-gesture-handler"
RNGoogleSignin:
:path: "../node_modules/@react-native-google-signin/google-signin"
RNInAppBrowser:
:path: "../node_modules/react-native-inappbrowser-reborn"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNReanimated:
Expand Down Expand Up @@ -1908,6 +1913,7 @@ SPEC CHECKSUMS:
RNFBCrashlytics: 28f83084ae8a4b9e6ad128e3a644c28bb5e16007
RNGestureHandler: 703ad8ac7a8c0999cfb58d5d54809fd4a8ee1c5a
RNGoogleSignin: c4381751eefd73c552b923ba347a9bfc6f18771c
RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364
RNLocalize: 4222a3756cdbe2dc9a5bdf445765a4d2572107cb
RNReanimated: 39e51016ec96da586de4747db982dd032a47ba81
RNScreens: e5093efe5103f3fd5f4479a0f0281ee5e6d81e11
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"react-native-fbsdk-next": "^12.1.0",
"react-native-gesture-handler": "^2.21.2",
"react-native-get-random-values": "^1.11.0",
"react-native-inappbrowser-reborn": "^3.7.0",
"react-native-input-spinner": "^1.8.1",
"react-native-keyboard-manager": "^6.5.16-0",
"react-native-loading-spinner-overlay": "^3.0.1",
Expand Down
6 changes: 6 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ const config = {
},
},
},
CheckoutNav: {
screens: {
CheckoutPaygreenReturn: 'paygreen/return',
CheckoutPaygreenCancel: 'paygreen/cancel',
},
},
},
};

Expand Down
10 changes: 7 additions & 3 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,10 @@
"card": "Credit card",
"cash_on_delivery": "Cash on delivery",
"edenred": "Edenred",
"edenred+card": "Edenred"
"edenred+card": "Edenred",
"conecs": "Titres-restaurant",
"swile": "Swile",
"restoflash": "Restoflash"
},
"CASH_ON_DELIVERY_DISCLAIMER": "You are going to pay by cash on delivery. Please prepare the exact amount and make sure to be reachable.",
"STORES": "Stores",
Expand Down Expand Up @@ -571,6 +574,7 @@
"TASK_DONE": "Done",
"TASK_CANCELLED": "Cancelled",
"ASK_TO_START_PICKUP_TITLE": "Pickup task",
"ASK_TO_START_PICKUP_MESSAGE": "The pickup task is not yet started."
}
"ASK_TO_START_PICKUP_MESSAGE": "The pickup task is not yet started.",
"PAYGREEN_RETURN_TEXT": "Please wait while we process your payment…"
}
}
5 changes: 3 additions & 2 deletions src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@
"ORDER__SHIPPING_TIME_RANGE__NOT_AVAILABLE": "Indisponible pour l'instant",
"EDENRED_ELIGIBLE_AMOUNT": "Montant éligible Ticket Restaurant®",
"EDENRED_COMPLEMENT": "Complément",
"BARCODE_TASK_ALREADY_ASSIGNED_TITLE": "Tâche déjà assignée",
"BARCODE_TASK_ALREADY_ASSIGNED_TITLE": "Tâche déjà assignée",
"BARCODE_TASK_ALREADY_ASSIGNED_ANOTHER_MESSAGE": "Cette tâche a déjà été assignée à un autre utilisateur",
"BARCODE_TASK_ALREADY_ASSIGNED_SELF_MESSAGE": "Cette tâche vous a déjà été assignée",
"BARCODE_TASK_ALREADY_ASSIGNED_UNASSIGN": "Désassigner",
Expand All @@ -543,6 +543,7 @@
"TASK_DONE": "Fait",
"TASK_CANCELLED": "Annulée",
"ASK_TO_START_PICKUP_TITLE": "Tâche de ramassage",
"ASK_TO_START_PICKUP_MESSAGE": "La tâche de ramassage n'est pas encore commencée."
"ASK_TO_START_PICKUP_MESSAGE": "La tâche de ramassage n'est pas encore commencée.",
"PAYGREEN_RETURN_TEXT": "Veuillez patienter pendant que nous traitons votre paiement…"
}
}
13 changes: 13 additions & 0 deletions src/navigation/checkout/PaygreenCancel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';

export default () => {

const navigation = useNavigation();

useEffect(() => {
navigation.navigate('CheckoutPayment');
}, [ navigation ]);

return null
}
27 changes: 27 additions & 0 deletions src/navigation/checkout/PaygreenReturn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useEffect } from 'react';
import { View } from 'react-native';
import { Text } from 'native-base';
import { useNavigation, useRoute } from '@react-navigation/native';
import { useDispatch } from 'react-redux';
import { useTranslation } from 'react-i18next';

import { checkout } from '../../redux/Checkout/actions';

export default () => {

const route = useRoute();
const dispatch = useDispatch();
const { t } = useTranslation();

const paymentOrderId = route.params?.po_id;

useEffect(() => {
dispatch(checkout('', null, false, route.params.po_id));
}, [ dispatch, route.params.po_id ]);

return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>{ t('PAYGREEN_RETURN_TEXT') }</Text>
</View>
)
}
121 changes: 73 additions & 48 deletions src/navigation/checkout/Payment.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, { Component } from 'react';
import React, { useCallback, useEffect } from 'react';
import { Center } from 'native-base';
import { View } from 'react-native';
import { Linking, View } from 'react-native';
import { connect } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { InAppBrowser } from 'react-native-inappbrowser-reborn';
import parseUrl from 'url-parse';

import {
loadPaymentMethods,
Expand All @@ -18,21 +21,21 @@ import PaymentMethodPicker from './components/PaymentMethodPicker';
import HeaderHeightAwareKeyboardAvoidingView from '../../components/HeaderHeightAwareKeyboardAvoidingView';
import { SafeAreaView } from 'react-native-safe-area-context';

class CreditCard extends Component {
componentDidMount() {
this.props.loadPaymentMethods();
}
const routesByCardGateway = {
stripe: 'CheckoutPaymentMethodCard',
// https://github.com/coopcycle/coopcycle-app/issues/1697
// 'mercadopago': 'CheckoutMercadopago',
};

_onPaymentMethodSelected(type) {
const inAppBrowserOptions = {}

const routesByCardGateway = {
stripe: 'CheckoutPaymentMethodCard',
// https://github.com/coopcycle/coopcycle-app/issues/1697
// 'mercadopago': 'CheckoutMercadopago',
};
const CreditCard = ({ cart, paymentMethods, paymentGateway, loadPaymentMethods, setPaymentMethod }) => {

const cardRoute = Object.prototype.hasOwnProperty.call(routesByCardGateway, this.props.paymentGateway) ?
routesByCardGateway[this.props.paymentGateway] : 'CheckoutPaymentMethodCard';
const navigation = useNavigation();

const onPaymentMethodSelected = useCallback((type) => {
const cardRoute = Object.prototype.hasOwnProperty.call(routesByCardGateway, paymentGateway) ?
routesByCardGateway[paymentGateway] : 'CheckoutPaymentMethodCard';

const routesByMethod = {
cash_on_delivery: 'CheckoutPaymentMethodCashOnDelivery',
Expand All @@ -41,49 +44,71 @@ class CreditCard extends Component {
'edenred+card': 'CheckoutPaymentMethodEdenred',
};

this.props.setPaymentMethod(type, () => {
this.props.navigation.navigate(routesByMethod[type]);
setPaymentMethod(type, async (result) => {
if (result.redirectUrl) {
try {
if (await InAppBrowser.isAvailable()) {
// https://github.com/proyecto26/react-native-inappbrowser/issues/131#issuecomment-663492025
await InAppBrowser.closeAuth();
InAppBrowser.openAuth(result.redirectUrl, 'coopcycle://', inAppBrowserOptions)
.then((response) => {
if (response.type === 'success' && response.url) {
const { hostname, pathname } = parseUrl(response.url, true);
if (hostname === 'paygreen' && (pathname === '/cancel' || pathname === '/return')) {
Linking.openURL(response.url)
}
}
});
} else {
Linking.openURL(result.redirectUrl);
}
} catch (e) {
Linking.openURL(result.redirectUrl);
}
} else {
navigation.navigate(routesByMethod[type]);
}
})
}

render() {
const { cart, paymentMethods, paymentGateway } = this.props;

if (!cart || paymentMethods.length === 0) {
return <View />;
}
}, [ navigation, paymentGateway, setPaymentMethod ]);

if (paymentMethods.length === 1 && paymentMethods[0].type === 'card') {
if (paymentGateway === 'mercadopago') {
this.props.navigation.navigate('CheckoutMercadopago');
return null;
}
useEffect(() => {
loadPaymentMethods();
}, [ loadPaymentMethods ])

return (
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
<HeaderHeightAwareKeyboardAvoidingView>
<CreditCardComp cart={cart} />
</HeaderHeightAwareKeyboardAvoidingView>
</SafeAreaView>
);
}
if (!cart || paymentMethods.length === 0) {
return <View />;
}

if (
paymentMethods.length === 1 &&
paymentMethods[0].type === 'cash_on_delivery'
) {
return <CashComp />;
if (paymentMethods.length === 1 && paymentMethods[0].type === 'card') {
if (paymentGateway === 'mercadopago') {
navigation.navigate('CheckoutMercadopago');
return null;
}

return (
<Center flex={1}>
<PaymentMethodPicker
methods={paymentMethods}
onSelect={this._onPaymentMethodSelected.bind(this)}
/>
</Center>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
<HeaderHeightAwareKeyboardAvoidingView>
<CreditCardComp cart={cart} />
</HeaderHeightAwareKeyboardAvoidingView>
</SafeAreaView>
);
}

if (
paymentMethods.length === 1 &&
paymentMethods[0].type === 'cash_on_delivery'
) {
return <CashComp />;
}

return (
<Center flex={1}>
<PaymentMethodPicker
methods={paymentMethods}
onSelect={onPaymentMethodSelected}
/>
</Center>
);
}

function mapStateToProps(state, ownProps) {
Expand Down
37 changes: 35 additions & 2 deletions src/navigation/checkout/components/PaymentMethodIcon.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import { Icon } from 'native-base';
import { Image } from 'react-native';
import { Box, Icon } from 'native-base';
import Foundation from 'react-native-vector-icons/Foundation';
import Svg, { Path, G } from 'react-native-svg';
import ConecsIcon from './PaymentMethodIcon/ConecsIcon';

const icons = {
card: 'credit-card',
Expand All @@ -19,16 +21,47 @@ const PaymentMethodIcon = ({ type }) => {
/>)
}

if (type === 'conecs') {
return (
<Icon size="xl" mr="2">
<ConecsIcon />
</Icon>
)
}

if (type === 'restoflash') {
return (
<Box mr="2">
<Image
resizeMode="contain"
source={require('../../../../assets/images/restoflash.png')}
style={{ width: 30, height: 30 }} />
</Box>
)
}

if (type === 'swile') {
return (
<Box mr="2">
<Image
resizeMode="contain"
source={require('../../../../assets/images/Swile_black.png')}
style={{ width: 40, height: 40 }} />
</Box>
)
}

if (type === 'edenred' || type === 'edenred+card') {
return (
<Icon size="xl" viewBox="0 0 413.24 265.47" mr="2">
<Icon size="xl" mr="2">
<Svg
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
id="Layer_1"
x={0}
y={0}
fill={ '#000000' }
viewBox="0 0 413.24 265.47"
>
<Path
d="M160.43 117.34c-6.79 0-11.1 4.42-12.44 10.28h24.16c-.82-6.47-5.35-10.28-11.72-10.28zM95.86 119.91c-8.64 0-14.09 5.96-14.09 14.29 0 8.23 5.55 14.39 14.09 14.39s14.29-5.86 14.29-14.39c0-8.53-5.76-14.29-14.29-14.29z"
Expand Down
Loading

0 comments on commit 60cfbd0

Please sign in to comment.