From 10815d8101bbb293d1e5d1e9a4f11a7b573d3daf Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 16 Nov 2022 15:54:45 +0100 Subject: [PATCH] DateTime component --- frontend/package-lock.json | 18 ++++++ frontend/package.json | 1 + frontend/src/components/BrowserSession.tsx | 15 +++-- frontend/src/components/CompatSsoLogin.tsx | 7 +- frontend/src/components/DateTime.stories.tsx | 67 ++++++++++++++++++++ frontend/src/components/DateTime.tsx | 55 ++++++++++++++++ 6 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 frontend/src/components/DateTime.stories.tsx create mode 100644 frontend/src/components/DateTime.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2528e10a..184672d5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "mas-frontend", "version": "0.0.0", "dependencies": { + "date-fns": "^2.29.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-relay": "^14.1.0", @@ -9105,6 +9106,18 @@ "integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==", "dev": true }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -30395,6 +30408,11 @@ "integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==", "dev": true }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 544e837a..acac4c9f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "build-storybook": "storybook build" }, "dependencies": { + "date-fns": "^2.29.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-relay": "^14.1.0", diff --git a/frontend/src/components/BrowserSession.tsx b/frontend/src/components/BrowserSession.tsx index 0def2179..cd7c75bd 100644 --- a/frontend/src/components/BrowserSession.tsx +++ b/frontend/src/components/BrowserSession.tsx @@ -14,8 +14,10 @@ import type { BrowserSession_session$key } from "./__generated__/BrowserSession_session.graphql"; import { graphql, useFragment } from "react-relay"; + import Block from "./Block"; -import { Body, Code, Subtitle } from "./Typography"; +import { Body, Subtitle } from "./Typography"; +import DateTime from "./DateTime"; type Props = { session: BrowserSession_session$key; @@ -37,17 +39,22 @@ const BrowserSession: React.FC = ({ session, isCurrent }) => { session ); - const lastAuthentication = data.lastAuthentication?.createdAt || "never"; + const lastAuthentication = data.lastAuthentication?.createdAt; const createdAt = data.createdAt; return ( {isCurrent && Current session} - Started: {createdAt} + Started: - Last authentication: {lastAuthentication} + Last authentication:{" "} + {lastAuthentication ? ( + + ) : ( + "never" + )} ); diff --git a/frontend/src/components/CompatSsoLogin.tsx b/frontend/src/components/CompatSsoLogin.tsx index 225c7340..0ca8e25e 100644 --- a/frontend/src/components/CompatSsoLogin.tsx +++ b/frontend/src/components/CompatSsoLogin.tsx @@ -16,6 +16,7 @@ import type { CompatSsoLogin_login$key } from "./__generated__/CompatSsoLogin_lo import { graphql, useFragment } from "react-relay"; import Block from "./Block"; import { Body, Bold, Code } from "./Typography"; +import DateTime from "./DateTime"; type Props = { login: CompatSsoLogin_login$key; @@ -44,11 +45,11 @@ const CompatSsoLogin: React.FC = ({ login }) => { info = ( <> - Started: {data.session.createdAt} + Started: {data.session.finishedAt ? ( - Finished: {data.session.createdAt} + Finished: ) : null} @@ -61,7 +62,7 @@ const CompatSsoLogin: React.FC = ({ login }) => { return ( - Requested: {data.createdAt} + Requested: {info} diff --git a/frontend/src/components/DateTime.stories.tsx b/frontend/src/components/DateTime.stories.tsx new file mode 100644 index 00000000..beb11898 --- /dev/null +++ b/frontend/src/components/DateTime.stories.tsx @@ -0,0 +1,67 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Meta, StoryObj } from "@storybook/react"; +import { sub } from "date-fns"; + +import DateTime from "./DateTime"; + +const now = new Date(2022, 11, 16, 15, 32, 10); + +const meta: Meta = { + title: "UI/DateTime", + component: DateTime, + tags: ["docsPage"], + args: { + now, + datetime: sub(now, { minutes: 30 }), + }, + argTypes: { + now: { + control: "date", + }, + datetime: { + control: "date", + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = {}; + +export const Now: Story = { + args: { + datetime: now, + }, +}; + +export const SecondsAgo: Story = { + args: { + datetime: sub(now, { seconds: 30 }), + }, +}; + +export const MinutesAgo: Story = { + args: { + datetime: sub(now, { minutes: 5 }), + }, +}; + +export const HoursAgo: Story = { + args: { + datetime: sub(now, { hours: 5 }), + }, +}; diff --git a/frontend/src/components/DateTime.tsx b/frontend/src/components/DateTime.tsx new file mode 100644 index 00000000..f18d4b5f --- /dev/null +++ b/frontend/src/components/DateTime.tsx @@ -0,0 +1,55 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { + formatISO, + intlFormat, + intlFormatDistance, + differenceInHours, + parseISO, +} from "date-fns"; + +type Props = { + className?: string; + datetime: Date | string; + now?: Date; +}; + +const DateTime = ({ + datetime: datetimeProps, + now: nowProps, + className, +}: Props) => { + const datetime = + typeof datetimeProps === "string" ? parseISO(datetimeProps) : datetimeProps; + const now = nowProps || new Date(); + const text = + Math.abs(differenceInHours(now, datetime, { roundingMethod: "round" })) > 1 + ? intlFormat(datetime, { + year: "numeric", + month: "short", + day: "numeric", + weekday: "short", + hour: "numeric", + minute: "numeric", + }) + : intlFormatDistance(datetime, now); + return ( + + ); +}; + +export default DateTime;