Skip to content

Commit

Permalink
feat(api): Add openServiceUrl API
Browse files Browse the repository at this point in the history
Similar to `openService` API, but returns URL instead of open the URL immediately.
  • Loading branch information
mt-max committed Aug 22, 2023
1 parent 001ca24 commit eeafa30
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 96 deletions.
14 changes: 14 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,20 @@ mtLinkSdk.openService('myaccount', { view: 'settings/update-email' });
| serviceId | `myaccount` | true | | Open MyAccount |
| options.view | string | false | `settings` (for mobile view)<p><strong>OR</strong></p>`settings/update-email` (for desktop view) | Directly go to the chosen page. Currently supported locations include:<li>`settings` - Main Moneytree account settings screen.</li><li>`settings/authorized-applications` - List of apps currently connected to Moneytree.</li><li>`settings/change-language` - Change Moneytree account language screen.<li>`settings/email-preferences` - Change Moneytree email preferences screen</li><li>`settings/delete-account` - Delete Moneytree account screen.</li><li>`settings/update-email` - Change Moneytree account email screen.</li><li>`settings/update-password` - Change Moneytree account password screen.</li><br> If no value is provided, it goes to the top page of MyAccount. |

### openServiceUrl

This method generates URLs to open various services provided by Moneytree, such as Moneytree Account Settings and Vault, etc. If you want to use the URLs for other purposes or load them in a different way, use this API instead of `openService`.

<strong>NOTE:</strong> calling this API before calling `init` will open the services view without branding (company logo etc.)

<h6>Usage:</h6>

```javascript
mtLinkSdk.openServiceUrl(serviceId, options);
```

This API has exactly the same parameters as `openService`, the only difference being that it returns an URL instead of opening immediately with `window.open`.

### requestLoginLink

Request for a password-less login link to be sent to the guest's email address. Clicking on the link in the email will log a guest in directly to the screen specified by the `loginLinkTo` parameter.
Expand Down
183 changes: 183 additions & 0 deletions src/api/__tests__/open-service-url.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import qs from 'qs';

import { MY_ACCOUNT_DOMAINS, VAULT_DOMAINS, LINK_KIT_DOMAINS } from '../../server-paths';
import { MtLinkSdk } from '../..';
import openServiceUrl from '../open-service-url';
import { generateConfigs } from '../../helper';

describe('api', () => {
describe('open-service-url', () => {
const clientId = 'clientId';

test('myaccount', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'myaccount');

const query = qs.stringify({
configs: generateConfigs()
});

expect(url).toBe(`${MY_ACCOUNT_DOMAINS.production}/?${query}`);
});

test('myaccount/change-language', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'myaccount', {
view: 'settings/change-language'
});

const query = qs.stringify({
configs: generateConfigs()
});

expect(url).toBe(`${MY_ACCOUNT_DOMAINS.production}/settings/change-language?${query}`);
});

test('vault', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'vault', {
showRememberMe: false
});

const query = qs.stringify({
configs: generateConfigs({
showRememberMe: false
})
});

expect(url).toBe(`${VAULT_DOMAINS.production}?${query}`);
});

test('vault/services-list', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'vault', {
view: 'services-list',
type: 'bank',
group: 'grouping_testing',
search: 'vault',
showRememberMe: false
});

const query = qs.stringify({
configs: generateConfigs({
showRememberMe: false
}),
group: 'grouping_testing',
type: 'bank',
search: 'vault'
});

expect(url).toBe(`${VAULT_DOMAINS.production}/services?${query}`);
});

test('vault/service-connection', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'vault', {
view: 'service-connection',
entityKey: 'fauxbank_test_bank',
showRememberMe: false
});

const query = qs.stringify({
configs: generateConfigs({
showRememberMe: false
})
});

expect(url).toBe(`${VAULT_DOMAINS.production}/service/fauxbank_test_bank?${query}`);
});

test('vault/connection-setting', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'vault', {
view: 'connection-setting',
credentialId: '123',
showRememberMe: false
});

const query = qs.stringify({
configs: generateConfigs({
showRememberMe: false
})
});

expect(url).toBe(`${VAULT_DOMAINS.production}/connection/123?${query}`);
});

test('vault/customer-support', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'vault', {
view: 'customer-support',
showRememberMe: false
});

const query = qs.stringify({
configs: generateConfigs({
showRememberMe: false
})
});

expect(url).toBe(`${VAULT_DOMAINS.production}/customer-support?${query}`);
});

test('link-kit', () => {
const url = openServiceUrl(new MtLinkSdk().storedOptions, 'link-kit');

const query = qs.stringify({
configs: generateConfigs()
});

expect(url).toBe(`${LINK_KIT_DOMAINS.production}?${query}`);
});

test('calling after init will includes client id', () => {
const cobrandClientId = 'cobrandClientId';
const locale = 'locale';

const mtLinkSdk = new MtLinkSdk();
mtLinkSdk.init(clientId, {
locale,
cobrandClientId
});

const url = openServiceUrl(mtLinkSdk.storedOptions, 'myaccount');

const query = qs.stringify({
client_id: clientId,
cobrand_client_id: cobrandClientId,
locale,
configs: generateConfigs()
});

expect(url).toBe(`${MY_ACCOUNT_DOMAINS.production}/?${query}`);
});

test('invalid service id', () => {
expect(() => {
openServiceUrl(new MtLinkSdk().storedOptions, 'invalid');
}).toThrow('[mt-link-sdk] Invalid `serviceId` in `openServiceUrl/openService`, got: invalid');
});

test('saml_subject_id is passed when initialized', () => {
const instance = new MtLinkSdk();
instance.init('clientId', { samlSubjectId: 'samlSubjectId' });

const url = openServiceUrl(instance.storedOptions, 'myaccount');

const query = qs.stringify({
client_id: 'clientId',
saml_subject_id: 'samlSubjectId',
configs: generateConfigs()
});

expect(url).toBe(`${MY_ACCOUNT_DOMAINS.production}/?${query}`);
});

test('undefined saml_subject_id should not be passed down', () => {
const instance = new MtLinkSdk();
instance.init('clientId', { samlSubjectId: undefined });

const url = openServiceUrl(instance.storedOptions, 'myaccount');

const query = qs.stringify({
client_id: 'clientId',
configs: generateConfigs()
});

expect(url).toBe(`${MY_ACCOUNT_DOMAINS.production}/?${query}`);
});
});
});
2 changes: 1 addition & 1 deletion src/api/__tests__/open-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe('api', () => {
test('invalid service id', () => {
expect(() => {
openService(new MtLinkSdk().storedOptions, 'invalid');
}).toThrow('[mt-link-sdk] Invalid `serviceId` in `openService`, got: invalid');
}).toThrow('[mt-link-sdk] Invalid `serviceId` in `openServiceUrl/openService`, got: invalid');
});

test('saml_subject_id is passed when initialized', () => {
Expand Down
90 changes: 90 additions & 0 deletions src/api/open-service-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { stringify } from 'qs';

import { generateConfigs, mergeConfigs } from '../helper';
import { MY_ACCOUNT_DOMAINS, VAULT_DOMAINS, LINK_KIT_DOMAINS } from '../server-paths';
import {
StoredOptions,
ServiceId,
OpenServicesUrlConfigsOptions,
ConnectionSettingType,
ServiceConnectionType,
ServicesListType
} from '../typings';

interface QueryData {
client_id?: string;
cobrand_client_id?: string;
locale?: string;
configs: string;
saml_subject_id?: string;
}

export default function openServiceUrl(
storedOptions: StoredOptions,
serviceId: ServiceId,
options: OpenServicesUrlConfigsOptions = {}
): string {
const { clientId, mode, cobrandClientId, locale, samlSubjectId } = storedOptions;
const { view = '', ...rest } = options;

const getQueryValue = (needStringify = true): string | QueryData => {
const query: QueryData = {
client_id: clientId,
cobrand_client_id: cobrandClientId,
locale,
saml_subject_id: samlSubjectId,
configs: generateConfigs(mergeConfigs(storedOptions, rest))
};

if (!needStringify) {
return query;
}

return stringify(query);
};

switch (serviceId) {
case 'vault':
if (!view) {
return `${VAULT_DOMAINS[mode]}?${getQueryValue()}`;
}

switch (view) {
case 'services-list':
// eslint-disable-next-line no-case-declarations
const { group, type, search } = options as ServicesListType;

return `${VAULT_DOMAINS[mode]}/services?${stringify({
...(getQueryValue(false) as QueryData),
group,
type,
search
})}`;

case 'service-connection':
// eslint-disable-next-line no-case-declarations
const { entityKey } = options as ServiceConnectionType;

return `${VAULT_DOMAINS[mode]}/service/${entityKey}?${getQueryValue()}`;

case 'connection-setting':
// eslint-disable-next-line no-case-declarations
const { credentialId } = options as ConnectionSettingType;

return `${VAULT_DOMAINS[mode]}/connection/${credentialId}?${getQueryValue()}`;

case 'customer-support':
default:
return `${VAULT_DOMAINS[mode]}/customer-support?${getQueryValue()}`;
}

case 'myaccount':
return `${MY_ACCOUNT_DOMAINS[mode]}/${view}?${getQueryValue()}`;

case 'link-kit':
return `${LINK_KIT_DOMAINS[mode]}?${getQueryValue()}`;

default:
throw new Error(`[mt-link-sdk] Invalid \`serviceId\` in \`openServiceUrl/openService\`, got: ${serviceId}`);
}
}
Loading

0 comments on commit eeafa30

Please sign in to comment.