fix(CalendarSync): replace window.confirm() with inline confirmation and rename file

- Replace blocking window.confirm() with showRevokeConfirm state + inline
  confirmation dialog in CalendarSyncSection
- Rename CalendarSync.tsx to CalendarSyncSection.tsx to match export convention

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Flea Flicker
2026-03-26 08:18:54 +00:00
parent 1e84823656
commit 21b7eff326
@@ -12,6 +12,7 @@ export function CalendarSyncSection({ staffId }: Props) {
const [actionLoading, setActionLoading] = useState<"generate" | "revoke" | null>(null); const [actionLoading, setActionLoading] = useState<"generate" | "revoke" | null>(null);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const [showRevokeConfirm, setShowRevokeConfirm] = useState(false);
useEffect(() => { useEffect(() => {
fetchToken(); fetchToken();
@@ -51,7 +52,8 @@ export function CalendarSyncSection({ staffId }: Props) {
} }
async function revokeToken() { async function revokeToken() {
if (!confirm("Revoke your calendar feed link? Anyone with the current link will lose access.")) { if (!showRevokeConfirm) {
setShowRevokeConfirm(true);
return; return;
} }
setActionLoading("revoke"); setActionLoading("revoke");
@@ -67,6 +69,7 @@ export function CalendarSyncSection({ staffId }: Props) {
setError(e instanceof Error ? e.message : "Failed to revoke token"); setError(e instanceof Error ? e.message : "Failed to revoke token");
} finally { } finally {
setActionLoading(null); setActionLoading(null);
setShowRevokeConfirm(false);
} }
} }
@@ -120,32 +123,59 @@ export function CalendarSyncSection({ staffId }: Props) {
</div> </div>
</div> </div>
<div className="flex gap-2"> {showRevokeConfirm ? (
<button <div className="flex items-center gap-3 p-3 bg-red-50 border border-red-200 rounded-lg">
onClick={generateToken} <p className="flex-1 text-sm text-red-700">
disabled={actionLoading !== null} Revoke your calendar feed link? Anyone with the current link will lose access.
className="flex items-center gap-1.5 px-3 py-2 bg-(--color-accent) text-white rounded-lg text-sm font-medium hover:bg-(--color-accent-hover) disabled:opacity-50" </p>
> <button
{actionLoading === "generate" ? ( onClick={revokeToken}
<RefreshCw size={14} className="animate-spin" /> disabled={actionLoading !== null}
) : ( className="flex items-center gap-1.5 px-3 py-1.5 bg-red-600 text-white rounded-lg text-sm font-medium hover:bg-red-700 disabled:opacity-50"
<RefreshCw size={14} /> >
)} {actionLoading === "revoke" ? (
Regenerate <RefreshCw size={14} className="animate-spin" />
</button> ) : (
<button <Trash2 size={14} />
onClick={revokeToken} )}
disabled={actionLoading !== null} Revoke
className="flex items-center gap-1.5 px-3 py-2 border border-red-200 rounded-lg text-sm text-red-600 hover:bg-red-50 disabled:opacity-50" </button>
> <button
{actionLoading === "revoke" ? ( onClick={() => setShowRevokeConfirm(false)}
<RefreshCw size={14} className="animate-spin" /> disabled={actionLoading !== null}
) : ( className="px-3 py-1.5 border border-stone-200 rounded-lg text-sm text-stone-600 hover:bg-stone-50 disabled:opacity-50"
<Trash2 size={14} /> >
)} Cancel
Revoke </button>
</button> </div>
</div> ) : (
<div className="flex gap-2">
<button
onClick={generateToken}
disabled={actionLoading !== null}
className="flex items-center gap-1.5 px-3 py-2 bg-(--color-accent) text-white rounded-lg text-sm font-medium hover:bg-(--color-accent-hover) disabled:opacity-50"
>
{actionLoading === "generate" ? (
<RefreshCw size={14} className="animate-spin" />
) : (
<RefreshCw size={14} />
)}
Regenerate
</button>
<button
onClick={revokeToken}
disabled={actionLoading !== null}
className="flex items-center gap-1.5 px-3 py-2 border border-red-200 rounded-lg text-sm text-red-600 hover:bg-red-50 disabled:opacity-50"
>
{actionLoading === "revoke" ? (
<RefreshCw size={14} className="animate-spin" />
) : (
<Trash2 size={14} />
)}
Revoke
</button>
</div>
)}
<p className="text-xs text-stone-400"> <p className="text-xs text-stone-400">
Regenerating will create a new URL and invalidate the old one. Regenerating will create a new URL and invalidate the old one.