feat(series): conditional early termination and custom completion message#1393
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds conditional early-termination support to SERIES instruments, along with the supporting renderer, gateway, and API changes needed to make it work end-to-end (in-person and remote assignments).
Series feature
terminatepredicate (params.terminate): called after each item is submitted; returningtrueends the series early so the remaining items are never administered. The terminating item's own record is still saved. Example use: a consent form as the first item that, when declined, skips the rest.completionMessage(params.completionMessage): returns a custom localized ({ en, fr }) message for the completion screen, ornullfor the default. Receives{ terminated, itemName }so the message can differ on early exit (e.g. "the questionnaire was not administered because you did not consent").defineSeriesInstrumentnow infers the item-name literal union, soterminate/completionMessagereceive a strongly-typeditemName. Itemdatais a generic defaulting toany, so it can be annotated inline without a cast.Renderer / gateway
SeriesInstrumentRendererevaluatesterminate, jumps to the completion screen on early exit, renders the customcompletionMessage, and emits a newcompleteflag on the submit payload.Root.tsx) marks a remote assignmentCOMPLETEvia thecompleteflag instead of comparing against the last item's id, so early termination completes the assignment correctly.API synchronizer (
gateway.synchronizer.ts)Consent form
DNP_GENERAL_CONSENT_FORM: changed the consent field from a checkbox to an accept/decline radio, and relaxed its schema fromz.literal(true)toz.boolean()so a decline is submittable (which drives the new early-exit demo inDNP_HAPPINESS_QUESTIONNAIRE_WITH_CONSENT).Docs / tests
terminateandcompletionMessageinpackages/instrument-guidelines/AGENTS.md.params(instrument.series.test.ts).CLAUDE.md.Verification
pnpm lintandpnpm testpass (36 test files, 244 passed / 1 pre-existing skip).🤖 Generated with Claude Code