From 7ac554e90e7541feab7e1cdbb7f68a4f34b26081 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 14 May 2021 14:47:13 +0200 Subject: [PATCH] Display the list of registered keys --- src/helpers/AccountHelper.ts | 17 +++ src/ui/routes/AccountSettingsRoute.tsx | 167 +++++++++++++++++++------ src/ui/widgets/AsyncWidget.tsx | 4 +- src/ui/widgets/TimestampWidget.tsx | 46 +++++++ 4 files changed, 191 insertions(+), 43 deletions(-) create mode 100644 src/ui/widgets/TimestampWidget.tsx diff --git a/src/helpers/AccountHelper.ts b/src/helpers/AccountHelper.ts index f7d403c..9449174 100644 --- a/src/helpers/AccountHelper.ts +++ b/src/helpers/AccountHelper.ts @@ -33,6 +33,12 @@ export interface NewAdminGeneralSettings { email: string; } +export interface AdminAccountKey { + id: number; + name: string; + time_add: number; +} + const SESSION_STORAGE_TOKEN = "auth_token"; let currentAccount: AdminAccount | null = null; @@ -248,4 +254,15 @@ export class AccountHelper { sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token); } + + /** + * Get the list of keys of an admin + * + * @param adminID The id of the target administrator + */ + static async GetAdminKeys(adminID: number): Promise { + return await serverRequest("accounts/keys", { + id: adminID, + }); + } } diff --git a/src/ui/routes/AccountSettingsRoute.tsx b/src/ui/routes/AccountSettingsRoute.tsx index e01f911..98b00db 100644 --- a/src/ui/routes/AccountSettingsRoute.tsx +++ b/src/ui/routes/AccountSettingsRoute.tsx @@ -9,15 +9,25 @@ import { Divider, Grid, Paper, + Table, + TableBody, + TableCell, + TableHead, + TableRow, TextField, Typography, } from "@material-ui/core"; import React from "react"; import { useParams } from "react-router-dom"; -import { AccountHelper, AdminAccount } from "../../helpers/AccountHelper"; +import { + AccountHelper, + AdminAccount, + AdminAccountKey, +} from "../../helpers/AccountHelper"; import { AsyncWidget } from "../widgets/AsyncWidget"; import { input, matAlert, snackbar } from "../widgets/DialogsProvider"; import { PageTitle } from "../widgets/PageTitle"; +import { TimestampWidget } from "../widgets/TimestampWidget"; export function AccountSettingsRoute() { let params: any = useParams(); @@ -70,7 +80,9 @@ class AccountSettingsRouteInner extends React.Component< admin={this.state.account} > - + ); @@ -126,37 +138,63 @@ class GeneralSettings extends React.Component< render() { return ( - +
+ - + - +
+ +
+
); } } -function KeySettingsSection() { - const registerNewKey = async () => { +export class KeySettingsSection extends React.Component< + { admin: AdminAccount }, + { keys: AdminAccountKey[]; counter: number } +> { + constructor(props: any) { + super(props); + + this.state = { + keys: [], + counter: 1, + }; + + this.load = this.load.bind(this); + this.build = this.build.bind(this); + this.registerNewKey = this.registerNewKey.bind(this); + } + + async load() { + const keys = await AccountHelper.GetAdminKeys(this.props.admin.id); + + this.setState({ keys: keys }); + } + + async registerNewKey() { try { const challenge = await AccountHelper.GetKeyRegistrationChallenge(); const credential = await navigator.credentials.create(challenge); @@ -176,32 +214,79 @@ function KeySettingsSection() { console.error(e); matAlert("Failed to register a new key!"); } - }; + } - return ( - - - - ); + render() { + return ( + + ); + } + + build() { + return ( + + + + + Key name + Date added + Actions + + + + {this.state.keys.map((key) => ( + + + {key.name} + + + + + Delete + + ))} + +
+ + + + {/* Action buttons */} +
+ +
+
+ ); + } } function SettingsSection(p: { title: string; children?: React.ReactNode }) { return ( - + - General settings + {p.title}
Promise; errorMessage: string; onBuild: () => ReactNode; @@ -23,7 +23,7 @@ export interface AsyncWidgetProperties { interface AsyncWidgetState { status: Status; - key?: number; + key?: number | string; } export class AsyncWidget extends React.Component< diff --git a/src/ui/widgets/TimestampWidget.tsx b/src/ui/widgets/TimestampWidget.tsx new file mode 100644 index 0000000..aef780d --- /dev/null +++ b/src/ui/widgets/TimestampWidget.tsx @@ -0,0 +1,46 @@ +import { Tooltip } from "@material-ui/core"; +import React from "react"; + +/** + * Display in human-readable way a timestamp + */ +export function TimestampWidget(props: { time: number }) { + const date = new Date(props.time * 1000); + const currDate = new Date(); + const diff = Math.floor(currDate.getTime() / 1000 - props.time); + + let diffStr = diff + " seconds ago"; + + if (diff === 0) diffStr = "Just now"; + else if (diff === 1) diffStr = "1 second ago"; + else if (diff === 60) diffStr = "1 minute ago"; + + if (diff > 60) diffStr = Math.floor(diff / 60) + " minutes ago"; + + if (diff === 3600) diffStr = "1 hour ago"; + + if (diff > 3600) diffStr = Math.floor(diff / 3600) + " hours ago"; + + const daysAgo = Math.floor(diff / (3600 * 24)); + if (daysAgo === 1) diffStr = "1 day ago"; + else if (daysAgo > 1) diffStr = daysAgo + " days ago"; + + const monthsAgo = Math.floor(daysAgo / 30); + if (monthsAgo === 1) diffStr = "1 month ago"; + else if (monthsAgo > 1) diffStr = monthsAgo + " months ago"; + + const yearsAgo = Math.floor(monthsAgo / 12); + if (yearsAgo === 1) diffStr = "1 year ago"; + else if (yearsAgo > 1) diffStr = yearsAgo + " years ago"; + + return ( + + {diffStr} + + ); +}