diff --git a/packages/frontend/src/app-extensions/index.ts b/packages/frontend/src/app-extensions/index.ts new file mode 100644 index 000000000..53942d2ab --- /dev/null +++ b/packages/frontend/src/app-extensions/index.ts @@ -0,0 +1,19 @@ +import type { FrontEndAppExtension } from './types' + +// Nothing for now +const APP_EXTENSIONS: Record = {} + +export function getExtension( + appKey?: string, + stepKey?: string, +): FrontEndAppExtension | null { + if (!appKey || !stepKey) { + return null + } + return APP_EXTENSIONS[`${appKey}-${stepKey}`] ?? null +} + +export type { + CheckStepButtonExtensionProps, + FrontEndAppExtension, +} from './types' diff --git a/packages/frontend/src/app-extensions/types.ts b/packages/frontend/src/app-extensions/types.ts new file mode 100644 index 000000000..d783c3e5e --- /dev/null +++ b/packages/frontend/src/app-extensions/types.ts @@ -0,0 +1,22 @@ +import type { IStep } from '@plumber/types' + +import type { ComponentType, ReactNode } from 'react' + +export interface CheckStepButtonExtensionProps { + step: IStep + /** The Check Step / Check Step Again button itself. */ + children: ReactNode +} + +export interface FrontEndAppExtension { + /** + * Wraps the Check Step / Check Step Again button. + * + * Mounted ONLY WHEN the button is enabled. + * TBD: Allow extending when button is disabled (for showing custom failure + * tooltip etc) + **/ + CheckStepButton?: ComponentType + + // Room to grow: ResultPanelWrapper, SubstepWrapper, etc. +} diff --git a/packages/frontend/src/components/FlowStepTestController/CheckAgainButton.tsx b/packages/frontend/src/components/FlowStepTestController/CheckAgainButton.tsx index 18e6f5d3d..081b22715 100644 --- a/packages/frontend/src/components/FlowStepTestController/CheckAgainButton.tsx +++ b/packages/frontend/src/components/FlowStepTestController/CheckAgainButton.tsx @@ -1,6 +1,6 @@ import { IExecutionStepMetadata, IStep } from '@plumber/types' -import { useCallback, useMemo } from 'react' +import { forwardRef, useCallback, useMemo } from 'react' import { IconType } from 'react-icons' import { BiChevronDown } from 'react-icons/bi' import { PiRobot, PiUser } from 'react-icons/pi' @@ -30,7 +30,10 @@ interface CheckAgainButtonProps { executionStepMetadata?: IExecutionStepMetadata } -export function CheckAgainButton(props: CheckAgainButtonProps) { +export const CheckAgainButton = forwardRef< + HTMLButtonElement, + CheckAgainButtonProps +>((props, ref) => { const { isUnstyledInfobox, onClick, isLoading, isDisabled, step } = props const isFormSgTrigger = step.appKey === FORMSG_APP_KEY && step.key === FORMSG_TRIGGER_KEY @@ -38,13 +41,14 @@ export function CheckAgainButton(props: CheckAgainButtonProps) { step.appKey === FORMSG_APP_KEY && step.key === MRF_ACTION_KEY if (isFormSgTrigger) { - return + return } if (isFormSgAction) { - return + return } return ( ) -} +}) /** * For UX reasons, we need to have a different button for FormSG. @@ -104,7 +108,10 @@ function FormSGMenuItem({ ) } -function FormSGCheckAgainButton(props: CheckAgainButtonProps) { +const FormSGCheckAgainButton = forwardRef< + HTMLButtonElement, + CheckAgainButtonProps +>((props, ref) => { const { isUnstyledInfobox: isTransparentInfobox, onClick, @@ -155,6 +162,7 @@ function FormSGCheckAgainButton(props: CheckAgainButtonProps) { colorScheme={isTransparentInfobox ? 'primary' : 'black'} > )} - + + + @@ -379,20 +402,22 @@ export default function FlowStepTestController( {isDirty ? 'Save' : 'Saved'} )} - - - + + + )}