import {
Disclosure,
DisclosureContent,
DisclosureProvider,
} from "@ariakit/react";
import { useAppConfig } from "../AppConfig/AppConfig.tsx";
import {
useLastSuccessfulSyncTs,
useSyncLog,
useSyncState,
type SyncState,
} from "../store/index.tsx";
import type { SyncAttempt } from "../store/types.ts";
import type { FailurePayload } from "../types.ts";
import { log } from "./style.css.ts";
import { SyncIcon } from "./SyncIcon.tsx";
function SyncActionSuccess(props: {
heading: string;
items: { id: string; name: string; deleted: boolean }[];
}) {
const { heading, items } = props;
return (
{heading}
{items.length > 0 ?
{items.map((item) => {
const name = item.name || "Unnamed item";
if (item.deleted) {
return (
-
Synced deletion of {name} (
{item.id})
);
}
return (
-
Synced {name} (
{item.id})
);
})}
:
Everything up to date.
}
);
}
const failureToLabel: Record = {
NETWORK_ERROR: "A network error occurred.",
API_ERROR: "Server responded with error ",
UNKNOWN_ERROR: "An unexpected error ocurred. Try restarting the app.",
VALIDATION_ERROR: "Data validation error occurred. Try restarting the app.",
};
function SyncActionFailure(props: {
heading: string;
failure: FailurePayload;
}) {
const { heading, failure } = props;
const label = failureToLabel[failure.type];
return (
{heading}
{": "}
{failure.type === "API_ERROR" ?
` ${label} ${failure.code}.`
: ` ${label}`}
);
}
const syncStateToLabel: Record = {
WAITING: "Waiting for additional changes...",
IDLE: "Sync enabled. Waiting for changes.",
AUTHENTICATING: "Verifying identity...",
ERROR: "Last sync unsuccessful. Waiting for changes.",
INACTIVE: "Sync not enabled. Log in or join to enable.",
SYNCING: "Syncing...",
};
export function SyncLogList(props: {
syncState: SyncState;
syncLog: SyncAttempt[];
lastSuccessfulSyncTs: number | null;
}) {
const { syncLog, syncState, lastSuccessfulSyncTs } = props;
const { fmt } = useAppConfig();
return (
{syncStateToLabel[syncState]}
{lastSuccessfulSyncTs ?
`Last successful sync at: ${fmt.dateTime(lastSuccessfulSyncTs)}`
: "Not synced yet."}
{syncLog.map((logItem) => {
const isFailure =
logItem.pull?.type === "FAILURE" || logItem.push?.type == "FAILURE";
const itemsSynced =
(logItem.pull?.type === "SUCCESS" ?
logItem.pull.value.pulled.length
: 0) +
(logItem.push?.type === "SUCCESS" ?
logItem.push.value.pushed.length + logItem.push.value.pulled.length
: 0);
return (
{isFailure ?
<>
Sync attempt failed
{fmt.dateTime(logItem.startedTs)}
>
: <>
{"Sync successful. "}
{itemsSynced === 0 ?
"Everything up to date."
: fmt.plural(itemsSynced, {
one: "1 item synced.",
other: "# items synced.",
})
}
{fmt.dateTime(logItem.startedTs)}
>
}
{logItem.pull && (
<>
{logItem.pull.type === "SUCCESS" ?
:
}
>
)}
{logItem.push && (
<>
{logItem.push.type === "SUCCESS" ?
<>
>
:
}
>
)}
);
})}
);
}
export function SyncLog() {
const syncState = useSyncState();
const syncLog = useSyncLog();
const lastSuccessfulSyncTs = useLastSuccessfulSyncTs();
return (
);
}