diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx index 9cee2d1e2..195766e03 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx @@ -6,7 +6,7 @@ import { RouteComponentProps, Redirect, } from "react-router-dom"; -import { FormattedDate, FormattedMessage, useIntl } from "react-intl"; +import { FormattedMessage, useIntl } from "react-intl"; import { Helmet } from "react-helmet"; import * as GQL from "src/core/generated-graphql"; import { @@ -44,6 +44,7 @@ import { useRatingKeybinds } from "src/hooks/keybinds"; import { useConfigurationContext } from "src/hooks/Config"; import { TruncatedText } from "src/components/Shared/TruncatedText"; import { goBackOrReplace } from "src/utils/history"; +import { FormattedDate } from "src/components/Shared/Date"; interface IProps { gallery: GQL.GalleryDataFragment; @@ -410,11 +411,7 @@ export const GalleryPage: React.FC = ({ gallery, add }) => {
{!!gallery.date && ( - + )}
diff --git a/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx b/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx index c794ddc14..c57bf45ad 100644 --- a/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx @@ -102,7 +102,7 @@ const GalleryWallCard: React.FC = ({ gallery }) => { )}
- {gallery.date && TextUtils.formatDate(intl, gallery.date)} + {gallery.date && TextUtils.formatFuzzyDate(intl, gallery.date)}
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx b/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx index d93b06466..b8e39ffe6 100644 --- a/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx +++ b/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx @@ -65,7 +65,7 @@ export const GroupDetailsPanel: React.FC = ({ /> = ({ image }) => {
- {!!image.date && ( - - )} + {!!image.date && } {resolution ? ( diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx index d01709287..95e03ff8b 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx @@ -89,7 +89,10 @@ export const PerformerDetailsPanel: React.FC = } title={ !fullWidth - ? TextUtils.formatDate(intl, performer.birthdate ?? undefined) + ? TextUtils.formatFuzzyDate( + intl, + performer.birthdate ?? undefined + ) : "" } fullWidth={fullWidth} @@ -218,7 +221,7 @@ export const CompressedPerformerDetailsPanel: React.FC = / = ( diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx index aee6ab344..3615f1327 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx @@ -6,7 +6,7 @@ import React, { useRef, useLayoutEffect, } from "react"; -import { FormattedDate, FormattedMessage, useIntl } from "react-intl"; +import { FormattedMessage, useIntl } from "react-intl"; import { Link, RouteComponentProps } from "react-router-dom"; import { Helmet } from "react-helmet"; import * as GQL from "src/core/generated-graphql"; @@ -51,6 +51,7 @@ import cx from "classnames"; import { TruncatedText } from "src/components/Shared/TruncatedText"; import { PatchComponent, PatchContainerComponent } from "src/patch"; import { goBackOrReplace } from "src/utils/history"; +import { FormattedDate } from "src/components/Shared/Date"; const SubmitStashBoxDraft = lazyComponent( () => import("src/components/Dialogs/SubmitDraft") @@ -613,13 +614,7 @@ const ScenePage: React.FC = PatchComponent("ScenePage", (props) => {
- {!!scene.date && ( - - )} + {!!scene.date && } )} -
{scene.date && TextUtils.formatDate(intl, scene.date)}
+
+ {scene.date && TextUtils.formatFuzzyDate(intl, scene.date)} +
diff --git a/ui/v2.5/src/components/Shared/Date.tsx b/ui/v2.5/src/components/Shared/Date.tsx new file mode 100644 index 000000000..78dd23afa --- /dev/null +++ b/ui/v2.5/src/components/Shared/Date.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { FormattedDate as IntlDate } from "react-intl"; +import { PatchComponent } from "src/patch"; + +// wraps FormattedDate to handle year or year/month dates +export const FormattedDate: React.FC<{ + value: string | number | Date | undefined; +}> = PatchComponent("Date", ({ value }) => { + if (typeof value === "string") { + // try parsing as year or year/month + const yearMatch = value.match(/^(\d{4})$/); + if (yearMatch) { + const year = parseInt(yearMatch[1], 10); + return ( + + ); + } + + const yearMonthMatch = value.match(/^(\d{4})-(\d{2})$/); + if (yearMonthMatch) { + const year = parseInt(yearMonthMatch[1], 10); + const month = parseInt(yearMonthMatch[2], 10) - 1; + + return ( + + ); + } + } + + return ; +}); diff --git a/ui/v2.5/src/utils/text.ts b/ui/v2.5/src/utils/text.ts index dc654ae18..2c5bb4648 100644 --- a/ui/v2.5/src/utils/text.ts +++ b/ui/v2.5/src/utils/text.ts @@ -336,8 +336,10 @@ function dateTimeToString(date: Date) { const getAge = (dateString?: string | null, fromDateString?: string | null) => { if (!dateString) return 0; - const birthdate = stringToDate(dateString); - const fromDate = fromDateString ? stringToDate(fromDateString) : new Date(); + const birthdate = stringToFuzzyDate(dateString); + const fromDate = fromDateString + ? stringToFuzzyDate(fromDateString) + : new Date(); if (!birthdate || !fromDate) return 0; @@ -459,6 +461,38 @@ const formatDate = (intl: IntlShape, date?: string, utc = true) => { }); }; +const formatFuzzyDate = (intl: IntlShape, date?: string, utc = true) => { + if (!date) { + return ""; + } + + // handle year or year/month dates + const yearMatch = date.match(/^(\d{4})$/); + if (yearMatch) { + const year = parseInt(yearMatch[1], 10); + return intl.formatDate(Date.UTC(year, 0), { + year: "numeric", + timeZone: utc ? "utc" : undefined, + }); + } + + const yearMonthMatch = date.match(/^(\d{4})-(\d{2})$/); + if (yearMonthMatch) { + const year = parseInt(yearMonthMatch[1], 10); + const month = parseInt(yearMonthMatch[2], 10) - 1; + return intl.formatDate(Date.UTC(year, month), { + year: "numeric", + month: "long", + timeZone: utc ? "utc" : undefined, + }); + } + + return intl.formatDate(date, { + format: "long", + timeZone: utc ? "utc" : undefined, + }); +}; + const formatDateTime = (intl: IntlShape, dateTime?: string, utc = false) => `${formatDate(intl, dateTime, utc)} ${intl.formatTime(dateTime, { timeZone: utc ? "utc" : undefined, @@ -519,6 +553,7 @@ const TextUtils = { sanitiseURL, domainFromURL, formatDate, + formatFuzzyDate, formatDateTime, secondsAsTimeString, abbreviateCounter,