@sbc-connect/nuxt-forms 0.1.10 → 0.1.12

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.
@@ -0,0 +1,68 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ export const useCanadaPost = () => {
4
+ const activeAddressField = ref<string>()
5
+ const address = reactive<ConnectAddress>({
6
+ street: '',
7
+ streetAdditional: '',
8
+ city: '',
9
+ region: '',
10
+ postalCode: '',
11
+ country: '',
12
+ locationDescription: '',
13
+ streetName: '',
14
+ streetNumber: '',
15
+ unitNumber: ''
16
+ })
17
+
18
+ const createAddressComplete = (
19
+ pca: any, key: string, id: string, countryIso2: string, countrySelect: boolean
20
+ ): object => {
21
+ const fields = [
22
+ { element: id, field: 'Line1', mode: pca.fieldMode.SEARCH }
23
+ ]
24
+ // Conditional to only allow country selection depending on control
25
+ const bar = countrySelect ? { visible: true, showCountry: true } : {}
26
+ const countries = {
27
+ defaultCode: countryIso2,
28
+ ...(countrySelect ? {} : { codesList: 'CA' })
29
+ }
30
+ const options = { key, bar, countries }
31
+ const addressComplete = new pca.Address(fields, options)
32
+ addressComplete.listen('populate', addressCompletePopulate)
33
+ return addressComplete
34
+ }
35
+
36
+ const enableAddressComplete = (id: string, countryIso2: string, countrySelect: boolean): void => {
37
+ activeAddressField.value = id
38
+ const config = useRuntimeConfig()
39
+ const pca = (window as any).pca
40
+ const key = config.public.addressCompleteKey as string
41
+ if (!pca || !key) {
42
+ console.warn('AddressComplete not initialized due to missing script and/or key')
43
+ return
44
+ }
45
+ if ((window as any).currentAddressComplete) {
46
+ (window as any).currentAddressComplete.destroy()
47
+ }
48
+ (window as any).currentAddressComplete = createAddressComplete(pca, key, id, countryIso2, countrySelect)
49
+ }
50
+
51
+ const addressCompletePopulate = (addressComplete: CanadaPostAddressResponse): void => {
52
+ address.street = addressComplete.Line1 || 'N/A'
53
+ address.streetAdditional = addressComplete.Line2 || ''
54
+ address.city = addressComplete.City
55
+ address.region = addressComplete.ProvinceCode
56
+ address.postalCode = addressComplete.PostalCode
57
+ address.country = addressComplete.CountryIso2
58
+ address.streetName = addressComplete.Street
59
+ address.streetNumber = addressComplete.BuildingNumber
60
+ address.unitNumber = addressComplete.SubBuilding
61
+ }
62
+
63
+ return {
64
+ activeAddressField,
65
+ address,
66
+ enableAddressComplete
67
+ }
68
+ }
@@ -0,0 +1,7 @@
1
+ export enum CanadaPostAddressResponseDataLevel {
2
+ UNKNOWN = 'Unknown',
3
+ PREMISE = 'Premise',
4
+ RANGEDPREMISE = 'RangedPremise',
5
+ STREET = 'Street',
6
+ CITY = 'City'
7
+ }
@@ -0,0 +1,38 @@
1
+ export interface CanadaPostAddressResponse {
2
+ Id: string
3
+ DomesticId: string
4
+ Language: string
5
+ LanguageAlternatives: string
6
+ Department: string
7
+ Company: string
8
+ SubBuilding: string
9
+ BuildingNumber: string
10
+ BuildingName: string
11
+ SecondaryStreet: string
12
+ Street: string
13
+ Block: string
14
+ Neighbourhood: string
15
+ District: string
16
+ City: string
17
+ Line1: string
18
+ Line2: string
19
+ Line3: string
20
+ Line4: string
21
+ Line5: string
22
+ AdminAreaName: string
23
+ AdminAreaCode: string
24
+ Province: string
25
+ ProvinceName: string
26
+ ProvinceCode: string
27
+ PostalCode: string
28
+ CountryName: string
29
+ CountryIso2: string
30
+ CountryIso3: string
31
+ CountryIsoNumber: number
32
+ SortingNumber1: string
33
+ SortingNumber2: string
34
+ Barcode: string
35
+ POBoxNumber: string
36
+ Label: string
37
+ DataLevel: CanadaPostAddressResponseDataLevel
38
+ }
@@ -0,0 +1 @@
1
+ export * from './zod-schemas'
@@ -2023,7 +2023,7 @@ export const countrySubdivisions = {
2023
2023
  ca: subdivisionsCa,
2024
2024
  us: subdivisionsUs
2025
2025
  }
2026
- export const iscCountriesListSortedByName = isoCountriesList.toSorted(
2026
+ export const isoCountriesListSortedByName = isoCountriesList.toSorted(
2027
2027
  (c1, c2) => {
2028
2028
  if (c1.name < c2.name) {
2029
2029
  return -1
@@ -0,0 +1,111 @@
1
+ import { z } from 'zod'
2
+
3
+ export function getRequiredAddressSchema() {
4
+ const t = useNuxtApp().$i18n.t
5
+
6
+ return z.object({
7
+ street: z
8
+ .string()
9
+ .min(1, t('connect.validation.fieldRequired'))
10
+ .max(50, t('connect.validation.maxChars', { count: 50 })),
11
+ streetAdditional: z
12
+ .string()
13
+ .max(50, t('connect.validation.maxChars', { count: 50 }))
14
+ .optional(),
15
+ city: z
16
+ .string()
17
+ .min(1, t('connect.validation.fieldRequired'))
18
+ .max(40, t('connect.validation.maxChars', { count: 40 })),
19
+ region: z
20
+ .string()
21
+ .optional(),
22
+ postalCode: z
23
+ .string()
24
+ .min(1, t('connect.validation.fieldRequired'))
25
+ .max(15, t('connect.validation.maxChars', { count: 15 })),
26
+ country: z
27
+ .string()
28
+ .min(1, t('connect.validation.fieldRequired')),
29
+ locationDescription: z
30
+ .string()
31
+ .max(80, t('connect.validation.maxChars', { count: 80 }))
32
+ .optional()
33
+ }).superRefine((data, ctx) => {
34
+ // validate region based on country
35
+ // required if country is US or CA
36
+ // optional and max 2 characters if not US or CA
37
+ const country = data.country
38
+ const region = data.region
39
+
40
+ if (region && region.length > 2) {
41
+ ctx.addIssue({
42
+ code: 'custom',
43
+ message: t('connect.validation.maxChars', { count: 2 }),
44
+ path: ['region']
45
+ })
46
+ }
47
+
48
+ if ((country === 'US' || country === 'CA') && region?.length === 0) {
49
+ ctx.addIssue({
50
+ code: 'custom',
51
+ message: t('connect.validation.fieldRequired'),
52
+ path: ['region']
53
+ })
54
+ }
55
+ })
56
+ }
57
+
58
+ export function getNonRequiredAddressSchema() {
59
+ const t = useNuxtApp().$i18n.t
60
+
61
+ return z.object({
62
+ street: z
63
+ .string()
64
+ .min(1, t('connect.validation.fieldRequired'))
65
+ .max(50, t('connect.validation.maxChars', { count: 50 }))
66
+ .optional()
67
+ .or(z.literal('')),
68
+ streetAdditional: z
69
+ .string()
70
+ .max(50, t('connect.validation.maxChars', { count: 50 }))
71
+ .optional(),
72
+ city: z
73
+ .string()
74
+ .min(1, t('connect.validation.fieldRequired'))
75
+ .max(40, t('connect.validation.maxChars', { count: 40 }))
76
+ .optional()
77
+ .or(z.literal('')),
78
+ region: z
79
+ .string()
80
+ .optional(),
81
+ postalCode: z
82
+ .string()
83
+ .min(1, t('connect.validation.fieldRequired'))
84
+ .max(15, t('connect.validation.maxChars', { count: 15 }))
85
+ .optional()
86
+ .or(z.literal('')),
87
+ country: z
88
+ .string()
89
+ .min(1, t('connect.validation.fieldRequired'))
90
+ .optional()
91
+ .or(z.literal('')),
92
+ locationDescription: z
93
+ .string()
94
+ .max(80, t('connect.validation.maxChars', { count: 80 }))
95
+ .optional()
96
+ }).superRefine((data, ctx) => {
97
+ // validate region based on country
98
+ // required if country is US or CA
99
+ // optional and max 2 characters if not US or CA
100
+ // const country = data.country
101
+ const region = data.region
102
+
103
+ if (region && region.length > 2) {
104
+ ctx.addIssue({
105
+ code: 'custom',
106
+ message: t('connect.validation.maxChars', { count: 2 }),
107
+ path: ['region']
108
+ })
109
+ }
110
+ })
111
+ }
@@ -0,0 +1 @@
1
+ export * from './addresses'
@@ -33,6 +33,12 @@ export default {
33
33
  text: {
34
34
  addressCanBePOBox: 'Street address, PO box, rural route, or general delivery address.',
35
35
  addressCannotBePOBox: 'Address cannot be a PO Box.'
36
+ },
37
+ validation: {
38
+ fieldRequired: 'This field is required',
39
+ maxChars: 'Maximum 0 characters | Maximum 1 character | Maximum {count} characters', // 0/1 most likely will never be used but required for pluralization
40
+ minChars: 'Minimum 0 characters | Minimum 1 character | Minimum {count} characters', // 0/1 most likely will never be used but required for pluralization
41
+ required: 'Required'
36
42
  }
37
43
  }
38
44
  }
package/nuxt.config.ts CHANGED
@@ -20,6 +20,17 @@ export default defineNuxtConfig({
20
20
  '#forms': resolve('./')
21
21
  },
22
22
 
23
+ app: {
24
+ head: {
25
+ link: [
26
+ { rel: 'stylesheet', href: '/css/addresscomplete-2.50.min.css' }
27
+ ],
28
+ script: [
29
+ { src: '/js/addresscomplete-2.50.min.js', type: 'text/javascript', defer: true }
30
+ ]
31
+ }
32
+ },
33
+
23
34
  i18n: {
24
35
  locales: [
25
36
  {
@@ -37,5 +48,11 @@ export default defineNuxtConfig({
37
48
  file: 'fr-CA.ts'
38
49
  }
39
50
  ]
51
+ },
52
+
53
+ runtimeConfig: {
54
+ public: {
55
+ addressCompleteKey: ''
56
+ }
40
57
  }
41
58
  })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-forms",
3
3
  "type": "module",
4
- "version": "0.1.10",
4
+ "version": "0.1.12",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
@@ -13,11 +13,12 @@
13
13
  "typescript": "^5.8.3",
14
14
  "vue-tsc": "^3.0.4",
15
15
  "@sbc-connect/eslint-config": "0.0.7",
16
- "@sbc-connect/playwright-config": "0.0.6",
16
+ "@sbc-connect/playwright-config": "0.0.7",
17
17
  "@sbc-connect/vitest-config": "0.0.6"
18
18
  },
19
19
  "dependencies": {
20
- "@sbc-connect/nuxt-base": "0.1.9"
20
+ "zod": "^4.0.17",
21
+ "@sbc-connect/nuxt-base": "0.1.11"
21
22
  },
22
23
  "scripts": {
23
24
  "preinstall": "npx only-allow pnpm",
@@ -29,8 +30,10 @@
29
30
  "lint": "eslint .",
30
31
  "lint:fix": "eslint --fix .",
31
32
  "test": "pnpm run test:unit; pnpm run test:e2e",
32
- "test:unit": "vitest run",
33
+ "test:unit": "vitest run --passWithNoTests",
34
+ "test:unit:watch": "vitest",
33
35
  "test:e2e": "npx playwright test",
36
+ "test:e2e:ui": "npx playwright test --ui",
34
37
  "typecheck": "npx nuxt typecheck"
35
38
  }
36
39
  }
@@ -0,0 +1,11 @@
1
+ /*! Copyright © 2009-2024 Postcode Anywhere (Holdings) Ltd. (http://www.postcodeanywhere.co.uk)
2
+ *
3
+ * AddressComplete v2.50
4
+ * Style for AddressComplete for the web.
5
+ *
6
+ * p-w-u-c1-1-x4rp 25/05/2024 00:09:50
7
+ */
8
+ .pca{margin:0;padding:0;position:static;border:none;box-sizing:content-box}.pca *{box-sizing:content-box}.pca .pcatext{font:.8rem arial;color:#333}.pca .pcalist{position:relative;list-style-type:none;list-style-position:outside;margin:0;padding:0;overflow-y:auto;overflow-x:hidden;background-color:#fafafa}.pca .pcaitem{cursor:pointer;position:relative;margin:0;padding:9px 10px 9px 10px;padding:7px 10px;line-height:15px;text-align:left;white-space:nowrap;border:solid 1px transparent;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#e5e5e5;border-bottom-color:transparent;padding-right:22px;filter:alpha(opacity=80);color:#000}.pca .pcaselected,.pca .pcaitem:hover{color:#333;background-color:#e5f0ff;background-color:#f0f0f0;border-width:1px;border-style:solid;border-color: transparent;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#e5e5e5;border-bottom-color:transparent;opacity:1;filter:alpha(opacity=100);color:#000}.pca .pcalastitem,.pca .pcalastitem:hover{border-bottom:none}.pca .pcadisableselect{-moz-user-select:none;-webkit-user-select:none}.pca .pcaautocomplete{margin:0;padding:0;border-width:1px;border-style:solid;border-color:#ccc;border-bottom:0;background:0;box-shadow:0 8px 17px 0 rgba(0,0,0,.2);width:inherit;position:absolute;z-index:9999999999}.pca .pcaanchor{margin:0;padding:0;border:0;background:0}.pca .pcaanchor .pcachain{position:relative}.pca .pcaautocomplete .pcaheader{background-color:#fafafa;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#ccc;color:#969696}.pca .pcaautocomplete .pcamessage{padding:8px 10px;line-height:18px}.pca .pcaautocomplete .pcalist{height:244px;width:auto;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#ccc}.pca .pcaautocomplete .pcafooter{border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#ccc;background-color:#fafafa;height:30px;box-sizing:content-box;min-width:138px;overflow:hidden;display:flex;align-items:center;justify-content:flex-end;padding:0 10px}.pca .pcaautocomplete .pcafooter.pca-showlogo{justify-content:space-between}.pca .pcanotification{background-color:#fafafa;padding:8px 10px 8px 10px;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);border-radius:2px;position:absolute;z-index:100000;transition:opacity .5s ease-in-out;-moz-transition:opacity .5s ease-in-out;-webkit-transition:opacity .5s ease-in-out;opacity:1;display:none}.pca .pcanotification.pcavisible{display:block}.pca .pcanotification.pcafade{opacity:0}.pca .pcanotification.pcaerror{background-color:#cb484f;color:#fff}.pca .pcaautocomplete .pcafooter .pcamessage{font:bold 9pt arial;color:#757575;margin-right:10px;padding:0;position:relative;float:right}.pca .pcamodal{position:fixed;top:50%;left:50%;z-index:100000}.pca .pcamodal .pcalist{height:244px;width:auto;min-width:200px;min-height:100px}.pca .pcamodal .pcaborder{position:absolute;width:100%;height:100%;top:0;left:0;background-color:#000;border-radius:0px;opacity:.20;filter:alpha(opacity=20)}.pca .pcamodal .pcaframe{position:relative;margin:12px;background-color:#f5f7f9;border-radius:0px;border-width:1px;border-style:solid;border-color: #c8cacc}.pca .pcamodal .pcacontent{position:relative;padding:15px}.pca .pcamodal .pcacontent .pcainputrow{width:450px;text-align:right}.pca .pcamodal .pcacontent .pcainputrow input{width:300px;border-width:1px;border-style:solid;border-color: #d4d4d4;padding:8px;margin:15px;background:#fff}.pca .pcamodal .pcacontent .pcainputrow input:invalid{-webkit-box-shadow:0 0 1.5px 1px red;-moz-box-shadow:0 0 1.5px 1px red;box-shadow:0 0 1.5px 1px red}.pca .pcamodal .pcacontent .pcainputrow .pcahalf{width:126px}.pca .pcamodal .pcacontent .pcainputrow label{font:bold 14px arial;color:#444444}.pca .pcamodal .pcaheader{position:relative;top:0;left:0;border-top:1px solid#e1e3e5;border-bottom:1px solid #c8cacc;border-radius:0px 0px 0 0;background:#e1e3e5;background:-moz-linear-gradient(top,#e1e3e5 0%,#e1e3e5 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#e1e3e5),color-stop(100%,#e1e3e5));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e1e3e5',endColorstr='#e1e3e5',GradientType=0)}.pca .pcamodal .pcaheader .pcatitle{font:bold 18px arial;color:#005db9;margin:15px}.pca .pcamodal .pcafooter{position:relative;bottom:0;left:0;border-top:1px solid #c8cacc;background:#fff}.pca .pcamodal .pcafooter .pcabutton{width:150px;margin:15px}.pca .pcafullscreen{position:fixed;top:0;left:0;height:100%;width:100%}.pca .pcamask{background-color:#000;opacity:.40;filter:alpha(opacity=40);z-index:100000}.pca .pcabutton{font:bold 14px arial;color:#444444;border:1px solid #d4d4d4;border-radius:0px;padding:8px;cursor:pointer;background:#f5f7f9;background:-moz-linear-gradient(top,#f5f7f9 0%,#f5f7f9 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f5f7f9),color-stop(100%,#f5f7f9));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f7f9',endColorstr='#f5f7f9',GradientType=0)}.pca .pcatooltip{position:absolute;z-index:100000}.pca .pcatooltip .pcabackground{position:absolute;height:100%;width:100%;background-color:#000;border-radius:5px;opacity:.6;filter:alpha(opacity=60)}.pca .pcatooltip .pcamessage{position:relative;padding:5px;font:.8rem arial;color:#fff}.pca .pcabutton:hover{color:#444444}.pca .pcalink{font:bold 9pt arial;cursor:pointer}.pca .pcaclear{clear:both}
9
+ .pcaflag{width:14px;height:12px;font-size:0;background-image:url(//ws1.postescanada-canadapost.ca/images/flags16x16.png);-moz-box-shadow:0 1px 2px rgba(128,128,128,.3);-webkit-box-shadow:0 1px 2px rgba(128,128,128,.3);box-shadow:0 1px 2px rgba(128,128,128,.3)}.pca .pcaautocomplete .pcafooter .pcaflagbutton{height:21px;position:relative;cursor:pointer;display:flex;align-items:center}.pca .pcaautocomplete .pcaflaglabel{position:relative;margin-left:8px}.pca .pcacountrylist .pcafooter .pcaflagbutton{background-image:url(//ws1.postescanada-canadapost.ca/images/icons/flag_clear_up.png)}.pca .pcacountrylist .pcalist .pcaitem{display:flex}.pca .pcacountrylist .pcafooter .pcaflagbutton:hover{background-image:url(//ws1.postescanada-canadapost.ca/images/icons/flag_clear_up_hover.png)}
10
+ .pca .pcaexpandable{background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/chevron.png);background-repeat:no-repeat;background-position-x:99%;background-position-y:50%;background-position:right 7px center}.pca .pcaautocomplete .pcafooter .geoLocationIcon{width:21px;height:21px;font-size:0;margin:0 5px 0 0;padding:5px 0 5px 5px;position:relative;float:right;cursor:pointer;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/geolocationicon.svg);background-position:right;background-repeat:no-repeat;color:#7e8593;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"!important;visibility:hidden}.pca .pcaautocomplete .pcafooter .geoLocationIcon.active{visibility:visible}.pca .pcaautocomplete .pcafooter .geoLocationIcon.working{background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/loader.gif)}.pca .pcaautocomplete .pcafooter .geoLocationMessage{color:#7e8593;padding:9px 0;position:relative;float:right;cursor:pointer;font-size:11px;visibility:hidden}.pca .pcaautocomplete .pcafooter .geoLocationMessage.active{visibility:visible}.pca .pcaautocomplete .pcafooter .pcalogo{width:68px;height:16px;margin:7px 0 0 7px;font-size:0;position:relative;float:left;background-repeat:no-repeat;background-size:contain;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/loqatelogoinverted.svg)}.pca .pcaautocomplete .pcafooter .adsylogo{width:68px;height:16px;margin:7px 0 0 7px;font-size:0;position:relative;float:left;background-repeat:no-repeat;background-size:contain;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/loqatelogoinverted.svg)}.pca .pcaautocomplete .pcafooter .aclogo{width:112px;height:15px;font-size:0;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/address_complete_logo_en.png)}.pca .pcaautocomplete .pcafooter .aclogo.pcalogofr{width:118px;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/address_complete_logo_fr.png)}.pca .pcaautocomplete .pcafooter .dtlogo{width:100px;height:14px;font-size:0;margin:9px 5px 6px 9px;position:relative;float:left;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/dt_express_capture_logo.png)}.pca .pcaautocomplete .pcafooter .anlogo{width:129px;height:11px;font-size:0;margin:10px 5px 9px 9px;position:relative;float:left;background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/address_now_logo.png)}.pca .pcaitem .pcadescription{color:#6b6b6b;margin-left:8px}.pca .pcaitem .pcautilitytype{padding-right:8px;font-style:italic}.pca .pca-visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}
11
+ .pcaaddresscomplete{}.pca .pcaautocomplete .pcaheader .pcamessageicon{background-image:url(//ws1.postescanada-canadapost.ca/images/icons/captureplus/info.png);height:15px;position:relative;top:2px;margin-right:8px;display:inline-block;width:15px}