diff options
| author | Joe Carstairs <118172583+jcarstairs-scottlogic@users.noreply.github.com> | 2024-01-25 16:59:42 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-25 16:59:42 +0000 |
| commit | 1a6eb7e2ff0bf551e1560c67170e90fa8ec2a8ea (patch) | |
| tree | 53f73dcca5693e656d50fac965955560a513a233 /src/components | |
| parent | 83c3460191a2089b56b091a7f4e09f39ac636e1e (diff) | |
33 / Pay annual subscription by PayPal (#68)
* Refactors paypal-buttons -> paypal-product-buttons WebComponent
* Pulls out address to data file
* Defines annual subscription prices data hash
* Styles paypal-product-buttons
* Styles <address>
* Details have cursor:pointer on the summary
* Moves Jyne section to separate page
* Rewrites payment options using details components
* Reworks translation typing
* Defines MembershipType enum
* Adds translations for MembershipType enum
* Can pay annual subs by PayPal
* Styles tables better
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/LallansIssue.astro | 4 | ||||
| -rw-r--r-- | src/components/Navbar/NavLinks.astro | 3 | ||||
| -rw-r--r-- | src/components/PayPalButtons.astro | 150 | ||||
| -rw-r--r-- | src/components/PaypalProductButtons.astro | 26 | ||||
| -rw-r--r-- | src/components/Scotsoun.astro | 4 |
5 files changed, 32 insertions, 155 deletions
diff --git a/src/components/LallansIssue.astro b/src/components/LallansIssue.astro index c8bc6eb..317ff2d 100644 --- a/src/components/LallansIssue.astro +++ b/src/components/LallansIssue.astro @@ -7,7 +7,7 @@ import type LallansIssue from '$types/LallansIssue'; import { Image } from 'astro:assets'; import LallansIssueContributions from './LallansIssueContributions.astro'; import LallansIssueContributors from './LallansIssueContributors.astro'; -import PayPalButtons from './PayPalButtons.astro'; +import PaypalProductButtons from './PaypalProductButtons.astro'; interface Props { issue: LallansIssue; @@ -27,7 +27,7 @@ const t = translate(locale); <div class="product__action-block"> <Image alt="" src={issue.img.width274} /> - <PayPalButtons + <PaypalProductButtons successPageUrl={relativePath(Astro.url.pathname, `payment-success-confirmation`)} productDescription={`Lallans ${issue.issueNumber} | ${issue.issueName}`} shortDescription={`Lallans ${issue.issueNumber}`} diff --git a/src/components/Navbar/NavLinks.astro b/src/components/Navbar/NavLinks.astro index 798c24e..36c7f6f 100644 --- a/src/components/Navbar/NavLinks.astro +++ b/src/components/Navbar/NavLinks.astro @@ -4,6 +4,7 @@ import translate from '$i18n/translate'; import tNews from '$i18n/translations/pages/news'; import tFurthsettins from '$i18n/translations/pages/furthsettins'; import tHame from '$i18n/translations/pages/home'; +import tJyne from '$i18n/translations/pages/jyne'; const locale = getLocaleFromPathOrDefault(Astro.url.pathname); const t = translate(locale); @@ -20,7 +21,7 @@ const t = translate(locale); <a class="btn" href={`/${locale}/furthsettins`}>{t(tFurthsettins, { key: 'title' })}</a> </li> <li> - <a class="btn" href={`/${locale}/#jyne`}>{t(tHame, { key: 'jyne' })}</a> + <a class="btn" href={`/${locale}/jyne`}>{t(tJyne, { key: 'title' })}</a> </li> <li> <a class="btn" href={`/${locale}/#contact`}>{t(tHame, { key: 'contact' })}</a> diff --git a/src/components/PayPalButtons.astro b/src/components/PayPalButtons.astro deleted file mode 100644 index cdea5cb..0000000 --- a/src/components/PayPalButtons.astro +++ /dev/null @@ -1,150 +0,0 @@ ---- -import env from '$lib/env'; -import type Price from '$types/Price'; - -interface Props { - successPageUrl: string; - productDescription: string; - shortDescription: string; - totalPrice: Price; -} - -const { successPageUrl, productDescription, shortDescription, totalPrice } = Astro.props; - -const PAYPAL_CLIENT_ID = - env.ENVIRONMENT === 'prod' ? env.PAYPAL_LIVE_CLIENT_ID : env.PAYPAL_SANDBOX_CLIENT_ID; ---- - -<paypal-buttons - data-paypal-client-id={PAYPAL_CLIENT_ID} - data-success-page-url={successPageUrl} - data-product-description={productDescription} - data-short-description={shortDescription} - data-total-price={totalPrice} -> - <div id="paypal-button-container"></div> -</paypal-buttons> - -<script> - import { PayPalNamespace, loadScript } from '@paypal/paypal-js'; - - const backendUrl = '/api'; - - class PayPalButtons extends HTMLElement { - constructor() { - super(); - - const paypalClientId = this.getStringDataAttribute('paypalClientId'); - - const paypalOptions = { - clientId: paypalClientId, - locale: 'en_GB', - commit: false, - currency: 'GBP', - intent: 'capture', - }; - - loadScript(paypalOptions) - .catch((err) => { - throw new Error('Failed to load the PayPal JS SDK script. ', err); - }) - .then((paypal) => { - const constructButtons = paypal?.Buttons; - if (paypal && constructButtons) { - const successPageUrl = this.dataset['successPageUrl'] ?? '.'; - this.makePaypalButtons(constructButtons, successPageUrl).render( - '#paypal-button-container' - ); - } - }); - } - - makePaypalButtons( - constructButtons: Required<PayPalNamespace>['Buttons'], - successPageUrl: string - ) { - const productDescription = this.getStringDataAttribute('productDescription'); - const shortDescription = this.getStringDataAttribute('shortDescription'); - const totalPrice = this.getStringDataAttribute('totalPrice'); - - return constructButtons({ - // This function is called to set up the transaction details without actually carrying it out - async createOrder() { - const body = JSON.stringify({ - productDescription, - shortDescription, - totalPrice, - }); - const headers = { - 'Content-Type': 'application/json', - }; - - let response; - try { - response = await fetch(`${backendUrl}/order`, { method: 'POST', body, headers }); - } catch (err) { - throw new Error(`Failed to create order. ${err}`); - } - - if (!response.ok) { - throw new Error(` - Failed to create order. Backend response was - ${response.status} ${response.statusText}. ${await response.text()} - `); - } - - const { orderId, approvalLink } = await response.json(); - console.info(` - Successfully created order with ID - ${orderId}. Approval link: ${approvalLink} - `); - return orderId; - }, - - // This function is called after payment is confirmed - async onApprove(data) { - const body = JSON.stringify({ - id: data.orderID, - isApproved: true, - }); - const headers = { - 'Content-Type': 'application/json', - }; - - let response; - try { - response = await fetch(`${backendUrl}/order`, { method: 'PATCH', body, headers }); - } catch (err) { - throw new Error(`Failed to capture order. ${err}`); - } - - if (!response.ok) { - throw new Error(` - Failed to capture order. Backend response was ${response.status} - ${response.statusText}. ${await response.text()} - `); - } - - const { orderId, requestStatus } = await response.json(); - console.info(` - Successfully captured order with ID ${orderId}, - request status is ${requestStatus}. - `); - - console.info('Redirecting to confirmation page...'); - window.location.href = successPageUrl; - }, - }); - } - - getStringDataAttribute(key: string): string { - const value = this.dataset[key]; - if (!value || typeof value !== 'string') { - throw new Error(`data-${key} attribute not provided to PayPalButtons component.`); - } - return value; - } - } - - customElements.define('paypal-buttons', PayPalButtons); -</script> diff --git a/src/components/PaypalProductButtons.astro b/src/components/PaypalProductButtons.astro new file mode 100644 index 0000000..0ebbd3f --- /dev/null +++ b/src/components/PaypalProductButtons.astro @@ -0,0 +1,26 @@ +--- +import env from '$lib/env'; +import type Price from '$types/Price'; + +interface Props { + successPageUrl: string; + productDescription: string; + shortDescription: string; + totalPrice: Price; +} + +const { successPageUrl, productDescription, shortDescription, totalPrice } = Astro.props; + +const PAYPAL_CLIENT_ID = + env.ENVIRONMENT === 'prod' ? env.PAYPAL_LIVE_CLIENT_ID : env.PAYPAL_SANDBOX_CLIENT_ID; +--- + +<paypal-product-buttons + paypal-client-id={PAYPAL_CLIENT_ID} + success-page-url={successPageUrl} + product-description={productDescription} + short-description={shortDescription} + total-price={totalPrice} +> + Loading PayPal buttons… +</paypal-product-buttons> diff --git a/src/components/Scotsoun.astro b/src/components/Scotsoun.astro index cca330d..7acae8b 100644 --- a/src/components/Scotsoun.astro +++ b/src/components/Scotsoun.astro @@ -4,7 +4,7 @@ import translate from '$i18n/translate'; import tSite from '$i18n/translations/site'; import tComponent from '$i18n/translations/components/scotsoun'; import type Scotsoun from '$types/Scotsoun'; -import PayPalButtons from './PayPalButtons.astro'; +import PaypalProductButtons from './PaypalProductButtons.astro'; import relativePath from '$lib/relativePath'; import { getLocaleFromPathOrThrow } from '$lib/getLocaleFromPath'; @@ -27,7 +27,7 @@ const t = translate(locale); </header> <div class="product__action-block"> <Image src={scotsoun.img.width192} alt="" /> - <PayPalButtons + <PaypalProductButtons successPageUrl={relativePath(Astro.url.pathname, `payment-success-confirmation`)} productDescription={`SSCD${scotsoun.scotsounId} | ${scotsoun.longName}`} shortDescription={`SSCD${scotsoun.scotsounId}`} |
