1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-19 13:54:25 +01:00

WIP: create react component to collect card data

This commit is contained in:
Sylvain 2020-11-23 17:36:33 +01:00
parent 0697d9cff1
commit b88c1009db
13 changed files with 178 additions and 24 deletions

View File

@ -0,0 +1,17 @@
import apiClient from './api-client';
import { AxiosResponse } from 'axios';
import { Setting } from '../models/setting';
import wrapPromise, { IWrapPromise } from '../lib/wrap-promise';
export default class SettingAPI {
async get (name: string): Promise<Setting> {
const res: AxiosResponse = await apiClient.get(`/api/settings/${name}`);
return res?.data?.setting;
}
static get (name: string): IWrapPromise<Setting> {
const api = new SettingAPI();
return wrapPromise(api.get(name));
}
}

View File

@ -0,0 +1,24 @@
/**
* This is a compatibility wrapper to allow usage of stripe.js Elements inside of the angular.js app
*/
import React from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { react2angular } from 'react2angular';
import { IApplication } from '../../models/application';
import SettingAPI from '../../api/setting';
import { loadStripe } from "@stripe/stripe-js";
declare var Application: IApplication;
const stripePublicKey = SettingAPI.get('stripe_public_key');
const ElementsWrapper: React.FC = () => {
const publicKey = stripePublicKey.read();
const stripePromise = loadStripe(publicKey.value);
return (
<Elements stripe={stripePromise} />
);
}
Application.Components.component('stripeElements', react2angular(ElementsWrapper));

View File

@ -3,7 +3,7 @@
*/
import Switch from 'react-switch';
import { react2angular } from 'react2angular';
import { IApplication } from '../models/application';
import { IApplication } from '../../models/application';
declare var Application: IApplication;

View File

@ -6,7 +6,7 @@ import React from 'react';
import Modal from 'react-modal';
import { useTranslation } from 'react-i18next';
import { Loader } from './loader';
import CustomAsset from '../api/custom-asset';
import CustomAssetAPI from '../api/custom-asset';
Modal.setAppElement('body');
@ -16,7 +16,7 @@ interface FabModalProps {
toggleModal: () => void
}
const blackLogoFile = CustomAsset.get('logo-black-file');
const blackLogoFile = CustomAssetAPI.get('logo-black-file');
export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal, children }) => {
const { t } = useTranslation('shared');

View File

@ -0,0 +1,71 @@
/**
* This component enables the user to type his card data.
*/
import React from 'react';
import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';
import { react2angular } from 'react2angular';
import { Loader } from './loader';
import { IApplication } from '../models/application';
declare var Application: IApplication;
const StripeCard: React.FC = () => {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
event.preventDefault();
// Stripe.js has not loaded yet
if (!stripe || !elements) { return; }
const cardElement = elements.getElement(CardElement);
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
console.log('[error]', error);
} else {
console.log('[PaymentMethod]', paymentMethod);
}
}
return (
<div className="stripe-card">
<form onSubmit={handleSubmit}>
<CardElement
options={{
style: {
base: {
fontSize: '16px',
color: '#424770',
'::placeholder': { color: '#aab7c4' }
},
invalid: {
color: '#9e2146',
iconColor: '#9e2146'
},
},
}}
/>
</form>
</div>
);
}
const StripeCardWrapper: React.FC = () => {
return (
<Loader>
<StripeCard />
</Loader>
);
}
Application.Components.component('stripeCard', react2angular(StripeCardWrapper));

View File

@ -5,7 +5,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { react2angular } from 'react2angular';
import moment from 'moment';
import { IApplication } from '../models/application';
import '../lib/i18n';
import { IFilterService } from 'angular';

View File

@ -705,7 +705,10 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon', 'cartItems', 'stripeKey', 'schedule',
function ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, wallet, helpers, $filter, coupon, cartItems, stripeKey, schedule) {
// user wallet amount
$scope.walletAmount = wallet.amount;
$scope.wallet = wallet;
// Global price (total of all items)
$scope.price = price.price;
// Price
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount);
@ -800,6 +803,9 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
* Callback to process the local payment, triggered on button click
*/
$scope.ok = function () {
if ($scope.method.payment_method === 'stripe') {
return payByStripe(reservation);
}
$scope.attempting = true;
// save subscription (if there's only a subscription selected)
if ($scope.reservation.slots_attributes.length === 0 && selectedPlan) {

View File

@ -0,0 +1,9 @@
export interface HistoryValue {
id: number,
value: string,
created_at: Date
user: {
id: number,
name: string
}
}

View File

@ -0,0 +1,8 @@
import { HistoryValue } from './history-value';
export interface Setting {
name: string,
value: string,
last_update: Date,
history: Array<HistoryValue>
}

View File

@ -10,9 +10,13 @@
<form name="stripeForm" stripe:form cart-items="cartItems" on-payment-success="onPaymentSuccess" stripe-key="{{stripeKey}}" class="form-horizontal">
<div class="panel-body">
<h3 class="m-t-xs" ng-if="walletAmount" ng-bind-html="'app.shared.wallet.you_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol }"></h3>
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic" ng-bind-html="'app.shared.stripe.credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol }"></p>
<div class="row">
<wallet-info current-user="currentUser"
reservation="reservation"
price="price"
remaining-price="amount"
wallet="wallet"/>
</div>
<div id="card-element"></div>
<div id="card-errors" role="alert"></div>

View File

@ -88,29 +88,31 @@
<%= flash_messages %>
<section class="vbox">
<stripe-elements>
<section class="vbox">
<header class="header header-md navbar navbar-fixed-top-xs">
<div ui-view="header"></div>
</header>
<header class="header header-md navbar navbar-fixed-top-xs">
<div ui-view="header"></div>
</header>
<section ui-view="content">
<section class="hbox stretch">
<aside id="nav" class="aside-md bg-red hidden-print" ui-view="leftnav"></aside>
<section ui-view="content">
<section class="hbox stretch">
<aside id="nav" class="aside-md bg-red hidden-print" ui-view="leftnav"></aside>
<section id="content">
<section class="vbox">
<section id="cookies-modal" ui-view="cookies">
</section>
<section id="content-main" class="scrollable" ui-view="main">
<section id="content">
<section class="vbox">
<section id="cookies-modal" ui-view="cookies">
</section>
<section id="content-main" class="scrollable" ui-view="main">
</section>
</section>
</section>
</section>
</section> <!-- /.hbox -->
</section>
</section> <!-- /.hbox -->
</section>
</section> <!-- /.vbox -->
</section> <!-- /.vbox -->
</stripe-elements>
<div class="app-generator">
<span class="app-version" uib-tooltip="{{'app.public.common.version' | translate}} {{version.current}}" ng-if="currentUser && currentUser.role == 'admin'" ng-click="versionModal()">

View File

@ -41,6 +41,8 @@
"@claviska/jquery-minicolors": "^2.3.5",
"@fortawesome/fontawesome-free": "5.14.0",
"@rails/webpacker": "5.2.1",
"@stripe/react-stripe-js": "^1.1.2",
"@stripe/stripe-js": "^1.11.0",
"@types/react": "^16.9.53",
"@types/react-dom": "^16.9.8",
"@uirouter/angularjs": "0.4",

View File

@ -1121,6 +1121,18 @@
webpack-cli "^3.3.12"
webpack-sources "^1.4.3"
"@stripe/react-stripe-js@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.1.2.tgz#a7f5ef5b4d7dc7fa723501b706644414cfe6dcba"
integrity sha512-07hu8RJXwWKGbvdvd1yt1cYvGtDB8jFX+q10f7FQuItUt9rlSo0am3WIx845iMHANiYgxyRb1PS201Yle9xxPQ==
dependencies:
prop-types "^15.7.2"
"@stripe/stripe-js@^1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.11.0.tgz#00e812d72a7760dae08237875066d263671478ee"
integrity sha512-SDNZKuETBEVkernd1tq8tL6wNfVKrl24Txs3p+4NYxoaIbNaEO7mrln/2Y/WRcQBWjagvhDIM5I6+X1rfK0qhQ==
"@types/angular@^1.6.39":
version "1.7.3"
resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.7.3.tgz#138c2f2f688e9dcb413c6052d9483d773ce7f627"