@sbc-connect/nuxt-pay 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @sbc-connect/nuxt-pay
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#172](https://github.com/bcgov/connect-nuxt/pull/172) [`c9e5d05`](https://github.com/bcgov/connect-nuxt/commit/c9e5d0519aff914196c38242f3a827473261af38) Thanks [@deetz99](https://github.com/deetz99)! - Implement useConnectPayQuery query defintions, useConnectPayService cache abstraction and update usage in connect-fee store.
8
+
9
+ ## 0.4.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [[`d91712d`](https://github.com/bcgov/connect-nuxt/commit/d91712db74c2e0c6b39f6fd38955fd60e82ce691)]:
14
+ - @sbc-connect/nuxt-auth@0.12.0
15
+
3
16
  ## 0.4.0
4
17
 
5
18
  ### Minor Changes
@@ -0,0 +1,43 @@
1
+ import type { DefineQueryOptions } from '@pinia/colada'
2
+
3
+ /**
4
+ * Resolves a query from the cache or fetches it from the network if necessary.
5
+ * * This utility ensures a cache entry exists and handles data fetching
6
+ * based on the current cache state and the `force` flag.
7
+ *
8
+ * @template TData - The expected shape of the data returned by the query.
9
+ * @template TError - The error type if the query fails. Defaults to `Error`.
10
+ * * @param options - The query definition object
11
+ * containing the key, query function, and cache settings (e.g., staleTime).
12
+ * @param [force=false] - When true, bypasses the cache and triggers
13
+ * a network call (cache.fetch). When false, returns cached data if fresh,
14
+ * or background refreshes if stale or in error state (cache.refresh).
15
+ * * @returns A promise that resolves to the query data.
16
+ * @throws throws the underlying network error if the fetch or refresh fails.
17
+ * * @example
18
+ * // uses cache if fresh
19
+ * const business = await getCachedOrFetch(businessOptions('BC123'));
20
+ * * // Forced fetch: ignores cache and hits API
21
+ * const freshData = await getCachedOrFetch(businessOptions('BC123'), true);
22
+ */
23
+ export async function getCachedOrFetch<TData>(
24
+ options: DefineQueryOptions<TData>,
25
+ force = false
26
+ ): Promise<TData> {
27
+ const cache = useQueryCache()
28
+ // NB: Required to prevent calls within 1ms causing a promise to return before the cached response is complete.
29
+ // i.e. without below:
30
+ // -> Call 1 for BC1234567 data
31
+ // -> Call 2 for BC1234567 data within 1ms
32
+ // -> Call 1 is cancelled
33
+ // -> Promise returns with undefined response from Call 1 instead of awaiting Call 2
34
+ await new Promise(resolve => setTimeout(resolve, 1))
35
+ // Ensures a query entry is present in the cache.
36
+ // will create one if it doesn't exist
37
+ const entry = cache.ensure(options)
38
+ const result = force
39
+ ? await cache.fetch(entry)
40
+ : await cache.refresh(entry)
41
+
42
+ return result.data!
43
+ }
@@ -0,0 +1 @@
1
+ export * from './get-cached-or-fetch'
@@ -0,0 +1 @@
1
+ export * from './pay'
@@ -0,0 +1,4 @@
1
+ export * from './mutate'
2
+ export * from './query'
3
+ export * from './query-keys'
4
+ export * from './service'
@@ -0,0 +1 @@
1
+ // TBD
@@ -0,0 +1,24 @@
1
+ // https://pinia-colada.esm.dev/guide/query-keys.html
2
+
3
+ /**
4
+ * IMPORTANT: Query Key Hierarchy
5
+ * * Our cache follows a strict hierarchy: ['connect', 'pay', accountId, ...rest].
6
+ * * 1. Account ID: The 'base' (accountId) MUST remain as the first dynamic segment.
7
+ * This allows us to invalidate an entire "folder" by targeting the parent key.
8
+ * * 2. ORDER: When updating keys, ensure the order of existing segments is preserved.
9
+ * Changing the order may break existing invalidation logic across the app.
10
+ */
11
+
12
+ export const useConnectPayQueryKeys = () => {
13
+ const { currentAccount } = storeToRefs(useConnectAccountStore())
14
+
15
+ const base = () => ['connect', 'pay', currentAccount.value?.id] as const
16
+
17
+ const keys = {
18
+ fee: (entityType: string, code: string, params: { priority?: boolean, futureEffective?: boolean } = {}) =>
19
+ [...base(), 'fee', entityType, code, params] as const,
20
+ payAccount: (accountId: string | number) => [...base(), 'pay-account', accountId] as const
21
+ }
22
+
23
+ return { keys }
24
+ }
@@ -0,0 +1,64 @@
1
+ // IMPORTANT: Query definitions are for GET requests only - for all other methods define a mutation in the ./mutate file
2
+ // https://pinia-colada.esm.dev/guide/queries.html
3
+ import { useQuery } from '@pinia/colada'
4
+ import type { UseQueryOptions, DefineQueryOptions } from '@pinia/colada'
5
+
6
+ type QueryOptions<T> = Omit<UseQueryOptions<T>, 'key' | 'query'> & {
7
+ query?: UseQueryOptions<T>['query']
8
+ }
9
+
10
+ type DefineOptions<TData, TError = Error> = Omit<DefineQueryOptions<TData, TError>, 'key' | 'query'> & {
11
+ query?: DefineQueryOptions<TData, TError>['query']
12
+ }
13
+
14
+ const DEFAULT_STALE_TIME = 60000
15
+
16
+ export const useConnectPayQuery = () => {
17
+ const { $payApi } = useNuxtApp()
18
+ const { keys } = useConnectPayQueryKeys()
19
+
20
+ function feeOptions(
21
+ entityType: string,
22
+ code: string,
23
+ params?: { priority?: boolean, futureEffective?: boolean },
24
+ options?: DefineOptions<ConnectFeeItem>) {
25
+ return defineQueryOptions({
26
+ query: () => $payApi<ConnectFeeItem>(`/fees/${entityType}/${code}`, { params }),
27
+ staleTime: DEFAULT_STALE_TIME,
28
+ ...options,
29
+ key: keys.fee(entityType, code, params)
30
+ })
31
+ }
32
+
33
+ function fee(
34
+ entityType: string,
35
+ code: string,
36
+ params?: { priority?: boolean, futureEffective?: boolean },
37
+ options?: QueryOptions<ConnectFeeItem>) {
38
+ return useQuery(() => feeOptions(entityType, code, params, options as DefineOptions<ConnectFeeItem>))
39
+ }
40
+
41
+ function payAccountOptions(
42
+ accountId: string | number,
43
+ options?: DefineOptions<ConnectPayAccount>) {
44
+ return defineQueryOptions({
45
+ query: () => $payApi<ConnectPayAccount>(`/accounts/${accountId}`),
46
+ staleTime: DEFAULT_STALE_TIME,
47
+ ...options,
48
+ key: keys.payAccount(accountId)
49
+ })
50
+ }
51
+
52
+ function payAccount(
53
+ accountId: string | number,
54
+ options?: QueryOptions<ConnectPayAccount>) {
55
+ return useQuery(() => payAccountOptions(accountId, options as DefineOptions<ConnectPayAccount>))
56
+ }
57
+
58
+ return {
59
+ feeOptions,
60
+ fee,
61
+ payAccountOptions,
62
+ payAccount
63
+ }
64
+ }
@@ -0,0 +1,30 @@
1
+ import { getCachedOrFetch } from '../helpers'
2
+
3
+ export const useConnectPayService = () => {
4
+ const query = useConnectPayQuery()
5
+
6
+ /* GET Requests */
7
+
8
+ async function getFee(
9
+ entityType: string,
10
+ code: string,
11
+ params?: { priority?: boolean, futureEffective?: boolean },
12
+ force = false
13
+ ): Promise<ConnectFeeItem> {
14
+ const options = query.feeOptions(entityType, code, params)
15
+ return await getCachedOrFetch(options, force)
16
+ }
17
+
18
+ async function getPayAccount(
19
+ accountId: string | number,
20
+ force = false
21
+ ): Promise<ConnectPayAccount> {
22
+ const options = query.payAccountOptions(accountId)
23
+ return await getCachedOrFetch(options, force)
24
+ }
25
+
26
+ return {
27
+ getFee,
28
+ getPayAccount
29
+ }
30
+ }
@@ -1,5 +1,5 @@
1
1
  export const useConnectFeeStore = defineStore('connect-pay-fee-store', () => {
2
- const { $payApi } = useNuxtApp()
2
+ const service = useConnectPayService()
3
3
  const { t } = useNuxtApp().$i18n
4
4
  const { baseModal } = useConnectModal()
5
5
 
@@ -139,7 +139,7 @@ export const useConnectFeeStore = defineStore('connect-pay-fee-store', () => {
139
139
  priority: true,
140
140
  futureEffective: true
141
141
  }
142
- return await $payApi<ConnectFeeItem>(`/fees/${entityType}/${code}`, { params })
142
+ return await service.getFee(entityType, code, params)
143
143
  } catch (error) {
144
144
  console.error('Error fetching Fee: ', error)
145
145
  }
@@ -226,13 +226,13 @@ export const useConnectFeeStore = defineStore('connect-pay-fee-store', () => {
226
226
  const accountId = useConnectAccountStore().currentAccount.id
227
227
  try {
228
228
  // get payment account
229
- const res = await $payApi<ConnectPayAccount>(`/accounts/${accountId}`)
230
- userPaymentAccount.value = res
229
+ userPaymentAccount.value = await service.getPayAccount(accountId)
230
+ const { cfsAccount } = userPaymentAccount.value
231
231
 
232
232
  // add options to allowedPaymentMethods
233
233
  let defaultMethod = userPaymentAccount.value.paymentMethod
234
234
  if (defaultMethod !== undefined) {
235
- const accountNum = userPaymentAccount.value.cfsAccount?.bankAccountNumber ?? ''
235
+ const accountNum = cfsAccount?.bankAccountNumber ?? ''
236
236
  allowedPaymentMethods.value.push({
237
237
  label: t(`connect.payMethod.label.${defaultMethod}`, { account: accountNum }),
238
238
  value: defaultMethod
@@ -245,7 +245,7 @@ export const useConnectFeeStore = defineStore('connect-pay-fee-store', () => {
245
245
  value: ConnectPayMethod.DIRECT_PAY
246
246
  })
247
247
  // if pad in confirmation period then set default payment to CC
248
- if (PAD_PENDING_STATES.includes(res.cfsAccount?.status)) {
248
+ if (PAD_PENDING_STATES.includes(cfsAccount?.status)) {
249
249
  defaultMethod = ConnectPayMethod.DIRECT_PAY
250
250
  }
251
251
  }
package/nuxt.config.ts CHANGED
@@ -13,7 +13,7 @@ export default defineNuxtConfig({
13
13
  extends: ['@sbc-connect/nuxt-auth'],
14
14
 
15
15
  imports: {
16
- dirs: ['interfaces', 'enums', 'stores']
16
+ dirs: ['interfaces', 'enums', 'stores', 'services']
17
17
  },
18
18
 
19
19
  alias: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-pay",
3
3
  "type": "module",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
@@ -11,12 +11,12 @@
11
11
  "nuxt": "4.4.6",
12
12
  "typescript": "6.0.3",
13
13
  "vue-tsc": "3.3.1",
14
- "@sbc-connect/eslint-config": "0.0.8",
14
+ "@sbc-connect/playwright-config": "0.2.0",
15
15
  "@sbc-connect/vitest-config": "0.2.0",
16
- "@sbc-connect/playwright-config": "0.2.0"
16
+ "@sbc-connect/eslint-config": "0.0.8"
17
17
  },
18
18
  "dependencies": {
19
- "@sbc-connect/nuxt-auth": "0.11.1"
19
+ "@sbc-connect/nuxt-auth": "0.12.0"
20
20
  },
21
21
  "scripts": {
22
22
  "preinstall": "npx only-allow pnpm",
@@ -29,6 +29,7 @@
29
29
  "lint:fix": "eslint --fix .",
30
30
  "test": "pnpm run test:unit; pnpm run test:e2e",
31
31
  "test:unit": "vitest run",
32
+ "test:unit:watch": "vitest",
32
33
  "test:unit:cov": "vitest --dir tests/unit --coverage",
33
34
  "test:e2e": "npx playwright test",
34
35
  "test:e2e:ui": "npx playwright test --ui",