You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-21 23:00:50 +03:00
DateTime component
This commit is contained in:
18
frontend/package-lock.json
generated
18
frontend/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "mas-frontend",
|
"name": "mas-frontend",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"date-fns": "^2.29.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-relay": "^14.1.0",
|
"react-relay": "^14.1.0",
|
||||||
@@ -9105,6 +9106,18 @@
|
|||||||
"integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==",
|
"integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@@ -30395,6 +30408,11 @@
|
|||||||
"integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==",
|
"integrity": "sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==",
|
||||||
"dev": true
|
"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": {
|
"debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"build-storybook": "storybook build"
|
"build-storybook": "storybook build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"date-fns": "^2.29.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-relay": "^14.1.0",
|
"react-relay": "^14.1.0",
|
||||||
|
|||||||
@@ -14,8 +14,10 @@
|
|||||||
|
|
||||||
import type { BrowserSession_session$key } from "./__generated__/BrowserSession_session.graphql";
|
import type { BrowserSession_session$key } from "./__generated__/BrowserSession_session.graphql";
|
||||||
import { graphql, useFragment } from "react-relay";
|
import { graphql, useFragment } from "react-relay";
|
||||||
|
|
||||||
import Block from "./Block";
|
import Block from "./Block";
|
||||||
import { Body, Code, Subtitle } from "./Typography";
|
import { Body, Subtitle } from "./Typography";
|
||||||
|
import DateTime from "./DateTime";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
session: BrowserSession_session$key;
|
session: BrowserSession_session$key;
|
||||||
@@ -37,17 +39,22 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
|
|||||||
session
|
session
|
||||||
);
|
);
|
||||||
|
|
||||||
const lastAuthentication = data.lastAuthentication?.createdAt || "never";
|
const lastAuthentication = data.lastAuthentication?.createdAt;
|
||||||
const createdAt = data.createdAt;
|
const createdAt = data.createdAt;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Block>
|
<Block>
|
||||||
{isCurrent && <Subtitle>Current session</Subtitle>}
|
{isCurrent && <Subtitle>Current session</Subtitle>}
|
||||||
<Body>
|
<Body>
|
||||||
Started: <Code>{createdAt}</Code>
|
Started: <DateTime datetime={createdAt} />
|
||||||
</Body>
|
</Body>
|
||||||
<Body>
|
<Body>
|
||||||
Last authentication: <Code>{lastAuthentication}</Code>
|
Last authentication:{" "}
|
||||||
|
{lastAuthentication ? (
|
||||||
|
<DateTime datetime={lastAuthentication} />
|
||||||
|
) : (
|
||||||
|
"never"
|
||||||
|
)}
|
||||||
</Body>
|
</Body>
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import type { CompatSsoLogin_login$key } from "./__generated__/CompatSsoLogin_lo
|
|||||||
import { graphql, useFragment } from "react-relay";
|
import { graphql, useFragment } from "react-relay";
|
||||||
import Block from "./Block";
|
import Block from "./Block";
|
||||||
import { Body, Bold, Code } from "./Typography";
|
import { Body, Bold, Code } from "./Typography";
|
||||||
|
import DateTime from "./DateTime";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
login: CompatSsoLogin_login$key;
|
login: CompatSsoLogin_login$key;
|
||||||
@@ -44,11 +45,11 @@ const CompatSsoLogin: React.FC<Props> = ({ login }) => {
|
|||||||
info = (
|
info = (
|
||||||
<>
|
<>
|
||||||
<Body>
|
<Body>
|
||||||
Started: <Code>{data.session.createdAt}</Code>
|
Started: <DateTime datetime={data.session.createdAt} />
|
||||||
</Body>
|
</Body>
|
||||||
{data.session.finishedAt ? (
|
{data.session.finishedAt ? (
|
||||||
<Body>
|
<Body>
|
||||||
Finished: <Code>{data.session.createdAt}</Code>
|
Finished: <DateTime datetime={data.session.finishedAt} />
|
||||||
</Body>
|
</Body>
|
||||||
) : null}
|
) : null}
|
||||||
<Body>
|
<Body>
|
||||||
@@ -61,7 +62,7 @@ const CompatSsoLogin: React.FC<Props> = ({ login }) => {
|
|||||||
return (
|
return (
|
||||||
<Block>
|
<Block>
|
||||||
<Body>
|
<Body>
|
||||||
Requested: <Code>{data.createdAt}</Code>
|
Requested: <DateTime datetime={data.createdAt} />
|
||||||
</Body>
|
</Body>
|
||||||
{info}
|
{info}
|
||||||
<Body>
|
<Body>
|
||||||
|
|||||||
67
frontend/src/components/DateTime.stories.tsx
Normal file
67
frontend/src/components/DateTime.stories.tsx
Normal file
@@ -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<typeof DateTime> = {
|
||||||
|
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<typeof DateTime>;
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
},
|
||||||
|
};
|
||||||
55
frontend/src/components/DateTime.tsx
Normal file
55
frontend/src/components/DateTime.tsx
Normal file
@@ -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 (
|
||||||
|
<time className={className} dateTime={formatISO(datetime)}>
|
||||||
|
{text}
|
||||||
|
</time>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateTime;
|
||||||
Reference in New Issue
Block a user