refactor: use date times with hooks everywhere
This commit is contained in:
parent
8b796cfec2
commit
1b780ed127
6 changed files with 35 additions and 27 deletions
|
|
@ -1,6 +1,11 @@
|
|||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
DEFAULT_TIME_FORMAT,
|
||||
import { DEFAULT_TIME_FORMAT, inferDateTimePreferences, rawFormatters } from "../datetime";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const {
|
||||
formatDate,
|
||||
formatDateTime,
|
||||
formatDateWithMonth,
|
||||
|
|
@ -8,12 +13,7 @@ import {
|
|||
formatShortDateTime,
|
||||
formatTime,
|
||||
formatTimeAgo,
|
||||
inferDateTimePreferences,
|
||||
} from "../datetime";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
} = rawFormatters;
|
||||
|
||||
const sampleDate = new Date("2026-01-10T14:30:00.000Z");
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ export function inferDateTimePreferences(locale?: string) {
|
|||
}
|
||||
|
||||
// 1/10/2026, 2:30 PM
|
||||
export function formatDateTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatDateTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(
|
||||
date,
|
||||
(validDate) => `${formatConfiguredDate(validDate, options, true)}, ${formatConfiguredTime(validDate, options)}`,
|
||||
|
|
@ -157,22 +157,22 @@ export function formatDateTime(date: DateInput, options: DateFormatOptions = {})
|
|||
}
|
||||
|
||||
// Jan 10, 2026
|
||||
export function formatDateWithMonth(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatDateWithMonth(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(date, (validDate) => formatConfiguredDateWithMonth(validDate, options));
|
||||
}
|
||||
|
||||
// 1/10/2026
|
||||
export function formatDate(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatDate(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(date, (validDate) => formatConfiguredDate(validDate, options, true));
|
||||
}
|
||||
|
||||
// 1/10
|
||||
export function formatShortDate(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatShortDate(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(date, (validDate) => formatConfiguredDate(validDate, options, false));
|
||||
}
|
||||
|
||||
// 1/10, 2:30 PM
|
||||
export function formatShortDateTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatShortDateTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(
|
||||
date,
|
||||
(validDate) => `${formatConfiguredDate(validDate, options, false)}, ${formatConfiguredTime(validDate, options)}`,
|
||||
|
|
@ -180,12 +180,12 @@ export function formatShortDateTime(date: DateInput, options: DateFormatOptions
|
|||
}
|
||||
|
||||
// 2:30 PM
|
||||
export function formatTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
function formatTime(date: DateInput, options: DateFormatOptions = {}): string {
|
||||
return formatValidDate(date, (validDate) => formatConfiguredTime(validDate, options));
|
||||
}
|
||||
|
||||
// 5 minutes ago
|
||||
export function formatTimeAgo(date: DateInput, now = Date.now()): string {
|
||||
function formatTimeAgo(date: DateInput, now = Date.now()): string {
|
||||
return formatValidDate(date, (validDate) => {
|
||||
if (Math.abs(now - validDate.getTime()) < 120_000) {
|
||||
return "just now";
|
||||
|
|
@ -222,3 +222,13 @@ export function useTimeFormat() {
|
|||
[locale, timeZone, currentNow, dateFormat, timeFormat],
|
||||
);
|
||||
}
|
||||
|
||||
export const rawFormatters = {
|
||||
formatDateTime,
|
||||
formatDateWithMonth,
|
||||
formatDate,
|
||||
formatShortDate,
|
||||
formatShortDateTime,
|
||||
formatTime,
|
||||
formatTimeAgo,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ import {
|
|||
} from "~/client/components/ui/dropdown-menu";
|
||||
import { Separator } from "~/client/components/ui/separator";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
||||
import { formatDateTime, formatTimeAgo } from "~/client/lib/datetime";
|
||||
import { parseError } from "~/client/lib/errors";
|
||||
import { cn } from "~/client/lib/utils";
|
||||
import type { BackupSchedule, Snapshot } from "~/client/lib/types";
|
||||
import type { GetRepositoryStatsResponse } from "~/client/api-client/types.gen";
|
||||
import { RepositoryInfoTabContent } from "../tabs/info";
|
||||
import { RepositorySnapshotsTabContent } from "../tabs/snapshots";
|
||||
import { useTimeFormat } from "~/client/lib/datetime";
|
||||
|
||||
export default function RepositoryDetailsPage({
|
||||
repositoryId,
|
||||
|
|
@ -50,6 +50,7 @@ export default function RepositoryDetailsPage({
|
|||
initialBackupSchedules?: BackupSchedule[];
|
||||
initialStats?: GetRepositoryStatsResponse;
|
||||
}) {
|
||||
const { formatDateTime, formatTimeAgo } = useTimeFormat();
|
||||
const navigate = useNavigate();
|
||||
const { tab } = useSearch({ from: "/(dashboard)/repositories/$repositoryId/" });
|
||||
const activeTab = tab || "info";
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { Archive, Clock, FolderOpen, HardDrive, Lock, Settings, Shield } from "l
|
|||
import { Card, CardContent, CardTitle } from "~/client/components/ui/card";
|
||||
import type { Repository } from "~/client/lib/types";
|
||||
import type { GetRepositoryStatsResponse } from "~/client/api-client/types.gen";
|
||||
import { formatDateTime, formatTimeAgo } from "~/client/lib/datetime";
|
||||
import type { RepositoryConfig } from "@zerobyte/core/restic";
|
||||
import { DoctorReport } from "../components/doctor-report";
|
||||
import { CompressionStatsChart } from "../components/compression-stats-chart";
|
||||
import { cn } from "~/client/lib/utils";
|
||||
import { useTimeFormat } from "~/client/lib/datetime";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
|
|
@ -33,6 +33,7 @@ function ConfigRow({ icon, label, value, mono, valueClassName }: ConfigRowProps)
|
|||
|
||||
export const RepositoryInfoTabContent = ({ repository, initialStats }: Props) => {
|
||||
const effectiveLocalPath = getEffectiveLocalPath(repository);
|
||||
const { formatDateTime, formatTimeAgo } = useTimeFormat();
|
||||
|
||||
const config = repository.config as RepositoryConfig;
|
||||
const hasLocalPath = Boolean(effectiveLocalPath);
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import { authClient } from "~/client/lib/auth-client";
|
|||
import {
|
||||
DATE_FORMATS,
|
||||
type DateFormatPreference,
|
||||
formatDateTime,
|
||||
TIME_FORMATS,
|
||||
type TimeFormatPreference,
|
||||
useTimeFormat,
|
||||
} from "~/client/lib/datetime";
|
||||
import { logger } from "~/client/lib/logger";
|
||||
import { type AppContext } from "~/context";
|
||||
|
|
@ -50,7 +50,7 @@ export function SettingsPage({ appContext, initialMembers, initialSsoSettings, i
|
|||
const [downloadDialogOpen, setDownloadDialogOpen] = useState(false);
|
||||
const [downloadPassword, setDownloadPassword] = useState("");
|
||||
const [isChangingPassword, setIsChangingPassword] = useState(false);
|
||||
const { locale, dateFormat, timeFormat } = useRootLoaderData();
|
||||
const { dateFormat, timeFormat } = useRootLoaderData();
|
||||
|
||||
const { tab } = useSearch({ from: "/(dashboard)/settings/" });
|
||||
const activeTab = tab || "account";
|
||||
|
|
@ -58,12 +58,7 @@ export function SettingsPage({ appContext, initialMembers, initialSsoSettings, i
|
|||
const navigate = useNavigate();
|
||||
const { activeMember, activeOrganization } = useOrganizationContext();
|
||||
const isOrgAdmin = activeMember?.role === "owner" || activeMember?.role === "admin";
|
||||
const dateTimePreview = formatDateTime("2026-01-10T14:30:00.000Z", {
|
||||
locale,
|
||||
timeZone: "UTC",
|
||||
dateFormat,
|
||||
timeFormat,
|
||||
});
|
||||
const { formatDateTime } = useTimeFormat();
|
||||
|
||||
const handleLogout = async () => {
|
||||
await authClient.signOut({
|
||||
|
|
@ -275,7 +270,7 @@ export function SettingsPage({ appContext, initialMembers, initialSsoSettings, i
|
|||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">Preview: {dateTimePreview}</p>
|
||||
<p className="text-sm text-muted-foreground">Preview: {formatDateTime(new Date())}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
|
|
|
|||
|
|
@ -35,16 +35,17 @@ import { Separator } from "~/client/components/ui/separator";
|
|||
import { Switch } from "~/client/components/ui/switch";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
||||
import { ManagedBadge } from "~/client/components/managed-badge";
|
||||
import { formatDateTime, formatTimeAgo } from "~/client/lib/datetime";
|
||||
import { parseError } from "~/client/lib/errors";
|
||||
import { cn } from "~/client/lib/utils";
|
||||
import { VolumeInfoTabContent } from "../tabs/info";
|
||||
import { FilesTabContent } from "../tabs/files";
|
||||
import { useTimeFormat } from "~/client/lib/datetime";
|
||||
|
||||
export function VolumeDetails({ volumeId }: { volumeId: string }) {
|
||||
const navigate = useNavigate();
|
||||
const searchParams = useSearch({ from: "/(dashboard)/volumes/$volumeId/" });
|
||||
const activeTab = searchParams.tab || "info";
|
||||
const { formatDateTime, formatTimeAgo } = useTimeFormat();
|
||||
|
||||
const { data } = useSuspenseQuery({
|
||||
...getVolumeOptions({ path: { shortId: volumeId } }),
|
||||
|
|
|
|||
Loading…
Reference in a new issue