B63+: wire wizard signal steps to B75 chrome and DRY skip.
This commit is contained in:
parent
09fa21d4b3
commit
8c7633da4a
6 changed files with 67 additions and 42 deletions
|
|
@ -1,27 +1,26 @@
|
|||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useActionState } from 'react'
|
||||
|
||||
import { createMunicipalityListSignalFormAction } from '@/app/(campaign)/campanha/(app)/municipios/municipalityStaffFormActions'
|
||||
import { CampaignFormActionMessage } from '@/components/campaign/shared/CampaignFormActionMessage'
|
||||
import { CampaignWizardShell } from '@/components/campaign/shared/CampaignWizardShell'
|
||||
import { WizardSignalSkipTrailing } from '@/components/campaign/municipality/WizardSignalSkipTrailing'
|
||||
import { useCampaignFormSuccessToast } from '@/components/campaign/shared/useCampaignFormSuccessToast'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Spinner } from '@/components/ui/Spinner'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import type { CampaignWizardActionId } from '@/lib/campaignActionRoutes'
|
||||
import { wizardSignalHref } from '@/lib/campaignActionRoutes'
|
||||
import { wizardFlowTitleForSlug } from '@/lib/campaignWizardCopy'
|
||||
import { CAMPAIGN_HOME } from '@/lib/campaignPaths'
|
||||
import type { MunicipalitySignalType } from '@/lib/schemas/municipalityUpdate'
|
||||
import { municipalitySignalTypeLabels } from '@/lib/schemas/municipalityUpdate'
|
||||
import {
|
||||
shouldShowWizardSignalSkip,
|
||||
resolveWizardSignalSkip,
|
||||
WIZARD_SIGNAL_BODY_STEP_TITLE_PREFIX,
|
||||
WIZARD_SIGNAL_SAVE_LABEL,
|
||||
WIZARD_SIGNAL_SKIP_LABEL,
|
||||
wizardSignalSkipHref,
|
||||
} from '@/lib/wizardSignalUi'
|
||||
|
||||
type WizardSignalBodyStepProps = {
|
||||
|
|
@ -46,7 +45,7 @@ export const WizardSignalBodyStep = ({
|
|||
createMunicipalityListSignalFormAction,
|
||||
{},
|
||||
)
|
||||
const showSkip = shouldShowWizardSignalSkip(entryAction)
|
||||
const skip = resolveWizardSignalSkip(entryAction)
|
||||
const stepTitle = `${WIZARD_SIGNAL_BODY_STEP_TITLE_PREFIX}: ${municipalitySignalTypeLabels[signalType]}`
|
||||
|
||||
useCampaignFormSuccessToast(state, () => {
|
||||
|
|
@ -55,16 +54,13 @@ export const WizardSignalBodyStep = ({
|
|||
|
||||
return (
|
||||
<CampaignWizardShell
|
||||
flowTitle={wizardFlowTitleForSlug(actionSlug)}
|
||||
isEntryStep={false}
|
||||
stepTitle={stepTitle}
|
||||
previousHref={wizardSignalHref(actionSlug, municipalitySlug, undefined, entryAction)}
|
||||
municipalityLabel={municipalityName}
|
||||
trailingAction={
|
||||
showSkip ? (
|
||||
<Button variant="link" size="sm" className="h-auto px-2 py-1 text-xs" asChild>
|
||||
<Link href={wizardSignalSkipHref()}>{WIZARD_SIGNAL_SKIP_LABEL}</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
skip={skip}
|
||||
trailingAction={skip ? <WizardSignalSkipTrailing skip={skip} /> : undefined}
|
||||
>
|
||||
<form
|
||||
action={submitAction}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import type { WizardSignalSkipAction } from '@/lib/wizardSignalUi'
|
||||
|
||||
type WizardSignalSkipTrailingProps = {
|
||||
skip: WizardSignalSkipAction
|
||||
}
|
||||
|
||||
export const WizardSignalSkipTrailing = ({ skip }: WizardSignalSkipTrailingProps) => (
|
||||
<Button variant="link" size="sm" className="h-auto px-2 py-1 text-xs" asChild>
|
||||
<Link href={skip.href}>{skip.label}</Link>
|
||||
</Button>
|
||||
)
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
import { Info } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { CampaignWizardShell } from '@/components/campaign/shared/CampaignWizardShell'
|
||||
import { WizardSignalSkipTrailing } from '@/components/campaign/municipality/WizardSignalSkipTrailing'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Drawer,
|
||||
|
|
@ -18,14 +18,16 @@ import {
|
|||
} from '@/components/ui/Drawer'
|
||||
import type { CampaignWizardActionId } from '@/lib/campaignActionRoutes'
|
||||
import { wizardActionHref, wizardSignalHref } from '@/lib/campaignActionRoutes'
|
||||
import { municipalitySignalTypeMeta } from '@/lib/municipalitySignalTypeMeta'
|
||||
import { wizardFlowTitleForSlug } from '@/lib/campaignWizardCopy'
|
||||
import {
|
||||
municipalitySignalTypeMeta,
|
||||
municipalitySignalTypeMetaByType,
|
||||
} from '@/lib/municipalitySignalTypeMeta'
|
||||
import type { MunicipalitySignalType } from '@/lib/schemas/municipalityUpdate'
|
||||
import { cn } from '@/lib/utils'
|
||||
import {
|
||||
shouldShowWizardSignalSkip,
|
||||
WIZARD_SIGNAL_SKIP_LABEL,
|
||||
resolveWizardSignalSkip,
|
||||
WIZARD_SIGNAL_TYPE_STEP_TITLE,
|
||||
wizardSignalSkipHref,
|
||||
} from '@/lib/wizardSignalUi'
|
||||
|
||||
type WizardSignalTypeStepProps = {
|
||||
|
|
@ -41,44 +43,33 @@ export const WizardSignalTypeStep = ({
|
|||
municipalitySlug,
|
||||
entryAction,
|
||||
}: WizardSignalTypeStepProps) => {
|
||||
const router = useRouter()
|
||||
const [infoType, setInfoType] = useState<MunicipalitySignalType | null>(null)
|
||||
const infoEntry = infoType
|
||||
? municipalitySignalTypeMeta.find((entry) => entry.type === infoType)
|
||||
: null
|
||||
const showSkip = shouldShowWizardSignalSkip(entryAction)
|
||||
const infoEntry = infoType ? municipalitySignalTypeMetaByType[infoType] : null
|
||||
const skip = resolveWizardSignalSkip(entryAction)
|
||||
|
||||
return (
|
||||
<>
|
||||
<CampaignWizardShell
|
||||
flowTitle={wizardFlowTitleForSlug(actionSlug)}
|
||||
isEntryStep={false}
|
||||
stepTitle={WIZARD_SIGNAL_TYPE_STEP_TITLE}
|
||||
previousHref={wizardActionHref(actionSlug)}
|
||||
municipalityLabel={municipalityName}
|
||||
contentAlign="end"
|
||||
trailingAction={
|
||||
showSkip ? (
|
||||
<Button variant="link" size="sm" className="h-auto px-2 py-1 text-xs" asChild>
|
||||
<Link href={wizardSignalSkipHref()}>{WIZARD_SIGNAL_SKIP_LABEL}</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
skip={skip}
|
||||
trailingAction={skip ? <WizardSignalSkipTrailing skip={skip} /> : undefined}
|
||||
>
|
||||
<ul className="grid list-none grid-cols-2 gap-3 md:grid-cols-3">
|
||||
{municipalitySignalTypeMeta.map((entry) => {
|
||||
const Icon = entry.icon
|
||||
return (
|
||||
<li key={entry.type} className="relative">
|
||||
<button
|
||||
type="button"
|
||||
<Link
|
||||
href={wizardSignalHref(actionSlug, municipalitySlug, entry.type, entryAction)}
|
||||
className={cn(
|
||||
'flex aspect-square w-full flex-col justify-between rounded-lg border border-border bg-transparent p-3 pr-10 text-left',
|
||||
'transition-colors hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
||||
)}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
wizardSignalHref(actionSlug, municipalitySlug, entry.type, entryAction),
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon className="size-5 shrink-0 text-foreground" aria-hidden />
|
||||
<div className="flex flex-col gap-0.5">
|
||||
|
|
@ -87,7 +78,7 @@ export const WizardSignalTypeStep = ({
|
|||
{entry.shortDescription}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</Link>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
|
|
|
|||
|
|
@ -51,3 +51,7 @@ export const municipalitySignalTypeMeta: MunicipalitySignalTypeMetaEntry[] =
|
|||
infoContent: signalTypeInfoContent[type],
|
||||
icon: signalTypeIcons[type],
|
||||
}))
|
||||
|
||||
export const municipalitySignalTypeMetaByType = Object.fromEntries(
|
||||
municipalitySignalTypeMeta.map((entry) => [entry.type, entry]),
|
||||
) as Record<MunicipalitySignalType, MunicipalitySignalTypeMetaEntry>
|
||||
|
|
|
|||
|
|
@ -11,9 +11,18 @@ export const WIZARD_SIGNAL_SAVE_LABEL = 'Salvar' as const
|
|||
|
||||
export const WIZARD_SIGNAL_SAVED_MESSAGE = 'Sinal registrado.' as const
|
||||
|
||||
export const wizardSignalSkipHref = (): string => CAMPAIGN_HOME
|
||||
export type WizardSignalSkipAction = {
|
||||
label: string
|
||||
href: string
|
||||
}
|
||||
|
||||
/** Skip is visible only when the wizard was embedded from another flow (not standalone register-signal). */
|
||||
export const shouldShowWizardSignalSkip = (
|
||||
entryAction: CampaignWizardActionId | undefined,
|
||||
): boolean => entryAction != null && entryAction !== 'register-signal'
|
||||
|
||||
export const resolveWizardSignalSkip = (
|
||||
entryAction: CampaignWizardActionId | undefined,
|
||||
): WizardSignalSkipAction | undefined =>
|
||||
shouldShowWizardSignalSkip(entryAction)
|
||||
? { label: WIZARD_SIGNAL_SKIP_LABEL, href: CAMPAIGN_HOME }
|
||||
: undefined
|
||||
|
|
|
|||
|
|
@ -1,18 +1,29 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { municipalitySignalTypeMeta } from '@/lib/municipalitySignalTypeMeta'
|
||||
import { CAMPAIGN_HOME } from '@/lib/campaignPaths'
|
||||
import { municipalitySignalTypeMeta, municipalitySignalTypeMetaByType } from '@/lib/municipalitySignalTypeMeta'
|
||||
import { municipalitySignalTypes } from '@/lib/schemas/municipalityUpdate'
|
||||
import { shouldShowWizardSignalSkip } from '@/lib/wizardSignalUi'
|
||||
import {
|
||||
resolveWizardSignalSkip,
|
||||
shouldShowWizardSignalSkip,
|
||||
WIZARD_SIGNAL_SKIP_LABEL,
|
||||
} from '@/lib/wizardSignalUi'
|
||||
|
||||
describe('wizardSignalUi', () => {
|
||||
it('hides skip for standalone register-signal entry', () => {
|
||||
expect(shouldShowWizardSignalSkip(undefined)).toBe(false)
|
||||
expect(shouldShowWizardSignalSkip('register-signal')).toBe(false)
|
||||
expect(resolveWizardSignalSkip(undefined)).toBeUndefined()
|
||||
expect(resolveWizardSignalSkip('register-signal')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('shows skip when embedded from another wizard action', () => {
|
||||
expect(shouldShowWizardSignalSkip('update-votes')).toBe(true)
|
||||
expect(shouldShowWizardSignalSkip('change-trend')).toBe(true)
|
||||
expect(resolveWizardSignalSkip('update-votes')).toEqual({
|
||||
label: WIZARD_SIGNAL_SKIP_LABEL,
|
||||
href: CAMPAIGN_HOME,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -21,7 +32,7 @@ describe('municipalitySignalTypeMeta', () => {
|
|||
expect(municipalitySignalTypeMeta).toHaveLength(municipalitySignalTypes.length)
|
||||
|
||||
for (const type of municipalitySignalTypes) {
|
||||
const entry = municipalitySignalTypeMeta.find((item) => item.type === type)
|
||||
const entry = municipalitySignalTypeMetaByType[type]
|
||||
expect(entry?.label.length).toBeGreaterThan(0)
|
||||
expect(entry?.shortDescription.length).toBeGreaterThan(0)
|
||||
expect(entry?.infoContent.length).toBeGreaterThan(20)
|
||||
|
|
|
|||
Loading…
Reference in a new issue