Skip to content

fix(document): do not reset form fields when changing document type - #1336

Merged
Paul-AUB merged 6 commits into
developfrom
feature/fix-document-types
May 26, 2026
Merged

fix(document): do not reset form fields when changing document type#1336
Paul-AUB merged 6 commits into
developfrom
feature/fix-document-types

Conversation

@Paul-AUB

Copy link
Copy Markdown
Contributor

🤔 What

  • Preserve all form field values when the user changes the document type in the create/edit document form
  • Add a payload filter at submit time so that only fields relevant to the selected type are sent to the API

🤷‍♂️ Why

Previously, switching the document type called resetContext(...) in DocumentTypeSelect, which wiped the entire form state back to defaults — keeping only title, mainLanguage, mainLanguageName, and authors. This meant:

  • A user who had filled in a description, publication date, authors, identifier, etc. would lose all that work by accidentally clicking a different type.
  • Switching back to the original type did not restore the values; they were gone.
  • There was also no symmetrical benefit: fields from a previous type were not filtered out of the API payload either, so irrelevant data could be submitted silently.

🔍 How

1. Stop resetting on type change (DocumentTypeSelect.jsx)

Replaced the resetContext({ type, title, mainLanguage, ... }) call in handleSelect with a single updateAttribute('type', newDocType). updateAttribute was already exposed by DocumentFormContext, so no context shape change was needed. Field visibility in FormContent.jsx is already conditional on the type, so hidden fields are never rendered — the data just stays alive in state until the user switches back.

2. Filter the API payload at submit time (documentTypeHelpers.js)

Added filterDocumentPayload(docAttributes) — a pure function that, given the current document state, returns only the fields that are actually visible/relevant for the current type:

  • Event — minimal set: title, description, datePublication, iso3166, authors (no files, no language, no advanced metadata)
  • Authorization To Publish — intermediate set: adds language and files (without license), but no advanced metadata or ISO regions
  • Everything else (simple media + all standard types) — full set; sub-type-specific fields like parent, pages, library, issue are included but will be null for types that don't use them, so buildFormData already skips them

The field groups mirror exactly the conditional rendering in FormContent.jsx, including the global AuthorsSection (rendered for all non-unknown types) and the Advanced Metadata accordion (rendered for all types except Event and Authorization).

3. Apply the filter before building FormData

filterDocumentPayload is called at the top of postDocument, updateDocument, and updateDocumentWithNewEntities before the FormData / JSON body is assembled.

🔗 Related API PR

None.

🧪 Testing

  1. Open the document creation form.
  2. Select Article, fill in title, description, authors, publication date, identifier, and a parent document.
  3. Switch to Image — all field values must be preserved (visible or not).
  4. Switch back to Article — all previously entered values must reappear.
  5. Submit as Image and inspect the network request — the POST body must not contain parent, pages, library, issue.
  6. Switch to Event, submit — the POST body must not contain files, mainLanguage, license, identifier, editor, subjects, creatorComment.
  7. Repeat steps 1–6 in edit mode (PUT) for an existing document.

📸 Previews

N/A — no visual change; the fix affects state management and API payload construction.

@Paul-AUB

Copy link
Copy Markdown
Contributor Author

Suite des discussions de #1334.
Désolé pour la boulette

@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@urien

urien commented May 22, 2026

Copy link
Copy Markdown
Contributor

Ok,
Cette fois ci je peux choisir le fait qu'il y a une autorisation et renseigner les infos. Par contre si je change le type d'article à collection, ce champ redevient bloqué et il demeure bloqué si je retourne sur le type article
image

@Paul-AUB

Copy link
Copy Markdown
Contributor Author

En effet, le champ parent est sauvegardé et continue de s'appliquer (il est conservé pour ne pas être perdu si on repasse sur un type qui en a besoin). Du coup la seule solution c'est de vider le champ parent si on bascule sur un document qui n'a pas ce champ (si on repasse sur un type article, il faudra le remettre à la main du coup).

Fixed

@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@urien urien left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merci @Paul-AUB j'ai fait les tests et cela fonctionne parfaitement

@ClemRz ClemRz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issues (Must Fix)

  • [CreateDocument.js:33-39] When the document type is Event, filterDocumentPayload strips the files key from the returned object (since files is not in the Event allowed fields). The subsequent destructuring const { files, ... } = filtered will yield files === undefined, and files.forEach(...) on line 39 will throw a TypeError: Cannot read properties of undefined (reading 'forEach'). The same issue exists in UpdateDocument.js:36 where for (const file of files) would also crash on undefined.

    Since Events don't render the file upload form, document.files will typically be [], but if a user adds files while on another type and then switches to Event before submitting, the crash path is reachable.

    Consider defaulting files to an empty array during destructuring:

    const { files = [], selectOptionAuthorizationDocument, ...rest } = filtered;
    

    Apply this in both CreateDocument.js and UpdateDocument.js.

Suggestions (Should Consider)

  • [documentTypeHelpers.js:210-246] The filterDocumentPayload function has no guard for when type is undefined or -1 (the UNKNOWN type used as the initial/default state). If filterDocumentPayload is ever called before the user selects a type, it would fall into the else branch (full field set), which is probably fine — but it might be worth adding a comment or an early return to make this intentional behavior explicit.

  • [AddFileForm/index.jsx:115-126] The change to isLicenseForced / isAuthForced logic is a behavioral change beyond what the PR title describes. Previously, isLicenseForced was parent !== null && license !== null and isAuthForced was parent !== null && selectOptionAuthorizationDocument !== null. Now both depend on authorizationDocument !== null. This means:

    • A document with a parent and a license set (but no authorization document) will no longer show the license as forced.
    • A document with a parent and a radio option selected (but no authorization document linked) will no longer show the auth as forced.

    If this is intentional (fixing a separate bug), consider mentioning it in the PR description so reviewers understand the motivation. If it's unintentional, the old conditions may need to be preserved.

  • [AddFileForm/index.jsx:120-126] The useEffect that resets authorizationDocument when the parent changes runs on every render where document.parent reference changes (even if the id is the same). The ref-based guard (prevParentIdRef) handles this correctly, but there's a missing blank line between the isAuthForced block and the useEffect block which hurts readability. Also, hooks are typically grouped together before any derived values — here the useEffect is sandwiched between derived state and the accept variable, which breaks the conventional hooks-first ordering.

Nitpicks (Optional)

  • [DocumentTypeSelect.jsx:35] Destructuring { isArticle, isIssue } from documentTypeHelpers at module level is fine, but it's a different pattern from how FormContent.jsx uses these helpers (destructuring inside the component body). Not blocking, but worth noting for consistency across the codebase.

  • [UpdateDocument.js:120] The id is destructured from docAttributes before filtering (const { id } = docAttributes), then filterDocumentPayload(docAttributes) is called which also includes id in the output (since id is in BASE_PAYLOAD_FIELDS). This is correct but slightly redundant — id is used for the URL and also ends up in the body. No action needed, just noting for clarity.

@Paul-AUB
Paul-AUB force-pushed the feature/fix-document-types branch from eff6807 to d237080 Compare May 26, 2026 20:40
@Paul-AUB
Paul-AUB requested a review from ClemRz May 26, 2026 20:40
@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@ClemRz ClemRz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions (Should Consider)

  • [AddFileForm/index.jsx:115-121] The useEffect that resets authorizationDocument when the parent changes uses document.parent as a dependency, which is an object reference. Every time setDocument produces a new state object (even for unrelated attribute changes), document.parent will be a new reference if it's a non-null object — though the prevParentIdRef guard correctly prevents spurious resets. Consider using document.parent?.id as the dependency instead, which is a primitive and avoids the effect body running at all on unrelated updates:

    const parentId = document.parent?.id ?? null;
    useEffect(() => {
      if (prevParentIdRef.current === parentId) return;
      prevParentIdRef.current = parentId;
      updateAttribute('authorizationDocument', null);
    }, [parentId, updateAttribute]);
  • [AddFileForm/index.jsx:113-125] The behavioral change to isLicenseForced / isAuthForced is a separate fix from the main PR goal (preserving form fields on type change). The old logic checked document.license !== null and document.selectOptionAuthorizationDocument !== null respectively; the new logic checks document.authorizationDocument !== null for both. This appears to fix the bug reported by @urien (field getting stuck as disabled after switching types), but it would help future readers if the PR description mentioned this as a deliberate fix and explained the reasoning — especially since it changes when the license/auth radio group becomes disabled.

  • [documentTypeHelpers.js:210] Minor robustness note: filterDocumentPayload destructures type from docAttributes without a guard. If called with undefined or null (e.g., due to a programming error upstream), it would throw. Since the comment already notes that UNKNOWN (-1) falls through intentionally, this is low-risk, but a defensive const { type = DocumentTypes.UNKNOWN } = docAttributes ?? {}; would make it bulletproof.

Nitpicks (Optional)

  • [DocumentTypeSelect.jsx:35] Destructuring { isArticle, isIssue } at module level is fine and arguably cleaner than doing it inside the component body (avoids re-destructuring on every render). If the team prefers this pattern going forward, it might be worth adopting it consistently across other files that use documentTypeHelpers.

  • [documentTypeHelpers.js:190-248] The field group constants (BASE_PAYLOAD_FIELDS, LANGUAGE_PAYLOAD_FIELDS, etc.) are well-organized. Consider adding a brief JSDoc comment on filterDocumentPayload explaining that the field groups mirror the conditional rendering in FormContent.jsx — this makes it easier for future maintainers to keep them in sync.

@Paul-AUB

Copy link
Copy Markdown
Contributor Author

Follow-up fixes

Authorization section locking (AddFileForm/index.jsx)

Bug: Selecting "There is an authorization to publish" then adding a file would freeze the entire authorization section (radio buttons + auth doc select all disabled).

Root cause: isAuthForced was checking selectOptionAuthorizationDocument !== null, which is the very value the user just set — so the section immediately locked itself.

Fix: isParentAuthForced (and isLicenseForced/isAuthForced derived from it) now requires both document.parent !== null and document.authorizationDocument !== null. The lock only engages when a parent document already has an authorization document linked in GrottoCenter — i.e., the inherited value is meaningful. A user-selected option no longer triggers the lock.


Bug: Switching document type from Article → Collection → Article left the authorization section permanently locked.

Root cause: The field-preservation fix (main PR) kept document.parent and document.authorizationDocument alive in state across type changes. On Collection, isParentAuthForced was still true (both fields set), even though Collection has no parent field. Switching back to Article kept the same ghost state.

Fix 1 — condition simplification: Since document.parent is now cleared when switching to a non-parent type (see below), parent !== null alone is sufficient to imply the current type supports parent documents. No extra type check needed.

Fix 2 — clear parent on type switch (DocumentTypeSelect.jsx): When handleSelect switches to a type that does not support a parent document (!isArticle && !isIssue), parent is reset to null. This is semantically correct — the parent field is not visible or editable on those types, so carrying its value over would produce ghost state that silently affects the auth section. Switching back to Article therefore starts with a clean parent, and isParentAuthForced is false until the user explicitly picks a parent with a linked authorization.


Payload safety (CreateDocument.js, UpdateDocument.js)

Added files = [] default in the destructuring of filterDocumentPayload's return value. For Event documents, files is stripped from the payload (Events have no file upload form), so without the default the subsequent files.forEach / for...of would throw a TypeError if a user had added files while on a different type before switching to Event and submitting.


Code quality

  • useEffect dependency (AddFileForm): Replaced document.parent (object reference) with parentId (document.parent?.id ?? null, a primitive) as the effect dependency. The useRef is initialized from the same variable. The effect body no longer runs on unrelated state updates that happen to produce a new parent object reference.
  • filterDocumentPayload robustness: Added a docAttributes ?? {} null-coalescing guard and a JSDoc comment explaining that field groups mirror FormContent.jsx conditional rendering — making it easier to keep them in sync.

@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@Paul-AUB
Paul-AUB force-pushed the feature/fix-document-types branch from 3bdb9e6 to b896ae8 Compare May 26, 2026 21:01
@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@Paul-AUB
Paul-AUB force-pushed the feature/fix-document-types branch from b896ae8 to 9285c71 Compare May 26, 2026 21:10
@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@Paul-AUB
Paul-AUB requested a review from ClemRz May 26, 2026 21:19

@ClemRz ClemRz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions (Should Consider)

  • [documentTypeHelpers.js:225-233] The AuthorizationToPublish branch includes FILE_PAYLOAD_FIELDS (which contains license, selectOptionAuthorizationDocument, authorizationDocument), but FormContent.jsx renders <AddFileForm showAuthorization={false} /> for that type — meaning the license selector and authorization radio group are never shown. These fields will be null and harmlessly skipped by buildFormData, but it's a minor semantic mismatch between "fields relevant to the type" and what's actually editable. Consider adding a brief comment in the AuthorizationToPublish branch noting that license/selectOptionAuthorizationDocument are included for structural consistency with FILE_PAYLOAD_FIELDS even though they're not user-editable for this type.

  • [UpdateDocument.js:117-123] In updateDocumentWithNewEntities, the filtered payload is sent as JSON.stringify(body). Unlike the updateDocument path (which uses buildFormData that skips nulls), JSON.stringify will include null-valued fields in the JSON body. This means fields like parent: null, pages: null, issue: "" will be sent to the API for types that don't use them. This is likely fine (the API should ignore irrelevant nulls), but it's worth noting the behavioral difference between the two update paths. If the API ever interprets null as "clear this field," it could produce unintended side effects for the duplicates merge flow.

Nitpicks (Optional)

  • [AddFileForm/index.jsx:116-121] The useEffect that resets authorizationDocument on parent change is well-placed and the prevParentIdRef pattern is solid. One minor readability note: the effect runs on mount with prevParentIdRef.current === parentId (both initialized from the same value), so it's a no-op on mount — which is correct. A one-line comment like // Skip initial mount — only react to actual parent changes would make this immediately obvious to future readers.

  • [documentTypeHelpers.js:190-195] The field group constants are well-organized. Consider adding Object.freeze() to prevent accidental mutation, or simply marking them with a @const JSDoc tag to signal intent — though this is purely stylistic given they're module-scoped const arrays.


All previous review concerns (the files = [] default, the useEffect dependency on a primitive parentId, and the behavioral change documentation) have been addressed in the latest push. The approach is sound — preserving form state across type switches while filtering the payload at submit time is a clean separation of concerns. The follow-up fixes for the authorization section locking are well-explained in the PR comments.

LGTM 👍

@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://orange-rock-0d4f87503-1336.westeurope.azurestaticapps.net

@Paul-AUB
Paul-AUB merged commit 27e5179 into develop May 26, 2026
9 checks passed
@Paul-AUB
Paul-AUB deleted the feature/fix-document-types branch May 26, 2026 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants