Skip to content

Commit 9f2e6e9

Browse files
committed
Hide add new payment method button for SFP
1 parent 72cef5d commit 9f2e6e9

12 files changed

Lines changed: 435 additions & 38 deletions

File tree

packages/commerce-sdk-react/src/constant.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,6 @@ export const CLIENT_KEYS = {
7575
SHOPPER_PROMOTIONS: 'shopperPromotions',
7676
SHOPPER_SEARCH: 'shopperSearch',
7777
SHOPPER_SEO: 'shopperSeo',
78-
SHOPPER_STORES: 'shopperStores'
78+
SHOPPER_STORES: 'shopperStores',
79+
SHOPPER_CONFIGURATIONS: 'shopperConfigurations'
7980
} as const
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import {CLIENT_KEYS} from '../../constant'
8+
import {ApiClients, CacheUpdateMatrix} from '../types'
9+
10+
const CLIENT_KEY = CLIENT_KEYS.SHOPPER_CONFIGURATIONS
11+
type Client = NonNullable<ApiClients[typeof CLIENT_KEY]>
12+
13+
// ShopperConfigurations API is primarily for reading configuration data
14+
// No mutations are currently supported
15+
export const cacheUpdateMatrix: CacheUpdateMatrix<Client> = {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import {renderHook} from '@testing-library/react'
8+
import {useConfigurations} from './query'
9+
10+
describe('ShopperConfigurations', () => {
11+
describe('useConfigurations', () => {
12+
it('should be defined', () => {
13+
expect(useConfigurations).toBeDefined()
14+
})
15+
})
16+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
export * from './query'
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import nock from 'nock'
8+
import {
9+
mockQueryEndpoint,
10+
renderHookWithProviders,
11+
waitAndExpectError,
12+
waitAndExpectSuccess,
13+
createQueryClient
14+
} from '../../test-utils'
15+
16+
import {Argument} from '../types'
17+
import * as queries from './query'
18+
19+
jest.mock('../../auth/index.ts', () => {
20+
const {default: mockAuth} = jest.requireActual('../../auth/index.ts')
21+
mockAuth.prototype.ready = jest.fn().mockResolvedValue({access_token: 'access_token'})
22+
return mockAuth
23+
})
24+
25+
type Queries = typeof queries
26+
const configurationsEndpoint = '/organizations/'
27+
// Not all endpoints use all parameters, but unused parameters are safely discarded
28+
const OPTIONS: Argument<Queries[keyof Queries]> = {
29+
parameters: {organizationId: 'f_ecom_zzrmy_orgf_001'}
30+
}
31+
32+
// Mock data for configurations
33+
const mockConfigurationsData = {
34+
configurations: [
35+
{
36+
id: 'gcp',
37+
value: 'test-gcp-api-key'
38+
},
39+
{
40+
id: 'einstein',
41+
value: 'test-einstein-api-key'
42+
}
43+
]
44+
}
45+
46+
describe('Shopper Configurations query hooks', () => {
47+
beforeEach(() => nock.cleanAll())
48+
afterEach(() => {
49+
expect(nock.pendingMocks()).toHaveLength(0)
50+
})
51+
52+
test('`useConfigurations` has meta.displayName defined', async () => {
53+
mockQueryEndpoint(configurationsEndpoint, mockConfigurationsData)
54+
const queryClient = createQueryClient()
55+
const {result} = renderHookWithProviders(
56+
() => {
57+
return queries.useConfigurations(OPTIONS)
58+
},
59+
{queryClient}
60+
)
61+
await waitAndExpectSuccess(() => result.current)
62+
expect(queryClient.getQueryCache().getAll()[0].meta?.displayName).toBe('useConfigurations')
63+
})
64+
65+
test('`useConfigurations` returns data on success', async () => {
66+
mockQueryEndpoint(configurationsEndpoint, mockConfigurationsData)
67+
const {result} = renderHookWithProviders(() => {
68+
return queries.useConfigurations(OPTIONS)
69+
})
70+
await waitAndExpectSuccess(() => result.current)
71+
expect(result.current.data).toEqual(mockConfigurationsData)
72+
})
73+
74+
test('`useConfigurations` returns error on error', async () => {
75+
mockQueryEndpoint(configurationsEndpoint, {}, 400)
76+
const {result} = renderHookWithProviders(() => {
77+
return queries.useConfigurations(OPTIONS)
78+
})
79+
await waitAndExpectError(() => result.current)
80+
})
81+
82+
test('`useConfigurations` handles 500 server error', async () => {
83+
mockQueryEndpoint(configurationsEndpoint, {}, 500)
84+
const {result} = renderHookWithProviders(() => {
85+
return queries.useConfigurations(OPTIONS)
86+
})
87+
await waitAndExpectError(() => result.current)
88+
})
89+
})
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import {UseQueryResult} from '@tanstack/react-query'
8+
import {ShopperConfigurations} from 'commerce-sdk-isomorphic'
9+
import {ApiClients, ApiQueryOptions, Argument, DataType, NullableParameters} from '../types'
10+
import {useQuery} from '../useQuery'
11+
import {mergeOptions, omitNullableParameters, pickValidParams} from '../utils'
12+
import * as queryKeyHelpers from './queryKeyHelpers'
13+
import {CLIENT_KEYS} from '../../constant'
14+
import useCommerceApi from '../useCommerceApi'
15+
16+
const CLIENT_KEY = CLIENT_KEYS.SHOPPER_CONFIGURATIONS
17+
type Client = NonNullable<ApiClients[typeof CLIENT_KEY]>
18+
19+
/**
20+
* Gets configuration information that encompasses toggles, preferences, and configuration that allow the application to be reactive to changes performed by the merchant, admin, or support engineer.
21+
*
22+
* @group ShopperConfigurations
23+
* @category Query
24+
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
25+
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
26+
* @returns A TanStack Query query hook with data from the Shopper Configurations `getConfigurations` endpoint.
27+
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-configurations?meta=getConfigurations| Salesforce Developer Center} for more information about the API endpoint.
28+
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperconfigurations.shopperconfigurations-1.html#getconfigurations | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
29+
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
30+
*/
31+
export const useConfigurations = (
32+
apiOptions: NullableParameters<Argument<Client['getConfigurations']>>,
33+
queryOptions: ApiQueryOptions<Client['getConfigurations']> = {}
34+
): UseQueryResult<DataType<Client['getConfigurations']>> => {
35+
type Options = Argument<Client['getConfigurations']>
36+
type Data = DataType<Client['getConfigurations']>
37+
const client = useCommerceApi(CLIENT_KEY)
38+
const methodName = 'getConfigurations'
39+
const requiredParameters = ShopperConfigurations.paramKeys[`${methodName}Required`]
40+
41+
// Parameters can be set in `apiOptions` or `client.clientConfig`
42+
// we must merge them in order to generate the correct query key.
43+
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions || {}))
44+
const parameters = pickValidParams(
45+
netOptions.parameters,
46+
ShopperConfigurations.paramKeys[methodName]
47+
)
48+
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
49+
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
50+
const method = async (options: Options) => await client[methodName](options)
51+
52+
queryOptions.meta = {
53+
displayName: 'useConfigurations',
54+
...queryOptions.meta
55+
}
56+
57+
return useQuery<Client, Options, Data>({...netOptions, parameters}, queryOptions, {
58+
method,
59+
queryKey,
60+
requiredParameters
61+
})
62+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2023, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import {ShopperConfigurations} from 'commerce-sdk-isomorphic'
8+
import {Argument, ExcludeTail} from '../types'
9+
import {pickValidParams} from '../utils'
10+
11+
// We must use a client with no parameters in order to have required/optional match the API spec
12+
type Client = ShopperConfigurations<{shortCode: string}>
13+
type Params<T extends keyof QueryKeys> = Partial<Argument<Client[T]>['parameters']>
14+
export type QueryKeys = {
15+
getConfigurations: [
16+
'/commerce-sdk-react',
17+
'/organizations/',
18+
string | undefined,
19+
'/configurations',
20+
Params<'getConfigurations'>
21+
]
22+
}
23+
24+
// This is defined here, rather than `types.ts`, because it relies on `Client` and `QueryKeys`,
25+
// and making those generic would add too much complexity.
26+
type QueryKeyHelper<T extends keyof QueryKeys> = {
27+
/** Generates the path component of the query key for an endpoint. */
28+
path: (params: Params<T>) => ExcludeTail<QueryKeys[T]>
29+
/** Generates the full query key for an endpoint. */
30+
queryKey: (params: Params<T>) => QueryKeys[T]
31+
}
32+
33+
export const getConfigurations: QueryKeyHelper<'getConfigurations'> = {
34+
path: (params) => [
35+
'/commerce-sdk-react',
36+
'/organizations/',
37+
params?.organizationId,
38+
'/configurations'
39+
],
40+
queryKey: (params: Params<'getConfigurations'>) => {
41+
return [
42+
...getConfigurations.path(params),
43+
pickValidParams(params || {}, ShopperConfigurations.paramKeys.getConfigurations)
44+
]
45+
}
46+
}

packages/commerce-sdk-react/src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from './ShopperSearch'
1717
export * from './ShopperStores'
1818
export * from './ShopperSeo'
1919
export * from './useAuthHelper'
20+
export * from './ShopperConfigurations'
2021
export {default as useAccessToken} from './useAccessToken'
2122
export {default as useCommerceApi} from './useCommerceApi'
2223
export {default as useEncUserId} from './useEncUserId'

packages/commerce-sdk-react/src/hooks/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import {InvalidateQueryFilters, QueryFilters, Updater, UseQueryOptions} from '@tanstack/react-query'
88
import {
99
ShopperBaskets,
10+
ShopperConfigurations,
1011
ShopperContexts,
1112
ShopperCustomers,
1213
ShopperExperience,
@@ -96,6 +97,7 @@ export interface ApiClients {
9697
shopperSearch?: ShopperSearch<ApiClientConfigParams>
9798
shopperSeo?: ShopperSeo<ApiClientConfigParams>
9899
shopperStores?: ShopperStores<ApiClientConfigParams>
100+
shopperConfigurations?: ShopperConfigurations<ApiClientConfigParams>
99101
}
100102

101103
export type ApiClient = NonNullable<ApiClients[keyof ApiClients]>

packages/commerce-sdk-react/src/provider.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import {
1818
ShopperBaskets,
1919
ShopperContexts,
20+
ShopperConfigurations,
2021
ShopperCustomers,
2122
ShopperExperience,
2223
ShopperLogin,
@@ -284,7 +285,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => {
284285
shopperPromotions: new ShopperPromotions(config),
285286
shopperSearch: new ShopperSearch(config),
286287
shopperSeo: new ShopperSeo(config),
287-
shopperStores: new ShopperStores(config)
288+
shopperStores: new ShopperStores(config),
289+
shopperConfigurations: new ShopperConfigurations(config)
288290
}
289291
}, [
290292
clientId,

0 commit comments

Comments
 (0)