Skip to content

Opportunity details: fold translation into Main communication (deduped); make all fields optional #544

@arturasmckwcz

Description

@arturasmckwcz

Scope

Opportunity Profile → Opportunity Details section
(src/components/Dashboard/Profile/sections/OpportunityDetails/)

Context

Today the section:

  • Maps Main communicationprofileLanguage with purpose: "general" (OpportunityDetailsDisplay.tsx:25, OpportunityDetailsEdit.tsx:91/106)
  • Maps Residents speakprofileLanguage with purpose: "recipient" (OpportunityDetailsDisplay.tsx:26, OpportunityDetailsEdit.tsx:92/107)
  • Treats several fields as mandatory via opportunityDetailsSchema.ts (description, number of volunteers, both language fields, activities), and the Save button is disabled={!isDirty || !isValid} (OpportunityDetailsEdit.tsx:327).

LangPurpose (need4deed-sdk) = general | translation | recipient.

Required behavior

Field → data mapping

  • Main communication — show profileLanguage entries with purpose: "general". A language must not be displayed more than once (dedupe).
  • Residents speak — show profileLanguage entries with purpose: "recipient" or purpose: "translation". A language must not be displayed more than once — dedupe across the two purposes (since a language can be tagged with both).
  • All other fields are the same (description, schedule/event, number of volunteers, activities, skills).

Edit behavior

  • Remove all mandatory rules — every field is optional (description, number of volunteers, Main communication, Residents speak, activities, etc.). An empty/blank field must not block saving.
  • The only thing that blocks submitting is a real validation failure (e.g. description over MAX_DESCRIPTION_LENGTH, malformed value) — not "required/empty" checks.

Files likely touched

  • OpportunityDetailsDisplay.tsx — Residents speak aggregates recipient + translation with dedupe; dedupe Main communication too (lines 25–26).
  • formatters.tsformatLanguagesByPurpose takes a single purpose; extend to accept multiple purposes + dedupe (or add a helper). languagesToFormValues likewise needs to seed Residents speak from both purposes.
  • OpportunityDetailsEdit.tsx — split defaultValues so Residents speak = recipient + translation (deduped); adjust submit payload; relax the Save gating (currently disabled={!isDirty || !isValid}).
  • opportunityDetailsSchema.ts — drop the required checks: description.min(1), numberOfVolunteers refine, languagesValidator "at least one language", activities.min(1). Keep only format/length validations (e.g. description.max(MAX_DESCRIPTION_LENGTH)).

Open questions

  1. Edit round-trip for the merged field. When a user edits Residents speak (now recipient + translation), what purpose do new/edited entries save as? Do existing translation-purpose languages get preserved on PATCH, or is the aggregation display-only? Current submit sends languagesMain / languagesResidents — confirm the payload shape for the merged field.
  2. Dedupe key — by language id (recommended) or by title?
  3. !isDirty guard. Spec says "the only block for submitting should be validation fail." Confirm whether the !isDirty part of the Save gating should also be dropped (allow saving an unchanged form) or kept.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions