diff --git a/package-lock.json b/package-lock.json index b6ddf24..408264c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@trusona/touchpoint-sdk", - "version": "0.0.1", + "version": "0.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@trusona/touchpoint-sdk", - "version": "0.0.1", + "version": "0.0.3", "license": "MIT", "dependencies": { - "lit": "^2.8.0" + "lit": "^2.8.0", + "luxon": "^3.4.3" }, "devDependencies": { "@babel/core": "^7.23.0", @@ -23,6 +24,7 @@ "@storybook/cli": "^7.4.5", "@storybook/web-components-vite": "^7.4.5", "@types/estree": "^1.0.2", + "@types/luxon": "^3.3.2", "babel-loader": "^9.1.3", "es-dev-server": "^2.1.0", "react": "^18.2.0", @@ -7191,6 +7193,12 @@ "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "dev": true }, + "node_modules/@types/luxon": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.2.tgz", + "integrity": "sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ==", + "dev": true + }, "node_modules/@types/mdx": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.6.tgz", @@ -13748,6 +13756,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz", + "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.3", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", diff --git a/package.json b/package.json index dfcdf17..f8b735c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trusona/touchpoint-sdk", - "version": "0.0.2", + "version": "0.0.3", "repository": { "type": "git", "url": "git+https://github.com/trusona/auth-cloud-touchpoint-sdk.git" @@ -39,6 +39,7 @@ "@storybook/cli": "^7.4.5", "@storybook/web-components-vite": "^7.4.5", "@types/estree": "^1.0.2", + "@types/luxon": "^3.3.2", "babel-loader": "^9.1.3", "es-dev-server": "^2.1.0", "react": "^18.2.0", @@ -50,7 +51,8 @@ "web-types-lit": "^0.1.0" }, "dependencies": { - "lit": "^2.8.0" + "lit": "^2.8.0", + "luxon": "^3.4.3" }, "ts-standard": { "ignore": [ diff --git a/src/components/fido-passkey-details-card/fido-passkey-details-card.stories.ts b/src/components/fido-passkey-details-card/fido-passkey-details-card.stories.ts index 98a37bd..7525467 100644 --- a/src/components/fido-passkey-details-card/fido-passkey-details-card.stories.ts +++ b/src/components/fido-passkey-details-card/fido-passkey-details-card.stories.ts @@ -2,6 +2,7 @@ import {Meta, StoryObj} from '@storybook/web-components' import {html} from 'lit' import './fido-passkey-details-card' +import {PasskeyDetails} from "./fido-passkey-details-card"; export default { title: 'Fido Passkey Details Card', @@ -29,24 +30,30 @@ export default { } } as Meta + +let passkeyDetails: PasskeyDetails = { + createdAt: '2023-10-12T17:12:13.183221Z', + createdOperatingSystem: 'Mac OS', + passkeyActivity: [ + { + lastUsedAt: '2023-10-13T17:12:13.183221Z', + operatingSystem: 'Android 14' + }, + { + lastUsedAt: '2023-10-14T17:12:13.183221Z', + operatingSystem: 'Android 14' + } + ] +} + export const Default: StoryObj = { name: 'Default', - args:{ - savedText: "Saved with iOS 16.2 on April 11, 2023, 12:01am", - lastUsedText:"iOS 16.2, April 11, 2023, 3:42pm", - lastUsedIsMobile: true, - prevLastUsedText:"MacOS 13.0.1, April 23rd, 2023, 4:21pm", - prevLastUsedIsMobile:false + args: { + passkeyDetails: passkeyDetails }, render: (args) => { return html` - + ` } diff --git a/src/components/fido-passkey-details-card/fido-passkey-details-card.ts b/src/components/fido-passkey-details-card/fido-passkey-details-card.ts index 4a9f167..8368e04 100644 --- a/src/components/fido-passkey-details-card/fido-passkey-details-card.ts +++ b/src/components/fido-passkey-details-card/fido-passkey-details-card.ts @@ -1,6 +1,8 @@ -import { LitElement, html, css, TemplateResult } from 'lit' -import { customElement, property } from 'lit/decorators.js' -import { sharedStyles } from '../../shared/style' +import {LitElement, html, css, TemplateResult} from 'lit' +import {customElement, property} from 'lit/decorators.js' +import {repeat} from 'lit/directives/repeat.js' +import {sharedStyles} from '../../shared/style' +import {DateTime} from 'luxon'; const componentStyle = css` @@ -82,20 +84,27 @@ const componentStyle = css` ` +export interface PasskeyActivity { + lastUsedAt: string + operatingSystem: string +} + +export interface PasskeyDetails { + createdAt: string + createdOperatingSystem: string + passkeyActivity: Array +} + @customElement('fido-passkey-details-card') class FidoPasskeyDetailsCard extends LitElement { - @property({ type: String }) savedText?: string - @property({ type: String }) lastUsedText: string = '' - @property({ type: String }) lastUsedIsMobile: string = 'false' + @property({type: Object}) passkeyDetails?: PasskeyDetails - @property({ type: String }) prevLastUsedText: string | null = null - @property({ type: String }) prevLastUsedIsMobile: string = 'false' + static styles = [sharedStyles, componentStyle] - static styles = [sharedStyles, componentStyle] - - render (): TemplateResult { - return html` + render(): TemplateResult { + console.log(this.passkeyDetails) + return html`
@@ -106,7 +115,7 @@ class FidoPasskeyDetailsCard extends LitElement { -

${this.savedText}

+

${this.getCreatedAtText()}

@@ -120,25 +129,71 @@ class FidoPasskeyDetailsCard extends LitElement { stroke="#444444" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round"/>
- ${this.getRow(this.lastUsedText, this.lastUsedIsMobile === 'true')} - ${this.getOptionalRow()} + ${this.getLastUsedActivity()}
` - } + } - private getRow (lastUsedText: string, lastUsedIsMobile: boolean): TemplateResult { - return html` + private getCreatedAtText(): string { + const createdAt = this.passkeyDetails?.createdAt + const os = this.passkeyDetails?.createdOperatingSystem + const formattedDate = this.getFormattedDate(createdAt ?? "") + if (formattedDate) { + return `Saved with ${os ?? "--"} on ${formattedDate}` + } else { + return "" + } + } + + private getLastUsedAtText(lastUsedAt?: string, lastUsedOs?: String): string { + const formattedDate = this.getFormattedDate(lastUsedAt ?? "") + return `${lastUsedOs ?? ""}, ${formattedDate}` + } + + private getFormattedDate(date: string) { + const parsedDate = DateTime.fromISO(date); + if (parsedDate.isValid) { + return parsedDate.toFormat("MMM d, yyyy, h:mm a ZZZZ") + } else { + return "" + } + } + + private getLastUsedActivity(): TemplateResult { + const activityList = this.passkeyDetails?.passkeyActivity + if (Array.isArray(activityList) && activityList.length > 0) { + return html` + ${repeat(this.passkeyDetails?.passkeyActivity ?? [], (activity: PasskeyActivity) => html` + ${this.getActivityRow(activity)} + `)}` + } else { + return html` + ${this.getActivityRow({ + lastUsedAt: this.passkeyDetails?.createdAt ?? "", + operatingSystem: this.passkeyDetails?.createdOperatingSystem ?? "" + })} + ` + } + } + + + private isMobile(operatingSystem?: string) { + return operatingSystem?.toLowerCase().includes('android') || operatingSystem?.toLowerCase().includes('ios') + } + + private getActivityRow(activity: PasskeyActivity): TemplateResult { + return html`
- ${this.getIcon(lastUsedIsMobile)} -

${lastUsedText}

+ ${this.getIcon(this.isMobile(activity.operatingSystem) ?? false)} +

${this.getLastUsedAtText(activity.lastUsedAt, activity.operatingSystem)}

` - } + } - private getIcon (isMobile: boolean): TemplateResult { - if (isMobile) { - return html` + private getIcon(isMobile: boolean): TemplateResult { + if (isMobile) { + return html` ` - } else { - return html` + } else { + return html` ` + } } - } - - private getOptionalRow (): TemplateResult { - if (this.prevLastUsedText && this.prevLastUsedText !== '') { - return this.getRow(this.prevLastUsedText, this.prevLastUsedIsMobile === 'true') - } else { - return html`` - } - } } declare global { - interface HTMLElementTagNameMap { - 'fido-passkey-details-card': FidoPasskeyDetailsCard - } + interface HTMLElementTagNameMap { + 'fido-passkey-details-card': FidoPasskeyDetailsCard + } } diff --git a/src/fido/fido-passkey-details/fido-passkey-details.stories.ts b/src/fido/fido-passkey-details/fido-passkey-details.stories.ts index b619495..ccb7c1c 100644 --- a/src/fido/fido-passkey-details/fido-passkey-details.stories.ts +++ b/src/fido/fido-passkey-details/fido-passkey-details.stories.ts @@ -27,25 +27,42 @@ export default { } } as Meta -let passkeyDetails : PasskeyDetails[] = [ +let passkeyDetails: PasskeyDetails[] = [ { - savedText: "Saved with iOS 16.2 on April 11, 2023, 12:01am", - lastUsedText:"iOS 16.2, April 11, 2023, 3:42pm", - lastUsedIsMobile: true, - prevLastUsedText:"MacOS 13.0.1, April 23rd, 2023, 4:21pm", - prevLastUsedIsMobile:false + createdAt: '2023-10-12T17:12:13.183221Z', + createdOperatingSystem: 'Mac OS', + passkeyActivity: [ + { + lastUsedAt: '2023-10-13T19:14:13.183221Z', + operatingSystem: 'Android 14' + }, + { + lastUsedAt: '2023-10-14T18:16:13.183221Z', + operatingSystem: 'Mac OS X 10.15' + } + ] + }, { + createdAt: '2023-10-10T17:12:13.183221Z', + createdOperatingSystem: 'Android 13' }, { - savedText: "Saved with Android 13 on April 11, 2023, 12:01am", - lastUsedText:"Android 13, April 11th, 2023, 3:42pm", - lastUsedIsMobile: true - }, + passkeyActivity: [ + { + lastUsedAt: '2023-10-03T17:10:13.183221Z', + operatingSystem: 'Android 10' + }, + { + lastUsedAt: '2023-10-01T17:14:13.183221Z', + operatingSystem: 'Android 10' + } + ] + } ] export const Default: StoryObj = { name: 'Default', - args:{ - passkeyDetails : passkeyDetails + args: { + passkeyDetails: passkeyDetails }, render: (args) => { return html` diff --git a/src/fido/fido-passkey-details/fido-passkey-details.ts b/src/fido/fido-passkey-details/fido-passkey-details.ts index f6d39e6..13cc01d 100644 --- a/src/fido/fido-passkey-details/fido-passkey-details.ts +++ b/src/fido/fido-passkey-details/fido-passkey-details.ts @@ -1,7 +1,8 @@ -import { LitElement, html, css, TemplateResult } from 'lit' -import { repeat } from 'lit/directives/repeat.js' -import { customElement, property } from 'lit/decorators.js' -import { sharedStyles } from '../../shared/style' +import {LitElement, html, css, TemplateResult} from 'lit' +import {repeat} from 'lit/directives/repeat.js' +import {customElement, property} from 'lit/decorators.js' +import {sharedStyles} from '../../shared/style' +import {PasskeyDetails} from "../../components/fido-passkey-details-card/fido-passkey-details-card"; const componentStyle = css` @@ -54,22 +55,14 @@ const componentStyle = css` ` -export default interface PasskeyDetails { - savedText: string - lastUsedText: string - lastUsedIsMobile: boolean - prevLastUsedText?: string | null - prevLastUsedIsMobile?: boolean | null -} - @customElement('fido-passkey-details') class FidoPasskeyDetails extends LitElement { - @property({ type: Array }) passkeyDetails: PasskeyDetails[] = new Array() + @property({type: Array}) passkeyDetails: PasskeyDetails[] = new Array() - static styles = [sharedStyles, componentStyle] + static styles = [sharedStyles, componentStyle] - render (): TemplateResult { - return html` + render(): TemplateResult { + return html`

Passkeys

${this.getPasskeys()} @@ -92,26 +85,20 @@ class FidoPasskeyDetails extends LitElement {
` - } + } - private getPasskeys (): TemplateResult { - return html` - ${repeat(this.passkeyDetails, (passkeyDetail: PasskeyDetails) => html` - + private getPasskeys(): TemplateResult { + return html` + ${repeat(this.passkeyDetails, (details: PasskeyDetails) => html` + `)} ` - } + } } declare global { - interface HTMLElementTagNameMap { - 'fido-passkey-details': FidoPasskeyDetails - } + interface HTMLElementTagNameMap { + 'fido-passkey-details': FidoPasskeyDetails + } } diff --git a/testpages/components/fido-passkey-details-card.html b/testpages/components/fido-passkey-details-card.html index 3ae1691..43eefdf 100644 --- a/testpages/components/fido-passkey-details-card.html +++ b/testpages/components/fido-passkey-details-card.html @@ -7,6 +7,23 @@ + + @@ -17,14 +34,12 @@ - - + + + diff --git a/testpages/fido/fido-passkey-details.html b/testpages/fido/fido-passkey-details.html index 2358cd0..afef5d9 100644 --- a/testpages/fido/fido-passkey-details.html +++ b/testpages/fido/fido-passkey-details.html @@ -9,16 +9,33 @@