- helpers puros movidos utilities->lib: slug, phone, wordStartFilter, voteEstimate (9 inversoes lib->utilities zeradas) - chaves de consent em src/lib/campaignConsentKeys.ts (client-safe); campaignInvite/campaignConsent re-exportam; onda0ConsentTexts referencia as constantes - 'server-only' em 21 loaders Payload/cache (CLI segue com --conditions=react-server) - ciclo de tipos supporterListFilters <-> supporterUi quebrado (SupporterListFilterInput estrutural; sqlFilters idem) - votePledgeData dividido: votePledgeViews (puro, client-safe) + votePledgeData (loaders, server-only) - padrao contract-module - predicados de role client-safe em src/lib/campaignRoles.ts; access/shared deriva deles (fonte unica); nav.ts para de importar o barrel campaignAccess (casts 'as CampaignUser' eliminados)
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
import { useActionState } from 'react'
|
|
|
|
import { VoteEstimateScenarioInputs } from '@/components/campaign/VoteEstimateScenarioInputs'
|
|
import { Alert, AlertDescription } from '@/components/ui/Alert'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Field, FieldError, FieldLabel } from '@/components/ui/field'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Spinner } from '@/components/ui/Spinner'
|
|
import type { CampaignFormActionState } from '@/utilities/campaignFormActionError'
|
|
import { fieldError } from '@/utilities/campaignFormFields'
|
|
import type { VoteEstimateScenarioViewModel } from '@/lib/voteEstimate'
|
|
|
|
type PledgeEstimateFormProps = {
|
|
pledgeID: number
|
|
currentEstimatedVotes: VoteEstimateScenarioViewModel
|
|
currentEstimateNote: string | null
|
|
formAction: (
|
|
state: CampaignFormActionState,
|
|
formData: FormData,
|
|
) => Promise<CampaignFormActionState>
|
|
}
|
|
|
|
/** Staff-only inline estimate. The leader never sees these fields. */
|
|
export const PledgeEstimateForm = ({
|
|
pledgeID,
|
|
currentEstimatedVotes,
|
|
currentEstimateNote,
|
|
formAction,
|
|
}: PledgeEstimateFormProps) => {
|
|
const [state, submitAction, isPending] = useActionState(formAction, {})
|
|
|
|
return (
|
|
<form action={submitAction} className="flex flex-col gap-3">
|
|
<input type="hidden" name="pledgeId" value={pledgeID} />
|
|
<VoteEstimateScenarioInputs
|
|
fieldPrefix="estimatedVotes"
|
|
values={currentEstimatedVotes}
|
|
idPrefix={`pledge-estimate-${pledgeID}`}
|
|
/>
|
|
<Field>
|
|
<FieldLabel htmlFor={`pledge-note-${pledgeID}`} className="text-xs">
|
|
Justificativa
|
|
</FieldLabel>
|
|
<Input
|
|
id={`pledge-note-${pledgeID}`}
|
|
name="estimateNote"
|
|
maxLength={1000}
|
|
defaultValue={currentEstimateNote ?? undefined}
|
|
className="min-h-11"
|
|
/>
|
|
</Field>
|
|
<Button
|
|
type="submit"
|
|
variant="secondary"
|
|
disabled={isPending}
|
|
className="min-h-11 self-start"
|
|
>
|
|
{isPending ? <Spinner data-icon="inline-start" aria-hidden="true" /> : null}
|
|
Salvar estimativa
|
|
</Button>
|
|
{fieldError(state.fieldErrors, 'estimatedVotes') ||
|
|
fieldError(state.fieldErrors, 'pessimistic') ||
|
|
fieldError(state.fieldErrors, 'central') ||
|
|
fieldError(state.fieldErrors, 'optimistic') ? (
|
|
<FieldError>
|
|
{fieldError(state.fieldErrors, 'estimatedVotes') ||
|
|
fieldError(state.fieldErrors, 'pessimistic') ||
|
|
fieldError(state.fieldErrors, 'central') ||
|
|
fieldError(state.fieldErrors, 'optimistic')}
|
|
</FieldError>
|
|
) : null}
|
|
{state.message && state.status !== 'success' ? (
|
|
<Alert variant="destructive">
|
|
<AlertDescription>{state.message}</AlertDescription>
|
|
</Alert>
|
|
) : null}
|
|
</form>
|
|
)
|
|
}
|