Skip to content

Commit

Permalink
First paddle integration
Browse files Browse the repository at this point in the history
  • Loading branch information
pschlan committed Oct 25, 2023
1 parent d4a64f0 commit 80e6808
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 44 deletions.
1 change: 1 addition & 0 deletions api/languages/fr.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
. '$projectName',
'dateFormat' => 'd/m/Y'
];

58 changes: 52 additions & 6 deletions frontend/src/components/settings/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { Box, Button, ButtonGroup, CircularProgress, Grid, InputLabel, LinearProgress, makeStyles, MenuItem, Paper, Select, TableContainer, Typography } from '@material-ui/core';
import { grey } from '@material-ui/core/colors';
import { useTranslation } from 'react-i18next';
import { createBillingPortalSession, getAPIKeys, getMFADevices, getUserProfile, updateUserProfile } from '../../utils/API';
import { createBillingPortalSession, getAPIKeys, getMFADevices, getSubscriptionLink, getUserProfile, updateUserProfile } from '../../utils/API';
import useTimezones from '../../hooks/useTimezones';
import useUserProfile from '../../hooks/useUserProfile';
import Breadcrumbs from '../misc/Breadcrumbs';
Expand All @@ -24,6 +24,7 @@ import DeleteMFADeviceDialog from './DeleteMFADeviceDialog';
import { RegexPatterns, SubscriptionStatus } from '../../utils/Constants';
import DeleteAccountDialog from './DeleteAccountDialog';
import ManageSubscriptionIcon from '@material-ui/icons/CreditCard';
import CancelSubscriptionIcon from '@material-ui/icons/Cancel';
import SubscriptionActiveIcon from '@material-ui/icons/FavoriteBorder';
import SubscriptionInactiveIcon from '@material-ui/icons/PauseCircleOutline';
import LearnMoreIcon from '@material-ui/icons/Loyalty';
Expand Down Expand Up @@ -69,7 +70,7 @@ const useStyles = makeStyles(theme => ({
}
}));

const REFRESH_INTERVAL = 5000;
const REFRESH_INTERVAL = 2000;

export default function Settings() {
const classes = useStyles();
Expand All @@ -82,6 +83,7 @@ export default function Settings() {
const [ isLoading, setIsLoading ] = useState(true);
const [ saving, setSaving ] = useState(false);
const [ isLoadingManageSubscription, setIsLoadingManageSubscription ] = useState(false);
const [ isLoadingCancelSubscription, setIsLoadingCancelSubscription ] = useState(false);

const [ showChangePassword, setShowChangePassword ] = useState(false);
const [ showChangeEmail, setShowChangeEmail ] = useState(false);
Expand Down Expand Up @@ -163,15 +165,37 @@ export default function Settings() {

function manageSubscription() {
setIsLoadingManageSubscription(true);
createBillingPortalSession()
.then(respone => window.location.href = respone.url)

if (userProfile.userSubscription.type === 'stripe') {
createBillingPortalSession()
.then(respone => window.location.href = respone.url)
.catch(() => {
enqueueSnackbar(t('settings.manageSubscriptionFailed'), { variant: 'error' });
setIsLoadingManageSubscription(false);
});
} else if (userProfile.userSubscription.type === 'paddle') {
getSubscriptionLink('manage')
.then(response => window.location.href = response.url)
.catch(() => {
enqueueSnackbar(t('settings.manageSubscriptionFailed'), { variant: 'error' });
setIsLoadingManageSubscription(false);
});
}
}

function cancelSubscription() {
setIsLoadingCancelSubscription(true);

getSubscriptionLink('cancel')
.then(response => window.location.href = response.url)
.catch(() => {
enqueueSnackbar(t('settings.manageSubscriptionFailed'), { variant: 'error' });
setIsLoadingManageSubscription(false);
setIsLoadingCancelSubscription(false);
});
}

const isCancelledSubscription = userProfile && userProfile.userSubscription && userProfile.userSubscription.status === SubscriptionStatus.CANCELLED;
const isExpiringSubscription = userProfile && userProfile.userSubscription && userProfile.userSubscription.status === SubscriptionStatus.EXPIRING;
const isPaymentReturn = window && window.location && window.location.search === '?checkoutSuccess=true';

useEffect(() => {
Expand Down Expand Up @@ -364,7 +388,7 @@ export default function Settings() {
</Grid>
<Grid item sm={6} xs={12} align='right'>
<ButtonGroup variant='contained' size='small'>
{userProfile.userSubscription &&
{userProfile.userSubscription && userProfile.userSubscription.type==='stripe' &&
<Button
size='small'
variant='contained'
Expand All @@ -375,6 +399,28 @@ export default function Settings() {
>
{t('settings.manageSubscription')}
</Button>}
{userProfile.userSubscription && userProfile.userSubscription.type==='paddle' && userProfile.userSubscription.status === SubscriptionStatus.ACTIVE && <ButtonGroup>
<Button
size='small'
variant='contained'
startIcon={isLoadingManageSubscription ? <CircularProgress size='small' /> : <ManageSubscriptionIcon />}
onClick={manageSubscription}
disabled={isLoadingManageSubscription || isCancelledSubscription || isExpiringSubscription}
float='right'
>
{t('settings.updatePaymentMethod')}
</Button>
<Button
size='small'
variant='contained'
startIcon={isLoadingCancelSubscription ? <CircularProgress size='small' /> : <CancelSubscriptionIcon />}
onClick={cancelSubscription}
disabled={isLoadingCancelSubscription || isCancelledSubscription || isExpiringSubscription}
float='right'
>
{t('settings.cancelSubscription')}
</Button>
</ButtonGroup>}
{!isPaymentReturn && ((!userProfile.userSubscription) || (userProfile.userSubscription.status === SubscriptionStatus.CANCELLED)) &&
<Button
size='small'
Expand Down
43 changes: 12 additions & 31 deletions frontend/src/components/settings/SubscribeDialog.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React, { useRef, useState } from 'react';
import { CircularProgress, Paper, Checkbox, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Link, makeStyles, TableCell, TableHead, Table, TableRow, MenuItem, TableBody, Select, Box, Grid, FormControlLabel } from '@material-ui/core';
import { CircularProgress, Paper, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, makeStyles, TableCell, TableHead, Table, TableRow, MenuItem, TableBody, Select, Box, Grid } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import { createCheckoutSession } from '../../utils/API';
import { useSnackbar } from 'notistack';
import { Config } from '../../utils/Config';
import YesIcon from '@material-ui/icons/Check';
import NoIcon from '@material-ui/icons/Close';
import { red, green } from '@material-ui/core/colors';
import SubscribeIcon from '@material-ui/icons/ShoppingCart';
import useUserProfile from '../../hooks/useUserProfile';

const useStyles = makeStyles(theme => ({
no: {
Expand All @@ -28,22 +27,22 @@ export default function SubscribeDialog({ onClose }) {

const onCloseHook = useRef(onClose, []);
const { t } = useTranslation();
const { enqueueSnackbar } = useSnackbar();

const [ state, setState ] = useState(States.TEASER);
const [ isLoadingOrder, setIsLoadingOrder ] = useState(false);
const [ productId, setProductId ] = useState('sustain10');
const [ acceptToS, setAcceptToS ] = useState(false);
const [ acceptRefundPolicy, setAcceptRefundPolicy ] = useState(false);

const userProfile = useUserProfile();

function startOrder() {
setIsLoadingOrder(true);
createCheckoutSession(productId)
.then(respone => window.location.href = respone.url)
.catch(() => {
enqueueSnackbar(t('settings.orderFailed'), { variant: 'error' })
setIsLoadingOrder(false);
});

window.location.href =
Config.sustainingMembership.paddle.paymentUrl(t('landingLocale'))
+ '#userId=' + userProfile.userId
+ '&email=' + encodeURIComponent(userProfile.userProfile.email)
+ '&product=' + productId
+ '&locale=' + t('paddleLocale');
}

return <Dialog open={true} onClose={onCloseHook.current} fullWidth maxWidth='md'>
Expand Down Expand Up @@ -128,24 +127,6 @@ export default function SubscribeDialog({ onClose }) {
<Paper>
<Box p={2}>
<Grid container xs={12} md={12}>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox />}
label={<Link href={Config.termsOfServiceURL} target="_blank" rel="noopener nofollow">{t('signup.acceptToS')}</Link>}
onChange={({target}) => setAcceptToS(target.checked)}
checked={acceptToS}
required
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox />}
label={<Link href={Config.refundPolicyURL} target="_blank" rel="noopener nofollow">{t('settings.subscribeDialog.acceptRefundPolicy')}</Link>}
onChange={({target}) => setAcceptRefundPolicy(target.checked)}
checked={acceptRefundPolicy}
required
/>
</Grid>
<Grid item xs={12}>
<Box display='flex' alignItems='center' mt={2}>
<Box mr={2}>
Expand All @@ -165,7 +146,7 @@ export default function SubscribeDialog({ onClose }) {
color='primary'
startIcon={isLoadingOrder ? <CircularProgress size='small' /> : <SubscribeIcon />}
onClick={() => startOrder()}
disabled={isLoadingOrder || !acceptToS || !acceptRefundPolicy}>
disabled={isLoadingOrder || !userProfile || !userProfile.userId}>
{t('settings.subscribeDialog.orderNow')}
</Button>
</Box>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/locales/de/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"paddleLocale": "de",
"landingLocale": "de",
"common": {
"menu": "Menü",
"contact": "Kontakt",
Expand Down Expand Up @@ -430,6 +432,8 @@
"manageSubscriptionFailed": "Fehler beim Laden des Abo-Verwaltungs-Portals. Bitte versuchen Sie es später erneut oder kontaktieren Sie unser Support-Team.",
"orderFailed": "Fehler beim Laden des Kaufabwicklungs-Portals. Bitte versuchen Sie es später erneut oder kontaktieren Sie unser Support-Team.",
"manageSubscription": "Abo verwalten",
"updatePaymentMethod": "Zahlungsart ändern",
"cancelSubscription": "Abo kündigen",
"subscribeDialog": {
"text1": "Durch eine Fördermitgliedschaft bei {{serviceName}} unterstützen Sie uns beim Betrieb und bei der Weiterentwicklung unseres Dienstes.",
"text2": "Als Dankeschön für Ihre Unterstützung können wir Fördermitgliedern exklusive Vorteile anbieten.",
Expand All @@ -450,7 +454,7 @@
"amountAMonth": "{{amount}} EUR / Monat",
"amountAYear": "{{amount}} EUR / Jahr",
"subscribeNow": "Jetzt Fördermitglied werden",
"orderNow": "Zahlungspflichtig bestellen",
"orderNow": "Jetzt bestellen",
"orderText": "Vielen Dank für Ihre Unterstützung! Sie können nun Ihren Unterstützungsbeitrag wählen und die Buchung abschließen.",
"acceptRefundPolicy": "Ich akzeptiere die Widerrufsbelehrung"
},
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"paddleLocale": "en",
"landingLocale": "en",
"common": {
"menu": "Menu",
"contact": "Contact",
Expand Down Expand Up @@ -454,6 +456,8 @@
},
"orderFailed": "Failed to load checkout portal. Please try again later or contact our support team.",
"manageSubscription": "Manage subscription",
"updatePaymentMethod": "Update payment method",
"cancelSubscription": "Cancel subscription",
"mfa": {
"devices": "Multi-Factor Authentication devices",
"noDevices": "No devices found. Add a MFA device now to secure your account.",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/locales/fr/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"paddleLocale": "fr",
"common": {
"menu": "Menu",
"followontwitter": "Twitter",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/locales/it/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"paddleLocale": "it",
"common": {
"menu": "Menu",
"contact": "Contatti",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/locales/ru/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"paddleLocale": "de",
"common": {
"menu": "Меню",
"followontwitter": "Twitter",
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/utils/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,16 +332,14 @@ export function deleteJobTestRun(handle) {
});
}

export function createCheckoutSession(product) {
return performRequest('CreateCheckoutSession', {
product
});
}

export function createBillingPortalSession() {
return performRequest('CreateBillingPortalSession', {});
}

export function getSubscriptionLink(type) {
return performRequest('GetSubscriptionLink', { type });
}

export function getMFADevices() {
return performRequest('GetMFADevices', {});
}
Expand Down

0 comments on commit 80e6808

Please sign in to comment.