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: add company document signer state machine #164

Merged
merged 1 commit into from
Feb 27, 2025
Merged

Conversation

serikjensen
Copy link
Member

This adds a document signer state machine to put together all steps in company document signer.

See workflow in figma here https://www.figma.com/design/6dxOSiONDiJoa9zY1wOwbs/Frontend-SDK-Partner-Design-File?node-id=5220-17923&m=dev

Proof of functionality

Assign signatory (as self) -> documents list -> signature form -> documents list

  • Initialized on assign signatory form
  • If verified as self signatory, continues to document list and is able to sign documents
  • Sign documents leads to the signature form
  • Signing the form leads back to documents list with the document status correctly updated
  • You can return to assign signatory form and update user information
Screen.Recording.2025-02-25.at.4.35.43.PM.mov

Inviting signatory

  • Initialized on assign signatory form
  • Not verified as self signatory so in next step is unable to sign documents (gets a not signed document status instead)
Screen.Recording.2025-02-25.at.4.39.07.PM.mov

Comment on lines +9 to +15
function hasRequiredParams<TParams extends object, TRequiredParams extends keyof TParams>(
params: TParams,
requiredParams: TRequiredParams[],
): params is TParams & Required<Pick<TParams, TRequiredParams>> {
return requiredParams.every(param => param in params && typeof params[param] !== 'undefined')
}

Copy link
Member Author

Choose a reason for hiding this comment

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

This provides a type guard for the existing useFlowParams hook below. We can assert that all the required params are supplied as expected and then communicate that with TS.

Without this TS determines a prop which is conditional in the flow interface (by design since it's not required for each flow component, only signature form) and throws an error

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! Looks good! Great use of types here

Comment on lines +15 to +21
export type MachineEventType<
TEventPayloads,
TEventType extends keyof TEventPayloads = keyof TEventPayloads,
> = {
type: TEventType
payload: TEventPayloads[TEventType]
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Needed to share this across state machines, lmk if there's a better file to put it in

Copy link
Contributor

@jeffredodd jeffredodd left a comment

Choose a reason for hiding this comment

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

Looks good! I don't feel confident enough in robot3 to be your approver but I think this looks like its on the right track.

signatoryId?: string
}

export const DocumentSigner = ({ companyId, signatoryId, onEvent }: DocumentSignerProps) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like this should be DocumentSignerMachine but thats just a suggestion I'm still not the most confident in robot3

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm but I also see this below too in documentSignerStateMachine. But it returns a flow so maybe Flow is the suffix i'm thinking fits here. Just seems like we have a lot of components called DocumentSigner.

Copy link
Member Author

Choose a reason for hiding this comment

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

So the thought around this is that Flow already is kind of a reserved word for the mega user flows like employee onboarding. These are still technically at the level of a component like payment method or compensation so the idea would be that they are usable in the same way.

I guess it would come down to if we felt ok making flow something that could be at the component level which is tough given that we have language around what flows mean atm

i also might be overthinking this lol here's the current docs on flows https://docs.gusto.com/embedded-payroll/docs/workflows-overview

Comment on lines +9 to +15
function hasRequiredParams<TParams extends object, TRequiredParams extends keyof TParams>(
params: TParams,
requiredParams: TRequiredParams[],
): params is TParams & Required<Pick<TParams, TRequiredParams>> {
return requiredParams.every(param => param in params && typeof params[param] !== 'undefined')
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! Looks good! Great use of types here

})
if (!hasRequiredParams(params, requiredParams)) {
const missingParam = requiredParams.find(param => typeof params[param] === 'undefined')
throw new Error(
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens when the required params are missing? Do we just throw an error and break the flow? Just trying to think of cases where this could happen.

Copy link
Member Author

Choose a reason for hiding this comment

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

It currently just breaks! i think we could address catching errors and providing an escape hatch with some sort of flow error boundary

import { type MachineEventType } from '@/types/Helpers'

type EventPayloads = {
[companyEvents.COMPANY_VIEW_FORM_TO_SIGN]: Schemas['Form']
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we should further scope these events for easier management, like documentSignerEvents.

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah +1 to providing better scope!

@dmortal
Copy link
Collaborator

dmortal commented Feb 26, 2025

this is awesome!

@serikjensen serikjensen merged commit fca76c1 into main Feb 27, 2025
1 check passed
@serikjensen serikjensen deleted the feat/GWS-3736 branch February 27, 2025 00:00
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