Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[commerce-sdk-react] Multisite support #769

Merged
merged 14 commits into from
Oct 20, 2022
16 changes: 16 additions & 0 deletions packages/commerce-sdk-react/src/auth/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ jest.mock('./storage', () => {
},
get(key: string) {
return map.get(key)
},
delete(key: string) {
map.delete(key)
}
}
})
Expand Down Expand Up @@ -149,6 +152,19 @@ describe('Auth', () => {
// @ts-expect-error private method
expect(() => auth.isTokenExpired()).toThrow()
})
test('site switch clears auth storage', () => {
const auth = new Auth(config)
// @ts-expect-error private method
auth.set('access_token', '123')
// @ts-expect-error private method
auth.set('refresh_token_guest', '456')
const switchSiteConfig = {...config, siteId: 'another site'}
const newAuth = new Auth(switchSiteConfig)
// @ts-expect-error private method
expect(newAuth.get('access_token')).not.toBe('123')
// @ts-expect-error private method
expect(newAuth.get('refresh_token_guest')).not.toBe('456')
})
test('isTokenExpired', () => {
const auth = new Auth(config)
const JWTNotExpired = jwt.sign({exp: Math.floor(Date.now() / 1000) + 1000}, 'secret')
Expand Down
24 changes: 24 additions & 0 deletions packages/commerce-sdk-react/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type AuthDataKeys =
| 'refresh_token_registered'
| 'token_type'
| 'usid'
| 'site_id'
type AuthDataMap = Record<
AuthDataKeys,
{
Expand Down Expand Up @@ -101,6 +102,11 @@ const DATA_MAP: AuthDataMap = {
callback: () => {
cookieStorage.delete('cc-nx-g')
}
},
site_id: {
// do we need this be a cookie to support plugin_slas?
kevinxh marked this conversation as resolved.
Show resolved Hide resolved
storage: localStorage,
key: 'site_id'
}
}

Expand Down Expand Up @@ -131,6 +137,16 @@ class Auth {
fetchOptions: config.fetchOptions
})

if (this.get('site_id') && this.get('site_id') !== config.siteId) {
// if site is switched, remove all existing auth data in storage
// and the next auth.ready() call with restart the auth flow
this.clearStorage()
}

if (!this.get('site_id')) {
this.set('site_id', config.siteId)
}

this.redirectURI = config.redirectURI
}

Expand All @@ -146,6 +162,14 @@ class Auth {
DATA_MAP[name].callback?.()
}

private clearStorage() {
Object.keys(DATA_MAP).forEach((key) => {
DATA_MAP[key as keyof typeof DATA_MAP].storage.delete(
kevinxh marked this conversation as resolved.
Show resolved Hide resolved
DATA_MAP[key as keyof typeof DATA_MAP].key
)
})
}

/**
* Every method in this class that returns a `TokenResponse` constructs it via this getter.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import React, {ReactElement} from 'react'
import React, {useState, ReactElement} from 'react'
// @ts-ignore
import {CommerceApiProvider} from 'commerce-sdk-react'
// @ts-ignore
Expand All @@ -21,9 +21,12 @@ const AppConfig = (props: AppConfigProps): ReactElement => {
const headers = {
'correlation-id': correlationId
}
const defaultSiteId = 'RefArchGlobal'
const [siteId, setSiteId] = useState(defaultSiteId)
const anotherSite = siteId === defaultSiteId ? 'RefArch' : defaultSiteId
return (
<CommerceApiProvider
siteId="RefArchGlobal"
siteId={siteId}
shortCode="8o7m175y"
clientId="c9c45bfd-0ed3-4aa2-9971-40f88962b836"
organizationId="f_ecom_zzrf_001"
Expand All @@ -34,6 +37,16 @@ const AppConfig = (props: AppConfigProps): ReactElement => {
headers={headers}
>
{props.children}
<div style={{position: 'fixed', right: 0, bottom: 0, margin: '8px'}}>
<h3>Site: {siteId}</h3>
<button
onClick={() => {
setSiteId(anotherSite)
}}
>
Switch to {anotherSite}
</button>
</div>
</CommerceApiProvider>
)
}
Expand Down