51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useRef, useState, useTransition } from "react";
|
||
|
|
|
||
|
|
type Props = {
|
||
|
|
initialNotes: string;
|
||
|
|
onSave: (notes: string) => Promise<void>;
|
||
|
|
};
|
||
|
|
|
||
|
|
export function NotesEditor({ initialNotes, onSave }: Props) {
|
||
|
|
const [value, setValue] = useState(initialNotes);
|
||
|
|
const [saved, setSaved] = useState(false);
|
||
|
|
const [isPending, startTransition] = useTransition();
|
||
|
|
const savedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||
|
|
|
||
|
|
const dirty = value !== initialNotes;
|
||
|
|
|
||
|
|
function handleSave() {
|
||
|
|
startTransition(async () => {
|
||
|
|
await onSave(value);
|
||
|
|
if (savedTimer.current) clearTimeout(savedTimer.current);
|
||
|
|
setSaved(true);
|
||
|
|
savedTimer.current = setTimeout(() => setSaved(false), 2000);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex flex-col gap-2 rounded-lg border border-muted/40 bg-surface p-4">
|
||
|
|
<label className="text-sm font-medium text-fg/60">Notatki</label>
|
||
|
|
<textarea
|
||
|
|
value={value}
|
||
|
|
onChange={(e) => { setValue(e.target.value); setSaved(false); }}
|
||
|
|
placeholder="Dodaj notatki do tego treningu…"
|
||
|
|
rows={3}
|
||
|
|
className="w-full resize-none rounded border border-muted/40 bg-bg px-3 py-2 text-sm text-fg placeholder:text-fg/30 focus:border-accent focus:outline-none"
|
||
|
|
/>
|
||
|
|
<div className="flex items-center justify-end gap-3">
|
||
|
|
{saved && <span className="text-xs text-fg/40">Zapisano</span>}
|
||
|
|
<button
|
||
|
|
onClick={handleSave}
|
||
|
|
disabled={!dirty || isPending}
|
||
|
|
className="rounded px-3 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-40"
|
||
|
|
style={{ background: "var(--color-accent)", color: "#fff" }}
|
||
|
|
>
|
||
|
|
{isPending ? "Zapisuję…" : "Zapisz"}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|