From e17e948dcac6b1546949617af769f9be049181a3 Mon Sep 17 00:00:00 2001 From: Isa Herico Velasco <7840857+iisa@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:35:55 -0800 Subject: [PATCH 01/10] receipts view --- demo/index.html | 51 +++++++++++++++++++ src/monthly-giving-circle.ts | 61 ++++++++++++++++++++++- src/presentational/button-style.ts | 74 ++++++++++++++++++++++++++++ src/presentational/mgc-title.ts | 5 +- src/receipts.ts | 78 ++++++++++++++++++++++++++++++ test/monthly-giving-circle.test.ts | 10 ++++ 6 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 src/presentational/button-style.ts create mode 100644 src/receipts.ts diff --git a/demo/index.html b/demo/index.html index 5fd6b5b..1c280fa 100644 --- a/demo/index.html +++ b/demo/index.html @@ -37,6 +37,7 @@
+
@@ -45,6 +46,56 @@ + diff --git a/src/monthly-giving-circle.ts b/src/monthly-giving-circle.ts index 21ad3ee..103edf6 100644 --- a/src/monthly-giving-circle.ts +++ b/src/monthly-giving-circle.ts @@ -1,22 +1,79 @@ /* eslint-disable no-debugger */ -import { LitElement, html } from 'lit'; +import { LitElement, html, TemplateResult, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import './welcome-message'; import './presentational/mgc-title'; +import './receipts'; +import './presentational/button-style'; @customElement('iaux-monthly-giving-circle') export class MonthlyGivingCircle extends LitElement { @property({ type: String }) patronName: string = ''; + @property({ type: Array }) receipts = []; + + @property({ type: String }) viewToDisplay: 'welcome' | 'receipts' = 'welcome'; + protected createRenderRoot() { return this; } + get showReceiptsCTA(): TemplateResult { + return html` + + + + `; + } + protected render() { + console.log('***', this.viewToDisplay, this.receipts); + if (this.viewToDisplay === 'receipts') { + return html` + + Recent donations + + + + + + + { + console.log('EmailReceiptRequest', event.detail); + alert(`Email receipt: ${JSON.stringify(event.detail.donation)}`); + }} + > + `; + } + return html` - + + Monthly Giving Circle + ${this.receipts.length ? this.showReceiptsCTA : nothing} + `; } diff --git a/src/presentational/button-style.ts b/src/presentational/button-style.ts new file mode 100644 index 0000000..c2dff98 --- /dev/null +++ b/src/presentational/button-style.ts @@ -0,0 +1,74 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +import '@internetarchive/icon-donate/icon-donate.js'; + +@customElement('iaux-button-style') +export class MonthlyGivingCircle extends LitElement { + @property({ type: String }) styleType: 'primary' | 'danger' | 'text' = + 'primary'; + + render() { + return html``; + } + + static styles = css` + ::slotted(button) { + height: 30px; + border: none; + cursor: pointer; + color: #fff; + line-height: normal; + border-radius: 0.4rem; + text-align: center; + vertical-align: middle; + /* font-size: 1rem; */ + display: inline-block; + padding: 0.6rem 1.2rem; + border: 1px solid transparent; + + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + } + + ::slotted(button:disabled), + ::slotted(button.disabled) { + cursor: not-allowed; + opacity: 0.5; + } + + ::slotted(button).transparent { + background-color: transparent; + } + + ::slotted(button).slim { + padding: 0; + } + + ::slotted(button.primary) { + background-color: #194880; + border-color: #c5d1df; + } + + ::slotted(button.secondary) { + background: #333; + } + + ::slotted(button.cancel) { + background-color: #e51c26; + border-color: #f8c6c8; + } + + ::slotted(button.link) { + color: #4b64ff; + border: none; + background: transparent; + display: flex; + align-items: flex-end; + } + `; +} diff --git a/src/presentational/mgc-title.ts b/src/presentational/mgc-title.ts index 8ad170e..7c83302 100644 --- a/src/presentational/mgc-title.ts +++ b/src/presentational/mgc-title.ts @@ -9,10 +9,7 @@ export class MonthlyGivingCircle extends LitElement { get heart(): TemplateResult | typeof nothing { return this.titleStyle === 'heart' - ? html` -
- Monthly Giving Circle - ` + ? html`
` : nothing; } diff --git a/src/receipts.ts b/src/receipts.ts new file mode 100644 index 0000000..601df5f --- /dev/null +++ b/src/receipts.ts @@ -0,0 +1,78 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +import './presentational/button-style'; + +type donation = { + status: string; + amount: number; + date: string; + id: string; +}; + +@customElement('iaux-mgc-receipts') +export class MGCWelcome extends LitElement { + @property({ type: Array }) donations = []; + + donationAmountFormatted(amount: number) { + return `USD ${amount}`; + } + + emailReceipt(donation: donation) { + this.dispatchEvent( + new CustomEvent('EmailReceiptRequest', { + detail: { + donation, + }, + }) + ); + } + + protected render() { + return html` +
+ + + + + + + + ${this.donations.length + ? this.donations.map((donation: donation) => { + const emailUnavailable = donation.status === 'pending'; + return html` + + + + + + + `; + }) + : html`

No recent donations found

`} +
DonorAmountStatusAction
${donation.date}${this.donationAmountFormatted(donation.amount)}${donation.status} + + + +
+
+ `; + } + + static styles = css` + table { + width: 100%; + text-align: left; + } + `; +} diff --git a/test/monthly-giving-circle.test.ts b/test/monthly-giving-circle.test.ts index cc605f0..19d43df 100644 --- a/test/monthly-giving-circle.test.ts +++ b/test/monthly-giving-circle.test.ts @@ -14,4 +14,14 @@ describe('IauxMonthlyGivingCircle', () => { // eslint-disable-next-line no-unused-expressions expect(el.querySelector('iaux-mgc-welcome')).to.not.be.null; }); + + it('displays receipt button when receipts are available', async () => { + const el = await fixture( + html`` + ); + + expect(el.querySelector('iaux-mgc-welcome')).to.not.be.null; + }); }); From 66e8fe8f7a2da396d66f489ef084ae38aa7659d2 Mon Sep 17 00:00:00 2001 From: Isa Herico Velasco <7840857+iisa@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:00:20 -0800 Subject: [PATCH 02/10] format date & view --- demo/index.html | 50 ++++++++++++++++-------------- src/monthly-giving-circle.ts | 6 +++- src/presentational/button-style.ts | 1 + src/presentational/mgc-title.ts | 5 +++ src/receipts.ts | 32 ++++++++++++++++++- 5 files changed, 69 insertions(+), 25 deletions(-) diff --git a/demo/index.html b/demo/index.html index 1c280fa..1499b5d 100644 --- a/demo/index.html +++ b/demo/index.html @@ -47,18 +47,7 @@ From fc5c59d000ef894ccf6d3054b30a3eb510361205 Mon Sep 17 00:00:00 2001 From: Isa Herico Velasco <7840857+iisa@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:43:41 -0800 Subject: [PATCH 09/10] v0.0.0-receipts5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index beca5ac..d0bd806 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@internetarchive/donation-monthly-portal", - "version": "0.0.0-receipts4", + "version": "0.0.0-receipts5", "description": "The Internet Archive Monthly Portal", "license": "AGPL-3.0-only", "main": "dist/index.js", From 352c005ed11c021e1ab7398149d84b7c3beaf866 Mon Sep 17 00:00:00 2001 From: Isa Herico Velasco <7840857+iisa@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:39:50 -0800 Subject: [PATCH 10/10] start summary-view --- demo/data-recent-donations.json | 11 --- demo/index.html | 75 +++++++++++++++++ package-lock.json | 14 +++- package.json | 1 + src/models/subscription-summary.ts | 62 ++++++++++++++ src/monthly-giving-circle.ts | 18 +++- src/plans.ts | 129 +++++++++++++++++++++++++++++ 7 files changed, 295 insertions(+), 15 deletions(-) delete mode 100644 demo/data-recent-donations.json create mode 100644 src/models/subscription-summary.ts create mode 100644 src/plans.ts diff --git a/demo/data-recent-donations.json b/demo/data-recent-donations.json deleted file mode 100644 index fe83524..0000000 --- a/demo/data-recent-donations.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "success": true, - "value": { - 'donation1': { - id: 1, - amount: 100 - - } - - } -} diff --git a/demo/index.html b/demo/index.html index 6a7d560..8dbd069 100644 --- a/demo/index.html +++ b/demo/index.html @@ -39,6 +39,7 @@
+
@@ -57,6 +58,76 @@ diff --git a/package-lock.json b/package-lock.json index e81bb58..66045b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "@internetarchive/donation-monthly-portal", - "version": "1.0.0", + "version": "0.0.0-receipts5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@internetarchive/donation-monthly-portal", - "version": "1.0.0", + "version": "0.0.0-receipts5", "license": "AGPL-3.0-only", "dependencies": { + "@internetarchive/iaux-notification-toast": "^0.0.0-alpha2", "@internetarchive/icon-donate": "^1.3.4", "lit": "^2.8.0" }, @@ -913,6 +914,15 @@ "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@internetarchive/iaux-notification-toast": { + "version": "0.0.0-alpha2", + "resolved": "https://registry.npmjs.org/@internetarchive/iaux-notification-toast/-/iaux-notification-toast-0.0.0-alpha2.tgz", + "integrity": "sha512-0wbHkP6xJmYE6uIreA0I2hMxC0aHOJzUjW+pFToXbBi8KzhNYvMucBL1jtMpV9HcXq7UsoS2wc0MHFc6lzcCJw==", + "license": "AGPL-3.0-only", + "dependencies": { + "lit": "^2.6.0" + } + }, "node_modules/@internetarchive/icon-donate": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/@internetarchive/icon-donate/-/icon-donate-1.3.4.tgz", diff --git a/package.json b/package.json index d0bd806..e41ae4a 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "ghpages:generate": "gh-pages -t -d ghpages -m \"Build for $(git log --pretty=format:\"%h %an %ai %s\" -n1) [skip ci]\"" }, "dependencies": { + "@internetarchive/iaux-notification-toast": "^0.0.0-alpha2", "@internetarchive/icon-donate": "^1.3.4", "lit": "^2.8.0" }, diff --git a/src/models/subscription-summary.ts b/src/models/subscription-summary.ts new file mode 100644 index 0000000..ab6c442 --- /dev/null +++ b/src/models/subscription-summary.ts @@ -0,0 +1,62 @@ +type BtNextBillingDate = { + date: string; + timezone_type: number; + timezone: string; +}; + +type BtData = { + billingDayOfMonth: number; + nextBillingDate: BtNextBillingDate; + status: string; // active, inactive + paymentMethodType: string; // cc, paypal, venmo, etc + last4: string | null; + cardType: string | null; + expirationMonth: string | null; + expirationYear: string | null; + paypalEmail?: string; + venmoUsername?: string; +}; + +type aSummary = { + id: string; + token: string; + amount: number; + start_date: string; + contribution_status_id: number; + is_test: boolean; + btdata: BtData; + oldAmount?: number; + oldDate?: string; + oldPaymentMethod?: string; + isCancelled?: boolean; +}; +export default class SubscriptionSummary { + summary: aSummary; + + currencyType: string; + + payment: BtData; + + constructor(summary: aSummary) { + this.summary = summary; + this.payment = summary.btdata; + this.currencyType = 'USD'; // not in data + } + + get id(): string { + // use token as unique id + return this.summary.token; + } + + get amount(): number { + return this.summary.amount; + } + + get startDate(): string { + return this.summary.start_date; + } + + get isTest(): boolean { + return this.summary.is_test; + } +} diff --git a/src/monthly-giving-circle.ts b/src/monthly-giving-circle.ts index 65183ce..ae4f20a 100644 --- a/src/monthly-giving-circle.ts +++ b/src/monthly-giving-circle.ts @@ -4,8 +4,9 @@ import { LitElement, html, TemplateResult, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import './welcome-message'; -import './presentational/mgc-title'; import './receipts'; +import './plans'; +import './presentational/mgc-title'; import './presentational/button-style'; import './presentational/update-queue'; @@ -17,6 +18,8 @@ export class MonthlyGivingCircle extends LitElement { @property({ type: Array }) updates = []; + @property({ type: Array }) plans = []; + @property({ type: String }) viewToDisplay: 'welcome' | 'receipts' = 'welcome'; protected createRenderRoot() { @@ -63,7 +66,6 @@ export class MonthlyGivingCircle extends LitElement { { - console.log('EmailReceiptRequest', event.detail); this.dispatchEvent( new CustomEvent('EmailReceiptRequest', { detail: { ...event.detail }, @@ -74,6 +76,18 @@ export class MonthlyGivingCircle extends LitElement { `; } + if (this.plans.length) { + return html` + + Monthly Giving Circle + ${this.receipts.length ? this.showReceiptsCTA : nothing} + + + `; + } + return html` Monthly Giving Circle diff --git a/src/plans.ts b/src/plans.ts new file mode 100644 index 0000000..9a899aa --- /dev/null +++ b/src/plans.ts @@ -0,0 +1,129 @@ +import { LitElement, html, css, nothing } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +import './presentational/button-style'; +import type SubscriptionSummary from './models/subscription-summary'; + +// type donation = { +// status: string; +// amount: number; +// date: string; +// id: string; +// }; + +@customElement('iaux-mgc-plans') +export class MGCPlans extends LitElement { + @property({ type: Array }) plans = []; + + donationAmountFormatted(amount: number) { + return `USD ${amount}`; + } + + dateFormatted(date: string) { + const splitDate = date.split('-'); + const year = splitDate[0]; + const month = parseInt(splitDate[1], 10); + const day = splitDate[2]; + + const monthMap: { [key: number]: string } = { + 1: 'January', + 2: 'February', + 3: 'March', + 4: 'April', + 5: 'May', + 6: 'June', + 7: 'July', + 8: 'August', + 9: 'September', + 10: 'October', + 11: 'November', + 12: 'December', + }; + + const displayMonth = monthMap[month]; + return `${displayMonth} ${day}, ${year}`; + } + + protected render() { + return html` +
+
    + ${this.plans.map((plan: SubscriptionSummary) => { + const methodType = + plan.payment.paymentMethodType ?? 'Method not found'; + const cardType = plan.payment.cardType ?? 'Card type not found'; + const last4 = plan.payment.last4 + ? `...${plan.payment.last4}` + : 'CC number not found'; + const nextBillingDate = plan.payment.nextBillingDate ?? ''; + console.log(' ******** '); + console.log('plan: ', plan); + return html` +
  • +
    +
    +

    Amount

    +

    ${plan.currencyType} ${plan.amount}/month

    + ${plan.isTest ? html`

    (Test payment)

    ` : nothing} +
    +
    +

    Method

    +

    ${methodType}

    + ${plan.payment.cardType === 'creditCard' + ? html`

    ${cardType}

    +

    ${last4}

    ` + : nothing} + ${plan.payment.paymentMethodType === 'Paypal' + ? html`

    + Paypal email: + ${plan.payment.paypalEmail} +

    ` + : nothing} + ${plan.payment.paymentMethodType === 'Venmo' + ? html`

    + Venmo username: + ${plan.payment.paypalEmail} +

    ` + : nothing} +

    + Expires: + ${plan.payment.expirationMonth ?? + 'month not found'}/${plan.payment.expirationYear ?? + 'year not found'} +

    +
    +
    +

    Next Donation

    +

    + ${nextBillingDate + ? html`${nextBillingDate}` + : 'not found'} +

    +
    +
    + +
  • + `; + })} +
+
+ `; + } + + static styles = css` + table { + width: 100%; + text-align: left; + max-width: 600px; + } + `; +}