diff options
| author | Adam Malczewski <[email protected]> | 2026-10-21 20:11:33 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-10-21 20:11:33 +0900 |
| commit | 564b2c1d03cf477d7cfc23414b60d1ec76904ecc (patch) | |
| tree | 16fc1956bb6cd7b83894104b24b9f02acd0751ec /src/features/chat/ui/PendingInputWarning.svelte | |
| parent | 7b7d6d01cf94ecad1dcaaa4b87670d50fe15790a (diff) | |
| download | dispatch-web-564b2c1d03cf477d7cfc23414b60d1ec76904ecc.tar.gz dispatch-web-564b2c1d03cf477d7cfc23414b60d1ec76904ecc.zip | |
fix(chat): delay delivery warning and shorten queued action label
Wait one second before displaying pending-input recovery UI, cancelling on confirmation or removal. Label the queued-message stop action Flush without changing behavior. Verified: 2451 frontend tests passed twice, typecheck, Biome, and build.
Diffstat (limited to 'src/features/chat/ui/PendingInputWarning.svelte')
| -rw-r--r-- | src/features/chat/ui/PendingInputWarning.svelte | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/src/features/chat/ui/PendingInputWarning.svelte b/src/features/chat/ui/PendingInputWarning.svelte new file mode 100644 index 0000000..c9e675e --- /dev/null +++ b/src/features/chat/ui/PendingInputWarning.svelte @@ -0,0 +1,47 @@ +<script lang="ts"> + import { onMount } from "svelte"; + import type { PendingInput } from "../pending-inputs"; + + let { + input, + onDiscard, + }: { + input: PendingInput; + onDiscard: (requestId: string) => void; + } = $props(); + + let visible = $state(false); + + // Presentation only: each keyed row gets one grace period, including restored + // or rejected inputs. Prop updates never restart it. Confirmation/discard + // removes the row, cancelling the timer along with any other unmount. + onMount(() => { + const timer = setTimeout(() => { + visible = true; + }, 1000); + return () => clearTimeout(timer); + }); +</script> + +{#if visible} + <div class="m-3 rounded border border-warning p-3 text-sm" role="status"> + <p> + {input.rejection + ? `Message rejected: ${input.rejection}` + : "Delivery unconfirmed. Your input is saved on this device."} + </p> + <p>Check the conversation history before sending again to avoid a duplicate.</p> + <textarea + class="textarea textarea-bordered mt-2 w-full" + aria-label="Saved message" + readonly + value={input.request.type === "chat.send" ? input.request.message : input.request.text} + ></textarea> + {#each input.request.images ?? [] as image} + <img class="my-2 max-h-32" src={image.url} alt="Saved attachment" /> + {/each} + <button class="btn btn-sm mt-2" onclick={() => onDiscard(input.request.requestId)} + >Discard saved copy</button + > + </div> +{/if} |
