Standardize date display

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-09-18 11:23:37 +02:00
parent 68feac5367
commit eabc34c3ac
19 changed files with 70 additions and 69 deletions

View File

@@ -3,7 +3,7 @@ import { useTranslate } from "@probo/i18n";
import { useLazyLoadQuery, graphql } from "react-relay"; import { useLazyLoadQuery, graphql } from "react-relay";
import { useLocation } from "react-router"; import { useLocation } from "react-router";
import type { SnapshotBannerQuery } from "./__generated__/SnapshotBannerQuery.graphql"; import type { SnapshotBannerQuery } from "./__generated__/SnapshotBannerQuery.graphql";
import { getSnapshotTypeUrlPath, getSnapshotTypeLabel, sprintf } from "@probo/helpers"; import { getSnapshotTypeUrlPath, getSnapshotTypeLabel, sprintf, formatDate } from "@probo/helpers";
const snapshotQuery = graphql` const snapshotQuery = graphql`
query SnapshotBannerQuery($snapshotId: ID!) { query SnapshotBannerQuery($snapshotId: ID!) {
@@ -28,7 +28,7 @@ type Props = {
}; };
export function SnapshotBanner({ snapshotId }: Props) { export function SnapshotBanner({ snapshotId }: Props) {
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const location = useLocation(); const location = useLocation();
const data = useLazyLoadQuery<SnapshotBannerQuery>(snapshotQuery, { snapshotId }); const data = useLazyLoadQuery<SnapshotBannerQuery>(snapshotQuery, { snapshotId });
@@ -53,7 +53,7 @@ export function SnapshotBanner({ snapshotId }: Props) {
{sprintf( {sprintf(
__("You are viewing a %s snapshot from %s"), __("You are viewing a %s snapshot from %s"),
getSnapshotTypeLabel(__, snapshot.type).toLocaleLowerCase(), getSnapshotTypeLabel(__, snapshot.type).toLocaleLowerCase(),
dateFormat(snapshot.createdAt, { year: "numeric", month: "short", day: "numeric" }) formatDate(snapshot.createdAt)
)} )}
</p> </p>
</div> </div>

View File

@@ -18,7 +18,7 @@ import { useTranslate } from "@probo/i18n";
import type { LinkedSnapshotsCardFragment$key } from "./__generated__/LinkedSnapshotsCardFragment.graphql"; import type { LinkedSnapshotsCardFragment$key } from "./__generated__/LinkedSnapshotsCardFragment.graphql";
import { useFragment } from "react-relay"; import { useFragment } from "react-relay";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { sprintf, getSnapshotTypeLabel, getSnapshotTypeUrlPath } from "@probo/helpers"; import { sprintf, getSnapshotTypeLabel, getSnapshotTypeUrlPath, formatDate } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { LinkedSnapshotsDialog } from "./LinkedSnapshotsDialog"; import { LinkedSnapshotsDialog } from "./LinkedSnapshotsDialog";
import clsx from "clsx"; import clsx from "clsx";
@@ -165,7 +165,7 @@ function SnapshotRow(props: {
}) { }) {
const snapshot = useFragment(linkedSnapshotFragment, props.snapshot); const snapshot = useFragment(linkedSnapshotFragment, props.snapshot);
const organizationId = useOrganizationId(); const organizationId = useOrganizationId();
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const urlPath = getSnapshotTypeUrlPath(snapshot.type); const urlPath = getSnapshotTypeUrlPath(snapshot.type);
const snapshotUrl = `/organizations/${organizationId}/snapshots/${snapshot.id}${urlPath}`; const snapshotUrl = `/organizations/${organizationId}/snapshots/${snapshot.id}${urlPath}`;
@@ -184,7 +184,7 @@ function SnapshotRow(props: {
</Td> </Td>
)} )}
<Td className="text-txt-tertiary"> <Td className="text-txt-tertiary">
{dateFormat(snapshot.createdAt, { year: "numeric", month: "short", day: "numeric" })} {formatDate(snapshot.createdAt)}
</Td> </Td>
<Td noLink width={50} className="text-end"> <Td noLink width={50} className="text-end">
<Button <Button

View File

@@ -12,7 +12,7 @@ import {
IconTrashCan, IconTrashCan,
} from "@probo/ui"; } from "@probo/ui";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { getSnapshotTypeLabel } from "@probo/helpers"; import { getSnapshotTypeLabel, formatDate } from "@probo/helpers";
import { Suspense, useMemo, useState, type ReactNode } from "react"; import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay"; import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
@@ -155,7 +155,7 @@ type RowProps = {
}; };
function SnapshotRow(props: RowProps) { function SnapshotRow(props: RowProps) {
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const isLinked = props.linkedSnapshots.has(props.snapshot.id); const isLinked = props.linkedSnapshots.has(props.snapshot.id);
const onClick = isLinked ? props.onUnlink : props.onLink; const onClick = isLinked ? props.onUnlink : props.onLink;
@@ -177,7 +177,7 @@ function SnapshotRow(props: RowProps) {
{props.snapshot.description || __("No description")} {props.snapshot.description || __("No description")}
</div> </div>
<div className="text-sm text-txt-tertiary flex-shrink-0"> <div className="text-sm text-txt-tertiary flex-shrink-0">
{dateFormat(props.snapshot.createdAt, { year: "numeric", month: "short", day: "numeric" })} {formatDate(props.snapshot.createdAt)}
</div> </div>
</div> </div>
<Button <Button

View File

@@ -16,7 +16,7 @@ import {
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { useFragment } from "react-relay"; import { useFragment } from "react-relay";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { sprintf, getAuditStateVariant, getAuditStateLabel } from "@probo/helpers"; import { sprintf, getAuditStateVariant, getAuditStateLabel, formatDate } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import clsx from "clsx"; import clsx from "clsx";
import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql"; import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql";
@@ -131,7 +131,7 @@ function AuditRow(props: {
const { __ } = useTranslate(); const { __ } = useTranslate();
const validUntilFormatted = audit.validUntil const validUntilFormatted = audit.validUntil
? new Date(audit.validUntil).toLocaleDateString() ? formatDate(audit.validUntil)
: __("No expiry"); : __("No expiry");
return ( return (

View File

@@ -32,7 +32,7 @@ import { FrameworkLogo } from "/components/FrameworkLogo";
import { ControlledField } from "/components/form/ControlledField"; import { ControlledField } from "/components/form/ControlledField";
import { useFormWithSchema } from "/hooks/useFormWithSchema"; import { useFormWithSchema } from "/hooks/useFormWithSchema";
import z from "zod"; import z from "zod";
import { getAuditStateLabel, getAuditStateVariant, auditStates, fileSize, sprintf, formatDatetime } from "@probo/helpers"; import { getAuditStateLabel, getAuditStateVariant, auditStates, fileSize, sprintf, formatDatetime, formatDate } from "@probo/helpers";
import type { AuditGraphNodeQuery } from "/hooks/graph/__generated__/AuditGraphNodeQuery.graphql"; import type { AuditGraphNodeQuery } from "/hooks/graph/__generated__/AuditGraphNodeQuery.graphql";
const updateAuditSchema = z.object({ const updateAuditSchema = z.object({
@@ -49,7 +49,7 @@ type Props = {
export default function AuditDetailsPage(props: Props) { export default function AuditDetailsPage(props: Props) {
const audit = usePreloadedQuery<AuditGraphNodeQuery>(auditNodeQuery, props.queryRef); const audit = usePreloadedQuery<AuditGraphNodeQuery>(auditNodeQuery, props.queryRef);
const auditEntry = audit.node; const auditEntry = audit.node;
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const organizationId = useOrganizationId(); const organizationId = useOrganizationId();
if (!auditEntry || !auditEntry.id || !auditEntry.framework) { if (!auditEntry || !auditEntry.id || !auditEntry.framework) {
@@ -209,7 +209,7 @@ export default function AuditDetailsPage(props: Props) {
{fileSize(__, auditEntry.report.size)} {fileSize(__, auditEntry.report.size)}
</span> </span>
<span> <span>
{__("Uploaded")} {dateFormat(auditEntry.report.createdAt)} {__("Uploaded")} {formatDate(auditEntry.report.createdAt)}
</span> </span>
</div> </div>
</div> </div>

View File

@@ -25,7 +25,7 @@ import { CreateAuditDialog } from "./dialogs/CreateAuditDialog";
import { useDeleteAudit, auditsQuery } from "../../../hooks/graph/AuditGraph"; import { useDeleteAudit, auditsQuery } from "../../../hooks/graph/AuditGraph";
import type { AuditGraphListQuery } from "/hooks/graph/__generated__/AuditGraphListQuery.graphql"; import type { AuditGraphListQuery } from "/hooks/graph/__generated__/AuditGraphListQuery.graphql";
import type { NodeOf } from "/types"; import type { NodeOf } from "/types";
import { getAuditStateLabel, getAuditStateVariant } from "@probo/helpers"; import { getAuditStateLabel, getAuditStateVariant, formatDate } from "@probo/helpers";
import type { import type {
AuditsPageFragment$data, AuditsPageFragment$data,
AuditsPageFragment$key, AuditsPageFragment$key,
@@ -141,7 +141,7 @@ function AuditRow({
connectionId: string; connectionId: string;
}) { }) {
const organizationId = useOrganizationId(); const organizationId = useOrganizationId();
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const deleteAudit = useDeleteAudit(entry, connectionId); const deleteAudit = useDeleteAudit(entry, connectionId);
return ( return (
@@ -153,8 +153,8 @@ function AuditRow({
{getAuditStateLabel(__, entry.state)} {getAuditStateLabel(__, entry.state)}
</Badge> </Badge>
</Td> </Td>
<Td>{dateFormat(entry.validFrom, { year: "numeric", month: "short", day: "numeric" }) || __("Not set")}</Td> <Td>{formatDate(entry.validFrom) || __("Not set")}</Td>
<Td>{dateFormat(entry.validUntil, { year: "numeric", month: "short", day: "numeric" }) || __("Not set")}</Td> <Td>{formatDate(entry.validUntil) || __("Not set")}</Td>
<Td> <Td>
{entry.report ? ( {entry.report ? (
<div className="flex flex-col"> <div className="flex flex-col">

View File

@@ -29,7 +29,7 @@ import { useOrganizationId } from "/hooks/useOrganizationId";
import { useParams } from "react-router"; import { useParams } from "react-router";
import { CreateContinualImprovementDialog } from "./dialogs/CreateContinualImprovementDialog"; import { CreateContinualImprovementDialog } from "./dialogs/CreateContinualImprovementDialog";
import { deleteContinualImprovementMutation, ContinualImprovementsConnectionKey } from "../../../hooks/graph/ContinualImprovementGraph"; import { deleteContinualImprovementMutation, ContinualImprovementsConnectionKey } from "../../../hooks/graph/ContinualImprovementGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers"; import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel, formatDate } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner"; import { SnapshotBanner } from "/components/SnapshotBanner";
import type { NodeOf } from "/types"; import type { NodeOf } from "/types";
import type { ContinualImprovementsPageQuery } from "./__generated__/ContinualImprovementsPageQuery.graphql"; import type { ContinualImprovementsPageQuery } from "./__generated__/ContinualImprovementsPageQuery.graphql";
@@ -214,9 +214,6 @@ function ImprovementRow({
const confirm = useConfirm(); const confirm = useConfirm();
const isSnapshotMode = Boolean(snapshotId); const isSnapshotMode = Boolean(snapshotId);
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const handleDelete = () => { const handleDelete = () => {
confirm( confirm(

View File

@@ -45,7 +45,7 @@ import {
} from "@probo/ui"; } from "@probo/ui";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { getDocumentTypeLabel, sprintf, documentTypes } from "@probo/helpers"; import { getDocumentTypeLabel, sprintf, documentTypes, formatDate } from "@probo/helpers";
import { import {
Link, Link,
Outlet, Outlet,
@@ -195,7 +195,7 @@ export default function DocumentDetailPage(props: Props) {
documentFragment, documentFragment,
node node
); );
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const organizationId = useOrganizationId(); const organizationId = useOrganizationId();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -607,13 +607,13 @@ export default function DocumentDetailPage(props: Props) {
</PropertyRow> </PropertyRow>
<PropertyRow label={__("Last modified")}> <PropertyRow label={__("Last modified")}>
<div className="text-sm text-txt-secondary"> <div className="text-sm text-txt-secondary">
{dateFormat(currentVersion.updatedAt)} {formatDate(currentVersion.updatedAt)}
</div> </div>
</PropertyRow> </PropertyRow>
{currentVersion.publishedAt && ( {currentVersion.publishedAt && (
<PropertyRow label={__("Published Date")}> <PropertyRow label={__("Published Date")}>
<div className="text-sm text-txt-secondary"> <div className="text-sm text-txt-secondary">
{dateFormat(currentVersion.publishedAt)} {formatDate(currentVersion.publishedAt)}
</div> </div>
</PropertyRow> </PropertyRow>
)} )}

View File

@@ -39,7 +39,7 @@ import {
} from "/hooks/graph/DocumentGraph"; } from "/hooks/graph/DocumentGraph";
import type { DocumentsPageListFragment$key } from "./__generated__/DocumentsPageListFragment.graphql"; import type { DocumentsPageListFragment$key } from "./__generated__/DocumentsPageListFragment.graphql";
import { useList, usePageTitle } from "@probo/hooks"; import { useList, usePageTitle } from "@probo/hooks";
import { sprintf, getDocumentTypeLabel } from "@probo/helpers"; import { sprintf, getDocumentTypeLabel, formatDate } from "@probo/helpers";
import { CreateDocumentDialog } from "./dialogs/CreateDocumentDialog"; import { CreateDocumentDialog } from "./dialogs/CreateDocumentDialog";
import type { DocumentsPageRowFragment$key } from "./__generated__/DocumentsPageRowFragment.graphql"; import type { DocumentsPageRowFragment$key } from "./__generated__/DocumentsPageRowFragment.graphql";
import { SortableTable, SortableTh } from "/components/SortableTable"; import { SortableTable, SortableTh } from "/components/SortableTable";
@@ -320,7 +320,7 @@ function DocumentRow({
} }
const isDraft = lastVersion.status === "DRAFT"; const isDraft = lastVersion.status === "DRAFT";
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const signatures = lastVersion.signatures?.edges?.map((edge) => edge?.node)?.filter(Boolean) ?? []; const signatures = lastVersion.signatures?.edges?.map((edge) => edge?.node)?.filter(Boolean) ?? [];
const signedCount = signatures.filter( const signedCount = signatures.filter(
(signature) => signature.state === "SIGNED" (signature) => signature.state === "SIGNED"
@@ -370,12 +370,7 @@ function DocumentRow({
</div> </div>
</Td> </Td>
<Td className="w-60"> <Td className="w-60">
{dateFormat(document.updatedAt, { {formatDate(document.updatedAt)}
year: "numeric",
month: "short",
day: "numeric",
weekday: "short",
})}
</Td> </Td>
<Td className="w-20"> <Td className="w-20">
{signedCount}/{signatures.length} {signedCount}/{signatures.length}

View File

@@ -26,7 +26,7 @@ import {
} from "react-relay"; } from "react-relay";
import { SortableTable } from "/components/SortableTable"; import { SortableTable } from "/components/SortableTable";
import type { MeasureEvidencesTabFragment_evidence$key } from "./__generated__/MeasureEvidencesTabFragment_evidence.graphql"; import type { MeasureEvidencesTabFragment_evidence$key } from "./__generated__/MeasureEvidencesTabFragment_evidence.graphql";
import { fileSize, fileType, promisifyMutation, sprintf } from "@probo/helpers"; import { fileSize, fileType, promisifyMutation, sprintf, formatDate } from "@probo/helpers";
import { EvidencePreviewDialog } from "../dialog/EvidencePreviewDialog"; import { EvidencePreviewDialog } from "../dialog/EvidencePreviewDialog";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { CreateEvidenceDialog } from "../dialog/CreateEvidenceDialog"; import { CreateEvidenceDialog } from "../dialog/CreateEvidenceDialog";
@@ -173,7 +173,7 @@ function EvidenceRow(props: {
snapshotId?: string; snapshotId?: string;
}) { }) {
const evidence = useFragment(evidenceFragment, props.evidenceKey); const evidence = useFragment(evidenceFragment, props.evidenceKey);
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const [mutate, isDeleting] = useMutation(deleteEvidenceMutation); const [mutate, isDeleting] = useMutation(deleteEvidenceMutation);
const confirm = useConfirm(); const confirm = useConfirm();
@@ -229,7 +229,7 @@ function EvidenceRow(props: {
<Td>{evidence.filename}</Td> <Td>{evidence.filename}</Td>
<Td>{fileType(__, evidence)}</Td> <Td>{fileType(__, evidence)}</Td>
<Td>{fileSize(__, evidence.size)}</Td> <Td>{fileSize(__, evidence.size)}</Td>
<Td>{dateFormat(evidence.createdAt)}</Td> <Td>{formatDate(evidence.createdAt)}</Td>
<Td noLink> <Td noLink>
{!props.hideActions && ( {!props.hideActions && (
<div className="flex gap-2"> <div className="flex gap-2">

View File

@@ -28,7 +28,7 @@ import {
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { CreateNonconformityDialog } from "./dialogs/CreateNonconformityDialog"; import { CreateNonconformityDialog } from "./dialogs/CreateNonconformityDialog";
import { deleteNonconformityMutation, NonconformitiesConnectionKey } from "../../../hooks/graph/NonconformityGraph"; import { deleteNonconformityMutation, NonconformitiesConnectionKey } from "../../../hooks/graph/NonconformityGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers"; import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel, formatDate } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner"; import { SnapshotBanner } from "/components/SnapshotBanner";
import { useParams } from "react-router"; import { useParams } from "react-router";
import type { NonconformitiesPageQuery } from "./__generated__/NonconformitiesPageQuery.graphql"; import type { NonconformitiesPageQuery } from "./__generated__/NonconformitiesPageQuery.graphql";
@@ -220,9 +220,6 @@ function NonconformityRow({
const confirm = useConfirm(); const confirm = useConfirm();
const [deleteNonconformity] = useMutation(deleteNonconformityMutation); const [deleteNonconformity] = useMutation(deleteNonconformityMutation);
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const nonconformityDetailUrl = isSnapshotMode const nonconformityDetailUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformities/${nonconformity.id}` ? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformities/${nonconformity.id}`

View File

@@ -28,7 +28,7 @@ import { useParams } from "react-router";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { CreateObligationDialog } from "./dialogs/CreateObligationDialog"; import { CreateObligationDialog } from "./dialogs/CreateObligationDialog";
import { deleteObligationMutation } from "../../../hooks/graph/ObligationGraph"; import { deleteObligationMutation } from "../../../hooks/graph/ObligationGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers"; import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel, formatDate } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner"; import { SnapshotBanner } from "/components/SnapshotBanner";
import type { ObligationsPageQuery } from "./__generated__/ObligationsPageQuery.graphql"; import type { ObligationsPageQuery } from "./__generated__/ObligationsPageQuery.graphql";
import type { import type {
@@ -205,9 +205,6 @@ function ObligationRow({
const confirm = useConfirm(); const confirm = useConfirm();
const isSnapshotMode = Boolean(snapshotId); const isSnapshotMode = Boolean(snapshotId);
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const handleDelete = () => { const handleDelete = () => {
confirm( confirm(

View File

@@ -5,7 +5,7 @@ import {
type PreloadedQuery, type PreloadedQuery,
} from "react-relay"; } from "react-relay";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { getSnapshotTypeLabel, getSnapshotTypeUrlPath } from "@probo/helpers"; import { getSnapshotTypeLabel, getSnapshotTypeUrlPath, formatDate } from "@probo/helpers";
import { import {
ActionDropdown, ActionDropdown,
Badge, Badge,
@@ -129,7 +129,7 @@ type SnapshotRowProps = {
}; };
function SnapshotRow(props: SnapshotRowProps) { function SnapshotRow(props: SnapshotRowProps) {
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const deleteSnapshot = useDeleteSnapshot(props.snapshot, props.connectionId); const deleteSnapshot = useDeleteSnapshot(props.snapshot, props.connectionId);
const typePath = getSnapshotTypeUrlPath(props.snapshot.type); const typePath = getSnapshotTypeUrlPath(props.snapshot.type);
@@ -146,7 +146,7 @@ function SnapshotRow(props: SnapshotRowProps) {
{props.snapshot.description || __("No description")} {props.snapshot.description || __("No description")}
</Td> </Td>
<Td className="text-txt-tertiary"> <Td className="text-txt-tertiary">
{dateFormat(props.snapshot.createdAt, { year: "numeric", month: "short", day: "numeric" })} {formatDate(props.snapshot.createdAt)}
</Td> </Td>
<Td noLink width={50} className="text-end"> <Td noLink width={50} className="text-end">
<ActionDropdown> <ActionDropdown>

View File

@@ -19,6 +19,7 @@ import {
IconCheckmark1, IconCheckmark1,
} from "@probo/ui"; } from "@probo/ui";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { formatDate } from "@probo/helpers";
import { useOutletContext } from "react-router"; import { useOutletContext } from "react-router";
import { useState, useCallback } from "react"; import { useState, useCallback } from "react";
import z from "zod"; import z from "zod";
@@ -87,7 +88,7 @@ export default function TrustCenterAccessTab() {
name: string; name: string;
active: boolean; active: boolean;
hasAcceptedNonDisclosureAgreement: boolean; hasAcceptedNonDisclosureAgreement: boolean;
createdAt: Date; createdAt: string;
}; };
const trustCenterData = useTrustCenterAccesses(organization.trustCenter?.id || ""); const trustCenterData = useTrustCenterAccesses(organization.trustCenter?.id || "");
@@ -98,7 +99,7 @@ export default function TrustCenterAccessTab() {
name: edge.node.name, name: edge.node.name,
active: edge.node.active, active: edge.node.active,
hasAcceptedNonDisclosureAgreement: edge.node.hasAcceptedNonDisclosureAgreement, hasAcceptedNonDisclosureAgreement: edge.node.hasAcceptedNonDisclosureAgreement,
createdAt: new Date(edge.node.createdAt) createdAt: edge.node.createdAt
})) ?? []; })) ?? [];
const handleInvite = inviteForm.handleSubmit(async (data) => { const handleInvite = inviteForm.handleSubmit(async (data) => {
@@ -216,7 +217,7 @@ export default function TrustCenterAccessTab() {
<Td className="font-medium">{access.name}</Td> <Td className="font-medium">{access.name}</Td>
<Td>{access.email}</Td> <Td>{access.email}</Td>
<Td> <Td>
{access.createdAt.toLocaleDateString()} {formatDate(access.createdAt)}
</Td> </Td>
<Td> <Td>
<Checkbox <Checkbox

View File

@@ -22,7 +22,7 @@ import {
} from "react-relay"; } from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { useParams } from "react-router"; import { useParams } from "react-router";
import { faviconUrl } from "@probo/helpers"; import { faviconUrl, formatDate } from "@probo/helpers";
import type { NodeOf } from "/types"; import type { NodeOf } from "/types";
import { CreateVendorDialog } from "./dialogs/CreateVendorDialog"; import { CreateVendorDialog } from "./dialogs/CreateVendorDialog";
import { import {
@@ -115,7 +115,7 @@ function VendorRow({
}) { }) {
const { snapshotId } = useParams<{ snapshotId?: string }>(); const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId); const isSnapshotMode = Boolean(snapshotId);
const { __, dateFormat } = useTranslate(); const { __ } = useTranslate();
const latestAssessment = vendor.riskAssessments?.edges[0]?.node; const latestAssessment = vendor.riskAssessments?.edges[0]?.node;
const deleteVendor = useDeleteVendor(vendor, connectionId); const deleteVendor = useDeleteVendor(vendor, connectionId);
@@ -135,11 +135,7 @@ function VendorRow({
</Td> </Td>
<Td> <Td>
{latestAssessment?.assessedAt {latestAssessment?.assessedAt
? dateFormat(latestAssessment.assessedAt, { ? formatDate(latestAssessment.assessedAt)
day: "2-digit",
weekday: "short",
month: "short",
})
: __("Not assessed")} : __("Not assessed")}
</Td> </Td>
<Td> <Td>

View File

@@ -18,7 +18,7 @@ import {
import { useFragment, useMutation, useRefetchableFragment } from "react-relay"; import { useFragment, useMutation, useRefetchableFragment } from "react-relay";
import type { VendorComplianceTabFragment_report$key } from "./__generated__/VendorComplianceTabFragment_report.graphql"; import type { VendorComplianceTabFragment_report$key } from "./__generated__/VendorComplianceTabFragment_report.graphql";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { sprintf, fileSize } from "@probo/helpers"; import { sprintf, fileSize, formatDate } from "@probo/helpers";
import { SortableTable, SortableTh } from "/components/SortableTable"; import { SortableTable, SortableTh } from "/components/SortableTable";
export const complianceReportsFragment = graphql` export const complianceReportsFragment = graphql`
@@ -175,7 +175,6 @@ function ReportRow(props: ReportRowProps) {
complianceReportFragment, complianceReportFragment,
props.reportKey props.reportKey
); );
const { dateFormat } = useTranslate();
const confirm = useConfirm(); const confirm = useConfirm();
const [deleteReport] = useMutationWithToasts(deleteReportMutation, { const [deleteReport] = useMutationWithToasts(deleteReportMutation, {
successMessage: __("Report deleted successfully"), successMessage: __("Report deleted successfully"),
@@ -207,8 +206,8 @@ function ReportRow(props: ReportRowProps) {
return ( return (
<Tr> <Tr>
<Td>{report.reportName}</Td> <Td>{report.reportName}</Td>
<Td>{dateFormat(report.reportDate)}</Td> <Td>{formatDate(report.reportDate)}</Td>
<Td>{dateFormat(report.validUntil)}</Td> <Td>{formatDate(report.validUntil)}</Td>
<Td>{fileSize(__, report.fileSize)}</Td> <Td>{fileSize(__, report.fileSize)}</Td>
{!props.isSnapshotMode && ( {!props.isSnapshotMode && (
<Td width={50} className="text-end"> <Td width={50} className="text-end">

View File

@@ -8,7 +8,7 @@ import { CountriesField } from "/components/form/CountriesField";
import { useOrganizationId } from "/hooks/useOrganizationId"; import { useOrganizationId } from "/hooks/useOrganizationId";
import { useMemo } from "react"; import { useMemo } from "react";
import { usePageTitle } from "@probo/hooks"; import { usePageTitle } from "@probo/hooks";
import { downloadFile } from "@probo/helpers"; import { downloadFile, formatDate } from "@probo/helpers";
import { useFragment, graphql } from "react-relay"; import { useFragment, graphql } from "react-relay";
import { UploadBusinessAssociateAgreementDialog } from "../dialogs/UploadBusinessAssociateAgreementDialog"; import { UploadBusinessAssociateAgreementDialog } from "../dialogs/UploadBusinessAssociateAgreementDialog";
import { DeleteBusinessAssociateAgreementDialog } from "../dialogs/DeleteBusinessAssociateAgreementDialog"; import { DeleteBusinessAssociateAgreementDialog } from "../dialogs/DeleteBusinessAssociateAgreementDialog";
@@ -268,10 +268,10 @@ export default function VendorOverviewTab() {
<p className="text-xs text-txt-secondary mt-1"> <p className="text-xs text-txt-secondary mt-1">
{__("Valid")} {__("Valid")}
{businessAssociateAgreement.validFrom && {businessAssociateAgreement.validFrom &&
` ${__("from")} ${new Date(businessAssociateAgreement.validFrom).toLocaleDateString()}` ` ${__("from")} ${formatDate(businessAssociateAgreement.validFrom)}`
} }
{businessAssociateAgreement.validUntil && {businessAssociateAgreement.validUntil &&
` ${__("until")} ${new Date(businessAssociateAgreement.validUntil).toLocaleDateString()}` ` ${__("until")} ${formatDate(businessAssociateAgreement.validUntil)}`
} }
</p> </p>
)} )}
@@ -335,10 +335,10 @@ export default function VendorOverviewTab() {
<p className="text-xs text-txt-secondary mt-1"> <p className="text-xs text-txt-secondary mt-1">
{__("Valid")} {__("Valid")}
{dataPrivacyAgreement.validFrom && {dataPrivacyAgreement.validFrom &&
` ${__("from")} ${new Date(dataPrivacyAgreement.validFrom).toLocaleDateString()}` ` ${__("from")} ${formatDate(dataPrivacyAgreement.validFrom)}`
} }
{dataPrivacyAgreement.validUntil && {dataPrivacyAgreement.validUntil &&
` ${__("until")} ${new Date(dataPrivacyAgreement.validUntil).toLocaleDateString()}` ` ${__("until")} ${formatDate(dataPrivacyAgreement.validUntil)}`
} }
</p> </p>
)} )}

View File

@@ -2,3 +2,22 @@ export function formatDatetime(dateString?: string | null): string | undefined {
if (!dateString) return undefined; if (!dateString) return undefined;
return `${dateString}T00:00:00Z`; return `${dateString}T00:00:00Z`;
} }
export function formatDate(dateInput?: string | null): string {
if (!dateInput) return '';
const date = parseDate(dateInput);
return date.toLocaleDateString();
}
function parseDate(dateString: string): Date {
if (dateString.includes('T')) {
return new Date(dateString);
}
const parts = dateString.split('-');
return new Date(
parseInt(parts[0], 10),
parts[1] ? parseInt(parts[1], 10) - 1 : 0,
parts[2] ? parseInt(parts[2], 10) : 1
);
}

View File

@@ -21,4 +21,4 @@ export { getAuditStateLabel, getAuditStateVariant, auditStates } from "./audits"
export { getStatusVariant, getStatusLabel, getStatusOptions } from "./registryStatus"; export { getStatusVariant, getStatusLabel, getStatusOptions } from "./registryStatus";
export { promisifyMutation } from "./relay"; export { promisifyMutation } from "./relay";
export { fileType, fileSize } from "./file"; export { fileType, fileSize } from "./file";
export { formatDatetime } from "./date"; export { formatDatetime, formatDate } from "./date";