@bcrs-shared-components/base-address 2.0.11 → 3.0.0

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.
package/BaseAddress.vue CHANGED
@@ -1,16 +1,3 @@
1
- //
2
- // Copyright © 2020 Province of British Columbia
3
- //
4
- // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5
- // the License. You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10
- // an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11
- // specific language governing permissions and limitations under the License.
12
- //
13
-
14
1
  <template>
15
2
  <div class="base-address">
16
3
  <!-- Display fields -->
@@ -19,36 +6,30 @@
19
6
  v-if="!editing"
20
7
  class="address-block"
21
8
  >
22
- <div class="address-block__info pre-line">
23
- <div class="address-block__info-row street-address">
9
+ <div class="address-block__info pre-wrap">
10
+ <p class="address-block__info-row">
24
11
  {{ addressLocal.streetAddress }}
25
- </div>
26
-
27
- <div class="address-block__info-row street-address-additional">
12
+ </p>
13
+ <p
14
+ v-if="addressLocal.streetAddressAdditional"
15
+ class="address-block__info-row"
16
+ >
28
17
  {{ addressLocal.streetAddressAdditional }}
29
- </div>
30
-
31
- <div class="address-block__info-row">
32
- <span class="address-city">{{ addressLocal.addressCity }}</span>
33
-
34
- <template v-if="addressLocal.addressRegion">
35
- <span class="address-region">&nbsp;{{ addressLocal.addressRegion }}</span>
36
- </template>
37
-
38
- <template v-if="addressLocal.postalCode">
39
- <span class="postal-code">&nbsp;{{ addressLocal.postalCode }}</span>
40
- </template>
41
- </div>
42
-
43
- <div class="address-block__info-row address-country">
44
- {{ getCountryName(addressCountry) }}
45
- </div>
46
-
47
- <template v-if="addressLocal.deliveryInstructions">
48
- <div class="address-block__info-row delivery-instructions mt-5 font-italic">
49
- {{ addressLocal.deliveryInstructions }}
50
- </div>
51
- </template>
18
+ </p>
19
+ <p class="address-block__info-row">
20
+ <span>{{ addressLocal.city }}</span>
21
+ <span v-if="addressLocal.region">&nbsp;{{ addressLocal.region }}&nbsp;</span>
22
+ <span v-if="addressLocal.postalCode">&nbsp;{{ addressLocal.postalCode }}</span>
23
+ </p>
24
+ <p class="address-block__info-row">
25
+ {{ getCountryName(country) }}
26
+ </p>
27
+ <p
28
+ v-if="addressLocal.deliveryInstructions"
29
+ class="address-block__info-row delivery-text"
30
+ >
31
+ {{ addressLocal.deliveryInstructions }}
32
+ </p>
52
33
  </div>
53
34
  </div>
54
35
  </v-expand-transition>
@@ -61,102 +42,115 @@
61
42
  name="address-form"
62
43
  lazy-validation
63
44
  >
45
+ <div class="form__row">
46
+ <v-autocomplete
47
+ v-model="addressLocal.country"
48
+ autocomplete="new-password"
49
+ :name="Math.random().toString()"
50
+ variant="filled"
51
+ class="address-country"
52
+ hide-no-data
53
+ item-title="name"
54
+ item-value="code"
55
+ :items="getCountries()"
56
+ :label="countryLabel"
57
+ :rules="[...schemaLocal.country]"
58
+ />
59
+ <!-- special field to select AddressComplete country, separate from our model field -->
60
+ <input
61
+ :id="countryId"
62
+ type="hidden"
63
+ :value="country"
64
+ >
65
+ </div>
64
66
  <div class="form__row">
65
67
  <!-- NB1: AddressComplete needs to be enabled each time user clicks in this search field.
66
68
  NB2: Only process first keypress -- assumes if user moves between instances of this
67
69
  component then they are using the mouse (and thus, clicking). -->
68
70
  <v-text-field
69
- :id="streetAddressId"
70
- v-model="addressLocal.streetAddress"
71
- autocomplete="chrome-off"
72
- :name="Math.random()"
73
- filled
71
+ :id="streetId"
72
+ v-model="addressLocal.street"
73
+ autocomplete="new-password"
74
74
  class="street-address"
75
- :hint="streetAddressHint"
75
+ variant="filled"
76
+ :hint="hideAddressHint ? '' : 'Street address, PO box, rural route, or general delivery address'"
77
+ :label="streetLabel"
78
+ :name="Math.random().toString()"
76
79
  persistent-hint
77
- :label="streetAddressLabel"
78
- :rules="[...rules.streetAddress, ...spaceRules]"
80
+ :rules="[...schemaLocal.street]"
79
81
  @keypress.once="enableAddressComplete()"
80
82
  @click="enableAddressComplete()"
81
83
  />
82
84
  </div>
83
85
  <div class="form__row">
84
86
  <v-textarea
85
- v-model="addressLocal.streetAddressAdditional"
87
+ v-model="addressLocal.streetAdditional"
88
+ autocomplete="new-password"
86
89
  auto-grow
87
- filled
90
+ variant="filled"
88
91
  class="street-address-additional"
89
- :label="streetAddressAdditionalLabel"
92
+ :label="streetAdditionalLabel"
93
+ :name="Math.random().toString()"
90
94
  rows="1"
91
- :rules="[...rules.streetAddressAdditional, ...spaceRules]"
95
+ :rules="!!addressLocal.streetAdditional ? [...schemaLocal.streetAdditional] : []"
92
96
  />
93
97
  </div>
94
98
  <div class="form__row three-column">
95
99
  <v-text-field
96
- v-model="addressLocal.addressCity"
97
- filled
100
+ v-model="addressLocal.city"
101
+ autocomplete="new-password"
102
+ variant="filled"
98
103
  class="item address-city"
99
- :label="addressCityLabel"
100
- :rules="[...rules.addressCity, ...spaceRules]"
104
+ :label="cityLabel"
105
+ :name="Math.random().toString()"
106
+ :rules="[...schemaLocal.city]"
101
107
  />
102
- <v-select
103
- v-if="useCountryRegions(addressCountry)"
104
- v-model="addressLocal.addressRegion"
105
- filled
108
+ <v-autocomplete
109
+ v-if="useCountryRegions(country)"
110
+ v-model="addressLocal.region"
111
+ autocomplete="new-password"
112
+ variant="filled"
106
113
  class="item address-region"
107
- :menu-props="{maxHeight:'40rem'}"
108
- :label="addressRegionLabel"
109
- item-text="name"
114
+ hide-no-data
115
+ item-title="name"
110
116
  item-value="short"
111
- :items="isAddressCountryCanadaAndExcludeBc ? getCanadaRegionsExcludeBC() :
112
- getCountryRegions(addressCountry)"
113
- :rules="[...rules.addressRegion, ...spaceRules]"
117
+ :items="getCountryRegions(country)"
118
+ :label="regionLabel"
119
+ :menu-props="{ maxHeight: '14rem' }"
120
+ :name="Math.random().toString()"
121
+ :rules="[...schemaLocal.region]"
114
122
  />
115
123
  <v-text-field
116
124
  v-else
117
- v-model="addressLocal.addressRegion"
118
- filled
125
+ v-model="addressLocal.region"
126
+ variant="filled"
119
127
  class="item address-region"
120
- :label="addressRegionLabel"
121
- :rules="[...rules.addressRegion, ...spaceRules]"
128
+ :label="regionLabel"
129
+ :name="Math.random().toString()"
130
+ :rules="[...schemaLocal.region]"
122
131
  />
123
132
  <v-text-field
124
133
  v-model="addressLocal.postalCode"
125
- filled
134
+ variant="filled"
126
135
  class="item postal-code"
127
136
  :label="postalCodeLabel"
128
- :rules="[...rules.postalCode, ...spaceRules]"
137
+ :name="Math.random().toString()"
138
+ :rules="[...schemaLocal.postalCode]"
129
139
  />
130
140
  </div>
131
- <div class="form__row">
132
- <v-select
133
- v-model="addressLocal.addressCountry"
134
- filled
135
- class="address-country"
136
- :label="addressCountryLabel"
137
- menu-props="auto"
138
- item-text="name"
139
- item-value="code"
140
- :items="getCountries()"
141
- :rules="[...rules.addressCountry, ...spaceRules]"
142
- @change="resetRegion()"
143
- />
144
- <!-- special field to select AddressComplete country, separate from our model field -->
145
- <input
146
- :id="addressCountryId"
147
- type="hidden"
148
- :value="addressCountry"
149
- >
150
- </div>
151
- <div class="form__row">
141
+ <div
142
+ v-if="!hideDeliveryAddress"
143
+ class="form__row"
144
+ >
152
145
  <v-textarea
153
146
  v-model="addressLocal.deliveryInstructions"
154
147
  auto-grow
155
- filled
148
+ variant="filled"
156
149
  class="delivery-instructions"
157
150
  :label="deliveryInstructionsLabel"
151
+ :name="Math.random().toString()"
158
152
  rows="2"
159
- :rules="[...rules.deliveryInstructions, ...spaceRules]"
153
+ :rules="!!addressLocal.deliveryInstructions ? [...schemaLocal.deliveryInstructions] : []"
160
154
  />
161
155
  </div>
162
156
  </v-form>
@@ -165,355 +159,174 @@
165
159
  </template>
166
160
 
167
161
  <script lang="ts">
168
- import Vue from 'vue'
169
- import { required } from 'vuelidate/lib/validators'
170
- import { Component, Mixins, Emit, Prop, Watch } from 'vue-property-decorator'
171
- import { Validations } from 'vuelidate-property-decorators'
172
- import { uniqueId } from 'lodash'
173
- import { ValidationMixin, CountriesProvincesMixin } from '@bcrs-shared-components/mixins'
174
-
175
- /**
176
- * The component for displaying and editing an address.
177
- * Vuelidate is used to implement the validation rules (eg, what 'required' means and whether it's satisfied).
178
- * Vuetify is used to display any validation errors/styling.
179
- * Optionally uses Canada Post AddressComplete (aka Postal Code Anywhere - PCA) for address lookup.
180
- */
181
- @Component({
182
- mixins: [ValidationMixin, CountriesProvincesMixin]
183
- })
184
- export default class BaseAddress extends Mixins(ValidationMixin, CountriesProvincesMixin) {
185
- /**
186
- * The validation object used by Vuelidate to compute address model validity.
187
- * @returns the Vuelidate validations object
188
- */
189
- @Validations()
190
- public validations (): any {
191
- return { addressLocal: { ...this.schemaLocal } }
192
- }
193
-
194
- /**
195
- * The address to be displayed/edited.
196
- * Default is "empty address" in case parent doesn't provide it (eg, for new address).
197
- */
198
- @Prop({
199
- default: () => ({
200
- streetAddress: '',
201
- streetAddressAdditional: '',
202
- addressCity: '',
203
- addressRegion: '',
204
- postalCode: '',
205
- addressCountry: '',
206
- deliveryInstructions: ''
207
- })
208
- })
209
- readonly address: object
210
-
211
- /** Whether the address should be shown in editing mode (true) or display mode (false). */
212
- @Prop({ default: false })
213
- readonly editing: boolean
214
-
215
- /** The address schema containing Vuelidate rules. */
216
- @Prop({ default: null })
217
- readonly schema: any
218
-
219
- @Prop({ default: false })
220
- readonly noPoBox: boolean
221
-
222
- @Prop({ default: '' })
223
- readonly deliveryInstructionsText: string
224
-
225
- @Prop({ default: false })
226
- readonly excludeBC: boolean
227
-
228
- resetRegion () {
229
- this.addressLocal['addressRegion'] = ''
230
- }
231
-
232
- /** A local (working) copy of the address, to contain the fields edited by the component (ie, the model). */
233
- addressLocal: object = {}
234
-
235
- /** A local (working) copy of the address schema. */
236
- schemaLocal: any = {}
237
-
238
- /** A unique id for this instance of this component. */
239
- uniqueId = uniqueId()
240
-
241
- /** A unique id for the Street Address input. */
242
- get streetAddressId (): string {
243
- return `street-address-${this.uniqueId}`
244
- }
245
-
246
- /** A unique id for the Address Country input. */
247
- addressCountryId (): string {
248
- return `address-country-${this.uniqueId}`
249
- }
250
-
251
- /** The Address Country, to simplify the template and so we can watch it below. */
252
- get addressCountry (): string {
253
- return this.addressLocal['addressCountry']
254
- }
255
-
256
- get isAddressCountryCanadaAndExcludeBc (): boolean {
257
- return this.addressLocal['addressCountry'] === 'CA' && this.excludeBC
258
- }
259
-
260
- /** The Street Address Additional label with 'optional' as needed. */
261
- get streetAddressAdditionalLabel (): string {
262
- return 'Additional Street Address' + (this.isSchemaRequired('streetAddressAdditional') ? '' : ' (Optional)')
263
- }
264
-
265
- /** The Street Address label with 'optional' as needed. */
266
- get streetAddressLabel (): string {
267
- return 'Street Address' + (this.isSchemaRequired('streetAddress') ? '' : ' (Optional)')
268
- }
269
-
270
- /** The Address City label with 'optional' as needed. */
271
- get addressCityLabel (): string {
272
- return 'City' + (this.isSchemaRequired('addressCity') ? '' : ' (Optional)')
273
- }
274
-
275
- /** The Address Region label with 'optional' as needed. */
276
- get addressRegionLabel (): string {
277
- let label: string
278
- let required = this.isSchemaRequired('addressRegion')
279
-
280
- // NB: make region required for Canada and USA
281
- if (this.addressLocal['addressCountry'] === 'CA') {
282
- label = 'Province'
283
- required = true
284
- } else if (this.addressLocal['addressCountry'] === 'US') {
285
- label = 'State'
286
- required = true
287
- } else {
288
- label = 'Province/State'
289
- }
290
-
291
- return label + (required ? '' : ' (Optional)')
292
- }
293
-
294
- /** The Postal Code label with 'optional' as needed. */
295
- get postalCodeLabel (): string {
296
- let label: string
297
- if (this.addressLocal['addressCountry'] === 'US') {
298
- label = 'Zip Code'
299
- } else {
300
- label = 'Postal Code'
162
+ import { defineComponent, onMounted, toRefs, watch } from 'vue-demi'
163
+ import {
164
+ baseRules,
165
+ useAddress,
166
+ useAddressComplete,
167
+ useCountryRegions,
168
+ useCountriesProvinces,
169
+ useBaseValidations,
170
+ spaceRules
171
+ } from '@/components/base-address/factories'
172
+ import { AddressIF, SchemaIF } from '@bcrs-shared-components/interfaces'
173
+ import { AddressValidationRules } from '@bcrs-shared-components/enums'
174
+
175
+ export default defineComponent({
176
+ name: 'BaseAddress',
177
+ props: {
178
+ value: {
179
+ type: Object as () => AddressIF,
180
+ default: () => ({
181
+ street: '',
182
+ streetAdditional: '',
183
+ city: '',
184
+ region: '',
185
+ postalCode: '',
186
+ country: '',
187
+ deliveryInstructions: ''
188
+ })
189
+ },
190
+ /* used for readonly mode vs edit mode */
191
+ editing: {
192
+ type: Boolean,
193
+ default: false
194
+ },
195
+ /* contains validation for each field */
196
+ schema: {
197
+ type: Object as () => SchemaIF,
198
+ default: null
199
+ },
200
+ /* triggers all current form validation errors */
201
+ triggerErrors: {
202
+ type: Boolean,
203
+ default: false
204
+ },
205
+ /* Hides the persistent hint field on Address Input */
206
+ hideAddressHint: {
207
+ type: Boolean,
208
+ default: false
209
+ },
210
+ /* Hides Delivery Address field (e.g. for Unit Notes) */
211
+ hideDeliveryAddress: {
212
+ type: Boolean,
213
+ default: false
301
214
  }
302
- return label + (this.isSchemaRequired('postalCode') ? '' : ' (Optional)')
303
- }
304
-
305
- /** The Address Country label with 'optional' as needed. */
306
- get addressCountryLabel (): string {
307
- return 'Country' + (this.isSchemaRequired('addressCountry') ? '' : ' (Optional)')
308
- }
309
-
310
- /** The Delivery Instructions label with 'optional' as needed. */
311
- get deliveryInstructionsLabel (): string {
312
- if (this.deliveryInstructionsText) {
313
- return this.deliveryInstructionsText + (this.isSchemaRequired('deliveryInstructions') ? '' : ' (Optional)')
314
- } else {
315
- return 'Delivery Instructions' + (this.isSchemaRequired('deliveryInstructions') ? '' : ' (Optional)')
316
- }
317
- }
318
-
319
- get streetAddressHint (): string {
320
- return this.noPoBox ? 'Address cannot be a PO Box' : ''
321
- }
322
-
323
- /** Whether the specified prop is required according to the schema. */
324
- isSchemaRequired (prop: string): boolean {
325
- return Boolean(this.schemaLocal && this.schemaLocal[prop] && this.schemaLocal[prop].required)
326
- }
327
-
328
- /** Array of validation rules used by input elements to prevent extra whitespace. */
329
- readonly spaceRules: Array<(v: string) => boolean | string> = [
330
- v => !/^\s/g.test(v) || 'Invalid spaces', // leading spaces
331
- v => !/\s$/g.test(v) || 'Invalid spaces', // trailing spaces
332
- v => !/\s\s/g.test(v) || 'Invalid word spacing' // multiple inline spaces
333
- ]
334
-
335
- /**
336
- * The Vuetify rules object. Used to display any validation errors/styling.
337
- * NB: As a getter, this is initialized between created() and mounted().
338
- * @returns the Vuetify validation rules object
339
- */
340
- get rules (): { [attr: string]: Array<() => boolean | string> } {
341
- return this.createVuetifyRulesObject('addressLocal') as { [attr: string]: Array<() => boolean | string> }
342
- }
343
- /** Emits an update message for the address prop, so that the caller can ".sync" with it. */
344
- @Emit('update:address')
345
- emitAddress (address: object): void { }
346
-
347
- /** Emits the validity of the address entered by the user. */
348
- @Emit('valid')
349
- emitValid (valid: boolean): void { }
350
-
351
- /**
352
- * Watches changes to the Schema object, so that if the parent changes the data, then
353
- * the working copy of it is updated.
354
- */
355
- @Watch('schema', { deep: true, immediate: true })
356
- onSchemaChanged (): void {
357
- this.schemaLocal = { ...this.schema }
358
- }
359
-
360
- /**
361
- * Watches changes to the Address object, so that if the parent changes the data, then
362
- * the working copy of it is updated.
363
- */
364
- @Watch('address', { deep: true, immediate: true })
365
- onAddressChanged (): void {
366
- this.addressLocal = { ...this.address }
367
- }
368
-
369
- /**
370
- * Watches changes to the Address Country and updates the schema accordingly.
371
- */
372
- @Watch('addressCountry')
373
- onAddressCountryChanged (): void {
374
- // skip this if component is called without a schema (eg, display mode)
375
- if (this.schema) {
376
- if (this.useCountryRegions(this.addressLocal['addressCountry'])) {
377
- // we are using a region list for the current country so make region a required field
378
- const addressRegion = { ...this.schema.addressRegion, required }
379
- // re-assign the local schema because Vue does not detect property addition
380
- this.schemaLocal = { ...this.schema, addressRegion }
215
+ },
216
+ emits: ['valid'],
217
+ setup (props, { emit }) {
218
+ const localSchema = { ...props.schema }
219
+ const {
220
+ addressLocal,
221
+ country,
222
+ schemaLocal,
223
+ isSchemaRequired,
224
+ labels
225
+ } = useAddress(toRefs(props).value, localSchema)
226
+
227
+ const origPostalCodeRules = localSchema.postalCode
228
+ const origRegionRules = localSchema.region
229
+
230
+ const { addressForm, resetValidation, validate } = useBaseValidations()
231
+
232
+ const { enableAddressComplete, uniqueIds } = useAddressComplete(addressLocal)
233
+
234
+ const countryProvincesHelpers = useCountriesProvinces()
235
+
236
+ const countryChangeHandler = (val: string, oldVal: string) => {
237
+ // do not trigger any changes if it is view only (summary instance)
238
+ if (!props.editing) return
239
+
240
+ if (val === 'CA') {
241
+ localSchema.postalCode = origPostalCodeRules.concat([baseRules.postalCode])
242
+ localSchema.region = origRegionRules
243
+ } else if (val === 'US') {
244
+ localSchema.postalCode = origPostalCodeRules.concat([baseRules.zipCode])
245
+ localSchema.region = origRegionRules
381
246
  } else {
382
- // we are not using a region list for the current country so remove required property
383
- const { required, ...addressRegion } = this.schema.addressRegion
384
- // re-assign the local schema because Vue does not detect property deletion
385
- this.schemaLocal = { ...this.schema, addressRegion }
247
+ localSchema.postalCode = origPostalCodeRules.concat([baseRules[AddressValidationRules.MAX_LENGTH](15)])
248
+ localSchema.region = [baseRules[AddressValidationRules.MAX_LENGTH](2), ...spaceRules]
386
249
  }
250
+ // reset other address fields (check is for loading an existing address)
251
+ if (oldVal) {
252
+ addressLocal.value.street = ''
253
+ addressLocal.value.streetAdditional = ''
254
+ addressLocal.value.city = ''
255
+ addressLocal.value.region = ''
256
+ addressLocal.value.postalCode = ''
257
+ }
258
+ // wait for schema update and validate the form
259
+ setTimeout(() => {
260
+ props.triggerErrors ? validate() : resetValidation()
261
+ }, 5)
387
262
  }
388
- }
389
-
390
- /**
391
- * Watches changes to the Address Local object, to catch any changes to the fields within the address.
392
- * Will notify the parent object with the new address and whether or not the address is valid.
393
- */
394
- @Watch('addressLocal', { deep: true, immediate: true })
395
- onAddressLocalChanged (): void {
396
- this.emitAddress(this.addressLocal)
397
- this.emitValid(!this.$v.$invalid)
398
- }
399
-
400
- /**
401
- * Determines whether to use a country's known regions (ie, provinces/states).
402
- * @param code the short code of the country
403
- * @returns whether to use v-select (true) or v-text-field (false) for input
404
- */
405
- useCountryRegions (code: string): boolean {
406
- return (code === 'CA' || code === 'US')
407
- }
408
-
409
- /** Enables AddressComplete for this instance of the address. */
410
- enableAddressComplete (): void {
411
- // If you want to use this component with the Canada Post AddressComplete service:
412
- // 1. The AddressComplete JavaScript script (and stylesheet) must be loaded.
413
- // 2. Your AddressComplete account key must be defined.
414
- const pca = window['pca']
415
- const key = window['addressCompleteKey']
416
- if (!pca || !key) {
417
- // eslint-disable-next-line no-console
418
- console.log('AddressComplete not initialized due to missing script and/or key')
419
- return
420
- }
421
-
422
- // Destroy the old object if it exists, and create a new one.
423
- if (window['currentAddressComplete']) {
424
- window['currentAddressComplete'].destroy()
425
- }
426
- window['currentAddressComplete'] = this.createAddressComplete(pca, key)
427
- }
428
-
429
- /**
430
- * Creates the AddressComplete object for this instance of the component.
431
- * @param pca the Postal Code Anywhere object provided by AddressComplete
432
- * @param key the key for the Canada Post account that is to be charged for lookups
433
- * @returns an object that is a pca.Address instance
434
- */
435
- createAddressComplete (pca, key: string): object {
436
- // Set up the two fields that AddressComplete will use for input.
437
- // Ref: https://www.canadapost.ca/pca/support/guides/advanced
438
- // Note: Use special field for country, which user can't click, and which AC will overwrite
439
- // but that we don't care about.
440
- const fields = [
441
- { element: this.streetAddressId, field: 'Line1', mode: pca.fieldMode.SEARCH },
442
- { element: this.addressCountryId, field: 'CountryName', mode: pca.fieldMode.COUNTRY }
443
- ]
444
- const options = { key }
445
263
 
446
- const addressComplete = new pca.Address(fields, options)
264
+ onMounted(() => {
265
+ countryChangeHandler(addressLocal.value.country, null)
266
+ })
447
267
 
448
- // The documentation contains sample load/populate callback code that doesn't work, but this will. The side effect
449
- // is that it breaks the autofill functionality provided by the library, but we really don't want the library
450
- // altering the DOM because Vue is already doing so, and the two don't play well together.
451
- addressComplete.listen('populate', this.addressCompletePopulate)
268
+ watch(() => addressLocal.value, (val) => {
269
+ let valid = true
270
+ /** checks each field against the schema rules to see if the address is valid or not
271
+ * NOTE: we don't want it to trigger error msgs yet which is why this does not call validate()
272
+ */
273
+ for (const key in val) {
274
+ for (const index in schemaLocal.value[key]) {
275
+ if (schemaLocal.value[key][index](val[key]) !== true) {
276
+ valid = false
277
+ break
278
+ }
279
+ }
280
+ if (!valid) break
281
+ }
282
+ emit('valid', valid)
283
+ }, { immediate: true, deep: true })
452
284
 
453
- return addressComplete
454
- }
285
+ watch(() => country.value, (val, oldVal) => {
286
+ countryChangeHandler(val, oldVal)
287
+ })
455
288
 
456
- /**
457
- * Callback to update the address data after the user chooses a suggested address.
458
- * @param address the data object returned by the AddressComplete Retrieve API
459
- */
460
- addressCompletePopulate (address: object): void {
461
- const newAddressLocal: object = {}
289
+ watch(() => props.triggerErrors, () => {
290
+ validate()
291
+ })
462
292
 
463
- newAddressLocal['streetAddress'] = address['Line1'] || 'N/A'
464
- // Combine extra address lines into Street Address Additional field.
465
- newAddressLocal['streetAddressAdditional'] = this.combineLines(
466
- this.combineLines(address['Line2'], address['Line3']),
467
- this.combineLines(address['Line4'], address['Line5'])
468
- )
469
- newAddressLocal['addressCity'] = address['City']
470
- if (this.useCountryRegions(address['CountryIso2'])) {
471
- // In this case, v-select will map known province code to province name
472
- // or v-select will be blank and user will have to select a known item.
473
- newAddressLocal['addressRegion'] = address['ProvinceCode']
474
- } else {
475
- // In this case, v-text-input will allow manual entry but province info is probably too long
476
- // so set region to null and add province name to the Street Address Additional field.
477
- // If length is excessive, user will have to fix it.
478
- newAddressLocal['addressRegion'] = null
479
- newAddressLocal['streetAddressAdditional'] = this.combineLines(
480
- newAddressLocal['streetAddressAdditional'], address['ProvinceName']
481
- )
293
+ return {
294
+ addressForm,
295
+ addressLocal,
296
+ country,
297
+ ...countryProvincesHelpers,
298
+ enableAddressComplete,
299
+ isSchemaRequired,
300
+ ...labels,
301
+ schemaLocal,
302
+ useCountryRegions,
303
+ ...uniqueIds,
304
+ validate
482
305
  }
483
- newAddressLocal['postalCode'] = address['PostalCode']
484
- newAddressLocal['addressCountry'] = address['CountryIso2']
485
-
486
- // re-assign the local address to force Vuetify update
487
- this.addressLocal = newAddressLocal
488
-
489
- // Validate the form, in case any fields are missing or incorrect.
490
- Vue.nextTick(() => { (this.$refs.addressForm as any).validate() })
491
306
  }
492
-
493
- combineLines (line1: string, line2: string) {
494
- if (!line1) return line2
495
- if (!line2) return line1
496
- return line1 + '\n' + line2
497
- }
498
- }
307
+ })
499
308
  </script>
500
309
 
501
310
  <style lang="scss" scoped>
502
- @import "@/assets/styles/theme.scss";
311
+ @import '@/assets/styles/theme.scss';
312
+
313
+ .delivery-text {
314
+ font-style: italic;
315
+ margin-top: 10px;
316
+ }
503
317
 
504
318
  // Address Block Layout
505
319
  .address-block {
506
320
  display: flex;
321
+ p {
322
+ margin-bottom: unset;
323
+ }
507
324
  }
508
325
 
509
326
  .address-block__info {
510
327
  flex: 1 1 auto;
511
328
  }
512
329
 
513
- .address-block__info-row {
514
- color: $gray7;
515
- }
516
-
517
330
  // Form Row Elements
518
331
  .form__row.three-column {
519
332
  align-items: stretch;
@@ -530,22 +343,8 @@ export default class BaseAddress extends Mixins(ValidationMixin, CountriesProvin
530
343
  }
531
344
  }
532
345
 
533
- // text field labels
534
- ::v-deep .v-label {
535
- color: $gray7;
536
- font-size: $px-16;
537
- font-weight: normal;
538
- }
539
-
540
- // text field inputs
541
- ::v-deep {
542
- .v-input input {
543
- color: $gray9;
544
- }
545
- }
546
-
547
- .pre-line {
548
- white-space: pre-line;
346
+ .pre-wrap {
347
+ white-space: pre-wrap;
549
348
  }
550
349
 
551
350
  // make 'readonly' inputs looks disabled