Skip to content

Commit

Permalink
Add Storefront Actions & added Smart Payment Buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
mstegmeyer committed May 7, 2024
1 parent 1e43910 commit 10b96dc
Show file tree
Hide file tree
Showing 24 changed files with 1,126 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ CLIENT_SECRET_SANDBOX=

SANDBOX=
MERCHANT_ID=

###> nelmio/cors-bundle ###
TRUSTED_PROXIES=127.0.0.1,localhost,REMOTE_ADDR
CORS_ALLOW_ORIGIN='^https?://(.*)(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###< nelmio/cors-bundle ###
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ devenv.local.nix

# PhpStorm
/.idea/


# js
node_modules/
bundle/Resources/app/storefront/dist/*
13 changes: 13 additions & 0 deletions bundle/Resources/app/storefront/build/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { join, resolve } = require('path');

module.exports = () => {
return {
resolve: {
alias: {
'@paypal': resolve(
join(__dirname, '..', 'node_modules', '@paypal'),
),
},
},
};
};
44 changes: 44 additions & 0 deletions bundle/Resources/app/storefront/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions bundle/Resources/app/storefront/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "swag-paypal-storefront",
"version": "1.0.0",
"private": true,
"description": "Shopware Storefront PayPal",
"license": "MIT",
"dependencies": {
"@paypal/paypal-js": "~8"
}
}
170 changes: 170 additions & 0 deletions bundle/Resources/app/storefront/src/checkout/swag-paypal-app.wallet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import DomAccess from 'src/helper/dom-access.helper';
import FormSerializeUtil from 'src/utility/form/form-serialize.util';
import AppClient from 'src/service/app-client.service';
import PageLoadingIndicatorUtil from 'src/utility/loading-indicator/page-loading-indicator.util';
import Plugin from 'src/plugin-system/plugin.class';
import {loadScript} from '@paypal/paypal-js';

const BASE_URL = 'http://localhost:8080/storefront/';

export default class SwagPaypalAppWallet extends Plugin {
static options = {
/**
* Options for the PayPal script
*/
languageIso: 'en_GB',
currency: 'EUR',
intent: 'capture',
commit: true,
clientId: '',
merchantPayerId: '',

/**
* Is set, if the plugin is used on the order edit page
*/
orderId: null,

/**
* Usage inside the plugin
*/
confirmOrderFormSelector: '#confirmOrderForm',
confirmOrderButtonSelector: 'button[type="submit"]',

/**
* In a productive app, we should filter this to only values that we need for PayPal order creation
*/
cart: {},
salesChannelContext: {},
};

init() {
this._client = new AppClient('SCDPayPalApp');

this.createButton();
}

async createButton() {
await this.fetchClientConfig();
const paypal = await this.createScript();
this.renderButton(paypal);
}

createScript() {
return loadScript(this.getScriptOptions());
}

renderButton(paypal) {
this.confirmOrderForm = DomAccess.querySelector(document, this.options.confirmOrderFormSelector);

DomAccess.querySelector(this.confirmOrderForm, this.options.confirmOrderButtonSelector).classList.add('d-none');

return paypal.Buttons(this.getButtonConfig()).render(this.el);
}


/**
* @return {Object}
*/
getScriptOptions() {
return {
components: 'buttons,messages',
'client-id': this.options.clientId,
commit: !!this.options.commit,
locale: this.options.languageIso,
currency: this.options.currency,
intent: this.options.intent,
'enable-funding': 'paylater,venmo',
'merchant-id': this.options.merchantPayerId,
};
}

getButtonConfig() {
return {
style: {
size: 'small',
shape: 'rect',
color: 'gold',
label: 'pay',
},

/**
* Will be called if when the payment process starts
*/
createOrder: this.createOrder.bind(this),

/**
* Will be called if the payment process is approved by paypal
*/
onApprove: this.onApprove.bind(this),

/**
* Check form validity & show loading spinner on confirm click
*/
onClick: this.onClick.bind(this),

/**
* Will be called if an error occurs during the payment process.
*/
onError: this.onError.bind(this),
};
}

/**
* @return {Promise}
*/
async createOrder() {
if (!this.confirmOrderForm.checkValidity()) {
throw new Error('Checkout form not valid');
}

const data = {
formData: FormSerializeUtil.serializeJson(this.confirmOrderForm),
cart: this.options.cart,
salesChannelContext: this.options.salesChannelContext,
orderId: this.options.orderId,
}

const response = await this._client.post(
`${BASE_URL}order/`,
{
body: JSON.stringify(data),
}
).then((response) => response.json());

return response.orderId;
}

onApprove(data) {
PageLoadingIndicatorUtil.create();

const input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'paypalOrderId');
input.setAttribute('value', data.orderID);

this.confirmOrderForm.appendChild(input);
this.confirmOrderForm.submit();
}

onClick(data, actions) {
if (!this.confirmOrderForm.checkValidity()) {
return actions.reject();
}

return actions.resolve();
}

onError(error) {
console.error(error);
window.location.reload();
}

async fetchClientConfig() {
const response = await this._client.get(`${BASE_URL}config/`);

this.options = {
...this.options,
...await response.json(),
};
}
}
7 changes: 7 additions & 0 deletions bundle/Resources/app/storefront/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Register them via the existing PluginManager
const PluginManager = window.PluginManager;
PluginManager.register(
'SwagPaypalAppWallet',
() => import('./checkout/swag-paypal-app.wallet'),
'[data-swag-paypal-app-wallet]',
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% sw_extends '@Storefront/storefront/page/checkout/confirm/index.html.twig' %}

{% block page_checkout_confirm_form_submit %}
{{ parent() }}

{% block page_checkout_confirm_form_submit_paypal_app_spb %}

{% if (context.paymentMethod.technicalName === 'payment_SCDPayPalApp_paypal') and page.order is not defined %}
<div data-swag-paypal-app-wallet="true"
data-swag-paypal-app-wallet-options="{{ {
currency: context.currency.isoCode,
cart: page.cart,
salesChannelContext: context,
}|json_encode }}">
</div>
{% endif %}

{% endblock %}
{% endblock %}
14 changes: 10 additions & 4 deletions bundle/manifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
<name>SCDPayPalApp</name>
<label>PayPal App</label>
<label lang="de-DE">PayPal App</label>
<description/>
<description lang="de-DE"/>
<author>shopware AG</author>
<copyright>(c) by shopware AG</copyright>
<version>0.0.2</version>
<icon>Resources/config/plugin.png</icon>
<version>0.0.3</version>
<license>MIT</license>
</meta>
<setup>
<registrationUrl>http://localhost:8080/lifecycle/register</registrationUrl>
<secret>devsecret</secret>
</setup>
<permissions>
<read>sales_channel</read>
<read>customer</read>
<read>currency</read>
<read>country</read>
<read>language</read>
<read>payment_method</read>
<read>shipping_method</read>
</permissions>
<webhooks>
<webhook name="appActivated" url="http://localhost:8080/lifecycle/activate" event="app.activated"/>
<webhook name="appDeactivated" url="http://localhost:8080/lifecycle/deactivate" event="app.deactivated"/>
Expand Down
14 changes: 14 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/doctrine-migrations-bundle": "^3.3",
"nelmio/cors-bundle": "^2.3",
"shopware/app-bundle": "^2.0",
"symfony/console": "7.0.*",
"symfony/dotenv": "7.0.*",
Expand All @@ -28,6 +29,15 @@
},
"sort-packages": true
},
"repositories": [
{
"type": "path",
"url": "../app*",
"options": {
"symlink": true
}
}
],
"autoload": {
"psr-4": {
"Swag\\PayPalApp\\": "src/"
Expand Down Expand Up @@ -68,5 +78,9 @@
"allow-contrib": false,
"require": "7.0.*"
}
},
"require-dev": {
"symfony/debug-bundle": "7.0.*",
"symfony/web-profiler-bundle": "7.0.*"
}
}
Loading

0 comments on commit 10b96dc

Please sign in to comment.