formik#FormikValues TypeScript Examples
The following examples show how to use
formik#FormikValues.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: test-utils.tsx From abacus with GNU General Public License v2.0 | 7 votes |
MockFormik = ({
children,
initialValues = {},
}: {
children: React.ReactNode
initialValues?: FormikValues
}) => {
return (
<Formik initialValues={initialValues} onSubmit={() => undefined}>
{children}
</Formik>
)
}
Example #2
Source File: useResetPasswordFormik.tsx From bouncecode-cms with GNU General Public License v3.0 | 7 votes |
function useResetPasswordFormik(
onSubmit: (
values: FormikValues,
formikHelpers: FormikHelpers<FormikValues>,
) => void | Promise<any>,
options?: Partial<FormikConfig<FormikValues>>,
) {
const {enqueueSnackbar} = useSnackbar();
const formik = useFormik({
...options,
initialValues: {
...initialValues,
...options?.initialValues,
},
validationSchema,
onSubmit,
});
useEffect(() => {
if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
variant: 'error',
});
}
}, [formik.submitCount, formik.isSubmitting]);
return formik;
}
Example #3
Source File: useInitialRequiredErrors.tsx From SQForm with MIT License | 7 votes |
// Until Formik exposes the validationSchema (again) via useFormikContext(), the solution has to be handled at the Form declaration level
// There's a few open PR's on this issue, here's one for reference: https://github.com/formium/formik/pull/2933
export function useInitialRequiredErrors<Values>(
validationSchema: AnyObjectSchema | undefined,
initialValues: FormikValues
): FormikErrors<Values> {
const initialRequiredErrorsRef = React.useRef(
Object.entries(validationSchema || {}).reduce((acc, [key, value]) => {
if (value?._exclusive?.required && !_getHasValue(initialValues[key])) {
return {...acc, [key]: 'Required'};
}
return acc;
}, {})
);
return initialRequiredErrorsRef.current;
}
Example #4
Source File: SQFormReadOnly.tsx From SQForm with MIT License | 6 votes |
function SQFormReadOnly<Values extends FormikValues>({
readOnlyFields,
initialValues,
enableReinitialize = false,
muiGridProps = {},
}: SQFormReadOnlyProps<Values>): JSX.Element {
return (
<Formik<Values>
initialValues={initialValues}
onSubmit={noop}
enableReinitialize={enableReinitialize}
>
{(_props) => {
return (
<Form>
<Grid
{...muiGridProps}
container
spacing={muiGridProps.spacing ?? 2}
>
{readOnlyFields.map((readOnlyField, index) => {
const props = {
key: readOnlyField?.key ?? index,
muiFieldProps: noBottomMarginStyle,
...readOnlyField,
};
if (readOnlyField?.mask) {
return <SQFormMaskedReadOnlyField {...props} />;
}
return <SQFormReadOnlyField {...props} />;
})}
</Grid>
</Form>
);
}}
</Formik>
);
}
Example #5
Source File: useSignUpFormik.tsx From bouncecode-cms with GNU General Public License v3.0 | 6 votes |
function useSignUpFormik(
onSubmit: (
values: FormikValues,
formikHelpers: FormikHelpers<FormikValues>,
) => void | Promise<any>,
options?: Partial<FormikConfig<FormikValues>>,
) {
const {enqueueSnackbar} = useSnackbar();
const formik = useFormik({
...options,
initialValues: {
...initialValues,
...options?.initialValues,
},
validationSchema,
onSubmit,
});
useEffect(() => {
if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
variant: 'error',
});
}
}, [formik.submitCount, formik.isSubmitting]);
return formik;
}
Example #6
Source File: useSignInFormik.tsx From bouncecode-cms with GNU General Public License v3.0 | 6 votes |
function useSigninFormik(
onSubmit: (
values: FormikValues,
formikHelpers: FormikHelpers<FormikValues>,
) => void | Promise<any>,
options?: Partial<FormikConfig<FormikValues>>,
) {
const {enqueueSnackbar} = useSnackbar();
const formik = useFormik({
...options,
initialValues: {
...initialValues,
...options?.initialValues,
},
validationSchema,
onSubmit,
});
useEffect(() => {
if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
variant: 'error',
});
}
}, [formik.submitCount, formik.isSubmitting]);
return formik;
}
Example #7
Source File: useResetPasswordSubmitCallback.tsx From bouncecode-cms with GNU General Public License v3.0 | 6 votes |
function useResetPasswordSubmitCallback() {
const {enqueueSnackbar} = useSnackbar();
return useCallback(
async (
values: FormikValues,
formikHelpers: FormikHelpers<FormikValues>,
) => {
try {
// await firebase.auth().sendPasswordResetEmail(values.email);
enqueueSnackbar('이메일을 확인해주세요.', {variant: 'success'});
} catch (e) {
console.error(e);
enqueueSnackbar(e.message, {variant: 'error'});
}
},
[],
);
}
Example #8
Source File: index.ts From SQForm with MIT License | 6 votes |
// Note - Formik fields expect empty strings and not nulls
// When initializing the forms initialValues we can use this function to replace all nulls with empty strings
export function sanitizeInitialValues(valuesObject: FormikValues): string {
return JSON.parse(
JSON.stringify(valuesObject, (_key, value) => {
return value === null ? '' : value;
})
);
}
Example #9
Source File: index.ts From SQForm with MIT License | 6 votes |
// If we want to send null to our API instead of empty strings
// Note - If this becomes a common scenario we can make this the default behavior for SQForm onSubmit
export function serializeFormValues(formValues: FormikValues): string {
return JSON.parse(
JSON.stringify(formValues, (_key, value) => {
return value === '' ? null : value;
})
);
}
Example #10
Source File: SQForm.tsx From SQForm with MIT License | 5 votes |
function SQForm<Values extends FormikValues>({
children,
enableReinitialize = false,
initialValues,
muiGridProps = {},
onSubmit,
validationSchema,
}: SQFormProps<Values>): JSX.Element {
const initialErrors = useInitialRequiredErrors(
validationSchema,
initialValues
);
// HACK: This is a workaround for: https://github.com/mui-org/material-ui-pickers/issues/2112
// Remove this reset handler when the issue is fixed.
const handleReset = () => {
document &&
document.activeElement &&
(document.activeElement as HTMLElement).blur();
};
const handleSubmit = useDebouncedCallback(
(values: Values, formikHelpers: FormikHelpers<Values>) =>
onSubmit(values, formikHelpers),
500,
{leading: true, trailing: false}
);
return (
<Formik<Values>
enableReinitialize={enableReinitialize}
initialErrors={initialErrors}
initialValues={initialValues}
onSubmit={handleSubmit}
onReset={handleReset}
validationSchema={validationSchema}
validateOnMount={true}
>
{(_props) => {
return (
<Form>
<Grid
{...muiGridProps}
container
spacing={muiGridProps.spacing ?? 2}
>
{children}
</Grid>
</Form>
);
}}
</Formik>
);
}
Example #11
Source File: useCommentCreateFormik.tsx From bouncecode-cms with GNU General Public License v3.0 | 5 votes |
export function useCommentCreateFormik(
postId: string,
options?: Partial<FormikConfig<FormikValues>>,
) {
const {enqueueSnackbar} = useSnackbar();
const [create] = useCommentCreateMutation({
onCompleted: () => {
formik.handleReset(null);
},
});
const onSubmit = async (
values: FormikValues,
formikHelpers: FormikHelpers<FormikValues>,
) => {
return create({
variables: {
data: {
postId,
text: values.text,
payload: {},
},
},
refetchQueries: [CommentsDocument, CommentStatDocument],
});
};
const formik = useFormik({
...options,
initialValues: {
...initialValues,
...options?.initialValues,
},
validationSchema,
onSubmit,
});
useEffect(() => {
if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
variant: 'error',
});
}
}, [formik.submitCount, formik.isSubmitting]);
return formik;
}
Example #12
Source File: index.tsx From youtube-2020-june-multi-step-form-formik with MIT License | 5 votes |
export function FormikStepper({ children, ...props }: FormikConfig<FormikValues>) {
const childrenArray = React.Children.toArray(children) as React.ReactElement<FormikStepProps>[];
const [step, setStep] = useState(0);
const currentChild = childrenArray[step];
const [completed, setCompleted] = useState(false);
function isLastStep() {
return step === childrenArray.length - 1;
}
return (
<Formik
{...props}
validationSchema={currentChild.props.validationSchema}
onSubmit={async (values, helpers) => {
if (isLastStep()) {
await props.onSubmit(values, helpers);
setCompleted(true);
} else {
setStep((s) => s + 1);
// the next line was not covered in the youtube video
//
// If you have multiple fields on the same step
// we will see they show the validation error all at the same time after the first step!
//
// If you want to keep that behaviour, then, comment the next line :)
// If you want the second/third/fourth/etc steps with the same behaviour
// as the first step regarding validation errors, then the next line is for you! =)
//
// In the example of the video, it doesn't make any difference, because we only
// have one field with validation in the second step :)
helpers.setTouched({});
}
}}
>
{({ isSubmitting }) => (
<Form autoComplete="off">
<Stepper alternativeLabel activeStep={step}>
{childrenArray.map((child, index) => (
<Step key={child.props.label} completed={step > index || completed}>
<StepLabel>{child.props.label}</StepLabel>
</Step>
))}
</Stepper>
{currentChild}
<Grid container spacing={2}>
{step > 0 ? (
<Grid item>
<Button
disabled={isSubmitting}
variant="contained"
color="primary"
onClick={() => setStep((s) => s - 1)}
>
Back
</Button>
</Grid>
) : null}
<Grid item>
<Button
startIcon={isSubmitting ? <CircularProgress size="1rem" /> : null}
disabled={isSubmitting}
variant="contained"
color="primary"
type="submit"
>
{isSubmitting ? 'Submitting' : isLastStep() ? 'Submit' : 'Next'}
</Button>
</Grid>
</Grid>
</Form>
)}
</Formik>
);
}
Example #13
Source File: index.tsx From youtube-2020-june-material-ui-themes with MIT License | 5 votes |
export function FormikStepper({
children,
...props
}: FormikConfig<FormikValues>) {
const childrenArray = React.Children.toArray(children) as React.ReactElement<
FormikStepProps
>[];
const [step, setStep] = useState(0);
const currentChild = childrenArray[step];
const [completed, setCompleted] = useState(false);
function isLastStep() {
return step === childrenArray.length - 1;
}
return (
<Formik
{...props}
validationSchema={currentChild.props.validationSchema}
onSubmit={async (values, helpers) => {
if (isLastStep()) {
await props.onSubmit(values, helpers);
setCompleted(true);
} else {
setStep(s => s + 1);
}
}}
>
{({ isSubmitting }) => (
<Form autoComplete="off">
<Stepper alternativeLabel activeStep={step}>
{childrenArray.map((child, index) => (
<Step
key={child.props.label}
completed={step > index || completed}
>
<StepLabel>{child.props.label}</StepLabel>
</Step>
))}
</Stepper>
{currentChild}
<Grid container spacing={2}>
{step > 0 ? (
<Grid item>
<Button
disabled={isSubmitting}
variant="contained"
color="primary"
onClick={() => setStep(s => s - 1)}
>
Back
</Button>
</Grid>
) : null}
<Grid item xs={12}>
<Button
startIcon={
isSubmitting ? <CircularProgress size="1rem" /> : null
}
disabled={isSubmitting}
type="submit"
fullWidth
>
{isSubmitting ? "Submitting" : isLastStep() ? "Submit" : "NeXt"}
</Button>
</Grid>
</Grid>
</Form>
)}
</Formik>
);
}
Example #14
Source File: SQFormStoryWrapper.tsx From SQForm with MIT License | 5 votes |
function Form({
children,
initialValues,
validationSchema,
muiGridProps,
showSubmit = true,
}: SQFormStoryWrapperProps): React.ReactElement {
const [value, setValue] = React.useState({});
const [snackbarState, {snackbar, closeSnackBar}] = useSnackbar();
const handleSubmit = (values: FormikValues) => {
setValue(values);
};
const firstUpdate = React.useRef(true);
React.useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
} else {
snackbar.success(
<pre style={{fontSize: '14px', margin: 0}}>
{JSON.stringify(value, null, 2)}
</pre>
);
}
}, [snackbar, value]);
return (
<>
<SQForm
initialValues={initialValues}
validationSchema={validationSchema}
muiGridProps={{wrap: 'nowrap', ...muiGridProps}}
onSubmit={handleSubmit}
>
{children}
{showSubmit && (
<Grid item={true} sm={2} style={{alignSelf: 'center'}}>
<SQFormButton>Submit</SQFormButton>
</Grid>
)}
</SQForm>
<Snackbar snackbarState={snackbarState} closeSnackBar={closeSnackBar} />
</>
);
}
Example #15
Source File: SQFormDialog.tsx From SQForm with MIT License | 5 votes |
function SQFormDialog<Values extends FormikValues>({
cancelButtonText = 'Cancel',
children,
disableBackdropClick = false,
isDisabled = false,
isOpen,
maxWidth = 'sm',
onClose,
onSave,
shouldDisplaySaveButton = true,
saveButtonText = 'Save',
tertiaryButtonText,
title,
enableReinitialize = false,
initialValues,
muiGridProps = {},
shouldRequireFieldUpdates = false,
validationSchema,
showSecondaryButton = true,
onTertiaryClick,
tertiaryStatus = 'HIDE_BUTTON',
tertiaryButtonVariant = 'outlined',
}: SQFormDialogProps<Values>): React.ReactElement {
const initialErrors = useInitialRequiredErrors(
validationSchema,
initialValues
);
return (
<Formik
enableReinitialize={enableReinitialize}
initialErrors={initialErrors}
initialValues={initialValues}
onSubmit={onSave}
validationSchema={validationSchema}
validateOnMount={true}
>
<SQFormDialogInner<Values>
cancelButtonText={cancelButtonText}
children={children}
disableBackdropClick={disableBackdropClick}
isDisabled={isDisabled}
isOpen={isOpen}
maxWidth={maxWidth}
onClose={onClose}
shouldDisplaySaveButton={shouldDisplaySaveButton}
saveButtonText={saveButtonText}
shouldRequireFieldUpdates={shouldRequireFieldUpdates}
title={title}
muiGridProps={muiGridProps}
showSecondaryButton={showSecondaryButton}
tertiaryStatus={tertiaryStatus}
tertiaryButtonText={tertiaryButtonText}
onTertiaryClick={onTertiaryClick}
tertiaryButtonVariant={tertiaryButtonVariant}
/>
</Formik>
);
}
Example #16
Source File: SQFormGuidedWorkflow.tsx From SQForm with MIT License | 4 votes |
function SQFormGuidedWorkflow<TValues extends FormikValues>({
taskModules,
mainTitle,
mainSubtitle,
initialCompletedTasks = 0,
isStrictMode = false,
onError,
containerStyles = {},
}: SQFormGuidedWorkflowProps<TValues>): React.ReactElement {
// Until Formik exposes the validationSchema (again) via Context, the solution has to be handled at the Form declaration level
// There's a few open PR's on this issue, here's one for reference: https://github.com/formium/formik/pull/2933
const getFormikInitialRequiredErrors = (
validationSchema?: SQFormGuidedWorkflowDataProps<TValues>['validationSchema']
) => {
if (validationSchema?.fields) {
const validationFields =
validationSchema.fields as Yup.ObjectSchema<TValues>;
return Object.entries(validationFields).reduce((acc, [key, value]) => {
if (value.tests[0]?.OPTIONS.name === 'required') {
return {...acc, [key]: 'Required'};
}
return acc;
}, {});
}
return {};
};
const classes = useStyles();
const {
state: taskModulesContext,
updateDataByID: updateTaskModuleContextByID,
} = useGuidedWorkflowContext<TValues>(taskModules);
const {taskModulesState, updateActiveTaskModule, enableNextTaskModule} =
useManageTaskModules<TValues>(initialCompletedTasks, taskModulesContext);
const transformedTaskModules = taskModules.map((taskModule, index) => {
const taskNumber = index + 1;
const taskName = taskModule.name;
const validationYupSchema = taskModule.formikProps?.validationSchema;
const initialErrors = getFormikInitialRequiredErrors(
taskModule.formikProps?.validationSchema
);
const isPanelExpanded =
taskModulesContext[taskModulesState.activeTaskModuleID].name === taskName;
const getIsDisabled = () => {
if (isStrictMode && taskModulesState.activeTaskModuleID !== taskNumber) {
return true;
}
if (
taskModule.isDisabled ||
taskModulesState.progressTaskModuleID < taskNumber
) {
return true;
}
return false;
};
const handleSubmit = async (
values: TValues,
formikBag: FormikHelpers<TValues>
) => {
const context = {
...taskModulesContext,
[taskNumber]: {
...taskModulesContext[taskNumber],
data: values,
},
};
try {
await taskModule.formikProps.onSubmit(values, formikBag, context);
updateTaskModuleContextByID(taskNumber, values);
enableNextTaskModule();
} catch (error) {
onError && onError(error as Error);
}
};
return {
...taskModule,
isDisabled: getIsDisabled(),
isInitiallyExpanded: taskModule.isInitiallyExpanded || isPanelExpanded,
expandPanel: () => {
/* do nothing */
}, // Faulty logic in the Accordion SSC requires precense of a function for isPanelExpanded to work
isPanelExpanded,
onClick: () => {
taskModule?.onClick && taskModule.onClick();
updateActiveTaskModule(taskNumber);
},
body: (
<Formik
enableReinitialize={true}
initialErrors={initialErrors}
initialValues={taskModulesContext[taskNumber].data}
onSubmit={handleSubmit}
validationSchema={validationYupSchema}
validateOnMount={true}
>
{({isSubmitting}) => (
<Form>
<CardContent className={classes.root}>
{isSubmitting || taskModule.isLoading ? (
<div data-testid="loadingSpinner">
<ComponentLoadingSpinner
message={
isSubmitting
? `Saving ${taskModule.title} outcome`
: taskModule.isLoadingMessage
}
/>
</div>
) : (
<>
{taskModule.additionalInformationSectionProps && (
<AdditionalInformationSection
{...taskModule.additionalInformationSectionProps}
isFailedState={taskModule.isFailedState}
/>
)}
<AgentScript
{...taskModule.scriptedTextProps}
isFailedState={taskModule.isFailedState}
/>
<OutcomeForm
{...taskModule.outcomeProps}
isFailedState={taskModule.isFailedState}
/>
</>
)}
</CardContent>
<CardActions className={classes.panelFooter}>
<SQFormButton type="reset" title="Reset Form">
{taskModule?.resetButtonText ?? 'Reset'}
</SQFormButton>
<SQFormButton
shouldRequireFieldUpdates={true}
isDisabled={
taskModule.isFailedState ||
taskModule?.isSubmitButtonDisabled ||
isSubmitting
}
>
{taskModule?.submitButtonText ?? 'Next'}
</SQFormButton>
</CardActions>
</Form>
)}
</Formik>
),
};
});
return (
<Section style={{padding: '20px', ...containerStyles}}>
<SectionHeader title={mainTitle} informativeHeading={mainSubtitle} />
<SectionBody>
<Accordion accordionPanels={transformedTaskModules} />
</SectionBody>
</Section>
);
}
Example #17
Source File: SQFormDialogStepper.tsx From SQForm with MIT License | 4 votes |
export function SQFormDialogStepper<Values extends FormikValues>({
cancelButtonText = 'Cancel',
children,
disableBackdropClick = false,
isOpen = false,
isNextDisabled = false,
maxWidth = 'sm',
onClose,
onSubmit,
title,
enableReinitialize = false,
muiGridProps = {},
dialogProps,
setValues,
fullWidth = true,
contentStyle,
initialValues,
...props
}: SQFormDialogStepperProps<Values>): JSX.Element {
const steps = children;
const [activeStep, setActiveStep] = React.useState(0);
const currentChild = steps[activeStep];
const [completed, setCompleted] = React.useState<number[]>([]);
const validationSchema = currentChild.props.validationSchema || null;
const classes = useStyles({steps});
const actionsClasses = useActionsStyles();
const stepperClasses = useStepperStyles();
const isLastStep = React.useMemo(() => {
return activeStep === steps.length - 1;
}, [activeStep, steps]);
const handleNext = () => {
setActiveStep(activeStep + 1);
setCompleted([...completed, activeStep]);
};
const handleStep = (step: number) => () => {
if (completed.includes(step)) {
setActiveStep(step);
}
};
const handleSubmit = async (
values: Values,
helpers: FormikHelpers<Values>
) => {
if (isLastStep) {
await onSubmit(values, helpers);
} else {
setValues && setValues(values);
handleNext();
}
};
function SubmitButton() {
const {errors, values, dirty} = useFormikContext<Record<string, unknown>>();
const isButtonDisabled = React.useMemo(() => {
if (isNextDisabled) {
return true;
}
if (!validationSchema) {
return false;
}
const currentStepKeys = Object.keys(validationSchema.fields);
const stepValues = currentStepKeys.every((step) => {
return !!values[step];
});
if (
!stepValues ||
currentStepKeys.some((step) => Object.keys(errors).includes(step)) ||
!dirty
) {
return true;
}
return false;
}, [errors, values, dirty]);
const primaryButtonText = isLastStep ? 'Submit' : 'Next';
return (
<RoundedButton
type="submit"
isDisabled={isButtonDisabled}
title={primaryButtonText}
>
{primaryButtonText}
</RoundedButton>
);
}
const handleClose = (
event: Record<string, unknown>,
reason: 'backdropClick' | 'escapeKeyDown' | 'cancelClick'
) => {
if (disableBackdropClick && reason === 'backdropClick') {
return;
}
onClose(event, reason);
};
return (
<Formik
{...props}
validationSchema={validationSchema}
onSubmit={handleSubmit}
initialValues={initialValues}
enableReinitialize={enableReinitialize}
>
{() => (
<Dialog
TransitionComponent={Transition}
disableBackdropClick={disableBackdropClick}
maxWidth={maxWidth}
open={isOpen}
onClose={handleClose}
fullWidth={fullWidth}
{...dialogProps}
>
<Form>
<DialogTitle disableTypography={true}>
<Typography variant="h4">{title}</Typography>
</DialogTitle>
<Divider />
{steps.length > 1 && (
<Grid container classes={stepperClasses}>
<Stepper
activeStep={activeStep}
classes={classes}
alternativeLabel={true}
>
{steps.map((child, index) => (
<Step key={`${child.props.label}-${index}`}>
<StepButton onClick={handleStep(index)}>
<Typography
variant="overline"
color={index === activeStep ? 'error' : 'initial'} // sets the color to orange if current step
>
{child?.props.label}
</Typography>
</StepButton>
</Step>
))}
</Stepper>
</Grid>
)}
<DialogContent
dividers
style={{
paddingTop: '40px',
paddingBottom: '40px',
...contentStyle,
}}
>
<Grid
{...muiGridProps}
container
spacing={muiGridProps.spacing ?? 3}
justifyContent="center"
>
{currentChild}
</Grid>
</DialogContent>
<DialogActions classes={actionsClasses}>
<RoundedButton
title={cancelButtonText}
onClick={onClose}
color="secondary"
variant="outlined"
>
{cancelButtonText}
</RoundedButton>
<SubmitButton />
</DialogActions>
</Form>
</Dialog>
)}
</Formik>
);
}
Example #18
Source File: SQFormDialogInner.tsx From SQForm with MIT License | 4 votes |
function SQFormDialogInner<Values extends FormikValues>({
cancelButtonText,
children,
disableBackdropClick,
isDisabled = false,
isOpen,
maxWidth,
onClose,
saveButtonText,
tertiaryButtonText,
shouldRequireFieldUpdates = false,
title,
muiGridProps,
shouldDisplaySaveButton = true,
showSecondaryButton = true,
tertiaryStatus = 'HIDE_BUTTON',
onTertiaryClick,
tertiaryButtonVariant,
}: SQFormDialogInnerProps<Values>): React.ReactElement {
const theme = useTheme();
const titleClasses = useTitleStyles(theme);
const actionsClasses = useActionsStyles(theme);
const primaryActionsClasses = usePrimaryActionStyles(theme);
const dialogContentClasses = useDialogContentStyles(theme);
const formikContext = useFormikContext<Values>();
function getIsDisabled() {
switch (tertiaryStatus) {
case 'IS_DISABLED':
return true;
case 'FORM_VALIDATION_ONLY':
return !formikContext.isValid;
default:
return false;
}
}
const {
isDialogOpen: isDialogAlertOpen,
openDialog: openDialogAlert,
closeDialog: closeDialogAlert,
} = useDialog();
const handleCancel = (
event: Record<string, unknown>,
reason: 'backdropClick' | 'escapeKeyDown' | 'cancelClick'
) => {
if (disableBackdropClick && reason === 'backdropClick') {
return;
}
if (!formikContext.dirty) {
onClose && onClose(event, reason);
} else {
openDialogAlert();
}
};
const confirmCancel = () => {
formikContext.resetForm();
onClose && onClose({}, 'escapeKeyDown');
closeDialogAlert();
};
const renderTertiaryButton = () => {
return (
<Grid
container={true}
justifyContent={showSecondaryButton ? 'space-between' : 'flex-end'}
>
{showSecondaryButton && (
<Grid item={true}>
<RoundedButton
title={cancelButtonText}
onClick={(event: Record<string, unknown>) =>
handleCancel(event, 'cancelClick')
}
color="secondary"
variant="outlined"
>
{cancelButtonText}
</RoundedButton>
</Grid>
)}
<Grid item={true}>
<span style={{paddingRight: '20px'}}>
<RoundedButton
title={tertiaryButtonText}
isDisabled={getIsDisabled()}
onClick={() => onTertiaryClick?.(formikContext)}
type="button"
variant={tertiaryButtonVariant}
>
{tertiaryButtonText}
</RoundedButton>
</span>
{shouldDisplaySaveButton && (
<SQFormButton
title={saveButtonText}
isDisabled={isDisabled}
shouldRequireFieldUpdates={shouldRequireFieldUpdates}
>
{saveButtonText}
</SQFormButton>
)}
</Grid>
</Grid>
);
};
return (
<>
<Dialog
maxWidth={maxWidth}
open={isOpen}
TransitionComponent={Transition}
onClose={
showSecondaryButton || disableBackdropClick ? handleCancel : undefined
}
>
<Form>
<DialogTitle disableTypography={true} classes={titleClasses}>
<Typography variant="h4">{title}</Typography>
</DialogTitle>
<DialogContent classes={dialogContentClasses}>
<Grid
{...muiGridProps}
container
spacing={muiGridProps?.spacing ?? 2}
>
{children}
</Grid>
</DialogContent>
<DialogActions
classes={
showSecondaryButton ? actionsClasses : primaryActionsClasses
}
>
{tertiaryStatus !== 'HIDE_BUTTON'
? renderTertiaryButton()
: showSecondaryButton && (
<RoundedButton
title={cancelButtonText}
onClick={(event: Record<string, unknown>) =>
handleCancel(event, 'cancelClick')
}
color="secondary"
variant="outlined"
>
{cancelButtonText}
</RoundedButton>
)}
{tertiaryStatus === 'HIDE_BUTTON' && shouldDisplaySaveButton && (
<SQFormButton
title={saveButtonText}
isDisabled={isDisabled}
shouldRequireFieldUpdates={shouldRequireFieldUpdates}
>
{saveButtonText}
</SQFormButton>
)}
</DialogActions>
</Form>
</Dialog>
<DialogAlert
isOpen={isDialogAlertOpen}
primaryButtonText="Continue"
secondaryButtonText="Go Back"
onPrimaryButtonClick={confirmCancel}
onSecondaryButtonClick={closeDialogAlert}
title={`Cancel Changes`}
>
You currently have unsaved changes which will be lost if you continue.
</DialogAlert>
</>
);
}
Example #19
Source File: EditHabitModal.tsx From nyxo-app with GNU General Public License v3.0 | 4 votes |
EditHabitModal = () => {
const show = useAppSelector(({ modal }) => modal.editHabit)
const habit = useAppSelector(getDraftEditHabit)
const dispatch = useAppDispatch()
if (!habit) return null
const {
title = '',
description = '',
period = Period.morning,
dayStreak = 0,
longestDayStreak = 0
} = habit
const closeModal = () => {
dispatch(toggleEditHabitModal(false))
}
const submitHabitChange = ({
title: newTitle,
description: newDescription,
period: newPeriod
}: FormikValues) => {
dispatch(
editHabitThunk(newTitle, newDescription, newPeriod, habit as Habit)
)
dispatch(toggleEditHabitModal(false))
}
return (
<StyledModal
hideModalContentWhileAnimating
isVisible={show}
useNativeDriver>
<Formik
validateOnMount
initialValues={{
title,
description,
period
}}
validationSchema={HabitSchema}
onSubmit={submitHabitChange}>
{({ handleChange, handleSubmit, handleBlur, values, isValid }) => (
<>
<Container>
<HabitModalTopRow
closeModal={closeModal}
saveModal={handleSubmit}
isValid={isValid}
formattedTitle={title}
/>
<ScrollView>
<HabitModalStreak
dayStreak={dayStreak}
longestDayStreak={longestDayStreak}
/>
<HabitModalFieldSection
handleChangeText={handleChange('title')}
onBlur={handleBlur('title')}
indicatorText="HABIT.TITLE_FIELD_INDICATOR"
placeholder="HABIT.TITLE_PLACEHOLDER"
inputMaxLength={titleMaxLength}
value={values.title}
isTitle
/>
<HabitModalFieldSection
handleChangeText={handleChange('description')}
onBlur={handleBlur('description')}
indicatorText="HABIT.DESCRIPTION_FIELD_INDICATOR"
placeholder="HABIT.DESCRIPTION_PLACEHOLDER"
inputMaxLength={descriptionMaxLength}
value={revertLineBreaks(values.description)}
isTitle={false}
/>
<HabitModalTimeSection
period={values.period}
setPeriod={handleChange('period')}
/>
</ScrollView>
</Container>
</>
)}
</Formik>
</StyledModal>
)
}