mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
O0+ (#34): consent key DRY, SQL int tests, Footer condicional, B68 suggest RSC
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
This commit is contained in:
parent
5c6ed8cf31
commit
cbe171c597
6 changed files with 128 additions and 19 deletions
|
|
@ -10,6 +10,7 @@ import { CampaignPageShell } from '@/components/campaign/shell/CampaignPageShell
|
|||
import { UNCOVERED_MUNICIPALITIES_LIST_HREF } from '@/lib/campaignHomeActions'
|
||||
import { isStaffCampaignRole } from '@/lib/campaignRoles'
|
||||
import { loadCampaignHomeSummary } from '@/utilities/campaignDashboardData'
|
||||
import { loadHomeSearchSuggestions } from '@/utilities/homeSearch/loadHomeSearchSuggestions'
|
||||
import { requireCampaignPageActor } from '@/utilities/campaignPageActor'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
|
@ -29,15 +30,24 @@ export default async function CampaignHomePage() {
|
|||
)
|
||||
|
||||
let summarySlot: ReactNode | undefined
|
||||
let initialSuggest: Awaited<ReturnType<typeof loadHomeSearchSuggestions>> | undefined
|
||||
if (staff) {
|
||||
const summaryView = await loadCampaignHomeSummary(payload, user)
|
||||
const [summaryView, suggest] = await Promise.all([
|
||||
loadCampaignHomeSummary(payload, user),
|
||||
loadHomeSearchSuggestions(payload, user),
|
||||
])
|
||||
summarySlot = <CampaignHomeSummary view={summaryView} />
|
||||
initialSuggest = suggest
|
||||
}
|
||||
|
||||
return (
|
||||
<CampaignPageShell aria-label="Início" className="h-full min-h-0">
|
||||
{staff ? (
|
||||
<CampaignHomeStaffChrome actions={actions} summarySlot={summarySlot} />
|
||||
<CampaignHomeStaffChrome
|
||||
actions={actions}
|
||||
initialSuggest={initialSuggest}
|
||||
summarySlot={summarySlot}
|
||||
/>
|
||||
) : (
|
||||
<CampaignHomeLayout actions={actions} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
import { SocialLinks } from './socialLinks'
|
||||
import { getCachedGlobal } from '@/utilities/globalReads'
|
||||
|
||||
export const Footer = () => (
|
||||
<footer className="flex flex-col items-center justify-center gap-3 p-4 text-center text-sm text-muted-foreground">
|
||||
<SocialLinks ariaLabel="Redes sociais do rodapé" />
|
||||
<Link href="/privacidade" className="text-primary underline-offset-4 hover:underline">
|
||||
Política de Privacidade
|
||||
</Link>
|
||||
</footer>
|
||||
)
|
||||
export const Footer = async () => {
|
||||
const privacy = await getCachedGlobal('privacy-policy', 0)()
|
||||
const showPrivacyLink = privacy.published === true
|
||||
|
||||
return (
|
||||
<footer className="flex flex-col items-center justify-center gap-3 p-4 text-center text-sm text-muted-foreground">
|
||||
<SocialLinks ariaLabel="Redes sociais do rodapé" />
|
||||
{showPrivacyLink ? (
|
||||
<Link href="/privacidade" className="text-primary underline-offset-4 hover:underline">
|
||||
Política de Privacidade
|
||||
</Link>
|
||||
) : null}
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ import { CampaignHomeSearch } from '@/components/campaign/dashboard/CampaignHome
|
|||
import { useHomeSearch } from '@/components/campaign/dashboard/HomeSearchContext'
|
||||
import {
|
||||
HomeSearchResultsProvider,
|
||||
InitialHomeSearchSuggestProvider,
|
||||
useHomeSearchResultsState,
|
||||
} from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import type { HomeSearchSuccessResponse } from '@/lib/campaignHomeSearchHits'
|
||||
|
||||
const CampaignHomeStaffSearchSlot = ({ searchResults }: { searchResults: ReactNode }) => {
|
||||
const searchResultsState = useHomeSearchResultsState()
|
||||
|
|
@ -58,18 +60,23 @@ const CampaignHomeStaffChromeInner = ({
|
|||
|
||||
export const CampaignHomeStaffChrome = ({
|
||||
actions,
|
||||
initialSuggest,
|
||||
searchResults,
|
||||
summarySlot,
|
||||
}: {
|
||||
actions: ReactNode
|
||||
/** B68 — RSC-loaded suggest hits; skips the first client POST on Início. */
|
||||
initialSuggest?: HomeSearchSuccessResponse
|
||||
searchResults?: ReactNode
|
||||
summarySlot?: ReactNode
|
||||
}) => (
|
||||
<CampaignGlobalSearchProvider>
|
||||
<CampaignHomeStaffChromeInner
|
||||
actions={actions}
|
||||
searchResults={searchResults}
|
||||
summarySlot={summarySlot}
|
||||
/>
|
||||
<InitialHomeSearchSuggestProvider initialSuggest={initialSuggest}>
|
||||
<CampaignHomeStaffChromeInner
|
||||
actions={actions}
|
||||
searchResults={searchResults}
|
||||
summarySlot={summarySlot}
|
||||
/>
|
||||
</InitialHomeSearchSuggestProvider>
|
||||
</CampaignGlobalSearchProvider>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,22 @@ export type HomeSearchResultsContextValue = {
|
|||
|
||||
const HomeSearchResultsContext = createContext<HomeSearchResultsContextValue | null>(null)
|
||||
|
||||
const InitialHomeSearchSuggestContext = createContext<HomeSearchSuccessResponse | undefined>(
|
||||
undefined,
|
||||
)
|
||||
|
||||
export const InitialHomeSearchSuggestProvider = ({
|
||||
initialSuggest,
|
||||
children,
|
||||
}: {
|
||||
initialSuggest: HomeSearchSuccessResponse | undefined
|
||||
children: ReactNode
|
||||
}) => (
|
||||
<InitialHomeSearchSuggestContext.Provider value={initialSuggest}>
|
||||
{children}
|
||||
</InitialHomeSearchSuggestContext.Provider>
|
||||
)
|
||||
|
||||
export const HomeSearchResultsProvider = ({
|
||||
value,
|
||||
children,
|
||||
|
|
@ -54,6 +70,7 @@ type HomeSearchErrorResponse = { status: 'error'; message: string }
|
|||
|
||||
export const useHomeSearchResultsState = (): HomeSearchResultsContextValue => {
|
||||
const { query, isDebouncing, uiFocused } = useHomeSearch()
|
||||
const initialSuggest = useContext(InitialHomeSearchSuggestContext)
|
||||
const [results, setResults] = useState<HomeSearchResultsState>({ status: 'idle' })
|
||||
const requestSeq = useRef(0)
|
||||
|
||||
|
|
@ -67,6 +84,12 @@ export const useHomeSearchResultsState = (): HomeSearchResultsContextValue => {
|
|||
return
|
||||
}
|
||||
|
||||
if (suggestMode && initialSuggest) {
|
||||
requestSeq.current += 1
|
||||
setResults({ status: 'success', data: initialSuggest })
|
||||
return
|
||||
}
|
||||
|
||||
const seq = ++requestSeq.current
|
||||
const controller = new AbortController()
|
||||
setResults({ status: 'loading' })
|
||||
|
|
@ -109,7 +132,7 @@ export const useHomeSearchResultsState = (): HomeSearchResultsContextValue => {
|
|||
return () => {
|
||||
controller.abort()
|
||||
}
|
||||
}, [query.debounced, searchMode, suggestMode])
|
||||
}, [initialSuggest, query.debounced, searchMode, suggestMode])
|
||||
|
||||
const isFetching = isDebouncing || results.status === 'loading'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
CAMPAIGN_INVITE_CONSENT_KEY,
|
||||
CAMPAIGN_PUSH_CONSENT_KEY,
|
||||
SUPPORTER_REGISTRATION_CONSENT_KEY,
|
||||
SUPPORTER_VOTE_INTENTION_CONSENT_KEY,
|
||||
} from '@/lib/campaignConsentKeys'
|
||||
|
|
@ -12,7 +13,7 @@ const ONDA0_CONSENT_KEYS = {
|
|||
leadershipAutofill: CAMPAIGN_INVITE_CONSENT_KEY,
|
||||
supporterRegistration: SUPPORTER_REGISTRATION_CONSENT_KEY,
|
||||
supporterVoteIntention: SUPPORTER_VOTE_INTENTION_CONSENT_KEY,
|
||||
campaignPush: 'campanha-notificacoes-push',
|
||||
campaignPush: CAMPAIGN_PUSH_CONSENT_KEY,
|
||||
} as const
|
||||
|
||||
export type Onda0ConsentKey = (typeof ONDA0_CONSENT_KEYS)[keyof typeof ONDA0_CONSENT_KEYS]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
// @vitest-environment node
|
||||
|
||||
import { sql } from '@payloadcms/db-postgres'
|
||||
import { getPayload, type Payload } from 'payload'
|
||||
import { beforeAll, describe, expect, it } from 'vitest'
|
||||
|
||||
import { ONDA0_CONSENT_ENTRIES } from '@/lib/onda0ConsentTexts'
|
||||
import { ONDA0_CONSENT_ENTRIES, ONDA0_CONSENT_KEY_LIST } from '@/lib/onda0ConsentTexts'
|
||||
import config from '@/payload.config'
|
||||
import { requireConsentByKey } from '@/utilities/campaignConsent'
|
||||
import { provisionOnda0ConsentAndPrivacy } from '@/utilities/onda0Provision'
|
||||
import {
|
||||
provisionOnda0ConsentAndPrivacy,
|
||||
provisionOnda0ConsentAndPrivacyDb,
|
||||
removeOnda0ConsentAndPrivacyDb,
|
||||
} from '@/utilities/onda0Provision'
|
||||
|
||||
import { assertTestDatabase } from '../helpers/assertTestDatabase'
|
||||
import { installCampaignFixtures } from '../helpers/campaignFixtures'
|
||||
|
|
@ -61,5 +66,60 @@ describe('Onda 0 provision (integration)', () => {
|
|||
),
|
||||
),
|
||||
)
|
||||
it('provisionOnda0ConsentAndPrivacyDb upserts and removes via SQL', async () => {
|
||||
await withSharedTestDatabaseLease(payload, CAMPAIGN_INVITE_CONSENT_LEASE_KEY, () =>
|
||||
withSharedTestDatabaseLease(payload, SUPPORTER_REGISTRATION_CONSENT_LEASE_KEY, () =>
|
||||
withSharedTestDatabaseLease(
|
||||
payload,
|
||||
SUPPORTER_VOTE_INTENTION_CONSENT_LEASE_KEY,
|
||||
async () => {
|
||||
const db = payload.db.drizzle
|
||||
|
||||
await provisionOnda0ConsentAndPrivacyDb(db)
|
||||
await provisionOnda0ConsentAndPrivacyDb(db)
|
||||
|
||||
const consentRows = await db.execute(sql`
|
||||
SELECT "key"
|
||||
FROM "consent"
|
||||
WHERE "key" IN (${sql.join(
|
||||
ONDA0_CONSENT_KEY_LIST.map((key) => sql`${key}`),
|
||||
sql`, `,
|
||||
)})
|
||||
ORDER BY "key"
|
||||
`)
|
||||
expect(consentRows.rows.map((row) => row.key)).toEqual(
|
||||
[...ONDA0_CONSENT_KEY_LIST].sort(),
|
||||
)
|
||||
|
||||
const privacyRows = await db.execute(sql`
|
||||
SELECT "published", "body"
|
||||
FROM "privacy_policy"
|
||||
LIMIT 1
|
||||
`)
|
||||
expect(privacyRows.rows[0]?.published).toBe(true)
|
||||
expect(privacyRows.rows[0]?.body).toBeTruthy()
|
||||
|
||||
await removeOnda0ConsentAndPrivacyDb(db)
|
||||
|
||||
const consentAfterDown = await db.execute(sql`
|
||||
SELECT count(*)::integer AS count
|
||||
FROM "consent"
|
||||
WHERE "key" IN (${sql.join(
|
||||
ONDA0_CONSENT_KEY_LIST.map((key) => sql`${key}`),
|
||||
sql`, `,
|
||||
)})
|
||||
`)
|
||||
expect(consentAfterDown.rows[0]?.count).toBe(0)
|
||||
|
||||
const privacyAfterDown = await db.execute(sql`
|
||||
SELECT "published"
|
||||
FROM "privacy_policy"
|
||||
LIMIT 1
|
||||
`)
|
||||
expect(privacyAfterDown.rows[0]?.published).toBe(false)
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue