polish(ui): loading feedback on sync/refresh buttons system-wide (#1156)
The "Synka bank nu" row in the transactions Importera split button fired syncAll() with zero visual feedback. SplitButton now takes busy/busyLabel per option: the primary face and the menu row swap to a spinning Loader2, show the busy label and go inert until the action resolves. useBankSync holds isBusy across the whole syncAll loop so the spinner does not flicker between per-connection syncs. Sweep of the rest of the system for async buttons missing the same feedback (convention: disabled + Loader2 animate-spin + label swap): - bokslut DigitalInlamning "Uppdatera status" (Bolagsverket poll): had no feedback at all; now disabled + spinner + "Uppdaterar ..." while polling - Stripe settings "Synka nu": had disabled + label swap but a static icon - Skatteverket "Verifiera": had disabled + label swap but no spinner - AgentMemoryPanel "Dolj"/"Aterstall" row actions: static icons on async patch; now swap to spinner for the busy row Checked and intentionally unchanged: Arcim migration "Synka igen" and "Ateranslut" (the whole step flips to a spinner view synchronously on click), skattekonto "Forsok igen" (page flips to loading view), AgentChat "Generera om" (streaming indicator is the feedback). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
bb551d1d59
commit
8a9162b948
@@ -182,6 +182,7 @@ export function DigitalInlamning({ periodId }: { periodId: string }) {
|
||||
const [submissions, setSubmissions] = useState<SubmissionRow[]>([])
|
||||
const [loadingSubmissions, setLoadingSubmissions] = useState(false)
|
||||
const [submissionsError, setSubmissionsError] = useState<string | null>(null)
|
||||
const [pollingEvents, setPollingEvents] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const signer = versions.find((version) => version.id === selectedVersionId)
|
||||
@@ -384,6 +385,7 @@ export function DigitalInlamning({ periodId }: { periodId: string }) {
|
||||
}
|
||||
|
||||
const handlePollEvents = async () => {
|
||||
setPollingEvents(true)
|
||||
try {
|
||||
const res = await fetch('/api/extensions/ext/bolagsverket/poll-events', {
|
||||
method: 'POST',
|
||||
@@ -399,6 +401,8 @@ export function DigitalInlamning({ periodId }: { periodId: string }) {
|
||||
toast({ title: 'Status uppdaterad från Bolagsverket' })
|
||||
} catch {
|
||||
toast({ title: 'Kunde inte hämta händelser', variant: 'destructive' })
|
||||
} finally {
|
||||
setPollingEvents(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,8 +798,19 @@ export function DigitalInlamning({ periodId }: { periodId: string }) {
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 text-sm">
|
||||
<div className="flex justify-end">
|
||||
<Button className="min-h-11" variant="outline" size="sm" onClick={() => void handlePollEvents()}>
|
||||
<RefreshCcw className="mr-2 h-4 w-4" /> Uppdatera status
|
||||
<Button
|
||||
className="min-h-11"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={pollingEvents}
|
||||
onClick={() => void handlePollEvents()}
|
||||
>
|
||||
{pollingEvents ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<RefreshCcw className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
{pollingEvents ? 'Uppdaterar …' : 'Uppdatera status'}
|
||||
</Button>
|
||||
</div>
|
||||
{submissionsError && <p className="text-xs text-destructive">{submissionsError}</p>}
|
||||
|
||||
Reference in New Issue
Block a user