Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(actions): Restructure ActionFormIndex and utilize ModalContext in forms #299

Merged
merged 10 commits into from
Jan 10, 2024

Conversation

hannasage
Copy link

@hannasage hannasage commented Jan 5, 2024

Purpose

To eliminate complexity created by PackageActionForm and each form handling their own modals.

Linked Issues to Close

N/A
(Part of ongoing CHIP Actions work)

Approach

Previously, we piped in props to an action form within the PackageActionForm component by cloning the children and piping data from the parent thru as new props. This gets confusing and convoluted whenever you want to add new props, have a unique prop for a specific form, etc. It also creates weird nesting dependencies for our form pages.

React.Children.map(
    children as CloneableChild[],
        (child: CloneableChild) =>
            React.cloneElement(child, {
                // Child has to be configured to take these
                item,
             })

🤢 Yucky icky gross complexity, yikez

So, to remedy this complexity and open us up to more accessible props, we now handle the following responsibilities from PackageActionForm within the ActionFormSwitch component:

  • Fetching the item (package)
  • Validating the action is valid for the given package
  • Displaying any fetch/validation errors for the above
  • Piping the item object through to the form page (Form pages have additionally been made to use the prop instead of using a fetch)
switch (type) {
    case Action.WITHDRAW_PACKAGE:
      return <WithdrawPackage item={item} />;
    case Action.ENABLE_RAI_WITHDRAW:
    case Action.DISABLE_RAI_WITHDRAW:
      return <ToggleRaiResponseWithdraw item={item} />;
    case Action.ISSUE_RAI:
      return <RaiIssue item={item} />;
    case Action.WITHDRAW_RAI:
      return <WithdrawRai item={item} />;
    case Action.RESPOND_TO_RAI:
      return <RespondToRai item={item} />;
    default:
      return <Navigate path="/" />;
  }

😍 Beautiful gorgeous wonderful simplicity, yay

One layer up, in ActionFormIndex where we render the switch, we also wrap it in a page container, the modal context, and provide breadcrumbs so form pages can remain singularly focused on rendering form fields and controlling their data.

Assorted Notes/Considerations/Learning

In testing CHIP actions, we've identified cases where control over props is a large advantage, so this untangling of prop control for action forms becomes even more useful as we move into waiver actions that have additional requirements.

@hannasage hannasage added the In Testing This PR is being tested by QA label Jan 5, 2024
@hannasage hannasage self-assigned this Jan 5, 2024
@hannasage hannasage marked this pull request as ready for review January 5, 2024 17:02
@hannasage hannasage removed the In Testing This PR is being tested by QA label Jan 5, 2024
export const WithdrawPackage = () => (
<PackageActionForm>
<WithdrawPackageForm />
</PackageActionForm>
Copy link
Author

@hannasage hannasage Jan 5, 2024

Choose a reason for hiding this comment

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

BEGONE ye ol' dependency! One example of how we no longer need to wrap these as the responsibilities handled by this are now handled in ActionFormIndex (breadcrumbs and page container), and ActionFormSwitch (item fetching and piping as props).

const { id, type } = useParams("/action/:id/:type");
return (
<SimplePageContainer>
<ModalProvider>
Copy link
Author

Choose a reason for hiding this comment

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

Notably we add a dependency, but isolate its usage to a point that wraps all action forms instead of wrapping them individually, and provides a replicable solution for future form indexes (i.e. Submission forms when refactored to a dynamic-path approach like Actions forms).

Copy link
Contributor

@pkim-gswell pkim-gswell left a comment

Choose a reason for hiding this comment

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

I'm liking the refactor decisions for these package actions 👍.
Leaving some suggestions/comments.

Comment on lines +158 to 176
{attachmentList.map(({ name, label, required }) => (
<I.FormField
key={name}
control={form.control}
name="additionalInformation"
name={`attachments.${name}`}
render={({ field }) => (
<I.FormItem>
<h3 className="font-bold text-2xl font-sans">
Additional Information
</h3>
<I.FormLabel className="font-normal">
Add anything else that you would like to share with CMS.
<I.FormLabel>
{label}
{required ? <I.RequiredIndicator /> : ""}
</I.FormLabel>
<I.Textarea {...field} className="h-[200px] resize-none" />
<I.FormDescription>4,000 characters allowed</I.FormDescription>
<I.Upload
files={field?.value ?? []}
setFiles={field.onChange}
/>
<I.FormMessage />
</I.FormItem>
)}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

Continuing on from my initial comment, RespondToRai would look like this:

// attachments
{attachmentList.map(({ name, label, required }) => (
  <I.FormField
    key={name}
    control={form.control}
    name={`attachments.${name}`}
    render={SlotAttachments({
      label: (
        <>
          {label}
          {required ? <I.RequiredIndicator /> : ""}
        </>
      ),
      message: <I.FormMessage />,
    })}
  />
))}

// additionalInfo
<I.FormField
  control={form.control}
  name="additionalInformation"
  render={SlotAdditionalInfo({
    label: "Add anything else that you would like to share with CMS.",
    description: "4,000 characters allowed",
  })}
/>

Copy link
Collaborator

@13bfrancis 13bfrancis left a comment

Choose a reason for hiding this comment

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

Left a few comments/questions for you

Comment on lines +59 to +60
const { setCancelModalOpen, setSuccessModalOpen, setErrorModalOpen } =
useModalContext();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't know why but when I see context I smile inside lol

Copy link
Collaborator

@13bfrancis 13bfrancis left a comment

Choose a reason for hiding this comment

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

When Paul is good with this I am. I like what you got going here

@hannasage hannasage force-pushed the actnidx branch 2 times, most recently from cf0bfe3 to 1b64581 Compare January 10, 2024 15:08
@hannasage hannasage merged commit 2bdcc7c into master Jan 10, 2024
16 checks passed
@hannasage hannasage deleted the actnidx branch January 10, 2024 15:34
Copy link
Contributor

🎉 This PR is included in version 1.5.0-val.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants