diff --git a/docs/plans/feed-atualizacoes-campanha-threads-impl.md b/docs/plans/feed-atualizacoes-campanha-threads-impl.md index d55a0846..628688df 100644 --- a/docs/plans/feed-atualizacoes-campanha-threads-impl.md +++ b/docs/plans/feed-atualizacoes-campanha-threads-impl.md @@ -113,8 +113,8 @@ estadual — leitura relativa à carteira (restrição da intenção). Sem % abs ## Fases verificáveis 1. **Tracer / pure (server):** `municipalityUpdateListUrl` + `municipalityUpdateOmnibox` - + unit specs (canonicalização, "todas polaridades→ausente", page clamp, - chips/sugestões/apply/remove) — `pnpm gate:fast`. + - unit specs (canonicalização, "todas polaridades→ausente", page clamp, + chips/sugestões/apply/remove) — `pnpm gate:fast`. 2. **Loader + view model:** `campaignUpdatesFeedData` + `loadCampaignUserDisplayByIds`; verificação por int spec leve do loader (carteira de advisor) se existir precedente análogo — senão unit puro. diff --git a/src/app/(campaign)/campanha/(app)/atualizacoes/createFormActions.ts b/src/app/(campaign)/campanha/(app)/atualizacoes/createFormActions.ts index 0db7d5ef..93dfdad6 100644 --- a/src/app/(campaign)/campanha/(app)/atualizacoes/createFormActions.ts +++ b/src/app/(campaign)/campanha/(app)/atualizacoes/createFormActions.ts @@ -26,6 +26,5 @@ export const createCampaignUpdatesFormAction = async ( revalidatePath('/campanha/atualizacoes') return { message: 'Atualização registrada com sucesso.' } }, - genericMessage: - 'Não foi possível registrar a atualização. Verifique o município e seu acesso.', + genericMessage: 'Não foi possível registrar a atualização. Verifique o município e seu acesso.', }) diff --git a/src/app/(campaign)/campanha/(app)/atualizacoes/page.tsx b/src/app/(campaign)/campanha/(app)/atualizacoes/page.tsx index d49aa73c..5f9cb462 100644 --- a/src/app/(campaign)/campanha/(app)/atualizacoes/page.tsx +++ b/src/app/(campaign)/campanha/(app)/atualizacoes/page.tsx @@ -4,11 +4,11 @@ import { getPayload } from 'payload' import { CampaignUpdatesFeed } from '@/components/campaign/municipality/CampaignUpdatesFeed' import { CampaignUpdatesFilters } from '@/components/campaign/municipality/CampaignUpdatesFilters' +import { CampaignListFooter } from '@/components/campaign/shared/CampaignListFooter' import { CampaignListPendingBoundary, CampaignListResults, } from '@/components/campaign/shared/CampaignListPending' -import { CampaignListFooter } from '@/components/campaign/shared/CampaignListFooter' import { CampaignPageShell } from '@/components/campaign/shell/CampaignPageShell' import { campaignPageMetadataFromCatalog } from '@/lib/campaignPageChrome' import { isCampaignStaff } from '@/utilities/campaignAccess' diff --git a/src/components/campaign/municipality/CampaignUpdatesCreateModal.tsx b/src/components/campaign/municipality/CampaignUpdatesCreateModal.tsx index 54d7fefe..d2704bd8 100644 --- a/src/components/campaign/municipality/CampaignUpdatesCreateModal.tsx +++ b/src/components/campaign/municipality/CampaignUpdatesCreateModal.tsx @@ -9,18 +9,13 @@ import { StrictCombobox } from '@/components/campaign/shared/StrictCombobox' import { useCampaignFormSuccessToast } from '@/components/campaign/shared/useCampaignFormSuccessToast' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogTitle } from '@/components/ui/dialog' -import { - Drawer, - DrawerContent, - DrawerDescription, - DrawerTitle, -} from '@/components/ui/Drawer' +import { Drawer, DrawerContent, DrawerDescription, DrawerTitle } from '@/components/ui/Drawer' import { Field, FieldDescription, FieldError, FieldLabel } from '@/components/ui/field' import { Spinner } from '@/components/ui/Spinner' import { useIsMobile } from '@/hooks/use-mobile' import { getMunicipalityCatalogEntry } from '@/lib/municipalityCatalog' -import type { CampaignUpdatesFeedFacets } from '@/utilities/municipality/campaignUpdatesFeedData' import { fieldError } from '@/utilities/campaignFormFields' +import type { CampaignUpdatesFeedFacets } from '@/utilities/municipality/campaignUpdatesFeedData' type CampaignUpdatesCreateModalProps = { open: boolean diff --git a/src/components/campaign/municipality/CampaignUpdatesFilters.tsx b/src/components/campaign/municipality/CampaignUpdatesFilters.tsx index cd3641fa..13a6e603 100644 --- a/src/components/campaign/municipality/CampaignUpdatesFilters.tsx +++ b/src/components/campaign/municipality/CampaignUpdatesFilters.tsx @@ -29,11 +29,7 @@ type CampaignUpdatesFiltersProps = { isStaff: boolean } -export const CampaignUpdatesFilters = ({ - state, - facets, - isStaff, -}: CampaignUpdatesFiltersProps) => { +export const CampaignUpdatesFilters = ({ state, facets, isStaff }: CampaignUpdatesFiltersProps) => { const { navigate, isPending } = useCampaignListFilterNavigation({ state, toHref: (next) => buildCampaignUpdatesFeedHref(next, 1), @@ -107,37 +103,37 @@ export const CampaignUpdatesFilters = ({ > { - runAction(applyCampaignUpdatesFeedSuggestion({ state, suggestionId })) - }} - onCommitQuery={(text) => { - runAction(applyCampaignUpdatesFeedSuggestion({ state, suggestionId: `q:${text}` })) - }} - onRemoveChip={(chipId) => { - runAction(removeCampaignUpdatesFeedChip({ state, chipId })) - }} - onClearAll={() => { - runAction(clearCampaignUpdatesFeedFilters()) - }} - trailing={ - - } - /> + label="Filtrar atualizações" + placeholder="Digite para filtrar (município, polaridade, autor…)" + chips={chips} + suggestions={suggestions} + query={query} + onQueryChange={setQuery} + isPending={isPending} + onSelectSuggestion={(suggestionId) => { + runAction(applyCampaignUpdatesFeedSuggestion({ state, suggestionId })) + }} + onCommitQuery={(text) => { + runAction(applyCampaignUpdatesFeedSuggestion({ state, suggestionId: `q:${text}` })) + }} + onRemoveChip={(chipId) => { + runAction(removeCampaignUpdatesFeedChip({ state, chipId })) + }} + onClearAll={() => { + runAction(clearCampaignUpdatesFeedFilters()) + }} + trailing={ + + } + /> [ - doc.id, - { name: doc.name, avatarUrl: mediaDocumentUrl(doc.avatar) }, - ]), + result.docs.map((doc) => [doc.id, { name: doc.name, avatarUrl: mediaDocumentUrl(doc.avatar) }]), ) } diff --git a/src/utilities/municipality/campaignUpdatesFeedData.ts b/src/utilities/municipality/campaignUpdatesFeedData.ts index 4eff665b..7ecfb1ef 100644 --- a/src/utilities/municipality/campaignUpdatesFeedData.ts +++ b/src/utilities/municipality/campaignUpdatesFeedData.ts @@ -99,7 +99,11 @@ export const loadCampaignUpdatesFeed = async ( urgent: Boolean(doc.urgent), adversarySignal: Boolean(doc.adversarySignal), createdAt: doc.createdAt, - author: { id: authorID, name: author?.name ?? 'Usuário', avatarUrl: author?.avatarUrl ?? null }, + author: { + id: authorID, + name: author?.name ?? 'Usuário', + avatarUrl: author?.avatarUrl ?? null, + }, municipality: municipality ? { id: municipalityID, name: municipality.name, slug: municipality.slug } : { id: municipalityID, name: 'Município', slug: '' }, diff --git a/src/utilities/municipality/municipalityUpdateListUrl.ts b/src/utilities/municipality/municipalityUpdateListUrl.ts index dc6c6a74..b469ae21 100644 --- a/src/utilities/municipality/municipalityUpdateListUrl.ts +++ b/src/utilities/municipality/municipalityUpdateListUrl.ts @@ -54,14 +54,7 @@ export type CampaignUpdatesFeedState = { authors?: number[] } -const campaignUpdatesFeedParamNames = [ - 'q', - 'slug', - 'polarity', - 'urgent', - 'author', - 'page', -] as const +const campaignUpdatesFeedParamNames = ['q', 'slug', 'polarity', 'urgent', 'author', 'page'] as const const campaignUpdatesFeedParamNameSet = new Set(campaignUpdatesFeedParamNames) diff --git a/src/utilities/municipality/municipalityUpdateOmnibox.ts b/src/utilities/municipality/municipalityUpdateOmnibox.ts index 7b3011fc..5f6206f5 100644 --- a/src/utilities/municipality/municipalityUpdateOmnibox.ts +++ b/src/utilities/municipality/municipalityUpdateOmnibox.ts @@ -229,12 +229,13 @@ export const removeCampaignUpdatesFeedChip = ({ if (chipId.startsWith('slug:')) { const slug = chipId.slice(5) const slugs = (state.slugs ?? []).filter((entry) => entry !== slug) - return { kind: 'url', state: withPageReset({ ...state, slugs: slugs.length ? slugs : undefined }) } + return { + kind: 'url', + state: withPageReset({ ...state, slugs: slugs.length ? slugs : undefined }), + } } if (chipId.startsWith('polarity:')) { - const polarities = (state.polarities ?? []).filter( - (entry) => entry !== chipId.slice(9), - ) + const polarities = (state.polarities ?? []).filter((entry) => entry !== chipId.slice(9)) return { kind: 'url', state: withPageReset({ diff --git a/tests/int/campaignUpdatesFeedData.int.spec.ts b/tests/int/campaignUpdatesFeedData.int.spec.ts index 6a7e1bf0..660cc386 100644 --- a/tests/int/campaignUpdatesFeedData.int.spec.ts +++ b/tests/int/campaignUpdatesFeedData.int.spec.ts @@ -91,9 +91,7 @@ describe('campaign updates feed data (C89)', () => { expect(result.cards[0]?.body).toBe('Visita no meu município') const facets = await loadCampaignUpdatesFeedFacets(payload, advisor) - expect(facets.municipalities.map((municipality) => municipality.slug)).toEqual([ - assigned.slug, - ]) + expect(facets.municipalities.map((municipality) => municipality.slug)).toEqual([assigned.slug]) expect(facets.authorOptions.map((option) => option.label)).toContain(coordinator.name) expect(facets.authorOptions.map((option) => option.label)).not.toContain(otherAdvisor.name) })