Skip to content

Commit c179072

Browse files
committed
feat(open-services): deeplink support
1 parent 3257cf4 commit c179072

File tree

5 files changed

+292
-13
lines changed

5 files changed

+292
-13
lines changed

docs/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,80 @@ mtLinkSdk.openService(serviceId, options);
202202
| - | - | - | - | - |
203203
| serviceId | `vault`, `myaccount-settings`, `link-kit` | true | | Open a service by Id, current supported services are:<br /><li>`vault` - Manage your financial institution credentials.</li><li>`myaccount-settings` - Manage your Moneytree account settings.</li><li>`link-kit` - View all your financial data.<br /><br /><strong>NOTE:</strong> This function will throw an error if you do not specify a valid service ID. |
204204
| options | object | false | Value set during `init`. | Optional parameters. Includes all options in [common options](#common-api-options). |
205+
| options.view | `services-list`, `service-connection`, `connection-setting`, `customer-support` | false | | We provide the way to open the Vault's specific pages. Please check the following sessions:<br /> <li>[Open Vault Services Page](#open-vault-services-page)</li><li>[Open Vault Service Connection Page](#open-vault-service-connection-page)</li><li>[Open Vault Service Setting Page](#open-vault-service-setting-page)</li><li>[Open Vault Customer Support Page](#open-vault-customer-support-page)</li> <br /><br /><strong>NOTE:</strong> The serviceId must be `vault` to enable this option.|
206+
207+
#### Open Vault Services Page
208+
209+
It has to include these properties of `options` below when calling [openService](#openservice) API.
210+
211+
<strong>NOTE:</strong> This scenario only works when serviceId is `vault`.
212+
213+
<h6>Usage:</h6>
214+
215+
```javascript
216+
mtLinkSdk.openService('vault', { view: 'services-list', type: 'bank', group: 'grouping_bank', search: 'japan' });
217+
```
218+
219+
| Parameter | Type | Required | Default Value | Description |
220+
| - | - | - | - | - |
221+
| serviceId | `vault` | true | | Open a Vault service.|
222+
| options.view | `services-list` | true | | Assign to open services page.|
223+
| options.type | `bank` (personal bank), <br />`credit_card` (personal credit card), <br />`stored_value` (electronic money), `point` (loyalty point), <br />`corporate` (corporate bank or card) | false | | Filter the services by type. |
224+
| options.group | `grouping_bank`, `grouping_bank_credit_card`, `grouping_bank_dc_card`, `grouping_corporate_credit_card`, `grouping_credit_card`, `grouping_credit_coop`, `grouping_credit_union`, `grouping_dc_pension_plan`, `grouping_debit_card`, `grouping_digital_money`, `grouping_ja_bank`, `grouping_life_insurance`, `grouping_point`, `grouping_regional_bank`, `grouping_stock`, `grouping_testing` | false | | Filter the services by group. |
225+
| options.search | string | false | | Filter the services by the search term. |
226+
227+
#### Open Vault Service Connection Page
228+
229+
It has to include these properties of `options` below when calling [openService](#openservice) API.
230+
231+
<strong>NOTE:</strong> This scenario only works when serviceId is `vault`.
232+
233+
<h6>Usage:</h6>
234+
235+
```javascript
236+
mtLinkSdk.openService('vault', { view: 'service-connection', entityKey: 'yucho_bank'});
237+
```
238+
239+
| Parameter | Type | Required | Default Value | Description |
240+
| - | - | - | - | - |
241+
| serviceId | `vault` | true | | Open a Vault service|
242+
| options.view | `service-connection` | true | | Assign to open service connection page|
243+
| options.entityKey | string | true | | Service entity key <br /><br /><strong>NOTE:</strong> Top page of the Vault would be shown if `entityKey` is invalid.|
244+
245+
#### Open Vault Service Setting Page
246+
247+
It has to include these properties of `options` below when calling [openService](#openservice) API.
248+
249+
<strong>NOTE:</strong> This scenario only works when serviceId is `vault`.
250+
251+
<h6>Usage:</h6>
252+
253+
```javascript
254+
mtLinkSdk.openService('vault', { view: 'connection-setting', credentialId: '123456'});
255+
```
256+
257+
| Parameter | Type | Required | Default Value | Description |
258+
| - | - | - | - | - |
259+
| serviceId | `vault` | true | | Open a Vault service|
260+
| options.view | `connection-setting` | true | | Assign to open connection setting page|
261+
| options.credentialId | string | true | | Service credential Id <br /><br /><strong>NOTE:</strong> Top page of the Vault would be shown if the `credentialId` is invalid.|
262+
263+
#### Open Vault Customer Support Page
264+
265+
It has to include these properties of `options` below when calling [openService](#openservice) API.
266+
267+
<strong>NOTE:</strong> This scenario only works when serviceId is `vault`.
268+
269+
<h6>Usage:</h6>
270+
271+
```javascript
272+
mtLinkSdk.openService('vault', { view: 'customer-support' });
273+
```
274+
275+
| Parameter | Type | Required | Default Value | Description |
276+
| - | - | - | - | - |
277+
| serviceId | `vault` | true | | Open a Vault service|
278+
| options.view | `customer-support` | true | | Assign to open customer support page|
205279

206280
### requestMagicLink
207281

src/api/__tests__/open-service.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,94 @@ describe('api', () => {
4444
expect(open).toBeCalledWith(url, '_self');
4545
});
4646

47+
test('vault/services-list', () => {
48+
open.mockClear();
49+
50+
openService(new MtLinkSdk().storedOptions, 'vault', {
51+
view: 'services-list',
52+
type: 'bank',
53+
group: 'grouping_testing',
54+
search: 'vault',
55+
showRememberMe: false,
56+
});
57+
58+
expect(open).toBeCalledTimes(1);
59+
60+
const query = qs.stringify({
61+
configs: generateConfigs({
62+
showRememberMe: false,
63+
}),
64+
group: 'grouping_testing',
65+
type: 'bank',
66+
search: 'vault',
67+
});
68+
const url = `${VAULT_DOMAINS.production}/services?${query}`;
69+
70+
expect(open).toBeCalledWith(url, '_self');
71+
});
72+
73+
test('vault/service-connection', () => {
74+
open.mockClear();
75+
76+
openService(new MtLinkSdk().storedOptions, 'vault', {
77+
view: 'service-connection',
78+
entityKey: 'fauxbank_test_bank',
79+
showRememberMe: false,
80+
});
81+
82+
expect(open).toBeCalledTimes(1);
83+
84+
const query = qs.stringify({
85+
configs: generateConfigs({
86+
showRememberMe: false,
87+
}),
88+
});
89+
const url = `${VAULT_DOMAINS.production}/service/fauxbank_test_bank?${query}`;
90+
91+
expect(open).toBeCalledWith(url, '_self');
92+
});
93+
94+
test('vault/connection-setting', () => {
95+
open.mockClear();
96+
97+
openService(new MtLinkSdk().storedOptions, 'vault', {
98+
view: 'connection-setting',
99+
credentialId: '123',
100+
showRememberMe: false,
101+
});
102+
103+
expect(open).toBeCalledTimes(1);
104+
105+
const query = qs.stringify({
106+
configs: generateConfigs({
107+
showRememberMe: false,
108+
}),
109+
});
110+
const url = `${VAULT_DOMAINS.production}/connection/123?${query}`;
111+
112+
expect(open).toBeCalledWith(url, '_self');
113+
});
114+
115+
test('vault/customer-support', () => {
116+
open.mockClear();
117+
118+
openService(new MtLinkSdk().storedOptions, 'vault', {
119+
view: 'customer-support',
120+
showRememberMe: false,
121+
});
122+
123+
expect(open).toBeCalledTimes(1);
124+
125+
const query = qs.stringify({
126+
configs: generateConfigs({
127+
showRememberMe: false,
128+
}),
129+
});
130+
const url = `${VAULT_DOMAINS.production}/customer-support?${query}`;
131+
132+
expect(open).toBeCalledWith(url, '_self');
133+
});
134+
47135
test('link-kit', () => {
48136
open.mockClear();
49137

src/api/open-service.ts

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,112 @@ import { stringify } from 'qs';
22

33
import { generateConfigs, mergeConfigs, getIsTabValue } from '../helper';
44
import { MY_ACCOUNT_DOMAINS, VAULT_DOMAINS, LINK_KIT_DOMAINS } from '../server-paths';
5-
import { StoredOptions, ServiceId, ConfigsOptions } from '../typings';
5+
import {
6+
StoredOptions,
7+
ServiceId,
8+
OpenServicesConfigsOptions,
9+
ConnectionSettingType,
10+
ServiceConnectionType,
11+
ServicesListType,
12+
} from '../typings';
13+
14+
interface QueryData {
15+
client_id?: string;
16+
cobrand_client_id?: string;
17+
locale?: string;
18+
configs: string;
19+
}
620

721
export default function openService(
822
storedOptions: StoredOptions,
923
serviceId: ServiceId,
10-
options: ConfigsOptions = {}
24+
options: OpenServicesConfigsOptions = {}
1125
): void {
1226
if (!window) {
1327
throw new Error('[mt-link-sdk] `openService` only works in the browser.');
1428
}
1529

1630
const { clientId, mode, cobrandClientId, locale } = storedOptions;
17-
const { isNewTab, ...rest } = options;
31+
const { isNewTab, view, ...rest } = options;
32+
33+
const getQueryValue = (needStringify = true): string | QueryData => {
34+
const query: QueryData = {
35+
client_id: clientId,
36+
cobrand_client_id: cobrandClientId,
37+
locale,
38+
configs: generateConfigs(mergeConfigs(storedOptions, rest)),
39+
};
1840

19-
const queryString = stringify({
20-
client_id: clientId,
21-
cobrand_client_id: cobrandClientId,
22-
locale,
23-
configs: generateConfigs(mergeConfigs(storedOptions, rest)),
24-
});
41+
if (!needStringify) {
42+
return query;
43+
}
44+
45+
return stringify(query);
46+
};
2547

2648
switch (serviceId) {
2749
case 'vault':
28-
window.open(`${VAULT_DOMAINS[mode]}?${queryString}`, getIsTabValue(isNewTab));
50+
if (!view) {
51+
window.open(`${VAULT_DOMAINS[mode]}?${getQueryValue()}`, getIsTabValue(isNewTab));
52+
break;
53+
}
54+
55+
switch (view) {
56+
case 'services-list':
57+
// eslint-disable-next-line no-case-declarations
58+
const { group, type, search } = options as ServicesListType;
59+
60+
window.open(
61+
`${VAULT_DOMAINS[mode]}/services?${stringify({
62+
...(getQueryValue(false) as QueryData),
63+
group,
64+
type,
65+
search,
66+
})}`,
67+
getIsTabValue(isNewTab)
68+
);
69+
break;
70+
71+
case 'service-connection':
72+
// eslint-disable-next-line no-case-declarations
73+
const { entityKey } = options as ServiceConnectionType;
74+
75+
window.open(
76+
`${VAULT_DOMAINS[mode]}/service/${entityKey}?${getQueryValue()}`,
77+
getIsTabValue(isNewTab)
78+
);
79+
break;
80+
81+
case 'connection-setting':
82+
// eslint-disable-next-line no-case-declarations
83+
const { credentialId } = options as ConnectionSettingType;
84+
85+
window.open(
86+
`${VAULT_DOMAINS[mode]}/connection/${credentialId}?${getQueryValue()}`,
87+
getIsTabValue(isNewTab)
88+
);
89+
break;
90+
91+
case 'customer-support':
92+
default:
93+
window.open(
94+
`${VAULT_DOMAINS[mode]}/customer-support?${getQueryValue()}`,
95+
getIsTabValue(isNewTab)
96+
);
97+
break;
98+
}
99+
29100
break;
30101

31102
case 'myaccount-settings':
32-
window.open(`${MY_ACCOUNT_DOMAINS[mode]}/settings?${queryString}`, getIsTabValue(isNewTab));
103+
window.open(
104+
`${MY_ACCOUNT_DOMAINS[mode]}/settings?${getQueryValue()}`,
105+
getIsTabValue(isNewTab)
106+
);
33107
break;
34108

35109
case 'link-kit':
36-
window.open(`${LINK_KIT_DOMAINS[mode]}?${queryString}`, getIsTabValue(isNewTab));
110+
window.open(`${LINK_KIT_DOMAINS[mode]}?${getQueryValue()}`, getIsTabValue(isNewTab));
37111
break;
38112

39113
default:

src/helper.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,19 @@ export function mergeConfigs(
6262
export function generateConfigs(configs: ConfigsOptions = {}): string {
6363
const snakeCaseConfigs: { [key: string]: string | AuthAction | boolean | undefined } = {};
6464

65+
const configKeys = [
66+
'email',
67+
'backTo',
68+
'authAction',
69+
'showAuthToggle',
70+
'showRememberMe',
71+
'isNewTab',
72+
];
73+
6574
for (const key in configs) {
66-
snakeCaseConfigs[snakeCase(key)] = configs[key as keyof ConfigsOptions];
75+
if (configKeys.includes(key)) {
76+
snakeCaseConfigs[snakeCase(key)] = configs[key as keyof ConfigsOptions];
77+
}
6778
}
6879

6980
return stringify({

src/typings.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@ export interface ConfigsOptions extends PrivateConfigsOptions {
1818
isNewTab?: boolean;
1919
}
2020

21+
export type ServicesListType = {
22+
view?: 'services-list';
23+
group?:
24+
| 'grouping_bank'
25+
| 'grouping_bank_credit_card'
26+
| 'grouping_bank_dc_card'
27+
| 'grouping_corporate_credit_card'
28+
| 'grouping_credit_card'
29+
| 'grouping_credit_coop'
30+
| 'grouping_credit_union'
31+
| 'grouping_dc_pension_plan'
32+
| 'grouping_debit_card'
33+
| 'grouping_digital_money'
34+
| 'grouping_ja_bank'
35+
| 'grouping_life_insurance'
36+
| 'grouping_point'
37+
| 'grouping_regional_bank'
38+
| 'grouping_stock'
39+
| 'grouping_testing';
40+
type?: 'bank' | 'credit_card' | 'stored_value' | 'point' | 'corporate';
41+
search?: string;
42+
};
43+
44+
export type ServiceConnectionType = { view?: 'service-connection'; entityKey: string };
45+
46+
export type ConnectionSettingType = { view?: 'connection-setting'; credentialId: string };
47+
48+
export type CustomerSupportType = { view?: 'customer-support' };
49+
50+
export type OpenServicesConfigsOptions = ConfigsOptions &
51+
(ServicesListType | ServiceConnectionType | ConnectionSettingType | CustomerSupportType);
52+
2153
export type Scopes = string | string[];
2254

2355
interface AuthorizeConfigsOptions {

0 commit comments

Comments
 (0)