Files
jellytau/src/lib/components/library/ClearHistoryButton.svelte
T
dtourolle ad48d89dfe chore(format): run prettier over src/ and scripts/
Formatting was configured but never enforced: `bun run format:check`
reported 199 unformatted files and ran in no workflow and in no git hook,
so .prettierrc (printWidth 100, trailing commas) described an intention
rather than the tree.

This is the one-time sweep that makes the check gateable. Whitespace and
token-reflow only -- no behavioural change: `bun run check` reports 0
errors and all 1053 frontend tests pass before and after.

Kept out of every other commit on purpose. A 199-file diff mixed with
real changes is unreviewable, and the next commit turns format:check
into a hard CI gate so this cannot silently accumulate again.
2026-08-21 17:41:44 +02:00

92 lines
3.0 KiB
Svelte

<!--
Erase watch history for a series or a season.
The backend does the work (`repository_clear_watch_history` → Jellyfin's
mark-unplayed, which is recursive over a container and also zeroes resume
positions); this only confirms the intent and reports the outcome. Clearing a
series returns it to "never watched", so it reopens on S1E1.
TRACES: UR-064 | DR-106
-->
<script lang="ts">
import { auth } from "$lib/stores/auth";
import { isServerReachable } from "$lib/stores/connectivity";
import { createLogger } from "$lib/utils/logger";
const log = createLogger("ClearHistoryButton");
interface Props {
/** Series or season id to clear. */
itemId: string;
/** Name shown in the confirm prompt. */
itemName: string;
/** What is being cleared, for the prompt wording. */
scope: "series" | "season";
size?: "sm" | "lg";
/** Called after a successful clear so the caller can reload. */
onCleared?: () => void;
}
let { itemId, itemName, scope, size = "lg", onCleared }: Props = $props();
let busy = $state(false);
const label = $derived(scope === "series" ? "Clear history" : "Clear season history");
async function handleClick() {
if (busy) return;
const subject = scope === "series" ? `all of “${itemName}”` : `“${itemName}”`;
// Destructive and not undoable — always ask, even though the server keeps
// no undo of its own.
if (
!confirm(
`Erase watch history for ${subject}?\n\n` +
"Every episode is marked unwatched and resume positions are cleared. " +
"This cannot be undone.",
)
) {
return;
}
busy = true;
try {
await auth.getRepository().clearWatchHistory(itemId);
onCleared?.();
} catch (e) {
log.error("Failed to clear watch history:", e);
alert(`Could not clear watch history: ${e instanceof Error ? e.message : String(e)}`);
} finally {
busy = false;
}
}
</script>
<button
onclick={handleClick}
disabled={busy || !$isServerReachable}
title={$isServerReachable
? "Mark everything unwatched and clear resume positions"
: "Needs a connection to the server"}
class="rounded-lg font-medium flex items-center gap-2 transition-colors
bg-[var(--color-surface)] hover:bg-[var(--color-surface-hover)]
disabled:opacity-40 disabled:cursor-not-allowed
{size === 'lg' ? 'px-6 py-2' : 'px-3 py-1.5 text-sm'}"
>
{#if busy}
<div
class="border-2 border-current border-t-transparent rounded-full animate-spin
{size === 'lg' ? 'w-5 h-5' : 'w-4 h-4'}"
></div>
{:else}
<svg class={size === "lg" ? "w-5 h-5" : "w-4 h-4"} fill="currentColor" viewBox="0 0 24 24">
<path
d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6a7 7 0 1 1 7 7c-1.93
0-3.68-.79-4.94-2.06l-1.42 1.42A8.95 8.95 0 0 0 13 21a9 9 0 0 0
0-18zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"
/>
</svg>
{/if}
{busy ? "Clearing…" : label}
</button>