@internetarchive/donation-form 0.5.16 → 0.5.17-a2

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,6 +22,8 @@ export declare class ContactForm extends LitElement {
22
22
  countryCodeAlpha2Field: HTMLSelectElement;
23
23
  errorMessage: HTMLDivElement;
24
24
  form: HTMLFormElement;
25
+ /** @keyof countries */
26
+ selectedCountry: string;
25
27
  reportValidity(): boolean;
26
28
  focus(): void;
27
29
  /** @inheritdoc */
@@ -1,6 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement, html, css } from 'lit';
3
- import { customElement, query } from 'lit/decorators.js';
3
+ import { customElement, property, query } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import { BillingInfo, CustomerInfo, DonorContactInfo, } from '@internetarchive/donation-form-data-models';
6
6
  import { SpacerOption } from '../badged-input';
@@ -10,6 +10,11 @@ import localePinImg from '@internetarchive/icon-locale-pin';
10
10
  import userIcon from '@internetarchive/icon-user';
11
11
  import { countries } from './countries';
12
12
  let ContactForm = class ContactForm extends LitElement {
13
+ constructor() {
14
+ super(...arguments);
15
+ /** @keyof countries */
16
+ this.selectedCountry = 'US';
17
+ }
13
18
  reportValidity() {
14
19
  const fieldBadgedInputs = [
15
20
  [this.emailField, this.emailBadgedInput],
@@ -140,14 +145,27 @@ let ContactForm = class ContactForm extends LitElement {
140
145
  `;
141
146
  }
142
147
  get countrySelectorTemplate() {
143
- const selectedCountry = 'US';
144
148
  return html `
145
149
  <badged-input>
146
- <select id="donation-contact-form-countryCodeAlpha2">
150
+ <select id="donation-contact-form-countryCodeAlpha2"
151
+ @change=${(e) => {
152
+ var _a, _b, _c, _d, _e, _f;
153
+ const currCountry = this.selectedCountry;
154
+ this.selectedCountry = ((_a = e.target) === null || _a === void 0 ? void 0 : _a.value) ? (_b = e.target) === null || _b === void 0 ? void 0 : _b.value : currCountry;
155
+ // update required visual cue on region/state/province
156
+ if (this.selectedCountry === 'US') {
157
+ (_c = this.regionBadgedInput) === null || _c === void 0 ? void 0 : _c.setAttribute('required', '');
158
+ (_d = this.regionField) === null || _d === void 0 ? void 0 : _d.setAttribute('required', '');
159
+ }
160
+ else {
161
+ (_e = this.regionBadgedInput) === null || _e === void 0 ? void 0 : _e.removeAttribute('required');
162
+ (_f = this.regionField) === null || _f === void 0 ? void 0 : _f.removeAttribute('required');
163
+ }
164
+ }}>
147
165
  ${Object.keys(countries).map(key => {
148
166
  const name = countries[key];
149
167
  return html `
150
- <option value=${key} ?selected=${key === selectedCountry}>${name}</option>
168
+ <option value=${key} ?selected=${key === this.selectedCountry}>${name}</option>
151
169
  `;
152
170
  })}
153
171
  </select>
@@ -397,6 +415,9 @@ __decorate([
397
415
  __decorate([
398
416
  query('form')
399
417
  ], ContactForm.prototype, "form", void 0);
418
+ __decorate([
419
+ property({ type: String })
420
+ ], ContactForm.prototype, "selectedCountry", void 0);
400
421
  ContactForm = __decorate([
401
422
  customElement('contact-form')
402
423
  ], ContactForm);
@@ -1 +1 @@
1
- {"version":3,"file":"contact-form.js","sourceRoot":"","sources":["../../../../src/form-elements/contact-form/contact-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, TemplateResult } from 'lit';\nimport { customElement, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport {\n BillingInfo,\n CustomerInfo,\n DonorContactInfo,\n} from '@internetarchive/donation-form-data-models';\nimport { AutoCompleteFieldOptions } from './autocomplete-field-options';\nimport { SpacerOption } from '../badged-input';\nimport { BadgedInput } from '../badged-input';\nimport '../badged-input';\n\nimport emailImg from '@internetarchive/icon-email';\nimport localePinImg from '@internetarchive/icon-locale-pin';\nimport userIcon from '@internetarchive/icon-user';\n\nimport { countries } from './countries';\n\n@customElement('contact-form')\nexport class ContactForm extends LitElement {\n @query('badged-input.donation-contact-form-email') emailBadgedInput!: BadgedInput;\n @query('#donation-contact-form-email') emailField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-first-name') firstNameBadgedInput!: BadgedInput;\n @query('#donation-contact-form-first-name') firstNameField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-last-name') lastNameBadgedInput!: BadgedInput;\n @query('#donation-contact-form-last-name') lastNameField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-postal-code') postalBadgedInput!: BadgedInput;\n @query('#donation-contact-form-postal-code') postalCodeField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-street-address')\n streetAddressBadgedInput!: BadgedInput;\n @query('#donation-contact-form-street-address') streetAddressField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-extended-address')\n extendedAddressBadgedInput!: BadgedInput;\n @query('#donation-contact-form-extended-address') extendedAddressField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-locality') localityBadgedInput!: BadgedInput;\n @query('#donation-contact-form-locality') localityField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-region') regionBadgedInput!: BadgedInput;\n @query('#donation-contact-form-region') regionField!: HTMLInputElement;\n\n @query('#donation-contact-form-countryCodeAlpha2') countryCodeAlpha2Field!: HTMLSelectElement;\n\n @query('#donation-contact-form-error-message') errorMessage!: HTMLDivElement;\n @query('form') form!: HTMLFormElement;\n\n reportValidity(): boolean {\n const fieldBadgedInputs: Array<[HTMLInputElement, BadgedInput]> = [\n [this.emailField, this.emailBadgedInput],\n [this.firstNameField, this.firstNameBadgedInput],\n [this.lastNameField, this.lastNameBadgedInput],\n [this.regionField, this.regionBadgedInput],\n [this.localityField, this.localityBadgedInput],\n [this.streetAddressField, this.streetAddressBadgedInput],\n [this.postalCodeField, this.postalBadgedInput],\n ];\n\n let isValid = true;\n fieldBadgedInputs.forEach(([inputElement, badgedInput]) => {\n const fieldValid = inputElement.checkValidity();\n isValid = isValid && fieldValid;\n if (!fieldValid) {\n badgedInput.error = true;\n }\n });\n\n if (!isValid) {\n this.errorMessage.innerText = 'Please enter any missing contact information below';\n } else {\n this.errorMessage.innerText = '';\n }\n\n return isValid;\n }\n\n focus(): void {\n this.emailField.focus();\n }\n\n /** @inheritdoc */\n render(): TemplateResult {\n return html`\n <div id=\"donation-contact-form-error-message\"></div>\n <form>\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-email',\n placeholder: 'Email',\n required: true,\n fieldType: 'email',\n name: 'email',\n autocomplete: 'email',\n maxlength: 255,\n icon: emailImg,\n })}\n </div>\n </fieldset>\n\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-first-name',\n placeholder: 'First name',\n name: 'fname',\n required: true,\n maxlength: 255,\n autocomplete: 'given-name',\n icon: userIcon,\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-last-name',\n placeholder: 'Last name',\n name: 'lname',\n autocomplete: 'family-name',\n required: true,\n maxlength: 255,\n })}\n </div>\n </fieldset>\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-street-address',\n placeholder: 'Address Line 1',\n required: true,\n autocomplete: 'address-line1',\n icon: localePinImg,\n name: 'street-address',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-extended-address',\n placeholder: 'Address Line 2 (optional)',\n autocomplete: 'address-line2',\n required: false,\n name: 'extended-address',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-locality',\n placeholder: 'City',\n autocomplete: 'address-level2',\n required: true,\n name: 'locality',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-region',\n placeholder: 'State / Province',\n autocomplete: 'address-level1',\n required: true,\n name: 'region',\n })}\n ${this.generateInput({\n id: 'donation-contact-form-postal-code',\n placeholder: 'Zip / Postal',\n autocomplete: 'postal-code',\n required: true,\n name: 'postal',\n maxlength: 9,\n // must start with a character, then may contain spaces\n validationPattern: '[a-zA-Z\\\\-\\\\d]+[a-zA-Z\\\\-\\\\d\\\\s]*',\n iconSpaceOption: SpacerOption.CompressSpace,\n })}\n </div>\n <div class=\"row\">\n ${this.countrySelectorTemplate}\n </div>\n </fieldset>\n </form>\n ${this.getStyles}\n `;\n }\n\n private get countrySelectorTemplate(): TemplateResult {\n const selectedCountry = 'US';\n\n return html`\n <badged-input>\n <select id=\"donation-contact-form-countryCodeAlpha2\">\n ${Object.keys(countries).map(key => {\n const name = countries[key];\n return html`\n <option value=${key} ?selected=${key === selectedCountry}>${name}</option>\n `;\n })}\n </select>\n </badged-input>\n `;\n }\n\n /** @inheritdoc */\n createRenderRoot(): this {\n // Render template without shadow DOM. Note that shadow DOM features like\n // encapsulated CSS and slots are unavailable.\n // Form autofill does not work properly in the shadow DOM\n // so we need our form fields in the light DOM\n return this;\n }\n\n // reset the error state when the user focuses the input\n private inputFocused(e: KeyboardEvent): void {\n this.errorMessage.innerText = '';\n const input = e.target as HTMLInputElement;\n const inputIdentifier = input.id;\n const badgedInput = this.querySelector(`badged-input.${inputIdentifier}`) as BadgedInput;\n badgedInput.error = false;\n }\n\n private generateInput(options: {\n id: string;\n placeholder: string;\n required?: boolean;\n fieldType?: 'text' | 'email';\n autocomplete?: AutoCompleteFieldOptions;\n maxlength?: number;\n name: string;\n icon?: TemplateResult;\n iconSpaceOption?: SpacerOption;\n validationPattern?: string;\n }): TemplateResult {\n const required = options.required ?? true;\n const fieldType = options.fieldType ?? 'text';\n const iconOption = options.iconSpaceOption ?? SpacerOption.LeaveSpace;\n\n return html`\n <badged-input\n class=${options.id}\n .icon=${options.icon}\n .iconSpaceOption=${iconOption}\n ?required=${options.required}\n >\n <label for=${options.id}>${options.placeholder}</label>\n <input\n type=${fieldType}\n id=${options.id}\n class=\"donation-contact-form-input\"\n name=${options.name}\n aria-label=${options.placeholder}\n placeholder=${options.placeholder}\n maxlength=${ifDefined(options.maxlength)}\n autocomplete=${options.autocomplete ?? 'on'}\n pattern=${ifDefined(options.validationPattern)}\n @focus=${this.inputFocused}\n ?required=${required}\n />\n </badged-input>\n `;\n }\n\n get donorContactInfo(): DonorContactInfo {\n return new DonorContactInfo({\n billing: this.billingInfo,\n customer: this.contactInfo,\n });\n }\n\n get billingInfo(): BillingInfo {\n const billingInfo = new BillingInfo({\n streetAddress: this.streetAddressField.value,\n extendedAddress: this.extendedAddressField.value,\n locality: this.localityField.value,\n region: this.regionField.value,\n postalCode: this.postalCodeField.value,\n countryCodeAlpha2: this.countryCodeAlpha2Field.value,\n });\n return billingInfo;\n }\n\n get contactInfo(): CustomerInfo {\n return new CustomerInfo({\n email: this.emailField.value,\n firstName: this.firstNameField.value,\n lastName: this.lastNameField.value,\n });\n }\n\n /**\n * This is not the normal LitElement styles block.\n *\n * This element uses the clear DOM instead of the shadow DOM so it can't use\n * the shadowRoot's isolated styling. This is a bit of a workaround to keep all of\n * the styling local by writing out our own <style> tag and just be careful about\n * the selectors since they will leak outside of this component.\n *\n * @readonly\n * @private\n * @type {TemplateResult}\n * @memberof ContactForm\n */\n private get getStyles(): TemplateResult {\n const noIconSpacerWidth = css`var(--badgedInputNoIconSpacerWidth, 3rem)`;\n const iconSpacerWidth = css`var(--badgedInputIconSpacerWidth, 5rem)`;\n\n const fieldSetSpacing = css`var(--fieldSetSpacing, 1rem)`;\n const fieldFontFamily = css`var(--fontFamily, \"Helvetica Neue\", Helvetica, Arial, sans-serif)`;\n const fieldFontSize = css`var(--contactFieldFontSize, 1.6rem)`;\n const fieldFontColor = css`var(--inputFieldFontColor, #333)`;\n\n const iconFieldWidth = css`calc(100% - ${iconSpacerWidth})`;\n const noIconFieldWidth = css`calc(100% - ${noIconSpacerWidth})`;\n\n return html`\n <style>\n /*\n **NOTE**\n This element is in the lightDOM so be sure to prefix all styles\n with \"contact-form\" so styles don't leak.\n */\n contact-form fieldset {\n border: 0;\n padding: 0;\n margin: 0;\n margin-bottom: ${fieldSetSpacing};\n background-color: white;\n }\n\n /* These 1px and 0 margins in the next few selectors are to account for the\n double outlines caused by the fields being right next to each other */\n contact-form .row {\n display: flex;\n margin: -1px 0 0 0;\n }\n\n contact-form fieldset .row:first-child {\n margin-top: 0;\n }\n\n contact-form badged-input.donation-contact-form-region {\n width: 60%;\n }\n\n contact-form badged-input.donation-contact-form-postal-code {\n width: 40%;\n }\n\n contact-form #donation-contact-form-region {\n width: ${iconFieldWidth};\n }\n\n contact-form #donation-contact-form-postal-code {\n width: ${noIconFieldWidth};\n }\n\n contact-form #donation-contact-form-error-message {\n color: red;\n font-size: 1.4rem;\n margin-bottom: 0.6rem;\n }\n\n contact-form #donation-contact-form-last-name {\n width: ${noIconFieldWidth};\n }\n\n /* only show for screen readers */\n contact-form label {\n position: absolute;\n left: -10000px;\n top: auto;\n width: 1px;\n height: 1px;\n overflow: hidden;\n }\n\n contact-form .donation-contact-form-input {\n width: ${iconFieldWidth};\n border: 0;\n outline: 0;\n background: transparent;\n font-weight: bold;\n color: ${fieldFontColor};\n font-size: ${fieldFontSize};\n padding: 0;\n font-family: ${fieldFontFamily};\n }\n\n contact-form .donation-contact-form-input::placeholder {\n color: revert;\n }\n\n contact-form #donation-contact-form-countryCodeAlpha2 {\n width: ${iconFieldWidth};\n height: 100%;\n box-sizing: border-box;\n font-weight: bold;\n font-size: ${fieldFontSize};\n font-family: ${fieldFontFamily};\n border: 0;\n background: #fff;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n }\n </style>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"contact-form.js","sourceRoot":"","sources":["../../../../src/form-elements/contact-form/contact-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, TemplateResult } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport {\n BillingInfo,\n CustomerInfo,\n DonorContactInfo,\n} from '@internetarchive/donation-form-data-models';\nimport { AutoCompleteFieldOptions } from './autocomplete-field-options';\nimport { SpacerOption } from '../badged-input';\nimport { BadgedInput } from '../badged-input';\nimport '../badged-input';\n\nimport emailImg from '@internetarchive/icon-email';\nimport localePinImg from '@internetarchive/icon-locale-pin';\nimport userIcon from '@internetarchive/icon-user';\n\nimport { countries } from './countries';\n\n@customElement('contact-form')\nexport class ContactForm extends LitElement {\n @query('badged-input.donation-contact-form-email') emailBadgedInput!: BadgedInput;\n @query('#donation-contact-form-email') emailField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-first-name') firstNameBadgedInput!: BadgedInput;\n @query('#donation-contact-form-first-name') firstNameField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-last-name') lastNameBadgedInput!: BadgedInput;\n @query('#donation-contact-form-last-name') lastNameField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-postal-code') postalBadgedInput!: BadgedInput;\n @query('#donation-contact-form-postal-code') postalCodeField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-street-address')\n streetAddressBadgedInput!: BadgedInput;\n @query('#donation-contact-form-street-address') streetAddressField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-extended-address')\n extendedAddressBadgedInput!: BadgedInput;\n @query('#donation-contact-form-extended-address') extendedAddressField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-locality') localityBadgedInput!: BadgedInput;\n @query('#donation-contact-form-locality') localityField!: HTMLInputElement;\n\n @query('badged-input.donation-contact-form-region') regionBadgedInput!: BadgedInput;\n @query('#donation-contact-form-region') regionField!: HTMLInputElement;\n\n @query('#donation-contact-form-countryCodeAlpha2') countryCodeAlpha2Field!: HTMLSelectElement;\n\n @query('#donation-contact-form-error-message') errorMessage!: HTMLDivElement;\n @query('form') form!: HTMLFormElement;\n\n /** @keyof countries */\n @property({ type: String }) selectedCountry = 'US';\n\n reportValidity(): boolean {\n const fieldBadgedInputs: Array<[HTMLInputElement, BadgedInput]> = [\n [this.emailField, this.emailBadgedInput],\n [this.firstNameField, this.firstNameBadgedInput],\n [this.lastNameField, this.lastNameBadgedInput],\n [this.regionField, this.regionBadgedInput],\n [this.localityField, this.localityBadgedInput],\n [this.streetAddressField, this.streetAddressBadgedInput],\n [this.postalCodeField, this.postalBadgedInput],\n ];\n\n let isValid = true;\n fieldBadgedInputs.forEach(([inputElement, badgedInput]) => {\n const fieldValid = inputElement.checkValidity();\n isValid = isValid && fieldValid;\n if (!fieldValid) {\n badgedInput.error = true;\n }\n });\n\n if (!isValid) {\n this.errorMessage.innerText = 'Please enter any missing contact information below';\n } else {\n this.errorMessage.innerText = '';\n }\n\n return isValid;\n }\n\n focus(): void {\n this.emailField.focus();\n }\n\n /** @inheritdoc */\n render(): TemplateResult {\n return html`\n <div id=\"donation-contact-form-error-message\"></div>\n <form>\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-email',\n placeholder: 'Email',\n required: true,\n fieldType: 'email',\n name: 'email',\n autocomplete: 'email',\n maxlength: 255,\n icon: emailImg,\n })}\n </div>\n </fieldset>\n\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-first-name',\n placeholder: 'First name',\n name: 'fname',\n required: true,\n maxlength: 255,\n autocomplete: 'given-name',\n icon: userIcon,\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-last-name',\n placeholder: 'Last name',\n name: 'lname',\n autocomplete: 'family-name',\n required: true,\n maxlength: 255,\n })}\n </div>\n </fieldset>\n <fieldset>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-street-address',\n placeholder: 'Address Line 1',\n required: true,\n autocomplete: 'address-line1',\n icon: localePinImg,\n name: 'street-address',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-extended-address',\n placeholder: 'Address Line 2 (optional)',\n autocomplete: 'address-line2',\n required: false,\n name: 'extended-address',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-locality',\n placeholder: 'City',\n autocomplete: 'address-level2',\n required: true,\n name: 'locality',\n })}\n </div>\n <div class=\"row\">\n ${this.generateInput({\n id: 'donation-contact-form-region',\n placeholder: 'State / Province',\n autocomplete: 'address-level1',\n required: true,\n name: 'region',\n })}\n ${this.generateInput({\n id: 'donation-contact-form-postal-code',\n placeholder: 'Zip / Postal',\n autocomplete: 'postal-code',\n required: true,\n name: 'postal',\n maxlength: 9,\n // must start with a character, then may contain spaces\n validationPattern: '[a-zA-Z\\\\-\\\\d]+[a-zA-Z\\\\-\\\\d\\\\s]*',\n iconSpaceOption: SpacerOption.CompressSpace,\n })}\n </div>\n <div class=\"row\">\n ${this.countrySelectorTemplate}\n </div>\n </fieldset>\n </form>\n ${this.getStyles}\n `;\n }\n\n private get countrySelectorTemplate(): TemplateResult {\n return html`\n <badged-input>\n <select id=\"donation-contact-form-countryCodeAlpha2\"\n @change=${(e: Event) => {\n const currCountry = this.selectedCountry;\n this.selectedCountry = (e.target as HTMLInputElement)?.value ? (e.target as HTMLInputElement)?.value as string : currCountry;\n // update required visual cue on region/state/province\n if (this.selectedCountry === 'US') {\n this.regionBadgedInput?.setAttribute('required', '');\n this.regionField?.setAttribute('required', '');\n } else {\n this.regionBadgedInput?.removeAttribute('required');\n this.regionField?.removeAttribute('required');\n }\n }}>\n ${Object.keys(countries).map(key => {\n const name = countries[key];\n return html`\n <option value=${key} ?selected=${key === this.selectedCountry}>${name}</option>\n `;\n })}\n </select>\n </badged-input>\n `;\n }\n\n /** @inheritdoc */\n createRenderRoot(): this {\n // Render template without shadow DOM. Note that shadow DOM features like\n // encapsulated CSS and slots are unavailable.\n // Form autofill does not work properly in the shadow DOM\n // so we need our form fields in the light DOM\n return this;\n }\n\n // reset the error state when the user focuses the input\n private inputFocused(e: KeyboardEvent): void {\n this.errorMessage.innerText = '';\n const input = e.target as HTMLInputElement;\n const inputIdentifier = input.id;\n const badgedInput = this.querySelector(`badged-input.${inputIdentifier}`) as BadgedInput;\n badgedInput.error = false;\n }\n\n private generateInput(options: {\n id: string;\n placeholder: string;\n required?: boolean;\n fieldType?: 'text' | 'email';\n autocomplete?: AutoCompleteFieldOptions;\n maxlength?: number;\n name: string;\n icon?: TemplateResult;\n iconSpaceOption?: SpacerOption;\n validationPattern?: string;\n }): TemplateResult {\n const required = options.required ?? true;\n const fieldType = options.fieldType ?? 'text';\n const iconOption = options.iconSpaceOption ?? SpacerOption.LeaveSpace;\n\n return html`\n <badged-input\n class=${options.id}\n .icon=${options.icon}\n .iconSpaceOption=${iconOption}\n ?required=${options.required}\n >\n <label for=${options.id}>${options.placeholder}</label>\n <input\n type=${fieldType}\n id=${options.id}\n class=\"donation-contact-form-input\"\n name=${options.name}\n aria-label=${options.placeholder}\n placeholder=${options.placeholder}\n maxlength=${ifDefined(options.maxlength)}\n autocomplete=${options.autocomplete ?? 'on'}\n pattern=${ifDefined(options.validationPattern)}\n @focus=${this.inputFocused}\n ?required=${required}\n />\n </badged-input>\n `;\n }\n\n get donorContactInfo(): DonorContactInfo {\n return new DonorContactInfo({\n billing: this.billingInfo,\n customer: this.contactInfo,\n });\n }\n\n get billingInfo(): BillingInfo {\n const billingInfo = new BillingInfo({\n streetAddress: this.streetAddressField.value,\n extendedAddress: this.extendedAddressField.value,\n locality: this.localityField.value,\n region: this.regionField.value,\n postalCode: this.postalCodeField.value,\n countryCodeAlpha2: this.countryCodeAlpha2Field.value,\n });\n return billingInfo;\n }\n\n get contactInfo(): CustomerInfo {\n return new CustomerInfo({\n email: this.emailField.value,\n firstName: this.firstNameField.value,\n lastName: this.lastNameField.value,\n });\n }\n\n /**\n * This is not the normal LitElement styles block.\n *\n * This element uses the clear DOM instead of the shadow DOM so it can't use\n * the shadowRoot's isolated styling. This is a bit of a workaround to keep all of\n * the styling local by writing out our own <style> tag and just be careful about\n * the selectors since they will leak outside of this component.\n *\n * @readonly\n * @private\n * @type {TemplateResult}\n * @memberof ContactForm\n */\n private get getStyles(): TemplateResult {\n const noIconSpacerWidth = css`var(--badgedInputNoIconSpacerWidth, 3rem)`;\n const iconSpacerWidth = css`var(--badgedInputIconSpacerWidth, 5rem)`;\n\n const fieldSetSpacing = css`var(--fieldSetSpacing, 1rem)`;\n const fieldFontFamily = css`var(--fontFamily, \"Helvetica Neue\", Helvetica, Arial, sans-serif)`;\n const fieldFontSize = css`var(--contactFieldFontSize, 1.6rem)`;\n const fieldFontColor = css`var(--inputFieldFontColor, #333)`;\n\n const iconFieldWidth = css`calc(100% - ${iconSpacerWidth})`;\n const noIconFieldWidth = css`calc(100% - ${noIconSpacerWidth})`;\n\n return html`\n <style>\n /*\n **NOTE**\n This element is in the lightDOM so be sure to prefix all styles\n with \"contact-form\" so styles don't leak.\n */\n contact-form fieldset {\n border: 0;\n padding: 0;\n margin: 0;\n margin-bottom: ${fieldSetSpacing};\n background-color: white;\n }\n\n /* These 1px and 0 margins in the next few selectors are to account for the\n double outlines caused by the fields being right next to each other */\n contact-form .row {\n display: flex;\n margin: -1px 0 0 0;\n }\n\n contact-form fieldset .row:first-child {\n margin-top: 0;\n }\n\n contact-form badged-input.donation-contact-form-region {\n width: 60%;\n }\n\n contact-form badged-input.donation-contact-form-postal-code {\n width: 40%;\n }\n\n contact-form #donation-contact-form-region {\n width: ${iconFieldWidth};\n }\n\n contact-form #donation-contact-form-postal-code {\n width: ${noIconFieldWidth};\n }\n\n contact-form #donation-contact-form-error-message {\n color: red;\n font-size: 1.4rem;\n margin-bottom: 0.6rem;\n }\n\n contact-form #donation-contact-form-last-name {\n width: ${noIconFieldWidth};\n }\n\n /* only show for screen readers */\n contact-form label {\n position: absolute;\n left: -10000px;\n top: auto;\n width: 1px;\n height: 1px;\n overflow: hidden;\n }\n\n contact-form .donation-contact-form-input {\n width: ${iconFieldWidth};\n border: 0;\n outline: 0;\n background: transparent;\n font-weight: bold;\n color: ${fieldFontColor};\n font-size: ${fieldFontSize};\n padding: 0;\n font-family: ${fieldFontFamily};\n }\n\n contact-form .donation-contact-form-input::placeholder {\n color: revert;\n }\n\n contact-form #donation-contact-form-countryCodeAlpha2 {\n width: ${iconFieldWidth};\n height: 100%;\n box-sizing: border-box;\n font-weight: bold;\n font-size: ${fieldFontSize};\n font-family: ${fieldFontFamily};\n border: 0;\n background: #fff;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n }\n </style>\n `;\n }\n}\n"]}
@@ -58,6 +58,17 @@ describe('Donation Form Controller', () => {
58
58
  yield elementUpdated(donationForm);
59
59
  yield promisedSleep(100);
60
60
  const contactForm = document.querySelector('contact-form');
61
+ // // check Zip Code Requirements
62
+ // expect((contactForm.querySelector('#donation-contact-form-countryCodeAlpha2') as HTMLSelectElement).value).to.equal('US');
63
+ // expect((contactForm.querySelector('#donation-contact-form-postal-code') as HTMLInputElement).hasAttribute('required')).to.be.true;
64
+ // // change country to outside US
65
+ // contactForm.querySelector('#donation-contact-form-countryCodeAlpha2')!.querySelector('option[value="AX"]')?.setAttribute('selected', 'selected');
66
+ // await promisedSleep(500);
67
+ // // country is now set to Aland Islands
68
+ // expect((contactForm.querySelector('#donation-contact-form-countryCodeAlpha2') as HTMLSelectElement).value).to.equal('AX');
69
+ // // zip input is no longer required
70
+ // expect((contactForm.querySelector('#donation-contact-form-postal-code') as HTMLInputElement).hasAttribute('required')).to.equal(333333);
71
+ // // check validation
61
72
  yield fillInContactForm(contactForm);
62
73
  // verify the Donate button is still disabled
63
74
  const donateButton = (_c = donationForm === null || donationForm === void 0 ? void 0 : donationForm.shadowRoot) === null || _c === void 0 ? void 0 : _c.querySelector('#donate-button');
@@ -1 +1 @@
1
- {"version":3,"file":"donation-form-controller.test.js","sourceRoot":"","sources":["../../../test/tests/donation-form-controller.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { html, fixture, expect, elementUpdated, oneEvent } from '@open-wc/testing';\n\nimport '../../src/donation-form-controller';\nimport { DonationFormController } from '../../src/donation-form-controller';\nimport { MockGrecaptcha, MockGrecaptchaMode } from '../mocks/payment-clients/mock-grecaptcha';\nimport { HostingEnvironment } from '../../src/braintree-manager/braintree-interfaces';\nimport { MockEndpointManager } from '../mocks/mock-endpoint-manager';\nimport { MockPaymentClients } from '../mocks/mock-payment-clients';\nimport { ContactForm } from '../../src/form-elements/contact-form/contact-form';\nimport { fillInContactForm } from '../helpers/fillInContactForm';\nimport { promisedSleep } from '../../src/util/promisedSleep';\nimport { MockModalManager } from '../mocks/mock-modal-manager';\nimport { MockHostedFieldsClient } from '../mocks/payment-clients/mock-hostedfields-client';\nimport { DonationForm } from '../../src/donation-form';\nimport { PaymentSelector } from '../../src/form-elements/payment-selector';\nimport { DonationFormHeader } from '../../src/form-elements/header/donation-form-header';\nimport { DonationFormEditDonation } from '@internetarchive/donation-form-edit-donation';\nimport { MockPaymentFlowHandlers } from '../mocks/flow-handlers/mock-payment-flow-handlers';\nimport { MockAnalyticsManager } from '@internetarchive/analytics-manager/dist/test/mock-analytics-manager';\n\ndescribe('Donation Form Controller', () => {\n beforeEach(() => {\n (window['grecaptcha' as any] as any) = new MockGrecaptcha(MockGrecaptchaMode.Success);\n });\n\n afterEach(() => {\n delete window['grecaptcha' as any];\n });\n\n it('has no shadowRoot', async () => {\n const el = (await fixture(html`\n <donation-form-controller></donation-form-controller>\n `)) as DonationFormController;\n\n expect(el.shadowRoot).to.equal(null);\n });\n\n it('can submit a donation', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const controller = (await fixture(html`\n <donation-form-controller .analyticsHandler=${mockAnalytics}> </donation-form-controller>\n `)) as DonationFormController;\n\n // configure the donation-form-controller\n const recaptchaElement = (await fixture(\n html`\n <div></div>\n `,\n )) as HTMLElement;\n const endpointManager = new MockEndpointManager();\n const paymentClients = new MockPaymentClients();\n const modalManager = new MockModalManager();\n controller.paymentClients = paymentClients;\n controller.modalManager = modalManager;\n controller.environment = HostingEnvironment.Development;\n controller.recaptchaElement = recaptchaElement;\n controller.endpointManager = endpointManager;\n controller.braintreeAuthToken = 'foo';\n controller.recaptchaSiteKey = 'bar';\n controller.venmoProfileId = 'baz';\n controller.referrer = 'test-referrer';\n controller.loggedInUser = 'test-user';\n\n // grab some internal elements to interact with\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const paymentSelector: PaymentSelector = donationForm?.shadowRoot?.querySelector(\n 'payment-selector',\n ) as PaymentSelector;\n const creditCardButton = paymentSelector?.shadowRoot?.querySelector('.credit-card-button');\n\n // click on the credit card button\n const ccClickEvent = new MouseEvent('click');\n creditCardButton?.dispatchEvent(ccClickEvent);\n\n // clicking on the credit card button will show the contact form so wait for it to be updated\n await elementUpdated(donationForm);\n await promisedSleep(100);\n const contactForm = document.querySelector('contact-form') as ContactForm;\n await fillInContactForm(contactForm);\n\n // verify the Donate button is still disabled\n const donateButton = donationForm?.shadowRoot?.querySelector(\n '#donate-button',\n ) as HTMLButtonElement;\n\n // simulates after the user has input all of the credit card fields\n const hostedFields = (await paymentClients.hostedFields.get()) as MockHostedFieldsClient;\n hostedFields.emitValidityChangedEvent(true);\n await promisedSleep(100);\n\n // verify that the donate button has become enabled and no request has been submitted\n expect(donateButton.disabled).to.equal(false);\n expect(endpointManager.requestSubmitted).to.equal(undefined);\n\n // click the donate button\n const donateClickEvent = new MouseEvent('click');\n donateButton?.dispatchEvent(donateClickEvent);\n await promisedSleep(100);\n\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowStarted');\n\n // verify that a payload has been requested to be submitted to the backend\n expect(endpointManager.requestSubmitted).to.not.equal(undefined);\n });\n\n it('sends Viewed analytics when it first updates', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n expect(mockAnalytics.sendEventOptions?.category).to.equal(analyticsCategory);\n expect(mockAnalytics.sendEventOptions?.action).to.equal('Viewed');\n });\n\n it('sends DonationInfoChanged analytics when donation info changes', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const donationHeader = donationForm.shadowRoot?.querySelector(\n 'donation-form-header',\n ) as DonationFormHeader;\n const editDonation = donationHeader?.shadowRoot?.querySelector(\n 'donation-form-edit-donation',\n ) as DonationFormEditDonation;\n const monthlyOption = editDonation?.shadowRoot?.querySelector('#donationType-monthly-option');\n const clickEvent = new MouseEvent('click');\n monthlyOption?.dispatchEvent(clickEvent);\n\n expect(mockAnalytics.sendEventOptions?.category).to.equal(analyticsCategory);\n expect(mockAnalytics.sendEventOptions?.action).to.equal('DonationInfoChanged');\n });\n\n it('sends ProviderSelected analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const paymentSelector = donationForm.shadowRoot?.querySelector(\n 'payment-selector',\n ) as PaymentSelector;\n\n // on the first payment provider chosen, the previousPaymentProvider is undefined\n const creditCardButton = paymentSelector.shadowRoot?.querySelector(\n '.credit-card-button',\n ) as HTMLButtonElement;\n setTimeout(() => {\n const ccClickEvent = new MouseEvent('click');\n creditCardButton.dispatchEvent(ccClickEvent);\n });\n await oneEvent(donationForm, 'paymentProviderSelected');\n expect(mockAnalytics.sendEventOptions?.action).to.equal('ProviderFirstSelected-CreditCard');\n\n // on subsequent payment provider choices, the previousPaymentProvider is populated\n const venmoButton = paymentSelector.shadowRoot?.querySelector('.venmo') as HTMLButtonElement;\n setTimeout(() => {\n const venmoClickEvent = new MouseEvent('click');\n venmoButton.dispatchEvent(venmoClickEvent);\n });\n await oneEvent(donationForm, 'paymentProviderSelected');\n expect(mockAnalytics.sendEventOptions?.action).to.equal('ProviderChangedTo-Venmo');\n });\n\n it('sends PaymentFlowCancelled analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const flowHandlers = new MockPaymentFlowHandlers();\n donationForm.paymentFlowHandlers = flowHandlers;\n await elementUpdated(donationForm);\n await promisedSleep(250);\n flowHandlers.paypalHandler.emitPaymentCancelledEvent();\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowCancelled');\n expect(mockAnalytics.sendEventOptions?.label).to.equal('PayPal');\n });\n\n it('sends PaymentFlowError analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const flowHandlers = new MockPaymentFlowHandlers();\n donationForm.paymentFlowHandlers = flowHandlers;\n await elementUpdated(donationForm);\n await promisedSleep(250);\n flowHandlers.paypalHandler.emitPaymentErrorEvent();\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowError');\n expect(mockAnalytics.sendEventOptions?.label).to.equal('PayPal-foo-error');\n });\n});\n"]}
1
+ {"version":3,"file":"donation-form-controller.test.js","sourceRoot":"","sources":["../../../test/tests/donation-form-controller.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { html, fixture, expect, elementUpdated, oneEvent } from '@open-wc/testing';\n\nimport '../../src/donation-form-controller';\nimport { DonationFormController } from '../../src/donation-form-controller';\nimport { MockGrecaptcha, MockGrecaptchaMode } from '../mocks/payment-clients/mock-grecaptcha';\nimport { HostingEnvironment } from '../../src/braintree-manager/braintree-interfaces';\nimport { MockEndpointManager } from '../mocks/mock-endpoint-manager';\nimport { MockPaymentClients } from '../mocks/mock-payment-clients';\nimport { ContactForm } from '../../src/form-elements/contact-form/contact-form';\nimport { fillInContactForm } from '../helpers/fillInContactForm';\nimport { promisedSleep } from '../../src/util/promisedSleep';\nimport { MockModalManager } from '../mocks/mock-modal-manager';\nimport { MockHostedFieldsClient } from '../mocks/payment-clients/mock-hostedfields-client';\nimport { DonationForm } from '../../src/donation-form';\nimport { PaymentSelector } from '../../src/form-elements/payment-selector';\nimport { DonationFormHeader } from '../../src/form-elements/header/donation-form-header';\nimport { DonationFormEditDonation } from '@internetarchive/donation-form-edit-donation';\nimport { MockPaymentFlowHandlers } from '../mocks/flow-handlers/mock-payment-flow-handlers';\nimport { MockAnalyticsManager } from '@internetarchive/analytics-manager/dist/test/mock-analytics-manager';\n\ndescribe('Donation Form Controller', () => {\n beforeEach(() => {\n (window['grecaptcha' as any] as any) = new MockGrecaptcha(MockGrecaptchaMode.Success);\n });\n\n afterEach(() => {\n delete window['grecaptcha' as any];\n });\n\n it('has no shadowRoot', async () => {\n const el = (await fixture(html`\n <donation-form-controller></donation-form-controller>\n `)) as DonationFormController;\n\n expect(el.shadowRoot).to.equal(null);\n });\n\n it('can submit a donation', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const controller = (await fixture(html`\n <donation-form-controller .analyticsHandler=${mockAnalytics}> </donation-form-controller>\n `)) as DonationFormController;\n\n // configure the donation-form-controller\n const recaptchaElement = (await fixture(\n html`\n <div></div>\n `,\n )) as HTMLElement;\n const endpointManager = new MockEndpointManager();\n const paymentClients = new MockPaymentClients();\n const modalManager = new MockModalManager();\n controller.paymentClients = paymentClients;\n controller.modalManager = modalManager;\n controller.environment = HostingEnvironment.Development;\n controller.recaptchaElement = recaptchaElement;\n controller.endpointManager = endpointManager;\n controller.braintreeAuthToken = 'foo';\n controller.recaptchaSiteKey = 'bar';\n controller.venmoProfileId = 'baz';\n controller.referrer = 'test-referrer';\n controller.loggedInUser = 'test-user';\n\n // grab some internal elements to interact with\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const paymentSelector: PaymentSelector = donationForm?.shadowRoot?.querySelector(\n 'payment-selector',\n ) as PaymentSelector;\n const creditCardButton = paymentSelector?.shadowRoot?.querySelector('.credit-card-button');\n\n // click on the credit card button\n const ccClickEvent = new MouseEvent('click');\n creditCardButton?.dispatchEvent(ccClickEvent);\n\n // clicking on the credit card button will show the contact form so wait for it to be updated\n await elementUpdated(donationForm);\n await promisedSleep(100);\n const contactForm = document.querySelector('contact-form') as ContactForm;\n\n // // check Zip Code Requirements\n\n // expect((contactForm.querySelector('#donation-contact-form-countryCodeAlpha2') as HTMLSelectElement).value).to.equal('US');\n // expect((contactForm.querySelector('#donation-contact-form-postal-code') as HTMLInputElement).hasAttribute('required')).to.be.true;\n\n // // change country to outside US\n // contactForm.querySelector('#donation-contact-form-countryCodeAlpha2')!.querySelector('option[value=\"AX\"]')?.setAttribute('selected', 'selected');\n // await promisedSleep(500);\n\n // // country is now set to Aland Islands\n // expect((contactForm.querySelector('#donation-contact-form-countryCodeAlpha2') as HTMLSelectElement).value).to.equal('AX');\n\n // // zip input is no longer required\n // expect((contactForm.querySelector('#donation-contact-form-postal-code') as HTMLInputElement).hasAttribute('required')).to.equal(333333);\n\n // // check validation\n\n await fillInContactForm(contactForm);\n\n // verify the Donate button is still disabled\n const donateButton = donationForm?.shadowRoot?.querySelector(\n '#donate-button',\n ) as HTMLButtonElement;\n\n // simulates after the user has input all of the credit card fields\n const hostedFields = (await paymentClients.hostedFields.get()) as MockHostedFieldsClient;\n hostedFields.emitValidityChangedEvent(true);\n await promisedSleep(100);\n\n // verify that the donate button has become enabled and no request has been submitted\n expect(donateButton.disabled).to.equal(false);\n expect(endpointManager.requestSubmitted).to.equal(undefined);\n\n // click the donate button\n const donateClickEvent = new MouseEvent('click');\n donateButton?.dispatchEvent(donateClickEvent);\n await promisedSleep(100);\n\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowStarted');\n\n // verify that a payload has been requested to be submitted to the backend\n expect(endpointManager.requestSubmitted).to.not.equal(undefined);\n });\n\n it('sends Viewed analytics when it first updates', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n expect(mockAnalytics.sendEventOptions?.category).to.equal(analyticsCategory);\n expect(mockAnalytics.sendEventOptions?.action).to.equal('Viewed');\n });\n\n it('sends DonationInfoChanged analytics when donation info changes', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const donationHeader = donationForm.shadowRoot?.querySelector(\n 'donation-form-header',\n ) as DonationFormHeader;\n const editDonation = donationHeader?.shadowRoot?.querySelector(\n 'donation-form-edit-donation',\n ) as DonationFormEditDonation;\n const monthlyOption = editDonation?.shadowRoot?.querySelector('#donationType-monthly-option');\n const clickEvent = new MouseEvent('click');\n monthlyOption?.dispatchEvent(clickEvent);\n\n expect(mockAnalytics.sendEventOptions?.category).to.equal(analyticsCategory);\n expect(mockAnalytics.sendEventOptions?.action).to.equal('DonationInfoChanged');\n });\n\n it('sends ProviderSelected analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const paymentSelector = donationForm.shadowRoot?.querySelector(\n 'payment-selector',\n ) as PaymentSelector;\n\n // on the first payment provider chosen, the previousPaymentProvider is undefined\n const creditCardButton = paymentSelector.shadowRoot?.querySelector(\n '.credit-card-button',\n ) as HTMLButtonElement;\n setTimeout(() => {\n const ccClickEvent = new MouseEvent('click');\n creditCardButton.dispatchEvent(ccClickEvent);\n });\n await oneEvent(donationForm, 'paymentProviderSelected');\n expect(mockAnalytics.sendEventOptions?.action).to.equal('ProviderFirstSelected-CreditCard');\n\n // on subsequent payment provider choices, the previousPaymentProvider is populated\n const venmoButton = paymentSelector.shadowRoot?.querySelector('.venmo') as HTMLButtonElement;\n setTimeout(() => {\n const venmoClickEvent = new MouseEvent('click');\n venmoButton.dispatchEvent(venmoClickEvent);\n });\n await oneEvent(donationForm, 'paymentProviderSelected');\n expect(mockAnalytics.sendEventOptions?.action).to.equal('ProviderChangedTo-Venmo');\n });\n\n it('sends PaymentFlowCancelled analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const flowHandlers = new MockPaymentFlowHandlers();\n donationForm.paymentFlowHandlers = flowHandlers;\n await elementUpdated(donationForm);\n await promisedSleep(250);\n flowHandlers.paypalHandler.emitPaymentCancelledEvent();\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowCancelled');\n expect(mockAnalytics.sendEventOptions?.label).to.equal('PayPal');\n });\n\n it('sends PaymentFlowError analytics', async () => {\n const mockAnalytics = new MockAnalyticsManager();\n const analyticsCategory = 'FooCategory';\n const controller = (await fixture(html`\n <donation-form-controller\n ?showCreditCardButtonText=${true}\n .analyticsCategory=${analyticsCategory}\n .analyticsHandler=${mockAnalytics}\n >\n </donation-form-controller>\n `)) as DonationFormController;\n\n const donationForm: DonationForm = controller.querySelector('donation-form') as DonationForm;\n const flowHandlers = new MockPaymentFlowHandlers();\n donationForm.paymentFlowHandlers = flowHandlers;\n await elementUpdated(donationForm);\n await promisedSleep(250);\n flowHandlers.paypalHandler.emitPaymentErrorEvent();\n expect(mockAnalytics.sendEventOptions?.action).to.equal('PaymentFlowError');\n expect(mockAnalytics.sendEventOptions?.label).to.equal('PayPal-foo-error');\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/donation-form",
3
- "version": "0.5.16",
3
+ "version": "0.5.17-a2",
4
4
  "description": "The Internet Archive Donation Form",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "dist/index.js",
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, css, TemplateResult } from 'lit';
2
- import { customElement, query } from 'lit/decorators.js';
2
+ import { customElement, property, query } from 'lit/decorators.js';
3
3
  import { ifDefined } from 'lit/directives/if-defined.js';
4
4
 
5
5
  import {
@@ -51,6 +51,9 @@ export class ContactForm extends LitElement {
51
51
  @query('#donation-contact-form-error-message') errorMessage!: HTMLDivElement;
52
52
  @query('form') form!: HTMLFormElement;
53
53
 
54
+ /** @keyof countries */
55
+ @property({ type: String }) selectedCountry = 'US';
56
+
54
57
  reportValidity(): boolean {
55
58
  const fieldBadgedInputs: Array<[HTMLInputElement, BadgedInput]> = [
56
59
  [this.emailField, this.emailBadgedInput],
@@ -186,15 +189,25 @@ export class ContactForm extends LitElement {
186
189
  }
187
190
 
188
191
  private get countrySelectorTemplate(): TemplateResult {
189
- const selectedCountry = 'US';
190
-
191
192
  return html`
192
193
  <badged-input>
193
- <select id="donation-contact-form-countryCodeAlpha2">
194
+ <select id="donation-contact-form-countryCodeAlpha2"
195
+ @change=${(e: Event) => {
196
+ const currCountry = this.selectedCountry;
197
+ this.selectedCountry = (e.target as HTMLInputElement)?.value ? (e.target as HTMLInputElement)?.value as string : currCountry;
198
+ // update required visual cue on region/state/province
199
+ if (this.selectedCountry === 'US') {
200
+ this.regionBadgedInput?.setAttribute('required', '');
201
+ this.regionField?.setAttribute('required', '');
202
+ } else {
203
+ this.regionBadgedInput?.removeAttribute('required');
204
+ this.regionField?.removeAttribute('required');
205
+ }
206
+ }}>
194
207
  ${Object.keys(countries).map(key => {
195
208
  const name = countries[key];
196
209
  return html`
197
- <option value=${key} ?selected=${key === selectedCountry}>${name}</option>
210
+ <option value=${key} ?selected=${key === this.selectedCountry}>${name}</option>
198
211
  `;
199
212
  })}
200
213
  </select>