From f36cc244b7a4bc3698bcddf6428131820a4f2514 Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Sun, 9 Aug 2026 02:39:53 -0300 Subject: [PATCH] =?UTF-8?q?fix(C94):=20draft=20mirror=20p/=20picks=20cumul?= =?UTF-8?q?ativos=20no=20omnibox=20+=20simplifica=C3=A7=C3=B5es=20do=20/si?= =?UTF-8?q?mplify?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/ActivityAgendaFilters.tsx | 19 +++++++--- .../campaign/activity/AgendaFeedChrome.tsx | 35 +++++++++++-------- .../campaign/activity/CalendarFeedDialog.tsx | 6 +--- .../campaign/shell/CampaignDesktopHeader.tsx | 6 ++-- .../shell/CampaignQuickActionsOverlay.tsx | 5 ++- src/utilities/activityAgendaOmnibox.ts | 2 +- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/components/campaign/activity/ActivityAgendaFilters.tsx b/src/components/campaign/activity/ActivityAgendaFilters.tsx index 896a9efe..ee99a6a7 100644 --- a/src/components/campaign/activity/ActivityAgendaFilters.tsx +++ b/src/components/campaign/activity/ActivityAgendaFilters.tsx @@ -2,7 +2,7 @@ import { MapPinnedIcon, PlusIcon } from 'lucide-react' import Link from 'next/link' -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { CampaignListOmnibox } from '@/components/campaign/shared/CampaignListOmnibox' import type { RelationOption } from '@/components/campaign/shared/RelationMultiSelect' @@ -35,6 +35,10 @@ type ActivityAgendaFiltersProps = { * Deputado presente (chip bool), with the desktop create entries as icon * buttons beside the bar. Mobile creates live in the FAB drawer, so the * trailing icons are desktop-only. Filter state stays on the URL. + * + * A local `draft` mirrors the URL state so consecutive picks within the same + * RSC pending window apply cumulatively (a bare `state` prop would drop the + * first selection while the router.replace round-trip is in flight). */ export const ActivityAgendaFilters = ({ state, @@ -45,8 +49,11 @@ export const ActivityAgendaFilters = ({ state, toHref: buildActivityAgendaHref, }) + const [draft, setDraft] = useState(state) const [query, setQuery] = useState('') + useEffect(() => setDraft(state), [state]) + const municipalityLabelsById = useMemo(() => { const map = new Map() for (const option of municipalityOptions) { @@ -65,8 +72,8 @@ export const ActivityAgendaFilters = ({ ) const chips = useMemo( - () => buildActivityAgendaOmniboxChips({ state, municipalityLabelsById }), - [state, municipalityLabelsById], + () => buildActivityAgendaOmniboxChips({ state: draft, municipalityLabelsById }), + [draft, municipalityLabelsById], ) const suggestionSeeds = useMemo( @@ -86,9 +93,11 @@ export const ActivityAgendaFilters = ({ const runAction = (action: ActivityAgendaOmniboxAction) => { if (action.kind === 'clear') { setQuery('') + setDraft({}) navigate({}) return } + setDraft(action.state) navigate(action.state) } @@ -103,10 +112,10 @@ export const ActivityAgendaFilters = ({ onQueryChange={setQuery} isPending={isPending} onSelectSuggestion={(suggestionId) => { - runAction(applyActivityAgendaOmniboxSuggestion({ state, suggestionId })) + runAction(applyActivityAgendaOmniboxSuggestion({ state: draft, suggestionId })) }} onRemoveChip={(chipId) => { - runAction(removeActivityAgendaOmniboxChip({ state, chipId })) + runAction(removeActivityAgendaOmniboxChip({ state: draft, chipId })) }} onClearAll={() => { runAction(clearActivityAgendaOmnibox()) diff --git a/src/components/campaign/activity/AgendaFeedChrome.tsx b/src/components/campaign/activity/AgendaFeedChrome.tsx index 85603b9b..9d1580b9 100644 --- a/src/components/campaign/activity/AgendaFeedChrome.tsx +++ b/src/components/campaign/activity/AgendaFeedChrome.tsx @@ -1,7 +1,7 @@ 'use client' import { CalendarIcon } from 'lucide-react' -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { CalendarFeedDialog, @@ -42,22 +42,27 @@ export const AgendaFeedChrome = ({ } }, [setContext, openFeed]) + const headerButton = useMemo( + () => ( + + ), + [canGenerate, openFeed], + ) + return ( <> - - - + {headerButton} setCopied(false), 2000) } - const handleRevoke = async (feedId: number) => { - await onRevokeFeed(feedId) - } - const handleClose = (next: boolean) => { if (next) return setCreatedUrl(null) @@ -198,7 +194,7 @@ export const CalendarFeedDialog = ({ type="button" variant="ghost" size="icon" - onClick={() => handleRevoke(feed.id)} + onClick={() => void onRevokeFeed(feed.id)} aria-label={`Revogar feed ${feed.label}`} > diff --git a/src/components/campaign/shell/CampaignDesktopHeader.tsx b/src/components/campaign/shell/CampaignDesktopHeader.tsx index c2ae25db..dbf68943 100644 --- a/src/components/campaign/shell/CampaignDesktopHeader.tsx +++ b/src/components/campaign/shell/CampaignDesktopHeader.tsx @@ -1,6 +1,6 @@ 'use client' -import type { ReactNode } from 'react' +import { Fragment, type ReactNode } from 'react' import { CampaignAIHeaderButton } from '@/components/campaign/shell/ai/CampaignAIHeaderButton' import { useCampaignHeaderActions } from '@/components/campaign/shell/CampaignPageChromeContext' @@ -15,7 +15,9 @@ export const CampaignDesktopHeader = ({ notificationBell }: { notificationBell?:
- {Object.values(headerActions)} + {Object.entries(headerActions).map(([id, node]) => ( + {node} + ))} {notificationBell ?? null}
diff --git a/src/components/campaign/shell/CampaignQuickActionsOverlay.tsx b/src/components/campaign/shell/CampaignQuickActionsOverlay.tsx index 377cac3a..eca83cbe 100644 --- a/src/components/campaign/shell/CampaignQuickActionsOverlay.tsx +++ b/src/components/campaign/shell/CampaignQuickActionsOverlay.tsx @@ -56,7 +56,10 @@ const OverlayActionsChrome = ({ label: action.label, icon: action.icon, description: action.description, - href: action.href, + // Dialog-style actions win over a route when both are present + // (`CampaignHomeActionButton` renders the href branch without + // onClick, which would silently drop the action and the close). + href: action.onAction ? undefined : action.href, onClick: action.onAction ? () => { action.onAction?.() diff --git a/src/utilities/activityAgendaOmnibox.ts b/src/utilities/activityAgendaOmnibox.ts index 490af7c8..f03399af 100644 --- a/src/utilities/activityAgendaOmnibox.ts +++ b/src/utilities/activityAgendaOmnibox.ts @@ -20,7 +20,7 @@ export type ActivityAgendaOmniboxAction = | { kind: 'url'; state: ActivityAgendaState } | { kind: 'clear' } -export type ActivityAgendaFilterOption = { +type ActivityAgendaFilterOption = { value: string label: string }