| 1 | /** |
| 2 | * Whether a button's submission is still working: posted and not yet |
| 3 | * answered, or answered and the page still loading what it changed. A |
| 4 | * button that only waits for "submitting" turns back on while the page |
| 5 | * still shows the old figures, so it looks as if nothing happened. |
| 6 | * |
| 7 | * `fields` names the submission, such as `{ intent: "delete", id }`: every |
| 8 | * one must match what was posted, so one row's button does not say |
| 9 | * "Deleting…" while another row's is the one going. With no `fields`, any |
| 10 | * submission that writes counts. A GET form (a search, a filter) is never |
| 11 | * pending here: it only reads. |
| 12 | */ |
| 13 | export type Submission = { |
| 14 | state: "idle" | "submitting" | "loading"; |
| 15 | formMethod?: string | null; |
| 16 | formData?: FormData | null; |
| 17 | }; |
| 18 | |
| 19 | export function isPending(submission: Submission, fields?: Record<string, string | null | undefined>): boolean { |
| 20 | if (submission.state === "idle" || !submission.formData) return false; |
| 21 | if (!submission.formMethod || submission.formMethod.toUpperCase() === "GET") return false; |
| 22 | const posted = submission.formData; |
| 23 | return Object.entries(fields ?? {}).every(([name, value]) => value == null || posted.get(name) === value); |
| 24 | } |