@internetarchive/donation-monthly-portal 0.0.0-editdate.1 → 0.0.0-editdate.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
22
22
  }
23
23
  updated(changed) {
24
24
  if (changed.has('currentlyEditing') && this.currentlyEditing) {
25
- this.form.focus();
25
+ this.dateInput.focus();
26
26
  }
27
27
  }
28
28
  render() {
@@ -35,13 +35,13 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
35
35
  >
36
36
  ${!this.currentlyEditing
37
37
  ? html ` <p class="current-date">
38
- ${(_a = this.plan) === null || _a === void 0 ? void 0 : _a.nextBillingDate}
38
+ ${(_a = this.plan) === null || _a === void 0 ? void 0 : _a.nextBillingDateLocale}
39
39
  <ia-mgc-update-status .status=${this.updateStatus}
40
40
  >${this.updateMessage}</ia-mgc-update-status
41
41
  >
42
42
  </p>
43
43
  <ia-button
44
- id="edit-date"
44
+ id="open-edit-date-form"
45
45
  class="ia-button link"
46
46
  .clickHandler=${() => {
47
47
  this.currentlyEditing = true;
@@ -69,16 +69,12 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
69
69
  await this.updateComplete;
70
70
  return;
71
71
  }
72
- this.form.querySelector('ia-button#edit-date').isDisabled =
73
- false;
72
+ this.allowEditing = false;
74
73
  await this.updateComplete;
75
74
  }
76
75
  /* Dispatches edit-date change request */
77
76
  requestDateUpdate(e) {
78
77
  e.preventDefault();
79
- console.log('<plan-date> - requestDateUpdate', {
80
- newValue: this.newDate,
81
- });
82
78
  this.dispatchEvent(new CustomEvent('updateDate', {
83
79
  detail: {
84
80
  plan: this.plan,
@@ -90,10 +86,10 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
90
86
  this.clearInputField();
91
87
  this.clearStatusMessaging();
92
88
  this.currentlyEditing = false;
89
+ this.allowEditing = false;
93
90
  }
94
91
  clearInputField() {
95
- const input = this.form.querySelector('input[name="edit-date"]');
96
- input.value = '';
92
+ this.dateInput.value = '';
97
93
  this.newDate = undefined;
98
94
  }
99
95
  async clearStatusMessaging() {
@@ -116,26 +112,23 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
116
112
  const today = new Date();
117
113
  const year = today.getFullYear() + 1; // Allow up to one year in the future
118
114
  const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
119
- const lastDayOfMonth = new Date(year, today.getMonth() + 1, 0).getDate();
120
- return `${year}-${month}-${lastDayOfMonth}`; // Last day of the month
115
+ return `${year}-${month}-${today.getDate()}`;
121
116
  }
122
117
  get editDateForm() {
123
- var _a, _b, _c, _d;
124
- console.log('editdate', {
125
- min: this.minDate,
126
- max: this.maxDate,
127
- plan: this.plan,
128
- nextBillingDate: (_a = this.plan) === null || _a === void 0 ? void 0 : _a.nextBillingDate,
129
- lastBillingDate: (_b = this.plan) === null || _b === void 0 ? void 0 : _b.lastBillingDateLocale,
130
- });
118
+ var _a, _b;
131
119
  return html `
132
120
  <section>
133
121
  <form id="edit-date">
134
- <p>Last donation date: ${(_c = this.plan) === null || _c === void 0 ? void 0 : _c.lastBillingDateLocale}</p>
122
+ <p id="form-info-last-donation-date">
123
+ Last donation date: ${(_a = this.plan) === null || _a === void 0 ? void 0 : _a.lastBillingDateLocale}
124
+ </p>
135
125
 
136
- <p>Next donation date: ${(_d = this.plan) === null || _d === void 0 ? void 0 : _d.nextBillingDate}</p>
126
+ <p id="form-info-next-donation-date">
127
+ Next donation date: ${(_b = this.plan) === null || _b === void 0 ? void 0 : _b.nextBillingDateLocale}
128
+ </p>
137
129
  <div class="date-holder">
138
130
  <input
131
+ required
139
132
  type="date"
140
133
  id="edit-date"
141
134
  name="edit-date"
@@ -143,24 +136,22 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
143
136
  max=${this.maxDate}
144
137
  value=""
145
138
  @focus=${() => this.clearStatusMessaging()}
146
- @change=${async (e) => {
147
- var _a, _b, _c, _d, _e;
139
+ @change=${async () => {
140
+ var _a, _b, _c, _d;
148
141
  this.clearStatusMessaging();
149
142
  await this.updateComplete;
150
- console.log('date changed', e.target.value);
151
- console.log('date changed THIS', this);
152
- const inputValue = e.target.value;
143
+ const inputValue = this.dateInput.value;
144
+ console.log(' ----- date input changed ----- ', inputValue, this.errorMessage);
153
145
  if (!inputValue) {
154
146
  this.errorMessage = 'Please enter a date';
155
- this.allowEditing = true;
147
+ this.allowEditing = false;
156
148
  return; // wait until date field returns a valid string
157
149
  }
158
150
  let validDate;
159
151
  try {
160
- validDate = new Date((_a = e.target) === null || _a === void 0 ? void 0 : _a.value);
152
+ validDate = new Date(`${inputValue}T00:00:00`);
161
153
  }
162
154
  catch (error) {
163
- console.error('Invalid date format:', error);
164
155
  this.errorMessage =
165
156
  'Please enter a valid date format (YYYY-MM-DD)';
166
157
  return; // wait until date field returns a valid string
@@ -178,16 +169,13 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
178
169
  this.allowEditing = false;
179
170
  return;
180
171
  }
181
- console.log('validDate', validDate);
182
172
  const newDate = new Date(validDate).toISOString();
183
173
  this.newDate = newDate;
184
- console.log('newDate', newDate);
185
- // Check if the date is in the past
186
174
  // Check if there has been a donation in the last month
187
- const hasLastDonationInfo = ((_b = this.plan) === null || _b === void 0 ? void 0 : _b.payment.lastBillingDate.date) &&
188
- new Date((_c = this.plan) === null || _c === void 0 ? void 0 : _c.payment.lastBillingDate.date);
175
+ const hasLastDonationInfo = ((_a = this.plan) === null || _a === void 0 ? void 0 : _a.payment.lastBillingDate.date) &&
176
+ new Date((_b = this.plan) === null || _b === void 0 ? void 0 : _b.payment.lastBillingDate.date);
189
177
  if (hasLastDonationInfo) {
190
- const lastDonationDate = new Date((_e = (_d = this.plan) === null || _d === void 0 ? void 0 : _d.payment.lastBillingDate.date) !== null && _e !== void 0 ? _e : '');
178
+ const lastDonationDate = new Date((_d = (_c = this.plan) === null || _c === void 0 ? void 0 : _c.payment.lastBillingDate.date) !== null && _d !== void 0 ? _d : '');
191
179
  const lastDonationMonth = lastDonationDate.getMonth();
192
180
  const lastDonationYear = lastDonationDate.getFullYear();
193
181
  const thisYear = validDate.getFullYear();
@@ -196,13 +184,21 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
196
184
  thisMonth === lastDonationMonth;
197
185
  if (isInLastMonth) {
198
186
  this.warningMessage =
199
- 'You have already made a donation this month. Is that cool with you?';
187
+ 'New donation date is in the same month as your last payment.';
200
188
  this.allowEditing = true;
201
189
  return;
202
190
  }
203
191
  }
204
- // Check if there has been a donation in the last 30 days
205
- console.log('newDate', newDate);
192
+ // Check if the new date is within the next 12 months
193
+ const twelveMonthsFromNow = new Date();
194
+ twelveMonthsFromNow.setFullYear(twelveMonthsFromNow.getFullYear() + 1);
195
+ twelveMonthsFromNow.setHours(0, 0, 0, 0);
196
+ if (chosenDate > twelveMonthsFromNow) {
197
+ this.errorMessage =
198
+ 'New donation date must be within the next 12 months.';
199
+ this.allowEditing = false;
200
+ return;
201
+ }
206
202
  this.allowEditing = true;
207
203
  }}
208
204
  />
@@ -232,7 +228,6 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
232
228
  // eslint-disable-next-line no-param-reassign
233
229
  iaButton.isDisabled = true;
234
230
  await iaButton.updateComplete;
235
- // check if request is in range
236
231
  this.requestDateUpdate(e);
237
232
  }}
238
233
  >
@@ -243,8 +238,8 @@ let MGCEditPlanDate = class MGCEditPlanDate extends LitElement {
243
238
  >
244
239
  </div>
245
240
  </div>
246
- <p class="error">${this.warningMessage}</p>
247
- <p class="error">${this.errorMessage}</p>
241
+ <p class="error warning-msg">${this.warningMessage}</p>
242
+ <p class="error error-msg">${this.errorMessage}</p>
248
243
  </form>
249
244
  </section>
250
245
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"date.js","sourceRoot":"","sources":["../../../src/form-sections/date.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n LitElement,\n html,\n PropertyValues,\n nothing,\n css,\n TemplateResult,\n} from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport '@internetarchive/donation-form-section';\n\nimport type { MonthlyPlan } from '../models/plan';\nimport '../presentational/ia-button';\nimport type { IauxButton } from '../presentational/ia-button';\nimport '../presentational/mgc-update-status';\n\n@customElement('ia-mgc-edit-date')\nexport class MGCEditPlanDate extends LitElement {\n @property({ type: Object }) plan?: MonthlyPlan;\n\n @property({ type: String }) newDate?: string;\n\n @property({ type: Boolean, reflect: true }) currentlyEditing: boolean = false;\n\n @property({ type: Boolean }) allowEditing: boolean = false;\n\n @property({ type: String }) updateMessage: string = '';\n\n @property({ type: String }) errorMessage: string = '';\n\n @property({ type: String }) warningMessage: string = '';\n\n @property({ type: String }) updateStatus: 'success' | 'fail' | '' = '';\n\n @query('form') form!: HTMLFormElement;\n\n @query('form ia-button#edit-date') formSubmitButton!: IauxButton;\n\n @query('form input[name=\"edit-date\"]')\n dateInput!: HTMLInputElement;\n\n willUpdate(changed: PropertyValues) {\n if (this.dateInput && changed.has('plan') && this.plan) {\n this.dateInput.setAttribute('min', this.minDate);\n this.dateInput.setAttribute('max', this.maxDate);\n }\n }\n\n updated(changed: PropertyValues) {\n if (changed.has('currentlyEditing') && this.currentlyEditing) {\n this.form.focus();\n }\n }\n\n protected render() {\n return html`\n <section>\n <donation-form-section\n badgemode=\"hidebadge\"\n headline=\"Change next donation date\"\n >\n ${!this.currentlyEditing\n ? html` <p class=\"current-date\">\n ${this.plan?.nextBillingDate}\n <ia-mgc-update-status .status=${this.updateStatus}\n >${this.updateMessage}</ia-mgc-update-status\n >\n </p>\n <ia-button\n id=\"edit-date\"\n class=\"ia-button link\"\n .clickHandler=${() => {\n this.currentlyEditing = true;\n this.clearStatusMessaging();\n }}\n >\n Edit...\n </ia-button>`\n : nothing}\n ${this.currentlyEditing ? this.editDateForm : nothing}\n </donation-form-section>\n </section>\n `;\n }\n\n /* External Function that is called by consumer to tell the form there has been data update */\n async dateUpdated(status: 'success' | 'fail') {\n this.clearInputField();\n\n this.updateStatus = status;\n this.updateMessage =\n status === 'success'\n ? 'Date updated'\n : 'Failed to update date, please try again';\n\n if (status === 'success') {\n this.closeForm();\n await this.updateComplete;\n return;\n }\n\n (this.form.querySelector('ia-button#edit-date') as IauxButton).isDisabled =\n false;\n\n await this.updateComplete;\n }\n\n /* Dispatches edit-date change request */\n requestDateUpdate(e: Event): void {\n e.preventDefault();\n console.log('<plan-date> - requestDateUpdate', {\n newValue: this.newDate,\n });\n this.dispatchEvent(\n new CustomEvent('updateDate', {\n detail: {\n plan: this.plan,\n newDate: this.newDate,\n },\n })\n );\n }\n\n closeForm() {\n this.clearInputField();\n this.clearStatusMessaging();\n this.currentlyEditing = false;\n }\n\n clearInputField() {\n const input = this.form.querySelector(\n 'input[name=\"edit-date\"]'\n ) as HTMLInputElement;\n input.value = '';\n this.newDate = undefined;\n }\n\n async clearStatusMessaging() {\n this.errorMessage = '';\n this.warningMessage = '';\n this.updateMessage = '';\n this.updateStatus = '';\n await this.updateComplete;\n }\n\n /* DISPLAY */\n get minDate(): string {\n const today = new Date();\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1); // Set to tomorrow\n const year = tomorrow.getFullYear();\n const month = String(tomorrow.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed\n return `${year}-${month}-${tomorrow.getDate()}`;\n }\n\n get maxDate(): string {\n const today = new Date();\n const year = today.getFullYear() + 1; // Allow up to one year in the future\n const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed\n const lastDayOfMonth = new Date(year, today.getMonth() + 1, 0).getDate();\n return `${year}-${month}-${lastDayOfMonth}`; // Last day of the month\n }\n\n get editDateForm(): TemplateResult {\n console.log('editdate', {\n min: this.minDate,\n max: this.maxDate,\n plan: this.plan,\n nextBillingDate: this.plan?.nextBillingDate,\n lastBillingDate: this.plan?.lastBillingDateLocale,\n });\n return html`\n <section>\n <form id=\"edit-date\">\n <p>Last donation date: ${this.plan?.lastBillingDateLocale}</p>\n\n <p>Next donation date: ${this.plan?.nextBillingDate}</p>\n <div class=\"date-holder\">\n <input\n type=\"date\"\n id=\"edit-date\"\n name=\"edit-date\"\n min=${this.minDate}\n max=${this.maxDate}\n value=\"\"\n @focus=${() => this.clearStatusMessaging()}\n @change=${async (e: Event) => {\n this.clearStatusMessaging();\n await this.updateComplete;\n\n console.log(\n 'date changed',\n (e.target as HTMLInputElement).value\n );\n console.log('date changed THIS', this);\n\n const inputValue = (e.target as HTMLInputElement).value;\n if (!inputValue) {\n this.errorMessage = 'Please enter a date';\n this.allowEditing = true;\n return; // wait until date field returns a valid string\n }\n\n let validDate;\n try {\n validDate = new Date(\n (e.target as HTMLInputElement)?.value as string\n );\n } catch (error) {\n console.error('Invalid date format:', error);\n this.errorMessage =\n 'Please enter a valid date format (YYYY-MM-DD)';\n return; // wait until date field returns a valid string\n }\n\n // Check if minimum date is at least tomorrow\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1); // Set to tomorrow\n tomorrow.setHours(0, 0, 0, 0);\n const chosenDate = new Date(validDate);\n chosenDate.setHours(0, 0, 0, 0);\n if (chosenDate < today) {\n this.errorMessage = 'Date must be at least tomorrow.';\n this.allowEditing = false;\n return;\n }\n\n console.log('validDate', validDate);\n\n const newDate = new Date(validDate).toISOString();\n this.newDate = newDate;\n console.log('newDate', newDate);\n\n // Check if the date is in the past\n\n // Check if there has been a donation in the last month\n\n const hasLastDonationInfo =\n this.plan?.payment.lastBillingDate.date &&\n new Date(this.plan?.payment.lastBillingDate.date);\n\n if (hasLastDonationInfo) {\n const lastDonationDate = new Date(\n this.plan?.payment.lastBillingDate.date ?? ''\n );\n const lastDonationMonth = lastDonationDate.getMonth();\n const lastDonationYear = lastDonationDate.getFullYear();\n\n const thisYear = validDate.getFullYear();\n const thisMonth = validDate.getMonth();\n const isInLastMonth =\n thisYear === lastDonationYear &&\n thisMonth === lastDonationMonth;\n\n if (isInLastMonth) {\n this.warningMessage =\n 'You have already made a donation this month. Is that cool with you?';\n this.allowEditing = true;\n return;\n }\n }\n // Check if there has been a donation in the last 30 days\n console.log('newDate', newDate);\n\n this.allowEditing = true;\n }}\n />\n </div>\n <div>\n <div class=\"cta-container\">\n <ia-button\n class=\"ia-button secondary\"\n .clickHandler=${(e: Event) => {\n e.preventDefault();\n this.closeForm();\n }}\n >\n Cancel\n </ia-button>\n <ia-button\n id=\"edit-date\"\n class=\"ia-button primary\"\n type=\"submit\"\n .isDisabled=${!this.allowEditing}\n .clickHandler=${async (e: Event, iaButton: IauxButton) => {\n this.clearStatusMessaging();\n\n if (!this.newDate) {\n this.errorMessage = 'Please enter a valid date';\n return;\n }\n\n // eslint-disable-next-line no-param-reassign\n (iaButton as IauxButton).isDisabled = true;\n await iaButton.updateComplete;\n\n // check if request is in range\n\n this.requestDateUpdate(e);\n }}\n >\n Update\n </ia-button>\n <ia-mgc-update-status .status=${this.updateStatus}\n >${this.updateMessage}</ia-mgc-update-status\n >\n </div>\n </div>\n <p class=\"error\">${this.warningMessage}</p>\n <p class=\"error\">${this.errorMessage}</p>\n </form>\n </section>\n `;\n }\n\n static styles = css`\n input[name='edit-date'] {\n margin: 10px 0;\n min-width: 140px;\n }\n\n .cta-container {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-content: center;\n justify-content: flex-start;\n align-items: center;\n gap: 10px;\n }\n\n p.error {\n color: var(--mgc-warning-color-dark, #bb0505);\n }\n\n ia-mgc-update-status {\n display: inline-block;\n margin-left: 1rem;\n }\n\n .checkbox-option-container {\n margin: 10px 0;\n display: flex;\n }\n `;\n}\n"]}
1
+ {"version":3,"file":"date.js","sourceRoot":"","sources":["../../../src/form-sections/date.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,UAAU,EACV,IAAI,EAEJ,OAAO,EACP,GAAG,GAEJ,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,wCAAwC,CAAC;AAGhD,OAAO,6BAA6B,CAAC;AAErC,OAAO,qCAAqC,CAAC;AAG7C,IAAa,eAAe,GAA5B,MAAa,eAAgB,SAAQ,UAAU;IAA/C;;QAK8C,qBAAgB,GAAY,KAAK,CAAC;QAEjD,iBAAY,GAAY,KAAK,CAAC;QAE/B,kBAAa,GAAW,EAAE,CAAC;QAE3B,iBAAY,GAAW,EAAE,CAAC;QAE1B,mBAAc,GAAW,EAAE,CAAC;QAE5B,iBAAY,GAA4B,EAAE,CAAC;IAkTzE,CAAC;IAzSC,UAAU,CAAC,OAAuB;QAChC,IAAI,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE;YACtD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;SAClD;IACH,CAAC;IAED,OAAO,CAAC,OAAuB;QAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE;YAC5D,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;SACxB;IACH,CAAC;IAES,MAAM;;QACd,OAAO,IAAI,CAAA;;;;;;YAMH,CAAC,IAAI,CAAC,gBAAgB;YACtB,CAAC,CAAC,IAAI,CAAA;oBACE,MAAA,IAAI,CAAC,IAAI,0CAAE,qBAAqB;kDACF,IAAI,CAAC,YAAY;uBAC5C,IAAI,CAAC,aAAa;;;;;;kCAMP,GAAG,EAAE;gBACnB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC9B,CAAC;;;6BAGU;YACjB,CAAC,CAAC,OAAO;YACT,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO;;;KAG1D,CAAC;IACJ,CAAC;IAED,8FAA8F;IAC9F,KAAK,CAAC,WAAW,CAAC,MAA0B;QAC1C,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC3B,IAAI,CAAC,aAAa;YAChB,MAAM,KAAK,SAAS;gBAClB,CAAC,CAAC,cAAc;gBAChB,CAAC,CAAC,yCAAyC,CAAC;QAEhD,IAAI,MAAM,KAAK,SAAS,EAAE;YACxB,IAAI,CAAC,SAAS,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,cAAc,CAAC;YAC1B,OAAO;SACR;QAED,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,MAAM,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAED,yCAAyC;IACzC,iBAAiB,CAAC,CAAQ;QACxB,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,YAAY,EAAE;YAC5B,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,SAAS;QACP,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,eAAe;QACb,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,oBAAoB;QACxB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAED,aAAa;IACb,IAAI,OAAO;QACT,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB;QACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,uBAAuB;QACvF,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,OAAO;QACT,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,qCAAqC;QAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,uBAAuB;QACpF,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IAC/C,CAAC;IAED,IAAI,YAAY;;QACd,OAAO,IAAI,CAAA;;;;kCAImB,MAAA,IAAI,CAAC,IAAI,0CAAE,qBAAqB;;;;kCAIhC,MAAA,IAAI,CAAC,IAAI,0CAAE,qBAAqB;;;;;;;;oBAQ9C,IAAI,CAAC,OAAO;oBACZ,IAAI,CAAC,OAAO;;uBAET,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE;wBAChC,KAAK,IAAI,EAAE;;YACnB,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YACxC,OAAO,CAAC,GAAG,CACT,kCAAkC,EAClC,UAAU,EACV,IAAI,CAAC,YAAY,CAClB,CAAC;YAEF,IAAI,CAAC,UAAU,EAAE;gBACf,IAAI,CAAC,YAAY,GAAG,qBAAqB,CAAC;gBAC1C,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC1B,OAAO,CAAC,+CAA+C;aACxD;YAED,IAAI,SAAS,CAAC;YACd,IAAI;gBACF,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,UAAU,WAAW,CAAC,CAAC;aAChD;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,YAAY;oBACf,+CAA+C,CAAC;gBAClD,OAAO,CAAC,+CAA+C;aACxD;YAED,6CAA6C;YAC7C,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;YACzB,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3B,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;YACjC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB;YACzD,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9B,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,UAAU,GAAG,KAAK,EAAE;gBACtB,IAAI,CAAC,YAAY,GAAG,iCAAiC,CAAC;gBACtD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC1B,OAAO;aACR;YAED,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAClD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YAEvB,uDAAuD;YACvD,MAAM,mBAAmB,GACvB,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,OAAO,CAAC,eAAe,CAAC,IAAI;gBACvC,IAAI,IAAI,CAAC,MAAA,IAAI,CAAC,IAAI,0CAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,mBAAmB,EAAE;gBACvB,MAAM,gBAAgB,GAAG,IAAI,IAAI,CAC/B,MAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,OAAO,CAAC,eAAe,CAAC,IAAI,mCAAI,EAAE,CAC9C,CAAC;gBACF,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC;gBACtD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,WAAW,EAAE,CAAC;gBAExD,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;gBACzC,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;gBACvC,MAAM,aAAa,GACjB,QAAQ,KAAK,gBAAgB;oBAC7B,SAAS,KAAK,iBAAiB,CAAC;gBAElC,IAAI,aAAa,EAAE;oBACjB,IAAI,CAAC,cAAc;wBACjB,8DAA8D,CAAC;oBACjE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;oBACzB,OAAO;iBACR;aACF;YAED,qDAAqD;YACrD,MAAM,mBAAmB,GAAG,IAAI,IAAI,EAAE,CAAC;YACvC,mBAAmB,CAAC,WAAW,CAC7B,mBAAmB,CAAC,WAAW,EAAE,GAAG,CAAC,CACtC,CAAC;YACF,mBAAmB,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAEzC,IAAI,UAAU,GAAG,mBAAmB,EAAE;gBACpC,IAAI,CAAC,YAAY;oBACf,sDAAsD,CAAC;gBACzD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC1B,OAAO;aACR;YAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;;;;;;;gCAOiB,CAAC,CAAQ,EAAE,EAAE;YAC3B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;;;;;;;;8BAQa,CAAC,IAAI,CAAC,YAAY;gCAChB,KAAK,EAAE,CAAQ,EAAE,QAAoB,EAAE,EAAE;YACvD,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAE5B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjB,IAAI,CAAC,YAAY,GAAG,2BAA2B,CAAC;gBAChD,OAAO;aACR;YAED,6CAA6C;YAC5C,QAAuB,CAAC,UAAU,GAAG,IAAI,CAAC;YAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;YAE9B,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;;;;8CAI6B,IAAI,CAAC,YAAY;mBAC5C,IAAI,CAAC,aAAa;;;;yCAII,IAAI,CAAC,cAAc;uCACrB,IAAI,CAAC,YAAY;;;KAGnD,CAAC;IACJ,CAAC;CAgCF,CAAA;AA9BQ,sBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BlB,CAAC;AA/T0B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAoB;AAEnB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAAkB;AAED;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;yDAAmC;AAEjD;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;qDAA+B;AAE/B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDAA4B;AAE3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qDAA2B;AAE1B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDAA6B;AAE5B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qDAA4C;AAExD;IAAd,KAAK,CAAC,MAAM,CAAC;6CAAwB;AAEH;IAAlC,KAAK,CAAC,0BAA0B,CAAC;yDAA+B;AAGjE;IADC,KAAK,CAAC,8BAA8B,CAAC;kDACT;AAtBlB,eAAe;IAD3B,aAAa,CAAC,kBAAkB,CAAC;GACrB,eAAe,CAiU3B;SAjUY,eAAe","sourcesContent":["import {\n LitElement,\n html,\n PropertyValues,\n nothing,\n css,\n TemplateResult,\n} from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport '@internetarchive/donation-form-section';\n\nimport type { MonthlyPlan } from '../models/plan';\nimport '../presentational/ia-button';\nimport type { IauxButton } from '../presentational/ia-button';\nimport '../presentational/mgc-update-status';\n\n@customElement('ia-mgc-edit-date')\nexport class MGCEditPlanDate extends LitElement {\n @property({ type: Object }) plan?: MonthlyPlan;\n\n @property({ type: String }) newDate?: string;\n\n @property({ type: Boolean, reflect: true }) currentlyEditing: boolean = false;\n\n @property({ type: Boolean }) allowEditing: boolean = false;\n\n @property({ type: String }) updateMessage: string = '';\n\n @property({ type: String }) errorMessage: string = '';\n\n @property({ type: String }) warningMessage: string = '';\n\n @property({ type: String }) updateStatus: 'success' | 'fail' | '' = '';\n\n @query('form') form!: HTMLFormElement;\n\n @query('form ia-button#edit-date') formSubmitButton!: IauxButton;\n\n @query('form input[name=\"edit-date\"]')\n dateInput!: HTMLInputElement;\n\n willUpdate(changed: PropertyValues) {\n if (this.dateInput && changed.has('plan') && this.plan) {\n this.dateInput.setAttribute('min', this.minDate);\n this.dateInput.setAttribute('max', this.maxDate);\n }\n }\n\n updated(changed: PropertyValues) {\n if (changed.has('currentlyEditing') && this.currentlyEditing) {\n this.dateInput.focus();\n }\n }\n\n protected render() {\n return html`\n <section>\n <donation-form-section\n badgemode=\"hidebadge\"\n headline=\"Change next donation date\"\n >\n ${!this.currentlyEditing\n ? html` <p class=\"current-date\">\n ${this.plan?.nextBillingDateLocale}\n <ia-mgc-update-status .status=${this.updateStatus}\n >${this.updateMessage}</ia-mgc-update-status\n >\n </p>\n <ia-button\n id=\"open-edit-date-form\"\n class=\"ia-button link\"\n .clickHandler=${() => {\n this.currentlyEditing = true;\n this.clearStatusMessaging();\n }}\n >\n Edit...\n </ia-button>`\n : nothing}\n ${this.currentlyEditing ? this.editDateForm : nothing}\n </donation-form-section>\n </section>\n `;\n }\n\n /* External Function that is called by consumer to tell the form there has been data update */\n async dateUpdated(status: 'success' | 'fail') {\n this.clearInputField();\n\n this.updateStatus = status;\n this.updateMessage =\n status === 'success'\n ? 'Date updated'\n : 'Failed to update date, please try again';\n\n if (status === 'success') {\n this.closeForm();\n await this.updateComplete;\n return;\n }\n\n this.allowEditing = false;\n await this.updateComplete;\n }\n\n /* Dispatches edit-date change request */\n requestDateUpdate(e: Event): void {\n e.preventDefault();\n this.dispatchEvent(\n new CustomEvent('updateDate', {\n detail: {\n plan: this.plan,\n newDate: this.newDate,\n },\n })\n );\n }\n\n closeForm() {\n this.clearInputField();\n this.clearStatusMessaging();\n this.currentlyEditing = false;\n this.allowEditing = false;\n }\n\n clearInputField() {\n this.dateInput.value = '';\n this.newDate = undefined;\n }\n\n async clearStatusMessaging() {\n this.errorMessage = '';\n this.warningMessage = '';\n this.updateMessage = '';\n this.updateStatus = '';\n await this.updateComplete;\n }\n\n /* DISPLAY */\n get minDate(): string {\n const today = new Date();\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1); // Set to tomorrow\n const year = tomorrow.getFullYear();\n const month = String(tomorrow.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed\n return `${year}-${month}-${tomorrow.getDate()}`;\n }\n\n get maxDate(): string {\n const today = new Date();\n const year = today.getFullYear() + 1; // Allow up to one year in the future\n const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed\n return `${year}-${month}-${today.getDate()}`;\n }\n\n get editDateForm(): TemplateResult {\n return html`\n <section>\n <form id=\"edit-date\">\n <p id=\"form-info-last-donation-date\">\n Last donation date: ${this.plan?.lastBillingDateLocale}\n </p>\n\n <p id=\"form-info-next-donation-date\">\n Next donation date: ${this.plan?.nextBillingDateLocale}\n </p>\n <div class=\"date-holder\">\n <input\n required\n type=\"date\"\n id=\"edit-date\"\n name=\"edit-date\"\n min=${this.minDate}\n max=${this.maxDate}\n value=\"\"\n @focus=${() => this.clearStatusMessaging()}\n @change=${async () => {\n this.clearStatusMessaging();\n await this.updateComplete;\n\n const inputValue = this.dateInput.value;\n console.log(\n ' ----- date input changed ----- ',\n inputValue,\n this.errorMessage\n );\n\n if (!inputValue) {\n this.errorMessage = 'Please enter a date';\n this.allowEditing = false;\n return; // wait until date field returns a valid string\n }\n\n let validDate;\n try {\n validDate = new Date(`${inputValue}T00:00:00`);\n } catch (error) {\n this.errorMessage =\n 'Please enter a valid date format (YYYY-MM-DD)';\n return; // wait until date field returns a valid string\n }\n\n // Check if minimum date is at least tomorrow\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1); // Set to tomorrow\n tomorrow.setHours(0, 0, 0, 0);\n const chosenDate = new Date(validDate);\n chosenDate.setHours(0, 0, 0, 0);\n if (chosenDate < today) {\n this.errorMessage = 'Date must be at least tomorrow.';\n this.allowEditing = false;\n return;\n }\n\n const newDate = new Date(validDate).toISOString();\n this.newDate = newDate;\n\n // Check if there has been a donation in the last month\n const hasLastDonationInfo =\n this.plan?.payment.lastBillingDate.date &&\n new Date(this.plan?.payment.lastBillingDate.date);\n\n if (hasLastDonationInfo) {\n const lastDonationDate = new Date(\n this.plan?.payment.lastBillingDate.date ?? ''\n );\n const lastDonationMonth = lastDonationDate.getMonth();\n const lastDonationYear = lastDonationDate.getFullYear();\n\n const thisYear = validDate.getFullYear();\n const thisMonth = validDate.getMonth();\n const isInLastMonth =\n thisYear === lastDonationYear &&\n thisMonth === lastDonationMonth;\n\n if (isInLastMonth) {\n this.warningMessage =\n 'New donation date is in the same month as your last payment.';\n this.allowEditing = true;\n return;\n }\n }\n\n // Check if the new date is within the next 12 months\n const twelveMonthsFromNow = new Date();\n twelveMonthsFromNow.setFullYear(\n twelveMonthsFromNow.getFullYear() + 1\n );\n twelveMonthsFromNow.setHours(0, 0, 0, 0);\n\n if (chosenDate > twelveMonthsFromNow) {\n this.errorMessage =\n 'New donation date must be within the next 12 months.';\n this.allowEditing = false;\n return;\n }\n\n this.allowEditing = true;\n }}\n />\n </div>\n <div>\n <div class=\"cta-container\">\n <ia-button\n class=\"ia-button secondary\"\n .clickHandler=${(e: Event) => {\n e.preventDefault();\n this.closeForm();\n }}\n >\n Cancel\n </ia-button>\n <ia-button\n id=\"edit-date\"\n class=\"ia-button primary\"\n type=\"submit\"\n .isDisabled=${!this.allowEditing}\n .clickHandler=${async (e: Event, iaButton: IauxButton) => {\n this.clearStatusMessaging();\n\n if (!this.newDate) {\n this.errorMessage = 'Please enter a valid date';\n return;\n }\n\n // eslint-disable-next-line no-param-reassign\n (iaButton as IauxButton).isDisabled = true;\n await iaButton.updateComplete;\n\n this.requestDateUpdate(e);\n }}\n >\n Update\n </ia-button>\n <ia-mgc-update-status .status=${this.updateStatus}\n >${this.updateMessage}</ia-mgc-update-status\n >\n </div>\n </div>\n <p class=\"error warning-msg\">${this.warningMessage}</p>\n <p class=\"error error-msg\">${this.errorMessage}</p>\n </form>\n </section>\n `;\n }\n\n static styles = css`\n input[name='edit-date'] {\n margin: 10px 0;\n min-width: 140px;\n }\n\n .cta-container {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-content: center;\n justify-content: flex-start;\n align-items: center;\n gap: 10px;\n }\n\n p.error {\n color: var(--mgc-warning-color-dark, #bb0505);\n }\n\n ia-mgc-update-status {\n display: inline-block;\n margin-left: 1rem;\n }\n\n .checkbox-option-container {\n margin: 10px 0;\n display: flex;\n }\n `;\n}\n"]}
@@ -43,7 +43,7 @@ export declare class MonthlyPlan {
43
43
  setAmount(newAmount: number): void;
44
44
  setNextBillingDate(newDate: string): void;
45
45
  get startDate(): string;
46
- get nextBillingDate(): string;
46
+ get nextBillingDateLocale(): string;
47
47
  get lastBillingDateLocale(): string;
48
48
  get hasBeenCancelled(): boolean;
49
49
  get isTest(): boolean;
@@ -27,7 +27,7 @@ export class MonthlyPlan {
27
27
  const date = new Date(this.plan.start_date);
28
28
  return date.toLocaleDateString();
29
29
  }
30
- get nextBillingDate() {
30
+ get nextBillingDateLocale() {
31
31
  const nextBillingDate = new Date(this.payment.nextBillingDate.date).toLocaleDateString(undefined, {
32
32
  year: 'numeric',
33
33
  month: 'short',
@@ -1 +1 @@
1
- {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/models/plan.ts"],"names":[],"mappings":"AAoCA,MAAM,OAAO,WAAW;IAOtB,YAAY,IAAU;;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,MAAA,IAAI,CAAC,QAAQ,mCAAI,KAAK,CAAC,CAAC,cAAc;IACxD,CAAC;IAED,IAAI,EAAE;QACJ,yBAAyB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,SAAiB;QACzB,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC/B,CAAC;IAED,kBAAkB,CAAC,OAAe;QAChC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,GAAG,OAAO,CAAC;IAC9C,CAAC;IAED,IAAI,SAAS;QACX,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,eAAe;QACjB,MAAM,eAAe,GAAG,IAAI,IAAI,CAC9B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAClC,CAAC,kBAAkB,CAAC,SAAS,EAAE;YAC9B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,WAAW,CAAC;IACxC,CAAC;IAED,IAAI,qBAAqB;QACvB,MAAM,eAAe,GAAG,IAAI,IAAI,CAC9B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAClC,CAAC,kBAAkB,CAAC,SAAS,EAAE;YAC9B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;QAE3D,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,WAAW,CAAC;IACxC,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC;IACxC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;IAwBI","sourcesContent":["type BtData = {\n billingDayOfMonth: number;\n nextBillingDate: {\n date: string;\n timezone_type: number;\n timezone: string;\n oldDate?: string; // optional for updates ISO UTC date string\n };\n lastBillingDate: {\n date: string;\n timezone_type: number;\n timezone: string;\n };\n status: string; // active, inactive\n paymentMethodType: string; // cc, paypal, venmo, etc\n last4: string | null;\n cardType: string | null;\n expirationMonth: string | null;\n expirationYear: string | null;\n paypalEmail?: string;\n venmoUsername?: string;\n};\n\ntype Plan = {\n token: string;\n amount: number;\n currency: string;\n start_date: string; // UTC\n is_test: boolean;\n btdata: BtData;\n oldAmount?: number;\n oldDate?: string;\n oldPaymentMethod?: string;\n isCancelled?: boolean;\n};\n\nexport class MonthlyPlan {\n plan: Plan;\n\n currency: string;\n\n payment: BtData;\n\n constructor(plan: Plan) {\n this.plan = plan;\n this.payment = plan.btdata;\n this.currency = plan.currency ?? 'USD'; // not in data\n }\n\n get id(): string {\n // use token as unique id\n return this.plan.token;\n }\n\n get currencySymbol(): string {\n return this.currency === 'USD' ? '$' : '';\n }\n\n get amount(): number {\n return this.plan.amount;\n }\n\n setAmount(newAmount: number) {\n this.plan.oldAmount = this.plan.amount;\n this.plan.amount = newAmount;\n }\n\n setNextBillingDate(newDate: string): void {\n this.payment.nextBillingDate.oldDate = this.payment.nextBillingDate.date;\n this.payment.nextBillingDate.date = newDate;\n }\n\n get startDate(): string {\n const date = new Date(this.plan.start_date);\n return date.toLocaleDateString();\n }\n\n get nextBillingDate(): string {\n const nextBillingDate = new Date(\n this.payment.nextBillingDate.date\n ).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n return nextBillingDate ?? 'not found';\n }\n\n get lastBillingDateLocale(): string {\n const lastBillingDate = new Date(\n this.payment.lastBillingDate.date\n ).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n console.log('lastBillingDate from model', lastBillingDate);\n\n return lastBillingDate ?? 'not found';\n }\n\n get hasBeenCancelled(): boolean {\n return this.plan.isCancelled === true;\n }\n\n get isTest(): boolean {\n return this.plan.is_test;\n }\n\n cancelPlan(): void {\n this.plan.isCancelled = true;\n }\n}\n\n/*\n\n{\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWlsc3luYyIsImlhdCI6MTczODYxNTY3NS41ODA4MTcsIm5iZiI6MTczODYxNTYxNS41ODA4MTcsImV4cCI6MTczODYxNjI3NS41ODA4MTcsImtleSI6eyJwaWQiOiJkd2NrN20iLCJjaWQiOjgwMzUzOCwiYW1vdW50Ijo1LCJwYXltZW50TWV0aG9kVG9rZW4iOiJxMXllYndoaiIsImN1c3RvbWVySWQiOiI4NTQ2MTk4MzUifSwidXNlciI6IkBpc2EtYXQtdGhlLWFyY2hpdmUifQ.TYlkU1ZZLHmj2ahrkTV7JGLmpCPN4BcOeDFPiXVj0pM\",\n \"amount\": 5,\n \"currency\": \"USD\",\n \"start_date\": \"2022-12-09 00:00:00\",\n \"contribution_status_id\": 5,\n \"is_test\": true,\n \"btdata\": {\n \"billingDayOfMonth\": 9,\n \"nextBillingDate\": {\n \"date\": \"2025-02-09 00:00:00.000000\",\n \"timezone_type\": 3,\n \"timezone\": \"UTC\"\n },\n \"status\": \"Active\",\n \"paymentMethodType\": \"creditCard\",\n \"last4\": \"1111\",\n \"cardType\": \"Visa\",\n \"expirationMonth\": \"12\",\n \"expirationYear\": \"2023\"\n }\n}\n */\n"]}
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/models/plan.ts"],"names":[],"mappings":"AAoCA,MAAM,OAAO,WAAW;IAOtB,YAAY,IAAU;;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,MAAA,IAAI,CAAC,QAAQ,mCAAI,KAAK,CAAC,CAAC,cAAc;IACxD,CAAC;IAED,IAAI,EAAE;QACJ,yBAAyB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,SAAiB;QACzB,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC/B,CAAC;IAED,kBAAkB,CAAC,OAAe;QAChC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,GAAG,OAAO,CAAC;IAC9C,CAAC;IAED,IAAI,SAAS;QACX,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,qBAAqB;QACvB,MAAM,eAAe,GAAG,IAAI,IAAI,CAC9B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAClC,CAAC,kBAAkB,CAAC,SAAS,EAAE;YAC9B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,WAAW,CAAC;IACxC,CAAC;IAED,IAAI,qBAAqB;QACvB,MAAM,eAAe,GAAG,IAAI,IAAI,CAC9B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAClC,CAAC,kBAAkB,CAAC,SAAS,EAAE;YAC9B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;QAE3D,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,WAAW,CAAC;IACxC,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC;IACxC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;IAwBI","sourcesContent":["type BtData = {\n billingDayOfMonth: number;\n nextBillingDate: {\n date: string;\n timezone_type: number;\n timezone: string;\n oldDate?: string; // optional for updates ISO UTC date string\n };\n lastBillingDate: {\n date: string;\n timezone_type: number;\n timezone: string;\n };\n status: string; // active, inactive\n paymentMethodType: string; // cc, paypal, venmo, etc\n last4: string | null;\n cardType: string | null;\n expirationMonth: string | null;\n expirationYear: string | null;\n paypalEmail?: string;\n venmoUsername?: string;\n};\n\ntype Plan = {\n token: string;\n amount: number;\n currency: string;\n start_date: string; // UTC\n is_test: boolean;\n btdata: BtData;\n oldAmount?: number;\n oldDate?: string;\n oldPaymentMethod?: string;\n isCancelled?: boolean;\n};\n\nexport class MonthlyPlan {\n plan: Plan;\n\n currency: string;\n\n payment: BtData;\n\n constructor(plan: Plan) {\n this.plan = plan;\n this.payment = plan.btdata;\n this.currency = plan.currency ?? 'USD'; // not in data\n }\n\n get id(): string {\n // use token as unique id\n return this.plan.token;\n }\n\n get currencySymbol(): string {\n return this.currency === 'USD' ? '$' : '';\n }\n\n get amount(): number {\n return this.plan.amount;\n }\n\n setAmount(newAmount: number) {\n this.plan.oldAmount = this.plan.amount;\n this.plan.amount = newAmount;\n }\n\n setNextBillingDate(newDate: string): void {\n this.payment.nextBillingDate.oldDate = this.payment.nextBillingDate.date;\n this.payment.nextBillingDate.date = newDate;\n }\n\n get startDate(): string {\n const date = new Date(this.plan.start_date);\n return date.toLocaleDateString();\n }\n\n get nextBillingDateLocale(): string {\n const nextBillingDate = new Date(\n this.payment.nextBillingDate.date\n ).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n return nextBillingDate ?? 'not found';\n }\n\n get lastBillingDateLocale(): string {\n const lastBillingDate = new Date(\n this.payment.lastBillingDate.date\n ).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n console.log('lastBillingDate from model', lastBillingDate);\n\n return lastBillingDate ?? 'not found';\n }\n\n get hasBeenCancelled(): boolean {\n return this.plan.isCancelled === true;\n }\n\n get isTest(): boolean {\n return this.plan.is_test;\n }\n\n cancelPlan(): void {\n this.plan.isCancelled = true;\n }\n}\n\n/*\n\n{\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWlsc3luYyIsImlhdCI6MTczODYxNTY3NS41ODA4MTcsIm5iZiI6MTczODYxNTYxNS41ODA4MTcsImV4cCI6MTczODYxNjI3NS41ODA4MTcsImtleSI6eyJwaWQiOiJkd2NrN20iLCJjaWQiOjgwMzUzOCwiYW1vdW50Ijo1LCJwYXltZW50TWV0aG9kVG9rZW4iOiJxMXllYndoaiIsImN1c3RvbWVySWQiOiI4NTQ2MTk4MzUifSwidXNlciI6IkBpc2EtYXQtdGhlLWFyY2hpdmUifQ.TYlkU1ZZLHmj2ahrkTV7JGLmpCPN4BcOeDFPiXVj0pM\",\n \"amount\": 5,\n \"currency\": \"USD\",\n \"start_date\": \"2022-12-09 00:00:00\",\n \"contribution_status_id\": 5,\n \"is_test\": true,\n \"btdata\": {\n \"billingDayOfMonth\": 9,\n \"nextBillingDate\": {\n \"date\": \"2025-02-09 00:00:00.000000\",\n \"timezone_type\": 3,\n \"timezone\": \"UTC\"\n },\n \"status\": \"Active\",\n \"paymentMethodType\": \"creditCard\",\n \"last4\": \"1111\",\n \"cardType\": \"Visa\",\n \"expirationMonth\": \"12\",\n \"expirationYear\": \"2023\"\n }\n}\n */\n"]}
package/dist/src/plans.js CHANGED
@@ -68,7 +68,7 @@ let IauxMgcPlans = class IauxMgcPlans extends LitElement {
68
68
  </div>
69
69
  <div class="next-donation">
70
70
  <h3>Next Donation</h3>
71
- <p>${plan.nextBillingDate}</p>
71
+ <p>${plan.nextBillingDateLocale}</p>
72
72
  </div>
73
73
  </div>
74
74
  ${this.planCTA(plan)}
@@ -1 +1 @@
1
- {"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/plans.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-param-reassign */\nimport { LitElement, html, css, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport type { MonthlyPlan } from './models/plan';\n\nimport './presentational/ia-button';\nimport type { IauxButton } from './presentational/ia-button';\n\n@customElement('ia-mgc-plans')\nexport class IauxMgcPlans extends LitElement {\n @property({ type: Array }) plans = [];\n\n @property({ type: Boolean, reflect: true }) canEdit = false;\n\n protected render() {\n return html`\n <section class=\"monthly-giving-circle\">\n <ul>\n ${this.plans.map((plan: MonthlyPlan) => {\n let methodType =\n plan.payment?.paymentMethodType ?? 'Method not found';\n if (methodType === 'creditCard') {\n methodType = 'Credit card';\n }\n const cardType = plan.payment?.cardType ?? 'Card type not found';\n const last4 = plan.payment?.last4\n ? `...${plan.payment?.last4}`\n : 'CC number not found';\n\n return html`\n <li class=${`${plan.plan.isCancelled ? 'cancelled' : ''}`}>\n <div class=\"info\">\n <div class=\"amount\">\n <h3>Amount</h3>\n <p>\n ${plan.currency}\n ${plan.currencySymbol}${plan.amount}/month\n </p>\n ${plan.isTest\n ? html`<p class=\"is-test\">(Test payment)</p>`\n : nothing}\n </div>\n <div class=\"payment-details\">\n <h3>Method</h3>\n <p>${methodType}</p>\n ${plan.payment?.paymentMethodType === 'creditCard'\n ? html`<p>${cardType}</p>\n <p>${last4}</p>`\n : nothing}\n ${plan.payment?.paymentMethodType === 'Paypal'\n ? html`<p>\n Paypal email:\n <a href=${`mailto:${plan.payment?.paypalEmail}`}\n >${plan.payment?.paypalEmail}</a\n >\n </p>`\n : nothing}\n ${plan.payment?.paymentMethodType === 'Venmo'\n ? html`<p>\n Venmo username:\n <a href=${`mailto:${plan.payment?.venmoUsername}`}\n >${plan.payment?.paypalEmail}</a\n >\n </p>`\n : nothing}\n ${plan.payment?.paymentMethodType !== 'creditCard'\n ? html`<p>\n Expires:\n ${plan.payment?.expirationMonth ??\n 'month not found'}/${plan.payment?.expirationYear ??\n 'year not found'}\n </p>`\n : nothing}\n </div>\n <div class=\"next-donation\">\n <h3>Next Donation</h3>\n <p>${plan.nextBillingDate}</p>\n </div>\n </div>\n ${this.planCTA(plan)}\n </li>\n `;\n })}\n </ul>\n </section>\n `;\n }\n\n planCTA(plan: MonthlyPlan) {\n if (!this.canEdit) {\n const mailToText = `mailto:donations@archive.org?subject=I'd like to update my monthly donation`;\n return html`<p class=\"email-edit-plan\">\n Need to update your plan further? Please email us at\n <a href=${mailToText}>donations@archive.org</a>.\n </p>`;\n }\n\n const ctaText = plan.plan.isCancelled\n ? 'Plan is cancelled'\n : 'Manage this monthly donation';\n\n return html`<ia-button\n class=\"ia-button link edit-donation\"\n .isDisabled=${plan.plan.isCancelled}\n .clickHandler=${async (e: Event, iaButton: IauxButton) => {\n // disable button\n iaButton.isDisabled = true;\n // open form\n this.dispatchEvent(\n new CustomEvent('editThisPlan', { detail: { plan } })\n );\n }}\n >${ctaText}</ia-button\n >`;\n }\n\n static styles = css`\n :host {\n max-height: 500px;\n overflow-y: scroll;\n display: block;\n }\n\n .is-test {\n font-size: 0.8rem;\n }\n\n li {\n border: 1px solid #23765d;\n background-color: #eeffee;\n display: block;\n width: inherit;\n }\n li.cancelled {\n background-color: lightgoldenrodyellow;\n }\n table {\n width: 100%;\n text-align: left;\n max-width: 600px;\n }\n\n ul {\n padding: 0;\n list-style-type: none;\n margin: 0;\n }\n\n ul li {\n border: 1px solid #23765d;\n background-color: #eeffee;\n margin: 0.5rem 0;\n padding: 0.5rem 0.5rem 1rem 0.5rem;\n position: relative;\n }\n\n ul li button.edit-donation {\n height: 30px;\n display: block;\n position: absolute;\n bottom: 0;\n }\n\n ul li .info {\n display: grid;\n min-height: 90px;\n grid-template-columns: 0.5fr 1fr 0.5fr;\n grid-template-rows: 1fr;\n gap: 0px 5px;\n grid-auto-flow: row;\n grid-template-areas: 'amount details next-donation';\n }\n\n ul li .info .amount {\n grid-area: amount;\n }\n\n ul li .info .payment-details {\n grid-area: details;\n }\n\n ul li .info .next-donation {\n grid-area: next-donation;\n }\n\n ul li .info > * {\n margin: 0 0 0.5rem 0;\n }\n\n ul li .info > * > * {\n margin: 0;\n }\n\n .email-edit-plan {\n margin-bottom: 0;\n }\n\n @media screen and (max-width: 500px) {\n ul li .info {\n display: block;\n }\n }\n `;\n}\n"]}
1
+ {"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/plans.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-param-reassign */\nimport { LitElement, html, css, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport type { MonthlyPlan } from './models/plan';\n\nimport './presentational/ia-button';\nimport type { IauxButton } from './presentational/ia-button';\n\n@customElement('ia-mgc-plans')\nexport class IauxMgcPlans extends LitElement {\n @property({ type: Array }) plans = [];\n\n @property({ type: Boolean, reflect: true }) canEdit = false;\n\n protected render() {\n return html`\n <section class=\"monthly-giving-circle\">\n <ul>\n ${this.plans.map((plan: MonthlyPlan) => {\n let methodType =\n plan.payment?.paymentMethodType ?? 'Method not found';\n if (methodType === 'creditCard') {\n methodType = 'Credit card';\n }\n const cardType = plan.payment?.cardType ?? 'Card type not found';\n const last4 = plan.payment?.last4\n ? `...${plan.payment?.last4}`\n : 'CC number not found';\n\n return html`\n <li class=${`${plan.plan.isCancelled ? 'cancelled' : ''}`}>\n <div class=\"info\">\n <div class=\"amount\">\n <h3>Amount</h3>\n <p>\n ${plan.currency}\n ${plan.currencySymbol}${plan.amount}/month\n </p>\n ${plan.isTest\n ? html`<p class=\"is-test\">(Test payment)</p>`\n : nothing}\n </div>\n <div class=\"payment-details\">\n <h3>Method</h3>\n <p>${methodType}</p>\n ${plan.payment?.paymentMethodType === 'creditCard'\n ? html`<p>${cardType}</p>\n <p>${last4}</p>`\n : nothing}\n ${plan.payment?.paymentMethodType === 'Paypal'\n ? html`<p>\n Paypal email:\n <a href=${`mailto:${plan.payment?.paypalEmail}`}\n >${plan.payment?.paypalEmail}</a\n >\n </p>`\n : nothing}\n ${plan.payment?.paymentMethodType === 'Venmo'\n ? html`<p>\n Venmo username:\n <a href=${`mailto:${plan.payment?.venmoUsername}`}\n >${plan.payment?.paypalEmail}</a\n >\n </p>`\n : nothing}\n ${plan.payment?.paymentMethodType !== 'creditCard'\n ? html`<p>\n Expires:\n ${plan.payment?.expirationMonth ??\n 'month not found'}/${plan.payment?.expirationYear ??\n 'year not found'}\n </p>`\n : nothing}\n </div>\n <div class=\"next-donation\">\n <h3>Next Donation</h3>\n <p>${plan.nextBillingDateLocale}</p>\n </div>\n </div>\n ${this.planCTA(plan)}\n </li>\n `;\n })}\n </ul>\n </section>\n `;\n }\n\n planCTA(plan: MonthlyPlan) {\n if (!this.canEdit) {\n const mailToText = `mailto:donations@archive.org?subject=I'd like to update my monthly donation`;\n return html`<p class=\"email-edit-plan\">\n Need to update your plan further? Please email us at\n <a href=${mailToText}>donations@archive.org</a>.\n </p>`;\n }\n\n const ctaText = plan.plan.isCancelled\n ? 'Plan is cancelled'\n : 'Manage this monthly donation';\n\n return html`<ia-button\n class=\"ia-button link edit-donation\"\n .isDisabled=${plan.plan.isCancelled}\n .clickHandler=${async (e: Event, iaButton: IauxButton) => {\n // disable button\n iaButton.isDisabled = true;\n // open form\n this.dispatchEvent(\n new CustomEvent('editThisPlan', { detail: { plan } })\n );\n }}\n >${ctaText}</ia-button\n >`;\n }\n\n static styles = css`\n :host {\n max-height: 500px;\n overflow-y: scroll;\n display: block;\n }\n\n .is-test {\n font-size: 0.8rem;\n }\n\n li {\n border: 1px solid #23765d;\n background-color: #eeffee;\n display: block;\n width: inherit;\n }\n li.cancelled {\n background-color: lightgoldenrodyellow;\n }\n table {\n width: 100%;\n text-align: left;\n max-width: 600px;\n }\n\n ul {\n padding: 0;\n list-style-type: none;\n margin: 0;\n }\n\n ul li {\n border: 1px solid #23765d;\n background-color: #eeffee;\n margin: 0.5rem 0;\n padding: 0.5rem 0.5rem 1rem 0.5rem;\n position: relative;\n }\n\n ul li button.edit-donation {\n height: 30px;\n display: block;\n position: absolute;\n bottom: 0;\n }\n\n ul li .info {\n display: grid;\n min-height: 90px;\n grid-template-columns: 0.5fr 1fr 0.5fr;\n grid-template-rows: 1fr;\n gap: 0px 5px;\n grid-auto-flow: row;\n grid-template-areas: 'amount details next-donation';\n }\n\n ul li .info .amount {\n grid-area: amount;\n }\n\n ul li .info .payment-details {\n grid-area: details;\n }\n\n ul li .info .next-donation {\n grid-area: next-donation;\n }\n\n ul li .info > * {\n margin: 0 0 0.5rem 0;\n }\n\n ul li .info > * > * {\n margin: 0;\n }\n\n .email-edit-plan {\n margin-bottom: 0;\n }\n\n @media screen and (max-width: 500px) {\n ul li .info {\n display: block;\n }\n }\n `;\n}\n"]}
@@ -0,0 +1 @@
1
+ import '../../src/form-sections/date';
@@ -0,0 +1,134 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { html, fixture, expect } from '@open-wc/testing';
3
+ import '../../src/form-sections/date';
4
+ import { MonthlyPlan } from '../../src/models/plan';
5
+ const lastPaymentWasOnTheFirstOfThisMonth = new Date();
6
+ lastPaymentWasOnTheFirstOfThisMonth.setHours(0, 0, 0, 0);
7
+ lastPaymentWasOnTheFirstOfThisMonth.setDate(1);
8
+ console.log('lastPaymentWasOnTheFirstOfThisMonth', lastPaymentWasOnTheFirstOfThisMonth.toISOString());
9
+ const nextMonth = new Date();
10
+ nextMonth.setMonth(nextMonth.getMonth() + 1);
11
+ const nextPaymentFirstOfMonth = new Date(nextMonth);
12
+ nextPaymentFirstOfMonth.setHours(0, 0, 0, 0);
13
+ nextPaymentFirstOfMonth.setDate(1);
14
+ console.log('nextPaymentFirstOfMonth', nextPaymentFirstOfMonth.toISOString());
15
+ const twelveMonthsFromNow = new Date();
16
+ twelveMonthsFromNow.setMonth(twelveMonthsFromNow.getMonth() + 12);
17
+ const twoYearsFromNow = new Date();
18
+ twoYearsFromNow.setFullYear(twoYearsFromNow.getFullYear() + 2);
19
+ twoYearsFromNow.setHours(0, 0, 0, 0);
20
+ const tomorrow = new Date();
21
+ tomorrow.setDate(tomorrow.getDate() + 1);
22
+ const today = new Date();
23
+ today.setHours(0, 0, 0, 0);
24
+ const yesterday = new Date();
25
+ yesterday.setDate(yesterday.getDate() - 1);
26
+ yesterday.setHours(0, 0, 0, 0);
27
+ const plan = new MonthlyPlan({
28
+ token: 'a.va.lid.T0ken',
29
+ amount: 5,
30
+ currency: 'USD',
31
+ start_date: '2024-07-01 00:00:00',
32
+ is_test: true,
33
+ btdata: {
34
+ billingDayOfMonth: 22,
35
+ nextBillingDate: {
36
+ date: nextPaymentFirstOfMonth.toISOString(),
37
+ timezone_type: 3,
38
+ timezone: 'UTC',
39
+ },
40
+ lastBillingDate: {
41
+ date: lastPaymentWasOnTheFirstOfThisMonth.toISOString(),
42
+ timezone_type: 3,
43
+ timezone: 'UTC',
44
+ },
45
+ status: 'Active',
46
+ paymentMethodType: 'Venmo',
47
+ last4: null,
48
+ cardType: null,
49
+ expirationMonth: null,
50
+ expirationYear: null,
51
+ },
52
+ });
53
+ describe('<ia-mgc-edit-date>', () => {
54
+ it('can toggle form', async () => {
55
+ var _a, _b, _c, _d;
56
+ const el = await fixture(html `<ia-mgc-edit-date .plan=${plan}></ia-mgc-edit-date>`);
57
+ const amountLabel = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.current-date');
58
+ expect(amountLabel).to.exist;
59
+ expect(amountLabel === null || amountLabel === void 0 ? void 0 : amountLabel.textContent).to.contain(plan.nextBillingDateLocale);
60
+ const cta = (_b = el.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('ia-button#open-edit-date-form');
61
+ expect(cta).to.exist;
62
+ // does not show form
63
+ expect(el.form).to.not.exist;
64
+ // does show form on Edit... click
65
+ cta.shadowRoot.querySelector('button').click();
66
+ await el.updateComplete;
67
+ expect(el.form).to.exist;
68
+ expect(el.hasAttribute('currentlyediting')).to.be.true;
69
+ // form now displays
70
+ expect(el.form.getAttribute('id')).to.equal('edit-date');
71
+ const lastDateLabel = el.form.querySelector('#form-info-last-donation-date');
72
+ const nextDateLabel = el.form.querySelector('#form-info-next-donation-date');
73
+ expect(lastDateLabel).to.contain.text(plan.lastBillingDateLocale);
74
+ expect(nextDateLabel).to.contain.text(plan.nextBillingDateLocale);
75
+ const requestDateUpdateButton = el.form.querySelector('ia-button#edit-date');
76
+ expect(requestDateUpdateButton).to.exist;
77
+ expect(requestDateUpdateButton.hasAttribute('isdisabled')).to.be.true;
78
+ expect(el.form.getAttribute('id')).to.equal('edit-date');
79
+ // input has min and max range set
80
+ // min is tomorrow, max is 12 months from now
81
+ const dateInput = el.form.querySelector('input');
82
+ expect(dateInput).to.exist;
83
+ expect(dateInput.getAttribute('type')).to.equal('date');
84
+ expect(dateInput.getAttribute('min')).to.equal(`${tomorrow.getFullYear()}-${String(tomorrow.getMonth() + 1).padStart(2, '0')}-${String(tomorrow.getDate()).padStart(2, '0')}`);
85
+ expect(dateInput.getAttribute('max')).to.equal(`${twelveMonthsFromNow.getFullYear()}-${String(twelveMonthsFromNow.getMonth() + 1).padStart(2, '0')}-${String(twelveMonthsFromNow.getDate()).padStart(2, '0')}`);
86
+ // checks if input value is invalid
87
+ // date before today
88
+ dateInput.setAttribute('value', '2008-11-11');
89
+ dateInput.dispatchEvent(new Event('change'));
90
+ await el.updateComplete;
91
+ expect(el.errorMessage).to.contain('Date must be at least tomorrow.');
92
+ expect(requestDateUpdateButton.hasAttribute('isdisabled')).to.be.true;
93
+ // date within 12 months
94
+ const twoYearsFromNowStr = `${twoYearsFromNow.getFullYear()}-${String(twoYearsFromNow.getMonth() + 1).padStart(2, '0')}-${String(twoYearsFromNow.getDate()).padStart(2, '0')}`;
95
+ dateInput.setAttribute('value', twoYearsFromNowStr);
96
+ dateInput.dispatchEvent(new Event('change'));
97
+ await el.updateComplete;
98
+ expect(el.errorMessage).to.contain('New donation date must be within the next 12 months.');
99
+ expect(requestDateUpdateButton.hasAttribute('isdisabled')).to.be.true;
100
+ // sets warning message when chosen date is in the same month as last payment
101
+ const lastDayOfCurrentMonth = new Date();
102
+ lastDayOfCurrentMonth.setHours(0, 0, 0, 0);
103
+ lastDayOfCurrentMonth.setMonth(lastDayOfCurrentMonth.getMonth() + 1);
104
+ lastDayOfCurrentMonth.setDate(0);
105
+ const lastDayOfCurrentMonthStr = `${lastDayOfCurrentMonth.getFullYear()}-${String(lastDayOfCurrentMonth.getMonth() + 1).padStart(2, '0')}-${lastDayOfCurrentMonth.getDate()}`;
106
+ dateInput.setAttribute('value', lastDayOfCurrentMonthStr);
107
+ dateInput.dispatchEvent(new Event('change'));
108
+ await el.updateComplete;
109
+ expect(el.errorMessage).to.contain('');
110
+ expect(el.warningMessage).to.contain('New donation date is in the same month as your last payment.');
111
+ expect(el.allowEditing).to.be.true;
112
+ expect(requestDateUpdateButton.hasAttribute('isdisabled')).to.be.true;
113
+ expect(el.newDate).to.contain(`${lastDayOfCurrentMonth.getFullYear()}-${String(lastDayOfCurrentMonth.getMonth() + 1).padStart(2, '0')}-${String(lastDayOfCurrentMonth.getDate()).padStart(2, '0')}`);
114
+ // can submit when date is valid
115
+ const nextMonthStr = `${nextMonth.getFullYear()}-${String(nextMonth.getMonth() + 1).padStart(2, '0')}-${nextMonth.getDate()}`;
116
+ dateInput.setAttribute('value', nextMonthStr);
117
+ dateInput.dispatchEvent(new Event('change'));
118
+ await el.updateComplete;
119
+ expect(el.errorMessage).to.contain('');
120
+ expect(el.newDate).to.contain(nextMonthStr);
121
+ expect(el.allowEditing).to.be.true;
122
+ expect(requestDateUpdateButton.hasAttribute('isdisabled')).to.be.false;
123
+ console.log(' ~~~ last test, button: ', requestDateUpdateButton);
124
+ // clicking Update fires a Custom Event
125
+ el.addEventListener('updateDate', (event) => {
126
+ console.log('updateDate event received ####', event);
127
+ const { newDate } = event.detail;
128
+ expect(newDate).to.contain(nextMonthStr);
129
+ });
130
+ (_d = (_c = requestDateUpdateButton.shadowRoot) === null || _c === void 0 ? void 0 : _c.querySelector('button')) === null || _d === void 0 ? void 0 : _d.click();
131
+ await el.updateComplete;
132
+ });
133
+ });
134
+ //# sourceMappingURL=date.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.test.js","sourceRoot":"","sources":["../../../test/form-sections/date.test.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line import/no-extraneous-dependencies\nimport { html, fixture, expect } from '@open-wc/testing';\n\nimport '../../src/form-sections/date';\nimport type { MGCEditPlanDate } from '../../src/form-sections/date';\nimport { MonthlyPlan } from '../../src/models/plan';\nimport type { IauxButton } from '../../src/presentational/ia-button';\n\nconst lastPaymentWasOnTheFirstOfThisMonth = new Date();\nlastPaymentWasOnTheFirstOfThisMonth.setHours(0, 0, 0, 0);\nlastPaymentWasOnTheFirstOfThisMonth.setDate(1);\nconsole.log(\n 'lastPaymentWasOnTheFirstOfThisMonth',\n lastPaymentWasOnTheFirstOfThisMonth.toISOString()\n);\n\nconst nextMonth = new Date();\nnextMonth.setMonth(nextMonth.getMonth() + 1);\n\nconst nextPaymentFirstOfMonth = new Date(nextMonth);\nnextPaymentFirstOfMonth.setHours(0, 0, 0, 0);\nnextPaymentFirstOfMonth.setDate(1);\nconsole.log('nextPaymentFirstOfMonth', nextPaymentFirstOfMonth.toISOString());\n\nconst twelveMonthsFromNow = new Date();\ntwelveMonthsFromNow.setMonth(twelveMonthsFromNow.getMonth() + 12);\n\nconst twoYearsFromNow = new Date();\ntwoYearsFromNow.setFullYear(twoYearsFromNow.getFullYear() + 2);\ntwoYearsFromNow.setHours(0, 0, 0, 0);\n\nconst tomorrow = new Date();\ntomorrow.setDate(tomorrow.getDate() + 1);\n\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\nconst yesterday = new Date();\nyesterday.setDate(yesterday.getDate() - 1);\nyesterday.setHours(0, 0, 0, 0);\n\nconst plan = new MonthlyPlan({\n token: 'a.va.lid.T0ken',\n amount: 5,\n currency: 'USD',\n start_date: '2024-07-01 00:00:00',\n is_test: true,\n btdata: {\n billingDayOfMonth: 22,\n nextBillingDate: {\n date: nextPaymentFirstOfMonth.toISOString(),\n timezone_type: 3,\n timezone: 'UTC',\n },\n lastBillingDate: {\n date: lastPaymentWasOnTheFirstOfThisMonth.toISOString(),\n timezone_type: 3,\n timezone: 'UTC',\n },\n status: 'Active',\n paymentMethodType: 'Venmo',\n last4: null,\n cardType: null,\n expirationMonth: null,\n expirationYear: null,\n },\n});\n\ndescribe('<ia-mgc-edit-date>', () => {\n it('can toggle form', async () => {\n const el = await fixture<MGCEditPlanDate>(\n html`<ia-mgc-edit-date .plan=${plan}></ia-mgc-edit-date>`\n );\n\n const amountLabel = el.shadowRoot?.querySelector('.current-date');\n expect(amountLabel).to.exist;\n expect(amountLabel?.textContent).to.contain(plan.nextBillingDateLocale);\n\n const cta = el.shadowRoot?.querySelector('ia-button#open-edit-date-form');\n expect(cta).to.exist;\n\n // does not show form\n expect(el.form).to.not.exist;\n\n // does show form on Edit... click\n cta!.shadowRoot!.querySelector('button')!.click();\n await el.updateComplete;\n\n expect(el.form).to.exist;\n\n expect(el.hasAttribute('currentlyediting')).to.be.true;\n\n // form now displays\n expect(el.form.getAttribute('id')).to.equal('edit-date');\n\n const lastDateLabel = el.form.querySelector(\n '#form-info-last-donation-date'\n );\n const nextDateLabel = el.form.querySelector(\n '#form-info-next-donation-date'\n );\n\n expect(lastDateLabel).to.contain.text(plan.lastBillingDateLocale);\n expect(nextDateLabel).to.contain.text(plan.nextBillingDateLocale);\n\n const requestDateUpdateButton = el.form.querySelector(\n 'ia-button#edit-date'\n ) as IauxButton;\n expect(requestDateUpdateButton).to.exist;\n expect(requestDateUpdateButton!.hasAttribute('isdisabled')).to.be.true;\n\n expect(el.form.getAttribute('id')).to.equal('edit-date');\n\n // input has min and max range set\n // min is tomorrow, max is 12 months from now\n const dateInput = el.form.querySelector('input');\n expect(dateInput).to.exist;\n expect(dateInput!.getAttribute('type')).to.equal('date');\n expect(dateInput!.getAttribute('min')).to.equal(\n `${tomorrow.getFullYear()}-${String(tomorrow.getMonth() + 1).padStart(\n 2,\n '0'\n )}-${String(tomorrow.getDate()).padStart(2, '0')}`\n );\n expect(dateInput!.getAttribute('max')).to.equal(\n `${twelveMonthsFromNow.getFullYear()}-${String(\n twelveMonthsFromNow.getMonth() + 1\n ).padStart(2, '0')}-${String(twelveMonthsFromNow.getDate()).padStart(\n 2,\n '0'\n )}`\n );\n\n // checks if input value is invalid\n // date before today\n dateInput!.setAttribute('value', '2008-11-11');\n dateInput!.dispatchEvent(new Event('change'));\n await el.updateComplete;\n\n expect(el.errorMessage).to.contain('Date must be at least tomorrow.');\n expect(requestDateUpdateButton!.hasAttribute('isdisabled')).to.be.true;\n\n // date within 12 months\n const twoYearsFromNowStr = `${twoYearsFromNow.getFullYear()}-${String(\n twoYearsFromNow.getMonth() + 1\n ).padStart(2, '0')}-${String(twoYearsFromNow.getDate()).padStart(2, '0')}`;\n dateInput!.setAttribute('value', twoYearsFromNowStr);\n dateInput!.dispatchEvent(new Event('change'));\n await el.updateComplete;\n\n expect(el.errorMessage).to.contain(\n 'New donation date must be within the next 12 months.'\n );\n expect(requestDateUpdateButton!.hasAttribute('isdisabled')).to.be.true;\n\n // sets warning message when chosen date is in the same month as last payment\n const lastDayOfCurrentMonth = new Date();\n lastDayOfCurrentMonth.setHours(0, 0, 0, 0);\n lastDayOfCurrentMonth.setMonth(lastDayOfCurrentMonth.getMonth() + 1);\n lastDayOfCurrentMonth.setDate(0);\n\n const lastDayOfCurrentMonthStr = `${lastDayOfCurrentMonth.getFullYear()}-${String(\n lastDayOfCurrentMonth.getMonth() + 1\n ).padStart(2, '0')}-${lastDayOfCurrentMonth.getDate()}`;\n dateInput!.setAttribute('value', lastDayOfCurrentMonthStr);\n dateInput!.dispatchEvent(new Event('change'));\n await el.updateComplete;\n\n expect(el.errorMessage).to.contain('');\n expect(el.warningMessage).to.contain(\n 'New donation date is in the same month as your last payment.'\n );\n expect(el.allowEditing).to.be.true;\n expect(requestDateUpdateButton!.hasAttribute('isdisabled')).to.be.true;\n expect(el.newDate).to.contain(\n `${lastDayOfCurrentMonth.getFullYear()}-${String(\n lastDayOfCurrentMonth.getMonth() + 1\n ).padStart(2, '0')}-${String(lastDayOfCurrentMonth.getDate()).padStart(\n 2,\n '0'\n )}`\n );\n\n // can submit when date is valid\n const nextMonthStr = `${nextMonth.getFullYear()}-${String(\n nextMonth.getMonth() + 1\n ).padStart(2, '0')}-${nextMonth.getDate()}`;\n dateInput!.setAttribute('value', nextMonthStr);\n dateInput!.dispatchEvent(new Event('change'));\n\n await el.updateComplete;\n\n expect(el.errorMessage).to.contain('');\n expect(el.newDate).to.contain(nextMonthStr);\n expect(el.allowEditing).to.be.true;\n expect(requestDateUpdateButton!.hasAttribute('isdisabled')).to.be.false;\n console.log(' ~~~ last test, button: ', requestDateUpdateButton);\n\n // clicking Update fires a Custom Event\n el.addEventListener('updateDate', (event: Event) => {\n console.log('updateDate event received ####', event);\n const { newDate } = (event as CustomEvent).detail;\n expect(newDate).to.contain(nextMonthStr);\n });\n\n requestDateUpdateButton.shadowRoot?.querySelector('button')?.click();\n await el.updateComplete;\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/donation-monthly-portal",
3
- "version": "0.0.0-editdate.1",
3
+ "version": "0.0.0-editdate.2",
4
4
  "description": "The Internet Archive Monthly Portal",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "dist/index.js",
@@ -48,7 +48,7 @@ export class MGCEditPlanDate extends LitElement {
48
48
 
49
49
  updated(changed: PropertyValues) {
50
50
  if (changed.has('currentlyEditing') && this.currentlyEditing) {
51
- this.form.focus();
51
+ this.dateInput.focus();
52
52
  }
53
53
  }
54
54
 
@@ -61,13 +61,13 @@ export class MGCEditPlanDate extends LitElement {
61
61
  >
62
62
  ${!this.currentlyEditing
63
63
  ? html` <p class="current-date">
64
- ${this.plan?.nextBillingDate}
64
+ ${this.plan?.nextBillingDateLocale}
65
65
  <ia-mgc-update-status .status=${this.updateStatus}
66
66
  >${this.updateMessage}</ia-mgc-update-status
67
67
  >
68
68
  </p>
69
69
  <ia-button
70
- id="edit-date"
70
+ id="open-edit-date-form"
71
71
  class="ia-button link"
72
72
  .clickHandler=${() => {
73
73
  this.currentlyEditing = true;
@@ -99,18 +99,13 @@ export class MGCEditPlanDate extends LitElement {
99
99
  return;
100
100
  }
101
101
 
102
- (this.form.querySelector('ia-button#edit-date') as IauxButton).isDisabled =
103
- false;
104
-
102
+ this.allowEditing = false;
105
103
  await this.updateComplete;
106
104
  }
107
105
 
108
106
  /* Dispatches edit-date change request */
109
107
  requestDateUpdate(e: Event): void {
110
108
  e.preventDefault();
111
- console.log('<plan-date> - requestDateUpdate', {
112
- newValue: this.newDate,
113
- });
114
109
  this.dispatchEvent(
115
110
  new CustomEvent('updateDate', {
116
111
  detail: {
@@ -125,13 +120,11 @@ export class MGCEditPlanDate extends LitElement {
125
120
  this.clearInputField();
126
121
  this.clearStatusMessaging();
127
122
  this.currentlyEditing = false;
123
+ this.allowEditing = false;
128
124
  }
129
125
 
130
126
  clearInputField() {
131
- const input = this.form.querySelector(
132
- 'input[name="edit-date"]'
133
- ) as HTMLInputElement;
134
- input.value = '';
127
+ this.dateInput.value = '';
135
128
  this.newDate = undefined;
136
129
  }
137
130
 
@@ -157,26 +150,23 @@ export class MGCEditPlanDate extends LitElement {
157
150
  const today = new Date();
158
151
  const year = today.getFullYear() + 1; // Allow up to one year in the future
159
152
  const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
160
- const lastDayOfMonth = new Date(year, today.getMonth() + 1, 0).getDate();
161
- return `${year}-${month}-${lastDayOfMonth}`; // Last day of the month
153
+ return `${year}-${month}-${today.getDate()}`;
162
154
  }
163
155
 
164
156
  get editDateForm(): TemplateResult {
165
- console.log('editdate', {
166
- min: this.minDate,
167
- max: this.maxDate,
168
- plan: this.plan,
169
- nextBillingDate: this.plan?.nextBillingDate,
170
- lastBillingDate: this.plan?.lastBillingDateLocale,
171
- });
172
157
  return html`
173
158
  <section>
174
159
  <form id="edit-date">
175
- <p>Last donation date: ${this.plan?.lastBillingDateLocale}</p>
160
+ <p id="form-info-last-donation-date">
161
+ Last donation date: ${this.plan?.lastBillingDateLocale}
162
+ </p>
176
163
 
177
- <p>Next donation date: ${this.plan?.nextBillingDate}</p>
164
+ <p id="form-info-next-donation-date">
165
+ Next donation date: ${this.plan?.nextBillingDateLocale}
166
+ </p>
178
167
  <div class="date-holder">
179
168
  <input
169
+ required
180
170
  type="date"
181
171
  id="edit-date"
182
172
  name="edit-date"
@@ -184,30 +174,27 @@ export class MGCEditPlanDate extends LitElement {
184
174
  max=${this.maxDate}
185
175
  value=""
186
176
  @focus=${() => this.clearStatusMessaging()}
187
- @change=${async (e: Event) => {
177
+ @change=${async () => {
188
178
  this.clearStatusMessaging();
189
179
  await this.updateComplete;
190
180
 
181
+ const inputValue = this.dateInput.value;
191
182
  console.log(
192
- 'date changed',
193
- (e.target as HTMLInputElement).value
183
+ ' ----- date input changed ----- ',
184
+ inputValue,
185
+ this.errorMessage
194
186
  );
195
- console.log('date changed THIS', this);
196
187
 
197
- const inputValue = (e.target as HTMLInputElement).value;
198
188
  if (!inputValue) {
199
189
  this.errorMessage = 'Please enter a date';
200
- this.allowEditing = true;
190
+ this.allowEditing = false;
201
191
  return; // wait until date field returns a valid string
202
192
  }
203
193
 
204
194
  let validDate;
205
195
  try {
206
- validDate = new Date(
207
- (e.target as HTMLInputElement)?.value as string
208
- );
196
+ validDate = new Date(`${inputValue}T00:00:00`);
209
197
  } catch (error) {
210
- console.error('Invalid date format:', error);
211
198
  this.errorMessage =
212
199
  'Please enter a valid date format (YYYY-MM-DD)';
213
200
  return; // wait until date field returns a valid string
@@ -227,16 +214,10 @@ export class MGCEditPlanDate extends LitElement {
227
214
  return;
228
215
  }
229
216
 
230
- console.log('validDate', validDate);
231
-
232
217
  const newDate = new Date(validDate).toISOString();
233
218
  this.newDate = newDate;
234
- console.log('newDate', newDate);
235
-
236
- // Check if the date is in the past
237
219
 
238
220
  // Check if there has been a donation in the last month
239
-
240
221
  const hasLastDonationInfo =
241
222
  this.plan?.payment.lastBillingDate.date &&
242
223
  new Date(this.plan?.payment.lastBillingDate.date);
@@ -256,13 +237,25 @@ export class MGCEditPlanDate extends LitElement {
256
237
 
257
238
  if (isInLastMonth) {
258
239
  this.warningMessage =
259
- 'You have already made a donation this month. Is that cool with you?';
240
+ 'New donation date is in the same month as your last payment.';
260
241
  this.allowEditing = true;
261
242
  return;
262
243
  }
263
244
  }
264
- // Check if there has been a donation in the last 30 days
265
- console.log('newDate', newDate);
245
+
246
+ // Check if the new date is within the next 12 months
247
+ const twelveMonthsFromNow = new Date();
248
+ twelveMonthsFromNow.setFullYear(
249
+ twelveMonthsFromNow.getFullYear() + 1
250
+ );
251
+ twelveMonthsFromNow.setHours(0, 0, 0, 0);
252
+
253
+ if (chosenDate > twelveMonthsFromNow) {
254
+ this.errorMessage =
255
+ 'New donation date must be within the next 12 months.';
256
+ this.allowEditing = false;
257
+ return;
258
+ }
266
259
 
267
260
  this.allowEditing = true;
268
261
  }}
@@ -296,8 +289,6 @@ export class MGCEditPlanDate extends LitElement {
296
289
  (iaButton as IauxButton).isDisabled = true;
297
290
  await iaButton.updateComplete;
298
291
 
299
- // check if request is in range
300
-
301
292
  this.requestDateUpdate(e);
302
293
  }}
303
294
  >
@@ -308,8 +299,8 @@ export class MGCEditPlanDate extends LitElement {
308
299
  >
309
300
  </div>
310
301
  </div>
311
- <p class="error">${this.warningMessage}</p>
312
- <p class="error">${this.errorMessage}</p>
302
+ <p class="error warning-msg">${this.warningMessage}</p>
303
+ <p class="error error-msg">${this.errorMessage}</p>
313
304
  </form>
314
305
  </section>
315
306
  `;
@@ -75,7 +75,7 @@ export class MonthlyPlan {
75
75
  return date.toLocaleDateString();
76
76
  }
77
77
 
78
- get nextBillingDate(): string {
78
+ get nextBillingDateLocale(): string {
79
79
  const nextBillingDate = new Date(
80
80
  this.payment.nextBillingDate.date
81
81
  ).toLocaleDateString(undefined, {
package/src/plans.ts CHANGED
@@ -75,7 +75,7 @@ export class IauxMgcPlans extends LitElement {
75
75
  </div>
76
76
  <div class="next-donation">
77
77
  <h3>Next Donation</h3>
78
- <p>${plan.nextBillingDate}</p>
78
+ <p>${plan.nextBillingDateLocale}</p>
79
79
  </div>
80
80
  </div>
81
81
  ${this.planCTA(plan)}