@connectid-tools/idp-selector-react 6.7.0 → 6.9.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/IntroText.js CHANGED
@@ -5,10 +5,11 @@ import { ThemeContext } from './ThemeContext';
5
5
  const introTextContent = {
6
6
  'verify-trust': 'ConnectID lets you verify your identity through details stored with an organisation you already trust, like your bank.',
7
7
  'verify-account': 'Verify your identity through an organisation you already have an account with, like your bank.',
8
- 'power': 'ConnectID gives you the power to choose how you share your details, using organisations you already trust.',
8
+ power: 'ConnectID gives you the power to choose how you share your details, using organisations you already trust.',
9
9
  'sign-up': 'ConnectID lets you sign up using details stored with an organisation you already trust, like your bank.',
10
10
  'bank-details-plus-personal-info': 'Provide your preferred bank account and personal details in a secure and simple way, without oversharing information.',
11
11
  'bank-details-only': 'Provide your preferred bank account details in a secure and simple way, without oversharing information.',
12
+ 'verify-age': 'Verify your age through an organisation you already have an account with, like your bank.',
12
13
  };
13
14
  export const IntroText = ({ type }) => {
14
15
  const theme = useContext(ThemeContext);
package/Popup.css CHANGED
@@ -153,7 +153,8 @@
153
153
  flex-shrink: 0;
154
154
  }
155
155
  .cid-idp-selector-popup-participants {
156
- margin-top: 24px;
156
+ list-style: none;
157
+ margin: 24px 0 16px 0;
157
158
  display: grid;
158
159
  grid-template-columns: 225px 225px;
159
160
  grid-gap: 16px;
@@ -173,33 +174,11 @@
173
174
  padding: 8px 16px;
174
175
  border: 1px solid #E9E9E9;
175
176
  }
176
- .cid-idp-selector-popup-participant-greyed-out {
177
- display: flex;
178
- align-items: center;
179
- border-radius: 12px;
180
- cursor: pointer;
181
- box-sizing: border-box;
182
- padding: 8px 16px;
183
- border: 1px solid #E9E9E9;
184
- background-color: #F4F4F4;
185
- cursor: default;
186
- margin-bottom: 4px;
187
- }
188
- .cid-idp-selector-popup-participant-greyed-out-text {
189
- color: #5C5C5C;
190
- font-size: 10px;
191
- }
192
177
  .cid-idp-selector-popup-participant-icon {
193
178
  width: 32px;
194
179
  height: 32px;
195
180
  border-radius: 8px;
196
181
  }
197
- .cid-idp-selector-popup-participant-icon-greyed-out {
198
- width: 32px;
199
- height: 32px;
200
- border-radius: 8px;
201
- opacity: 60%
202
- }
203
182
  .cid-idp-selector-popup-participant-description {
204
183
  position: absolute;
205
184
  width: 1px;
@@ -224,16 +203,26 @@
224
203
  text-overflow: ellipsis;
225
204
  width: 90%;
226
205
  }
227
- .cid-idp-selector-popup-participant-name-greyed-out {
228
- font-size: 14px;
206
+ .cid-idp-selector-popup-missing {
207
+ border-radius: 12px;
208
+ background: #F4F4F4;
209
+ padding: 18px;
210
+ }
211
+ .cid-idp-selector-popup-missing-title {
212
+ color: var(--charcoal);
229
213
  font-family: var(--font);
214
+ font-size: 12px;
215
+ font-weight: 600;
216
+ line-height: 120%;
217
+ margin: 0;
218
+ }
219
+ .cid-idp-selector-popup-missing-text {
230
220
  color: var(--charcoal75);
231
- margin-left: 12px;
232
- overflow: hidden;
233
- white-space: nowrap;
234
- text-overflow: ellipsis;
235
- width: 90%;
236
-
221
+ font-family: var(--font);
222
+ font-size: 12px;
223
+ font-weight: 400;
224
+ line-height: 120%;
225
+ margin: 8px 0 0 0;
237
226
  }
238
227
  .cid-idp-selector-popup-manual {
239
228
  font-family: var(--font);
@@ -294,18 +283,6 @@
294
283
  max-width: 466px;
295
284
  }
296
285
 
297
- .cid-greyout-participant-name {
298
- position: absolute;
299
- display: inline-flex;
300
- flex-direction: row;
301
- align-items: center;
302
- }
303
-
304
- .cid-idp-selector-button-info-icon-greyed-out {
305
- margin-right: 2px;
306
- flex-shrink: 0;
307
- }
308
-
309
286
  @media (prefers-reduced-motion: reduce) {
310
287
  .cid-idp-selector-popup-logo-dot {
311
288
  animation: none;
@@ -324,6 +301,7 @@
324
301
  margin: 20px 0;
325
302
  }
326
303
  .cid-idp-selector-popup-participants {
304
+ margin: 16px 0 12px 0;
327
305
  grid-template-columns: 190px 190px;
328
306
  }
329
307
  }
@@ -358,13 +336,9 @@
358
336
  margin: 20px auto 0 auto;
359
337
  }
360
338
  .cid-idp-selector-popup-participants {
361
- margin-top: 12px;
362
339
  grid-template-columns: 1fr;
363
340
  max-height: 550px;
364
341
  }
365
- .cid-idp-selector-popup-participant-greyed-out {
366
- margin-bottom: 8px;
367
- }
368
342
  .cid-idp-selector-popup-participant-name {
369
343
  overflow: inherit;
370
344
  white-space: normal;
@@ -372,9 +346,6 @@
372
346
  width: 100%;
373
347
  font-size: 16px;
374
348
  }
375
- .cid-greyout-participant-name {
376
- margin-top: -6px;
377
- }
378
349
  .cid-idp-selector-popup-close {
379
350
  position: absolute;
380
351
  padding: 8px;
package/Popup.js CHANGED
@@ -12,7 +12,7 @@ import { useEffect, useRef, useState } from 'react';
12
12
  import ReactDOM from 'react-dom';
13
13
  import { useMediaQuery } from 'react-responsive';
14
14
  import { useAnalytics } from './analytics';
15
- import { filterAuthorisationServers, getManualAuthorisationServer, mapAuthorisationServerToDeviceType, } from './certification';
15
+ import { filterAuthorisationServers, getManualAuthorisationServer } from './certification';
16
16
  import './global.css';
17
17
  import { InfoBox } from './InfoBox';
18
18
  import { getCurrentUrlOrigin } from './navigator';
@@ -20,7 +20,6 @@ import { NoIdpError } from './NoIdpError';
20
20
  import { ParticipantsLoader } from './ParticipantsLoader';
21
21
  import './Popup.css';
22
22
  import { useOverrideShiftTab, useOverrideTab } from './TabHook';
23
- import { getDeviceType } from './userAgent';
24
23
  import detectIncognito from './incognito';
25
24
  export const Popup = ({ onProceed, onCancel, onError, claims, requiredClaims, showAllParticipants, certificationStatus, popupTitle, rpDataSharingDescription, enableManualVerification, requiredCertifications, rpLogoUrl, participants, error, isLoading, }) => {
26
25
  const [isIncognito, setIsIncognito] = useState();
@@ -123,14 +122,6 @@ export const Popup = ({ onProceed, onCancel, onError, claims, requiredClaims, sh
123
122
  }
124
123
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: "cid-idp-selector-popup-title-container", children: renderClaimsTitle() }), renderClaimList()] }));
125
124
  };
126
- const participantTile = (AuthorisationServerId, CustomerFriendlyName, CustomerFriendlyLogoUri, deviceType) => {
127
- if (deviceType === 'desktop') {
128
- return (_jsxs("div", { children: [_jsx("span", { id: `participant-greyed-out-description-${CustomerFriendlyName}`, className: "cid-idp-selector-popup-participant-description", "aria-hidden": "true", children: "available on mobile only" }), _jsxs("li", { "data-testid": "participant-greyed-out", className: "cid-idp-selector-popup-participant-greyed-out", "aria-disabled": "true", "aria-describedby": `participant-greyed-out-description-${CustomerFriendlyName}`, tabIndex: 0, children: [_jsx("img", { className: "cid-idp-selector-popup-participant-icon-greyed-out", src: CustomerFriendlyLogoUri, alt: `${CustomerFriendlyName} logo` }), _jsx("div", { className: "cid-idp-selector-popup-participant-name-greyed-out", title: CustomerFriendlyName, "data-testid": "participant-name", children: CustomerFriendlyName })] }, AuthorisationServerId), _jsxs("div", { className: "cid-greyout-participant-name", children: [_jsxs("svg", { className: "cid-idp-selector-button-info-icon-greyed-out", width: "8", height: "8", viewBox: "0 0 13 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M6.53509 12.3572C9.59207 12.3572 12.0702 9.81483 12.0702 6.67859C12.0702 3.54239 9.59207 1 6.53509 1C3.47814 1 1 3.54239 1 6.67859C1 9.81483 3.47814 12.3572 6.53509 12.3572Z", stroke: "#262626", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M5.25781 9.29883H7.81247", stroke: "#262626", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M6.53515 4.49472C6.7703 4.49472 6.96093 4.29915 6.96093 4.05791C6.96093 3.81666 6.7703 3.62109 6.53515 3.62109C6.3 3.62109 6.10938 3.81666 6.10938 4.05791C6.10938 4.29915 6.3 4.49472 6.53515 4.49472Z", fill: "#262626", stroke: "#262626", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M6.53515 9.29989V6.24219H5.68359", stroke: "#262626", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("div", { "data-testid": "cid-greyout-participant-name-mobile-only", className: "cid-idp-selector-popup-participant-greyed-out-text", "aria-describedby": `participant-greyed-out-description-${CustomerFriendlyName}`, children: "Available on mobile only" })] })] }));
129
- }
130
- else {
131
- return (_jsxs("li", { "data-testid": "participant", className: "cid-idp-selector-popup-participant", tabIndex: 0, onClick: () => onProceed(AuthorisationServerId, CustomerFriendlyName), children: [_jsx("img", { className: "cid-idp-selector-popup-participant-icon", src: CustomerFriendlyLogoUri, alt: `${CustomerFriendlyName} logo` }), _jsx("div", { className: "cid-idp-selector-popup-participant-name", title: CustomerFriendlyName, "data-testid": "participant-name", children: CustomerFriendlyName })] }, AuthorisationServerId));
132
- }
133
- };
134
125
  const renderAuthorisationServers = () => {
135
126
  if (isLoading) {
136
127
  return (_jsxs("div", { className: "cid-idp-selector-popup-provider-wrapper", children: [_jsx("h3", { className: "cid-idp-selector-popup-subtitle", children: "Choose a provider" }), _jsx(ParticipantsLoader, {})] }));
@@ -142,18 +133,19 @@ export const Popup = ({ onProceed, onCancel, onError, claims, requiredClaims, sh
142
133
  return (_jsx("div", { className: "cid-idp-selector-popup-info-box-wrapper-warn", children: _jsx(NoIdpError, { dataTestId: "participant-error", hasManualIdp: false }) }));
143
134
  }
144
135
  const authorisationServers = participants
145
- .map((participant) => participant.AuthorisationServers)
146
- .flat()
136
+ .flatMap((participant) => participant.AuthorisationServers)
147
137
  .sort((authServer1, authServer2) => authServer1.CustomerFriendlyName.localeCompare(authServer2.CustomerFriendlyName));
148
138
  const manualAuthorisationServer = getManualAuthorisationServer(authorisationServers, showAllParticipants);
149
139
  const authorisationServersWithoutManual = authorisationServers.filter(({ AuthorisationServerId }) => AuthorisationServerId !== (manualAuthorisationServer === null || manualAuthorisationServer === void 0 ? void 0 : manualAuthorisationServer.AuthorisationServerId));
150
140
  const filterByClaims = requiredClaims || claims;
151
141
  const filteredAuthorisationServers = filterAuthorisationServers(authorisationServersWithoutManual, showAllParticipants, certificationStatus, filterByClaims, requiredCertifications);
152
- const filteredAuthServerByDevice = mapAuthorisationServerToDeviceType(filteredAuthorisationServers, getDeviceType());
142
+ // Getting all auth servers that have certifications with profile type 'Redirect' and profile variant 'FAPI2 Adv. OP w/Private Key, PAR'
143
+ const authorisationServerWithProfileRedirectFapi2 = authorisationServersWithoutManual.filter(({ AuthorisationServerCertifications }) => {
144
+ return AuthorisationServerCertifications.find(({ ProfileType, ProfileVariant }) => ProfileType === 'Redirect' && ProfileVariant === 'FAPI2 Adv. OP w/Private Key, PAR');
145
+ });
146
+ const missingAuthorisationServerWithProfileRedirectFapi2 = authorisationServerWithProfileRedirectFapi2.length !== filteredAuthorisationServers.length;
153
147
  const hasManualIdp = enableManualVerification && !!manualAuthorisationServer;
154
- return (_jsxs(_Fragment, { children: [filteredAuthorisationServers.length > 0 ? (_jsxs("div", { className: "cid-idp-selector-popup-provider-wrapper", children: [_jsx("h3", { className: "cid-idp-selector-popup-subtitle", children: "Choose a provider" }), _jsx("ul", { className: "cid-idp-selector-popup-participants", "data-testid": "participants", children: Array.from(filteredAuthServerByDevice.entries()).map(([authServer, device]) => {
155
- return (_jsx("div", { children: participantTile(authServer.AuthorisationServerId, authServer.CustomerFriendlyName, authServer.CustomerFriendlyLogoUri, device) }, authServer.AuthorisationServerId));
156
- }) })] })) : (_jsx("div", { className: "cid-idp-selector-popup-info-box-error-wrapper", "data-testid": "popup-error-info-box", children: _jsx(NoIdpError, { hasManualIdp: hasManualIdp }) })), enableManualVerification && manualAuthorisationServer && (_jsx(_Fragment, { children: _jsxs("p", { className: "cid-idp-selector-popup-manual", children: [_jsx("span", { className: "cid-idp-selector-popup-manual-title", "data-testid": "manual-verification-text", children: "Or, use a document to verify your identity" }), _jsx("span", { className: "cid-idp-selector-popup-manual-action", tabIndex: 0, onClick: () => onProceed(manualAuthorisationServer.AuthorisationServerId, manualAuthorisationServer.CustomerFriendlyName), "data-testid": "manual-verification-action", role: "link", children: "Verify with a document" }), _jsx("span", { className: "cid-idp-selector-popup-manual-description", children: "ConnectID does not collect, hold or store your personal information at any time." })] }) }))] }));
148
+ return (_jsxs(_Fragment, { children: [filteredAuthorisationServers.length > 0 ? (_jsxs("div", { className: "cid-idp-selector-popup-provider-wrapper", children: [_jsx("h3", { className: "cid-idp-selector-popup-subtitle", children: "Choose a provider" }), _jsx("ul", { className: "cid-idp-selector-popup-participants", "data-testid": "participants", children: filteredAuthorisationServers.map(({ AuthorisationServerId, CustomerFriendlyName, CustomerFriendlyLogoUri }) => (_jsxs("li", { "data-testid": "participant", className: "cid-idp-selector-popup-participant", tabIndex: 0, onClick: () => onProceed(AuthorisationServerId, CustomerFriendlyName), children: [_jsx("img", { className: "cid-idp-selector-popup-participant-icon", src: CustomerFriendlyLogoUri, alt: `${CustomerFriendlyName} logo` }), _jsx("div", { className: "cid-idp-selector-popup-participant-name", title: CustomerFriendlyName, "data-testid": "participant-name", children: CustomerFriendlyName })] }, AuthorisationServerId))) }), missingAuthorisationServerWithProfileRedirectFapi2 && (_jsxs("div", { className: "cid-idp-selector-popup-missing", "data-testid": "missing-auth-server", children: [_jsx("p", { className: "cid-idp-selector-popup-missing-title", children: "Can't find your provider?" }), _jsx("p", { className: "cid-idp-selector-popup-missing-text", children: "Not all of our identity providers are available for this verification." })] }))] })) : (_jsx("div", { className: "cid-idp-selector-popup-info-box-error-wrapper", "data-testid": "popup-error-info-box", children: _jsx(NoIdpError, { hasManualIdp: hasManualIdp }) })), enableManualVerification && manualAuthorisationServer && (_jsx(_Fragment, { children: _jsxs("p", { className: "cid-idp-selector-popup-manual", children: [_jsx("span", { className: "cid-idp-selector-popup-manual-title", "data-testid": "manual-verification-text", children: "Or, use a document to verify your identity" }), _jsx("span", { className: "cid-idp-selector-popup-manual-action", tabIndex: 0, onClick: () => onProceed(manualAuthorisationServer.AuthorisationServerId, manualAuthorisationServer.CustomerFriendlyName), "data-testid": "manual-verification-action", role: "link", children: "Verify with a document" }), _jsx("span", { className: "cid-idp-selector-popup-manual-description", children: "ConnectID does not collect, hold or store your personal information at any time." })] }) }))] }));
157
149
  };
158
150
  return ReactDOM.createPortal(_jsxs("div", { className: "cid-idp-selector-popup", tabIndex: 0, ref: popupRef, onKeyDown: handleEnterEsc, children: [_jsxs("div", { className: "cid-idp-selector-popup-logo-container", children: [_jsxs("div", { className: "cid-idp-selector-popup-logos", children: [_jsxs("svg", { role: "img", focusable: "false", className: "cid-idp-selector-popup-logo", viewBox: "0 0 132.37 157.84", "data-testid": "cid-logo", children: [_jsx("title", { children: "ConnectID logo" }), _jsx("path", { d: "M102.22,91.65c0,19.9-16.13,36.03-36.03,36.03s-36.03-16.13-36.03-36.03,16.13-36.03,36.03-36.03c9.95,0,18.96,4.03,25.48,10.55l40.71-40.71c-6.52-6.52-10.55-15.52-10.55-25.46h-30.14c0,13.45,4.02,25.95,10.92,36.39-10.45-6.9-22.96-10.93-36.42-10.93C29.63,25.47,0,55.1,0,91.65s29.63,66.19,66.19,66.19,66.19-29.63,66.19-66.19h-30.16Z" })] }), rpLogoUrl && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "cid-idp-selector-popup-logo-dots", children: [_jsx("div", { className: "cid-idp-selector-popup-logo-dot" }), _jsx("div", { className: "cid-idp-selector-popup-logo-dot" }), _jsx("div", { className: "cid-idp-selector-popup-logo-dot" })] }), _jsx("img", { className: "cid-idp-selector-popup-logo-rp", src: rpLogoUrl, alt: "RP logo", "data-testid": "rp-logo" })] }))] }), _jsxs("button", { "aria-label": "Close popup", "data-testid": "popup-close", className: "cid-idp-selector-popup-close", onClick: onCancel, tabIndex: 0, ref: closeButtonRef, children: [_jsx("span", { className: "cid-idp-selector-popup-close-label", children: "Close" }), _jsx("svg", { clipRule: "evenodd", fillRule: "evenodd", strokeLinejoin: "round", strokeMiterlimit: "2", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "m12 10.93 5.719-5.72c.146-.146.339-.219.531-.219.404 0 .75.324.75.749 0 .193-.073.385-.219.532l-5.72 5.719 5.719 5.719c.147.147.22.339.22.531 0 .427-.349.75-.75.75-.192 0-.385-.073-.531-.219l-5.719-5.719-5.719 5.719c-.146.146-.339.219-.531.219-.401 0-.75-.323-.75-.75 0-.192.073-.384.22-.531l5.719-5.719-5.72-5.719c-.146-.147-.219-.339-.219-.532 0-.425.346-.749.75-.749.192 0 .385.073.531.219z" }) })] })] }), _jsxs("div", { className: "cid-idp-selector-popup-title-description-container", children: [_jsx("h2", { className: "cid-idp-selector-popup-title", children: popupTitle }), _jsx("p", { className: "cid-idp-selector-popup-description", children: rpDataSharingDescription })] }), renderClaims(), renderAuthorisationServers(), _jsx("div", { className: "cid-idp-selector-popup-info-box-wrapper", children: _jsxs(InfoBox, { children: [_jsx("h4", { className: "cid-idp-selector-popup-info-box-title", children: "What is ConnectID?" }), _jsxs("p", { className: "cid-idp-selector-popup-info-box-text", "data-testid": "whats-cid-text", children: ["ConnectID is an Australian-owned digital identity solution which allows you to securely prove who you are. ConnectID does not see or store your personal data. Visit", ' ', _jsx("a", { className: "cid-idp-selector-popup-info-box-link", href: "https://www.connectid.com.au", onClick: handleConnectIdLinkClicked, target: "_blank", tabIndex: 0, "data-testid": "info-box-link", ref: infoboxLinkRef, children: "connectid.com.au" }), ' ', "to find out more."] })] }) })] }), document.querySelector('body'));
159
151
  };
package/README.md CHANGED
@@ -43,7 +43,7 @@ Your page should render a widget similar to this 👇 And when the button is cli
43
43
  | rpDataSharingDescription | The text that goes under the popup title explaining how shared data will be used. | string | no | 'Your details will be shared with the current website.' |
44
44
  | enableManualVerification | Whether an option to verify identity manually is displayed or not. | boolean | no | false |
45
45
  | type | The type of ConnectID button widget. [More details here](#type) | 'tiny' \| 'medium benefits' \| 'medium process' \| 'full benefits' \| 'full process' | no | undefined (shows only ConnectID button). |
46
- | introTextType | The text that goes above the ConnectID button. [More details here](#introTextType) | 'verify-trust' \| 'verify-account' \| 'power' \| 'sign-up' \| 'bank-details-plus-personal-info' \| 'bank-details-only' | yes when `type` is set. | - |
46
+ | introTextType | The text that goes above the ConnectID button. [More details here](#introTextType) | 'verify-trust' \| 'verify-account' \| 'power' \| 'sign-up' \| 'bank-details-plus-personal-info' \| 'bank-details-only' \| 'verify-age' | yes when `type` is set. | - |
47
47
  | fullProcessCollapsible | Whether process items are collapsible or not. Only available when `type` is `full process`. | boolean | no | false |
48
48
  | showAllParticipants | Show all participants regardless of any other option. **_This should only be used for testing_**. | boolean | no | false |
49
49
  | theme | ConnectID button theme. | 'dark' \| 'light' | no | 'dark' |
@@ -188,6 +188,7 @@ All elements have classes that can be styled with CSS to match you brand identit
188
188
  `sign-up`: ConnectID lets you sign up using details stored with an organisation you already trust, like your bank.\
189
189
  `bank-details-plus-personal-info`: Provide your preferred bank account and personal details in a secure and simple way, without oversharing information.\
190
190
  `bank-details-only`: Provide your preferred bank account details in a secure and simple way, without oversharing information.
191
+ `verify-age`: Verify your age through an organisation you already have an account with, like your bank.
191
192
  </details>
192
193
 
193
194
  ### <a name="infoContent"></a>infoContent option
@@ -222,6 +223,12 @@ The SVG image below the ConnectID button has either option dark or light mode. B
222
223
 
223
224
  ## 🚀 Release Notes
224
225
 
226
+ ### 6.9.0 (Jun 5, 2025)
227
+ - Add new `introTextType` option: `verify-age`.
228
+
229
+ ### 6.8.0 (May 7, 2025)
230
+ - Show message in the IDP list when any IDP with `ProfileType=Redirect` and `ProfileVariant=FAPI2 Adv. OP w/Private Key, PAR` is not being displayed.
231
+
225
232
  ### 6.7.0 (May 5, 2025)
226
233
  - Detect incognito.
227
234
 
@@ -3,6 +3,6 @@ export declare const filterAuthorisationServers: (authorisationServers: Authoris
3
3
  export declare const getManualAuthorisationServer: (authorisationServers: AuthorisationServer[], showAllParticipants: boolean) => AuthorisationServer | undefined;
4
4
  export declare const removeExpiredOrNotStartedCertifications: (authorisationServers: AuthorisationServer[]) => AuthorisationServer[];
5
5
  export declare const filterAuthorisationServerByClaims: (authorisationServers: AuthorisationServer[], claims: Claim[]) => AuthorisationServer[];
6
- export declare const mapAuthorisationServerToDeviceType: (authorisationServers: AuthorisationServer[], deviceType: Device) => Map<AuthorisationServer, Device>;
7
6
  export declare const filterAuthorisationServerByCertification: (authorisationServers: AuthorisationServer[], status: CertificationStatus, requiredCertifications?: RequiredCertification[]) => AuthorisationServer[];
7
+ export declare const filterAuthorisationServerByDevice: (authorisationServers: AuthorisationServer[], deviceType: Device) => AuthorisationServer[];
8
8
  export declare const hasStarted: (startDateStr: string) => boolean;
package/certification.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { getDeviceType } from './userAgent';
1
2
  const requiredCertificationsMap = {
2
3
  'TDIF.IDP': { type: 'TDIF Accreditation', variant: 'Identity Provider' },
3
4
  'Redirect.FAPI2': { type: 'Redirect', variant: 'FAPI2 Adv. OP w/Private Key, PAR' },
@@ -6,7 +7,9 @@ export const filterAuthorisationServers = (authorisationServers, showAllParticip
6
7
  if (showAllParticipants)
7
8
  return authorisationServers;
8
9
  const authorisationServersWithValidCertifications = removeExpiredOrNotStartedCertifications(authorisationServers);
9
- const filteredAuthorisationServersByClaims = filterAuthorisationServerByClaims(authorisationServersWithValidCertifications, claims);
10
+ const device = getDeviceType();
11
+ const filteredAuthorisationServersByDevice = filterAuthorisationServerByDevice(authorisationServersWithValidCertifications, device);
12
+ const filteredAuthorisationServersByClaims = filterAuthorisationServerByClaims(filteredAuthorisationServersByDevice, claims);
10
13
  const filteredAuthorisationServers = filterAuthorisationServerByCertification(filteredAuthorisationServersByClaims, certificationStatus, requiredCertifications);
11
14
  return filteredAuthorisationServers;
12
15
  };
@@ -37,20 +40,6 @@ export const filterAuthorisationServerByClaims = (authorisationServers, claims)
37
40
  return profileVariants.every((profileVariant) => authorisationServerProfileVariants.includes(profileVariant));
38
41
  });
39
42
  };
40
- export const mapAuthorisationServerToDeviceType = (authorisationServers, deviceType) => {
41
- const authServerMap = new Map();
42
- if (deviceType === 'mobile') {
43
- authorisationServers.forEach((authorisationServer) => {
44
- authServerMap.set(authorisationServer, 'mobile');
45
- });
46
- return authServerMap;
47
- }
48
- authorisationServers.map((authorisationServer) => {
49
- const channelCertifications = authorisationServer.AuthorisationServerCertifications.filter((cert) => cert.ProfileType === 'Channel');
50
- authServerMap.set(authorisationServer, channelCertifications.length === 1 && channelCertifications[0].ProfileVariant === 'app' ? 'desktop' : 'mobile');
51
- });
52
- return authServerMap;
53
- };
54
43
  export const filterAuthorisationServerByCertification = (authorisationServers, status, requiredCertifications) => {
55
44
  const filteredByStatus = filterByStatus(authorisationServers, status);
56
45
  const filteredByStatusAndRequiredCertifications = filterByRequiredCertifications(filteredByStatus, requiredCertifications);
@@ -81,6 +70,18 @@ const filterByRequiredCertifications = (authorisationServers, requiredCertificat
81
70
  return requiredCertificationsFound === requiredCertifications.length;
82
71
  });
83
72
  };
73
+ // mobile return all authorisation servers
74
+ // tablet and desktop return all authorisation servers but those ones with only one certification and that certification is app
75
+ export const filterAuthorisationServerByDevice = (authorisationServers, deviceType) => {
76
+ if (deviceType === 'mobile')
77
+ return authorisationServers;
78
+ const onlyAppAuthorisationServers = authorisationServers.filter((authorisationServer) => {
79
+ const channelCertifications = authorisationServer.AuthorisationServerCertifications.filter((cert) => cert.ProfileType === 'Channel');
80
+ return channelCertifications.length === 1 && channelCertifications[0].ProfileVariant === 'app';
81
+ });
82
+ const onlyAppAuthorisationServersIds = onlyAppAuthorisationServers.map((authorisationServer) => authorisationServer.AuthorisationServerId);
83
+ return authorisationServers.filter((authorisationServer) => !onlyAppAuthorisationServersIds.includes(authorisationServer.AuthorisationServerId));
84
+ };
84
85
  const isExpired = (expiryDateStr) => {
85
86
  const expiryDate = parseCertificationDate(expiryDateStr);
86
87
  expiryDate.setHours(23);
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert';
2
2
  import { describe, it } from 'node:test';
3
- import { filterAuthorisationServerByClaims, filterAuthorisationServers, getManualAuthorisationServer, mapAuthorisationServerToDeviceType, removeExpiredOrNotStartedCertifications, } from './certification';
3
+ import { filterAuthorisationServerByClaims, filterAuthorisationServerByDevice, filterAuthorisationServers, getManualAuthorisationServer, removeExpiredOrNotStartedCertifications, } from './certification';
4
4
  describe('filterAuthorisationServers', () => {
5
5
  it('should return all authorisation servers if showAllParticipants is true regardless of certification status, required certifications and claims', () => {
6
6
  const authorisationServers = [
@@ -306,82 +306,93 @@ describe('removeExpiredCertifications', () => {
306
306
  });
307
307
  });
308
308
  describe('filterAuthorisationServerByDevice', () => {
309
- const authorisationServers = [
310
- {
311
- AuthorisationServerId: '71fe3927-f596-4192-ab9a-f6644cdb9b2b',
312
- CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
313
- CustomerFriendlyName: 'Mock Bank A',
314
- AuthorisationServerCertifications: [
315
- {
316
- CertificationStartDate: '10/04/1900',
317
- CertificationExpirationDate: '10/04/2024',
318
- Status: 'Certified',
319
- ProfileVariant: 'web',
320
- ProfileType: 'Channel',
321
- },
322
- ],
323
- },
324
- {
325
- AuthorisationServerId: '71fe3927-f596-4192-ab9a-f6644cdb9b2x',
326
- CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
327
- CustomerFriendlyName: 'Mock Bank B',
328
- AuthorisationServerCertifications: [
329
- {
330
- CertificationStartDate: '10/04/1900',
331
- CertificationExpirationDate: '10/04/2024',
332
- Status: 'Certified',
333
- ProfileVariant: 'web',
334
- ProfileType: 'Channel',
335
- },
336
- ],
337
- },
338
- {
339
- AuthorisationServerId: 'fa8573a1-953a-4085-b5f7-070a42a4d5a9',
340
- CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankC.svg',
341
- CustomerFriendlyName: 'Mock Bank C',
342
- AuthorisationServerCertifications: [
343
- {
344
- CertificationStartDate: '10/04/1900',
345
- CertificationExpirationDate: '10/04/2024',
346
- Status: 'Certified',
347
- ProfileVariant: 'app',
348
- ProfileType: 'Channel',
349
- },
350
- ],
351
- },
352
- {
353
- AuthorisationServerId: 'fa8573a1-953a-4085-b5f7-070a42a4d5a1',
354
- CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankC.svg',
355
- CustomerFriendlyName: 'Mock Bank D',
356
- AuthorisationServerCertifications: [],
357
- },
358
- ];
359
- it('should return all auth servers when device is mobile', () => {
360
- const authServers = mapAuthorisationServerToDeviceType(authorisationServers, 'mobile');
361
- const values = Array.from(authServers.values());
362
- assert.deepStrictEqual(values.every((value) => value === 'mobile'), true);
363
- });
364
- it('should not return auth servers with only app cert when device is desktop', () => {
365
- const authServers = mapAuthorisationServerToDeviceType(authorisationServers, 'desktop');
366
- const filteredAuthServers = Array.from(authServers)
367
- .filter(([_, device]) => device === 'mobile')
368
- .map(([key, _]) => key);
369
- assert.deepStrictEqual(filteredAuthServers, [
370
- authorisationServers[0],
371
- authorisationServers[1],
372
- authorisationServers[3],
373
- ]);
309
+ it('should return all authorisation servers for mobile', () => {
310
+ const authorisationServers = [
311
+ {
312
+ AuthorisationServerId: '1',
313
+ CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
314
+ CustomerFriendlyName: 'Mock Bank A',
315
+ AuthorisationServerCertifications: [
316
+ {
317
+ ProfileType: 'Channel',
318
+ ProfileVariant: 'app',
319
+ CertificationExpirationDate: '10/04/2099',
320
+ Status: 'Certified',
321
+ CertificationStartDate: '10/04/1900',
322
+ },
323
+ ],
324
+ },
325
+ {
326
+ AuthorisationServerId: '2',
327
+ CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
328
+ CustomerFriendlyName: 'Mock Bank B',
329
+ AuthorisationServerCertifications: [
330
+ {
331
+ ProfileType: 'Channel',
332
+ ProfileVariant: 'web',
333
+ CertificationExpirationDate: '10/04/2099',
334
+ Status: 'Certified',
335
+ CertificationStartDate: '10/04/1900',
336
+ },
337
+ ],
338
+ },
339
+ ];
340
+ assert.deepStrictEqual(filterAuthorisationServerByDevice(authorisationServers, 'mobile'), authorisationServers);
374
341
  });
375
- it('should not return auth servers with only app cert when device is tablet', () => {
376
- const authServers = mapAuthorisationServerToDeviceType(authorisationServers, 'tablet');
377
- console.log(authServers);
378
- const filteredAuthServers = Array.from(authServers)
379
- .filter(([_, device]) => device === 'mobile')
380
- .map(([key, _]) => key);
381
- assert.deepStrictEqual(filteredAuthServers, [
382
- authorisationServers[0],
383
- authorisationServers[1],
384
- authorisationServers[3],
385
- ]);
342
+ it('should return all authorisation servers except those with only app certification when desktop', () => {
343
+ const authorisationServers = [
344
+ {
345
+ AuthorisationServerId: '1',
346
+ CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
347
+ CustomerFriendlyName: 'Mock Bank A',
348
+ // has only app certification (removed)
349
+ AuthorisationServerCertifications: [
350
+ {
351
+ ProfileType: 'Channel',
352
+ ProfileVariant: 'app',
353
+ CertificationExpirationDate: '10/04/2099',
354
+ Status: 'Certified',
355
+ CertificationStartDate: '10/04/1900',
356
+ },
357
+ ],
358
+ },
359
+ {
360
+ AuthorisationServerId: '2',
361
+ CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
362
+ CustomerFriendlyName: 'Mock Bank B',
363
+ AuthorisationServerCertifications: [
364
+ {
365
+ ProfileType: 'Channel',
366
+ ProfileVariant: 'web',
367
+ CertificationExpirationDate: '10/04/2099',
368
+ Status: 'Certified',
369
+ CertificationStartDate: '10/04/1900',
370
+ },
371
+ ],
372
+ },
373
+ {
374
+ AuthorisationServerId: '3',
375
+ CustomerFriendlyLogoUri: 'https://static.sandbox.connectid.com.au/BankA.svg',
376
+ CustomerFriendlyName: 'Mock Bank C',
377
+ // has web and app certifications (okay)
378
+ AuthorisationServerCertifications: [
379
+ {
380
+ ProfileType: 'Channel',
381
+ ProfileVariant: 'app',
382
+ CertificationExpirationDate: '10/04/2099',
383
+ Status: 'Certified',
384
+ CertificationStartDate: '10/04/1900',
385
+ },
386
+ {
387
+ ProfileType: 'Channel',
388
+ ProfileVariant: 'web',
389
+ CertificationExpirationDate: '10/04/2099',
390
+ Status: 'Certified',
391
+ CertificationStartDate: '10/04/1900',
392
+ },
393
+ ],
394
+ },
395
+ ];
396
+ assert.deepStrictEqual(filterAuthorisationServerByDevice(authorisationServers, 'desktop'), [authorisationServers[1], authorisationServers[2]]);
386
397
  });
387
398
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@connectid-tools/idp-selector-react",
3
- "version": "6.7.0",
3
+ "version": "6.9.0",
4
4
  "description": "React component for IDP Selector.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -26,8 +26,8 @@
26
26
  "homepage": "https://github.com/connectid-tools/idp-selector-react",
27
27
  "devDependencies": {
28
28
  "@babel/preset-typescript": "^7.27.1",
29
- "@types/node": "^22.15.3",
30
- "@types/react": "^18.3.20",
29
+ "@types/node": "^22.15.29",
30
+ "@types/react": "^18.3.23",
31
31
  "@types/react-dom": "^18.3.7",
32
32
  "cypress": "^13.17.0",
33
33
  "jest-environment-jsdom": "^29.7.0",
package/types.d.ts CHANGED
@@ -28,7 +28,7 @@ export type AnalyticsEvent = 'ConnectID Button Displayed' | 'ConnectID Button Cl
28
28
  export type Analytics = {
29
29
  track: (event: AnalyticsEvent, data?: Record<string, unknown>) => void;
30
30
  };
31
- export type IntroTextType = 'verify-trust' | 'verify-account' | 'power' | 'sign-up' | 'bank-details-plus-personal-info' | 'bank-details-only';
31
+ export type IntroTextType = 'verify-trust' | 'verify-account' | 'power' | 'sign-up' | 'bank-details-plus-personal-info' | 'bank-details-only' | 'verify-age';
32
32
  export type CidButtonType = 'tiny' | 'medium benefits' | 'medium process' | 'full benefits' | 'full process';
33
33
  export type CidButtonTypeConfig = {
34
34
  hasIntro: boolean;