From df8b9ee97f406c3adc1b70fac63ee5325f5ed7c3 Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Mon, 30 Oct 2023 20:09:12 +0100 Subject: [PATCH] Unify time distance format --- .../Assets/AssetList/AssetEntry/index.tsx | 10 +- .../Notifications/NotificationCard/index.tsx | 12 +- .../RecentActivityTable/index.tsx | 10 +- src/utils/formatTimeDistance.ts | 155 +++++++++++++++++- src/utils/timeAgo.ts | 54 ------ 5 files changed, 166 insertions(+), 75 deletions(-) delete mode 100644 src/utils/timeAgo.ts diff --git a/src/components/Assets/AssetList/AssetEntry/index.tsx b/src/components/Assets/AssetList/AssetEntry/index.tsx index 8f4c13d4a..d009d3661 100644 --- a/src/components/Assets/AssetList/AssetEntry/index.tsx +++ b/src/components/Assets/AssetList/AssetEntry/index.tsx @@ -1,9 +1,9 @@ import { DefaultTheme, useTheme } from "styled-components"; import { InsightType } from "../../../../types"; +import { formatTimeDistance } from "../../../../utils/formatTimeDistance"; import { getInsightImportanceColor } from "../../../../utils/getInsightImportanceColor"; import { getInsightTypeInfo } from "../../../../utils/getInsightTypeInfo"; import { getInsightTypeOrderPriority } from "../../../../utils/getInsightTypeOrderPriority"; -import { timeAgo } from "../../../../utils/timeAgo"; import { Tooltip } from "../../../common/Tooltip"; import { GlobeIcon } from "../../../common/icons/GlobeIcon"; import { getAssetTypeInfo } from "../../utils"; @@ -82,10 +82,10 @@ export const AssetEntry = (props: AssetEntryProps) => { const servicesTitle = props.entry.services.join(", "); - const timeDistance = timeAgo(lastSeenDateTime, "short"); - const timeDistanceString = timeDistance - ? `${timeDistance.value}${timeDistance.unit}` - : ""; + const timeDistanceString = formatTimeDistance(lastSeenDateTime, { + format: "short", + withDescriptiveWords: false + }).replace(" ", ""); const timeDistanceTitle = new Date(lastSeenDateTime).toString(); return ( diff --git a/src/components/Notifications/NotificationCard/index.tsx b/src/components/Notifications/NotificationCard/index.tsx index 03404c2d2..850992282 100644 --- a/src/components/Notifications/NotificationCard/index.tsx +++ b/src/components/Notifications/NotificationCard/index.tsx @@ -1,6 +1,6 @@ import { DefaultTheme, useTheme } from "styled-components"; +import { formatTimeDistance } from "../../../utils/formatTimeDistance"; import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; -import { timeAgo } from "../../../utils/timeAgo"; import { InsightScope } from "../../Insights/types"; import { Badge } from "../../common/Badge"; import { Tooltip } from "../../common/Tooltip"; @@ -101,7 +101,9 @@ export const NotificationCard = (props: NotificationCardProps) => { const title = props.data.title; const linkName = getLinkName(props.data.data); - const timeDistance = timeAgo(props.data.timestamp); + const timeDistanceString = formatTimeDistance(props.data.timestamp, { + format: "medium" + }); return ( { {title} - {timeDistance && ( + {timeDistanceString && ( - - {timeDistance.value} {timeDistance.unit} ago - + {timeDistanceString} )} diff --git a/src/components/RecentActivity/RecentActivityTable/index.tsx b/src/components/RecentActivity/RecentActivityTable/index.tsx index 38271e55b..85b07ecbb 100644 --- a/src/components/RecentActivity/RecentActivityTable/index.tsx +++ b/src/components/RecentActivity/RecentActivityTable/index.tsx @@ -8,10 +8,10 @@ import { useMemo } from "react"; import { useTheme } from "styled-components"; import { Duration } from "../../../globals"; import { isNumber } from "../../../typeGuards/isNumber"; +import { formatTimeDistance } from "../../../utils/formatTimeDistance"; import { getInsightImportanceColor } from "../../../utils/getInsightImportanceColor"; import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; import { getInsightTypeOrderPriority } from "../../../utils/getInsightTypeOrderPriority"; -import { timeAgo } from "../../../utils/timeAgo"; import { Badge } from "../../common/Badge"; import { Button } from "../../common/Button"; import { Tooltip } from "../../common/Tooltip"; @@ -65,10 +65,10 @@ export const RecentActivityTable = (props: RecentActivityTableProps) => { const renderTimeDistance = (timestamp: string, viewMode: ViewMode) => { const title = new Date(timestamp).toString(); - const timeDistance = timeAgo(timestamp, "short"); - const timeDistanceString = timeDistance - ? `${timeDistance.value}${timeDistance.unit}` - : ""; + const timeDistanceString = formatTimeDistance(timestamp, { + format: "short", + withDescriptiveWords: false + }).replace(" ", ""); return viewMode === "table" ? ( diff --git a/src/utils/formatTimeDistance.ts b/src/utils/formatTimeDistance.ts index f9759b531..481618d80 100644 --- a/src/utils/formatTimeDistance.ts +++ b/src/utils/formatTimeDistance.ts @@ -1,6 +1,151 @@ -import { intlFormatDistance } from "date-fns"; +import intervalToDuration from "date-fns/intervalToDuration"; +import { isNumber } from "../typeGuards/isNumber"; -export const formatTimeDistance = (dateTime: string) => - intlFormatDistance(new Date(dateTime), new Date(), { - numeric: "always", - }); +export type TimeUnit = + | "seconds" + | "minutes" + | "hours" + | "days" + | "weeks" + | "months" + | "years"; + +const unitFormats = { + seconds: { + short: "s", + medium: "sec", + long: "second" + }, + minutes: { + short: "m", + medium: "min", + long: "minute" + }, + hours: { + short: "h", + medium: "hr", + long: "hour" + }, + days: { + short: "d", + medium: "d", + long: "day" + }, + weeks: { + short: "wk", + medium: "wk", + long: "week" + }, + months: { + short: "mo", + medium: "mo", + long: "month" + }, + years: { + short: "y", + medium: "yr", + long: "year" + } +}; + +const getTimeDistance = ( + date: string, + dateTimeToCompare: string +): { value: number; unit: TimeUnit } | undefined => { + const { years, months, weeks, days, hours, minutes, seconds } = + intervalToDuration({ + start: new Date(date), + end: new Date(dateTimeToCompare) + }); + + let value: number | undefined; + let unit: TimeUnit | undefined; + + if (seconds) { + value = seconds; + unit = "seconds"; + } + + if (minutes) { + value = minutes; + unit = "minutes"; + } + + if (hours) { + value = hours; + unit = "hours"; + } + + if (days) { + value = days; + unit = "days"; + } + + if (weeks) { + value = weeks; + unit = "weeks"; + } + + if (months) { + value = months; + unit = "months"; + } + + if (years) { + value = years; + unit = "years"; + } + + if (!unit || !isNumber(value)) { + return; + } + + return { + value, + unit + }; +}; + +export const formatTimeDistance = ( + dateTime: string, + options?: { + format?: "short" | "medium" | "long"; + withDescriptiveWords?: boolean; + } +) => { + const now = new Date(); + const dateTimeToCompare = new Date(dateTime).valueOf(); + + const distance = getTimeDistance(now.toISOString(), dateTime); + + if (!distance) { + return ""; + } + + const withDescriptiveWords = + typeof options?.withDescriptiveWords === "boolean" + ? options.withDescriptiveWords + : true; + const format = options?.format || "long"; + let unitString = unitFormats[distance.unit][format]; + + if (distance.value === 1 && format === "long") { + unitString = `${unitString}s`; + } + + const distanceString = distance ? `${distance.value} ${unitString}` : ""; + + if (withDescriptiveWords) { + if (dateTimeToCompare > now.valueOf()) { + return `in ${distanceString}`; + } + + if (dateTimeToCompare < now.valueOf()) { + return `${distanceString} ago`; + } + + return "now"; + } + + return distanceString; +}; diff --git a/src/utils/timeAgo.ts b/src/utils/timeAgo.ts deleted file mode 100644 index 355417527..000000000 --- a/src/utils/timeAgo.ts +++ /dev/null @@ -1,54 +0,0 @@ -import intervalToDuration from "date-fns/intervalToDuration"; -import { isNumber } from "../typeGuards/isNumber"; - -export const timeAgo = ( - date: string, - format?: "short" | "medium" -): { value: number; unit: string } | undefined => { - const { years, months, days, hours, minutes, seconds } = intervalToDuration({ - start: new Date(), - end: new Date(date) - }); - - let value: number | undefined; - let unit: string | undefined; - - if (seconds) { - value = seconds; - unit = format === "short" ? "s" : "sec"; - } - - if (minutes) { - value = minutes; - unit = format === "short" ? "m" : "min"; - } - - if (hours) { - value = hours; - unit = "h"; - } - - if (days) { - value = days; - unit = "d"; - } - - if (months) { - value = months; - unit = "mo"; - } - - if (years) { - value = years; - unit = "y"; - } - - if (!unit || !isNumber(value)) { - return; - } - - return { - value, - unit - }; -};