mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
allow payment with stripe-modal react component
This commit is contained in:
parent
4ca2299776
commit
6c39191efa
@ -14,7 +14,7 @@ class API::PricesController < API::ApiController
|
||||
@prices = @prices.where(priceable_id: params[:priceable_id]) if params[:priceable_id]
|
||||
end
|
||||
if params[:plan_id]
|
||||
plan_id = if params[:plan_id] =~ /no|nil|null|undefined/i
|
||||
plan_id = if /no|nil|null|undefined/i.match?(params[:plan_id])
|
||||
nil
|
||||
else
|
||||
params[:plan_id]
|
||||
@ -37,7 +37,11 @@ class API::PricesController < API::ApiController
|
||||
end
|
||||
|
||||
def compute
|
||||
price_parameters = compute_price_params
|
||||
price_parameters = if params[:reservation]
|
||||
compute_reservation_price_params
|
||||
elsif params[:subscription]
|
||||
compute_subscription_price_params
|
||||
end
|
||||
# user
|
||||
user = User.find(price_parameters[:user_id])
|
||||
# reservable
|
||||
@ -74,12 +78,16 @@ class API::PricesController < API::ApiController
|
||||
params.require(:price).permit(:amount)
|
||||
end
|
||||
|
||||
def compute_price_params
|
||||
def compute_reservation_price_params
|
||||
params.require(:reservation).permit(:reservable_id, :reservable_type, :plan_id, :user_id, :nb_reserve_places, :payment_schedule,
|
||||
tickets_attributes: %i[event_price_category_id booked],
|
||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||
end
|
||||
|
||||
def compute_subscription_price_params
|
||||
params.require(:subscription).permit(:plan_id, :user_id, :payment_schedule)
|
||||
end
|
||||
|
||||
def coupon_params
|
||||
params.permit(:coupon_code)
|
||||
end
|
||||
|
@ -4,7 +4,7 @@ import { CartItems, PaymentConfirmation } from '../models/payment';
|
||||
|
||||
export default class PaymentAPI {
|
||||
static async confirm (stp_payment_method_id: string, cart_items: CartItems): Promise<PaymentConfirmation> {
|
||||
const res: AxiosResponse = await apiClient.post(`/api/payment/confirm`, {
|
||||
const res: AxiosResponse = await apiClient.post(`/api/payments/confirm_payment`, {
|
||||
payment_method_id: stp_payment_method_id,
|
||||
cart_items
|
||||
});
|
||||
|
@ -1,18 +1,12 @@
|
||||
import apiClient from './api-client';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import wrapPromise, { IWrapPromise } from '../lib/wrap-promise';
|
||||
import { CartItems } from '../models/payment';
|
||||
import { ComputePriceResult } from '../models/price';
|
||||
|
||||
export default class PriceAPI {
|
||||
async compute (cartItems: CartItems): Promise<ComputePriceResult> {
|
||||
static async compute (cartItems: CartItems): Promise<ComputePriceResult> {
|
||||
const res: AxiosResponse = await apiClient.post(`/api/prices/compute`, cartItems);
|
||||
return res?.data?.custom_asset;
|
||||
}
|
||||
|
||||
static compute (cartItems: CartItems): IWrapPromise<ComputePriceResult> {
|
||||
const api = new PriceAPI();
|
||||
return wrapPromise(api.compute(cartItems));
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,9 @@ import wrapPromise, { IWrapPromise } from '../lib/wrap-promise';
|
||||
import { Wallet } from '../models/wallet';
|
||||
|
||||
export default class WalletAPI {
|
||||
async getByUser (user_id: number): Promise<Wallet> {
|
||||
static async getByUser (user_id: number): Promise<Wallet> {
|
||||
const res: AxiosResponse = await apiClient.get(`/api/wallet/by_user/${user_id}`);
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static getByUser (user_id: number): IWrapPromise<Wallet> {
|
||||
const api = new WalletAPI();
|
||||
return wrapPromise(api.getByUser(user_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Supports Strong-Customer Authentication (SCA).
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, ReactNode, useEffect, useState } from 'react';
|
||||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { Loader } from './loader';
|
||||
import { IApplication } from '../models/application';
|
||||
@ -43,27 +43,43 @@ interface StripeModalProps {
|
||||
const cgvFile = CustomAssetAPI.get(CustomAssetName.CgvFile);
|
||||
|
||||
const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuccess, cartItems, currentUser, schedule , processPayment = true }) => {
|
||||
// customer's wallet
|
||||
const [wallet, setWallet] = useState(null);
|
||||
// server-computed price with all details
|
||||
const [price, setPrice] = useState(null);
|
||||
// remaining price = total price - wallet amount
|
||||
const [remainingPrice, setRemainingPrice] = useState(0);
|
||||
const userWallet = WalletAPI.getByUser(cartItems.reservation?.user_id || cartItems.subscription?.user_id);
|
||||
const priceInfo = PriceAPI.compute(cartItems);
|
||||
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
const cgv = cgvFile.read();
|
||||
const wallet = userWallet.read();
|
||||
const price = priceInfo.read();
|
||||
|
||||
// is the component ready to display?
|
||||
const [ready, setReady] = useState(false);
|
||||
// errors to display in the UI (stripe errors mainly)
|
||||
const [errors, setErrors] = useState(null);
|
||||
// are we currently processing the payment (ie. the form was submit, but the process is still running)?
|
||||
const [submitState, setSubmitState] = useState(false);
|
||||
// did the user accepts the terms of services (CGV)?
|
||||
const [tos, setTos] = useState(false);
|
||||
|
||||
const { t } = useTranslation('shared');
|
||||
const cgv = cgvFile.read();
|
||||
|
||||
|
||||
/**
|
||||
* Refresh the remaining price on each display
|
||||
* On each display:
|
||||
* - Refresh the wallet
|
||||
* - Refresh the price
|
||||
* - Refresh the remaining price
|
||||
*/
|
||||
useEffect(() => {
|
||||
const wLib = new WalletLib(wallet);
|
||||
setRemainingPrice(wLib.computeRemainingPrice(price.price));
|
||||
})
|
||||
if (!cartItems) return;
|
||||
WalletAPI.getByUser(cartItems.reservation?.user_id || cartItems.subscription?.user_id).then((wallet) => {
|
||||
setWallet(wallet);
|
||||
PriceAPI.compute(cartItems).then((res) => {
|
||||
setPrice(res);
|
||||
const wLib = new WalletLib(wallet);
|
||||
setRemainingPrice(wLib.computeRemainingPrice(res.price));
|
||||
setReady(true);
|
||||
})
|
||||
})
|
||||
}, [cartItems]);
|
||||
|
||||
/**
|
||||
* Check if there is currently an error to display
|
||||
@ -82,7 +98,7 @@ const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuc
|
||||
/**
|
||||
* Triggered when the user accepts or declines the Terms of Sales
|
||||
*/
|
||||
const toggleTos = (event: ChangeEvent): void => {
|
||||
const toggleTos = (): void => {
|
||||
setTos(!tos);
|
||||
}
|
||||
|
||||
@ -114,6 +130,9 @@ const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuc
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component as 'currently submitting'
|
||||
*/
|
||||
const handleSubmit = (): void => {
|
||||
setSubmitState(true);
|
||||
}
|
||||
@ -153,8 +172,8 @@ const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuc
|
||||
closeButton={false}
|
||||
customFooter={logoFooter()}
|
||||
className="stripe-modal">
|
||||
<WalletInfo reservation={cartItems.reservation} currentUser={currentUser} wallet={wallet} price={price.price} />
|
||||
<StripeElements>
|
||||
{ready && <StripeElements>
|
||||
<WalletInfo reservation={cartItems?.reservation} currentUser={currentUser} wallet={wallet} price={price?.price} />
|
||||
<StripeForm onSubmit={handleSubmit}
|
||||
onSuccess={handleFormSuccess}
|
||||
onError={handleFormError}
|
||||
@ -183,7 +202,7 @@ const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuc
|
||||
className="validate-btn">
|
||||
{t('app.shared.stripe.confirm_payment_of_', { AMOUNT: formatPrice(remainingPrice) })}
|
||||
</button>
|
||||
</StripeElements>
|
||||
</StripeElements>}
|
||||
</FabModal>
|
||||
);
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
cartItems: null
|
||||
};
|
||||
|
||||
// currently logged-in user
|
||||
$scope.currentUser = $rootScope.currentUser;
|
||||
|
||||
/**
|
||||
* Add the provided slot to the shopping cart (state transition from free to 'about to be reserved')
|
||||
* and increment the total amount of the cart if needed.
|
||||
@ -312,9 +315,12 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
/**
|
||||
* This will open/close the stripe payment modal
|
||||
*/
|
||||
$scope.toggleStripeModal = () => {
|
||||
$scope.toggleStripeModal = (beforeApply) => {
|
||||
setTimeout(() => {
|
||||
$scope.stripe.showModal = !$scope.stripe.showModal;
|
||||
if (typeof beforeApply === 'function') {
|
||||
beforeApply();
|
||||
}
|
||||
$scope.$apply();
|
||||
}, 50);
|
||||
};
|
||||
@ -693,8 +699,15 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
* Open a modal window that allows the user to process a credit card payment for his current shopping cart.
|
||||
*/
|
||||
const payByStripe = function (reservation) {
|
||||
$scope.stripe.cartItems = mkRequestParams({ reservation }, $scope.coupon.applied);
|
||||
$scope.toggleStripeModal();
|
||||
$scope.toggleStripeModal(() => {
|
||||
let request = { reservation };
|
||||
if (reservation.slots_attributes.length === 0 && reservation.plan_id) {
|
||||
request = mkSubscription($scope.selectedPlan.id, reservation.user_id, $scope.schedule.requested_schedule, 'stripe');
|
||||
} else {
|
||||
request.reservation.payment_method = 'stripe';
|
||||
}
|
||||
$scope.stripe.cartItems = mkRequestParams(request, $scope.coupon.applied);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Open a modal window that allows the user to process a local payment for his current shopping cart (admin only).
|
||||
|
@ -203,7 +203,7 @@
|
||||
<stripe-modal is-open="stripe.showModal"
|
||||
toggle-modal="toggleStripeModal"
|
||||
after-success="afterStripeSuccess"
|
||||
cartItems="stripe.cartItems"
|
||||
cart-items="stripe.cartItems"
|
||||
current-user="currentUser"
|
||||
schedule="schedule.payment_schedule"/>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user