mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-07-22 23:12:02 +00:00
7.3 KiB
7.3 KiB
Send All From Creator — Design
Date: 2026-07-04 Status: Approved for planning
Summary
Add a "Send all from [Creator]" button to the STL packages page that queues every
sendable package from a given creator for delivery to the user's Telegram. The
button appears in the packages-tab toolbar only when the list is filtered by a
single creator (?creator=<name>).
This reuses the existing single-send infrastructure (BotSendRequest +
pg_notify('bot_send', id) + the bot's send-listener) and closely mirrors the
existing sendAllInGroupAction. No bot, DB schema, or send-listener changes are
required.
Context
Relevant existing pieces:
- Creator field:
Package.creatoris a nullable, indexedStringon thePackagemodel (prisma/schema.prisma:476-524). Filtering by exact creator is cheap. - Creator filter: The packages list already supports
?creator=<name>(src/app/(app)/stls/page.tsx:22,38), rendered by the packages column as a clickable value (package-columns.tsx). - Single send:
send-to-telegram-button.tsx→POST /api/telegram/bot/sendcreates aBotSendRequest(statusPENDING) and firespg_notify('bot_send', requestId); the button then polls the request to completion. - Existing bulk send (group):
sendAllInGroupAction(groupId)insrc/app/(app)/stls/actions.ts:515-591fetches the group's packages, filters to those withdestChannelId+destMessageId, skips any with an existingPENDING/SENDINGrequest for the same package + telegram link, creates aBotSendRequestper remaining package, and firespg_notifyper package. It is wired into the table viahandleSendAllInGroup(stl-table.tsx:264-278) with aconfirm()dialog and a success toast — no polling. - Bot side:
bot/src/send-listener.tsprocesses everyBotSendRequestuniformly; nothing there needs to change.
Requirements
- When the packages tab is filtered by a single creator (
?creator=<name>is present), show a toolbar button labeled "Send all from [Creator]". - When no creator filter is active, the button is not rendered.
- Clicking the button shows a confirmation dialog before sending (consistent with the single-send and group-send flows, since this pushes files to Telegram).
- On confirm, queue all sendable packages from that creator across all pages — not just the current page.
- Skip packages that are not yet uploaded (missing
destChannelId/destMessageId) and packages that already have aPENDING/SENDINGrequest for the same package + telegram link (dedup). - Report real counts back to the user via toast, e.g. "Queued 12 packages from [Creator]" and, when applicable, a skipped count.
- No polling — the bulk action queues and returns; sends process in the background via the bot listener (same behavior as group send).
Design
Server action — sendAllFromCreatorAction(creatorName: string)
New action in src/app/(app)/stls/actions.ts, mirroring sendAllInGroupAction:
- Auth check (
auth()), returnUnauthorizedif no session. - Load the user's
TelegramLink; if none, return "No linked Telegram account. Link one in Settings." - Reject an empty/blank
creatorName(guard against sending the entire "no creator" set — see Edge cases). - Fetch sendable packages directly with a
wherefilter (no in-memory filtering):prisma.package.findMany({ where: { creator: creatorName, destChannelId: { not: null }, destMessageId: { not: null }, }, select: { id: true }, }) - If none, return "No uploaded packages found for this creator."
- For each package, skip if an existing
PENDING/SENDINGBotSendRequestexists for that package + telegram link; otherwise create aBotSendRequest(statusPENDING) and firepg_notify('bot_send', id)(best-effort, wrapped in try/catch — the bot also polls). revalidatePath("/stls").- Return counts so the UI can show them. This is a small improvement over
sendAllInGroupAction, which currently returns{ success: true, data: undefined }. Shape:where{ success: true, data: { queued: number, skipped: number } }skippedcounts packages that already had a live request. (Packages not yet uploaded are excluded by the query and not counted as skipped.)
UI — toolbar button in stl-table.tsx
- Derive the active creator from the URL:
const activeCreator = searchParams.get("creator") ?? "";(parallel to the existingactiveTagatstl-table.tsx:445). - In the packages-tab toolbar (
stl-table.tsx:478flex flex-wrap items-center gap-2row), render the button only whenactiveCreatoris non-empty:(Reuse the icon already used by the send action; place near the Upload / Group buttons.){activeCreator && ( <Button variant="outline" size="sm" className="h-9 gap-1.5" onClick={handleSendAllFromCreator}> <Send className="h-3.5 w-3.5" /> Send all from {activeCreator} </Button> )} - Add
handleSendAllFromCreator, modeled onhandleSendAllInGroup(stl-table.tsx:264-278):const handleSendAllFromCreator = useCallback(() => { if (!confirm(`Send all packages from "${activeCreator}" to your Telegram?`)) return; startTransition(async () => { const result = await sendAllFromCreatorAction(activeCreator); if (result.success) { const { queued, skipped } = result.data; toast.success( `Queued ${queued} package${queued === 1 ? "" : "s"} from ${activeCreator}` + (skipped ? ` (${skipped} already queued)` : "") ); router.refresh(); } else { toast.error(result.error); } }); }, [activeCreator, router]); - Import
sendAllFromCreatorActionalongside the existingsendAllInGroupActionimport (stl-table.tsx:51).
Data flow
User (filtered by creator) → clicks button → confirm dialog
→ sendAllFromCreatorAction(creatorName)
→ for each sendable, un-queued package: create BotSendRequest + pg_notify
→ returns { queued, skipped } → toast + router.refresh()
(background) bot send-listener consumes each BotSendRequest → delivers to user
Edge cases
- Blank creator: The action rejects an empty/whitespace
creatorNameso a stray?creator=never queues every package. The UI already gates the button on a non-emptyactiveCreator, so this is defense-in-depth. - No linked Telegram account: Returns an error toast, queues nothing.
- No uploaded packages for creator: Returns an error toast, queues nothing.
- All packages already queued:
queued: 0,skipped: N→ toast reflects it. - pg_notify failure: Swallowed per-package (best-effort); the bot's periodic poll picks the request up. Matches existing behavior.
Out of scope / non-goals
- No per-row "send all from this creator" action (toolbar-only, per decision).
- No progress polling / live completion tracking for the bulk send.
- No changes to the bot,
send-listener,BotSendRequestschema, or API routes. - No batching/throttling beyond what the bot listener already does.
Files touched
src/app/(app)/stls/actions.ts— addsendAllFromCreatorAction.src/app/(app)/stls/_components/stl-table.tsx— deriveactiveCreator, addhandleSendAllFromCreator, render the toolbar button, import the new action.