formik#FormikHelpers TypeScript Examples
The following examples show how to use
formik#FormikHelpers.
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: SQFormScrollableCardsMenuWrapper.stories.tsx From SQForm with MIT License | 7 votes |
function ScrollableDetails(): React.ReactElement {
const initialValues = {
name: '',
};
const validationSchema = Yup.object({
name: Yup.string().required().min(12),
});
const handleSubmit = (
values: typeof initialValues,
formikHelpers: FormikHelpers<typeof initialValues>
) => {
window.alert(JSON.stringify(values, null, 2));
formikHelpers.setSubmitting(false);
formikHelpers.resetForm();
};
return (
<SQFormScrollableCard
isHeaderDisabled={true}
isSelfBounding={true}
initialValues={initialValues}
onSubmit={handleSubmit}
shouldRequireFieldUpdates={true}
validationSchema={validationSchema}
>
<SQFormTextField name="name" label="Name" size={12} />
</SQFormScrollableCard>
);
}
Example #2
Source File: SQFormScrollableCardsMenuWrapper.stories.tsx From SQForm with MIT License | 7 votes |
function ScrollablePermissions(): React.ReactElement {
const initialValues = {
isAdmin: false,
};
const validationSchema = Yup.object({
isAdmin: Yup.boolean(),
});
const handleSubmit = (
values: typeof initialValues,
formikHelpers: FormikHelpers<typeof initialValues>
) => {
window.alert(JSON.stringify(values, null, 2));
formikHelpers.setSubmitting(false);
formikHelpers.resetForm();
};
return (
<SQFormScrollableCard
isHeaderDisabled={true}
isSelfBounding={true}
initialValues={initialValues}
onSubmit={handleSubmit}
shouldRequireFieldUpdates={true}
validationSchema={validationSchema}
>
<SQFormCheckbox name="isAdmin" label="Admin" size={12} />
</SQFormScrollableCard>
);
}
Example #3
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 #4
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 #5
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 #6
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 #7
Source File: AvailableSubnetsControl.tsx From assisted-ui-lib with Apache License 2.0 | 6 votes |
useAutoSelectSingleAvailableSubnet = (
hasNoMachineNetworks: boolean,
setFieldValue: FormikHelpers<NetworkConfigurationValues>['setFieldValue'],
cidr: MachineNetwork['cidr'],
clusterId: string,
) => {
useEffect(() => {
if (hasNoMachineNetworks) {
setFieldValue('machineNetworks', [{ cidr, clusterId }], true);
}
}, [hasNoMachineNetworks, cidr, clusterId, setFieldValue]);
}
Example #8
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 #9
Source File: SingleInputForm.tsx From bada-frame with GNU General Public License v3.0 | 5 votes |
export default function SingleInputForm(props: Props) {
const [loading, SetLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const submitForm = async (
values: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
SetLoading(true);
await props.callback(values.passphrase, setFieldError);
SetLoading(false);
};
return (
<Formik<formValues>
initialValues={{ passphrase: '' }}
onSubmit={submitForm}
validationSchema={Yup.object().shape({
passphrase: Yup.string().required(constants.REQUIRED),
})}
validateOnChange={false}
validateOnBlur={false}>
{({ values, touched, errors, handleChange, handleSubmit }) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group>
<Group>
<Form.Control
type={showPassword ? 'text' : props.fieldType}
placeholder={props.placeholder}
value={values.passphrase}
onChange={handleChange('passphrase')}
isInvalid={Boolean(
touched.passphrase && errors.passphrase
)}
disabled={loading}
autoFocus
/>
{props.fieldType === 'password' && (
<Button
type="button"
onClick={() =>
setShowPassword(!showPassword)
}>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
</Button>
)}
<Form.Control.Feedback type="invalid">
{errors.passphrase}
</Form.Control.Feedback>
</Group>
</Form.Group>
<SubmitButton
buttonText={props.buttonText}
loading={loading}
/>
<br />
</Form>
)}
</Formik>
);
}
Example #10
Source File: UpdateBirthdayModal.tsx From frontend with MIT License | 5 votes |
function UpdateBirthdayModal({
isOpen,
handleClose,
person,
}: {
isOpen: boolean
handleClose: (data?: Person) => void
person: UpdatePerson
}) {
const { t } = useTranslation()
const dateBefore18Years = new Date(new Date().setFullYear(new Date().getFullYear() - 18))
const initialValues: BirthdayFormData = {
birthday: format(new Date(person.birthday ?? dateBefore18Years), formatString),
}
const mutation = useMutation<AxiosResponse<Person>, AxiosError<ApiErrors>, UpdatePerson>({
mutationFn: updateCurrentPerson(),
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.success'), 'success'),
})
const onSubmit = async (
values: BirthdayFormData,
{ setFieldError }: FormikHelpers<BirthdayFormData>,
) => {
try {
const birthDate = new Date(values?.birthday)
await mutation.mutateAsync({ ...person, birthday: birthDate }).then((data) => {
handleClose(data.data)
})
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<StyledModal
open={isOpen}
onClose={() => handleClose()}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description">
<Box className={classes.modal}>
<IconButton className={classes.close} onClick={() => handleClose()}>
<CloseIcon />
</IconButton>
<h2>Обнови рожден ден</h2>
<GenericForm<BirthdayFormData>
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12} sm={8}>
<FormTextField
type="date"
name="birthday"
label="Кога е твоят рожден ден?"
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={6}>
<SubmitButton fullWidth />
</Grid>
</Grid>
</GenericForm>
</Box>
</StyledModal>
)
}
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: SQForm.stories.tsx From SQForm with MIT License | 5 votes |
handleSubmit = <TValues extends unknown>(
values: TValues,
actions: FormikHelpers<TValues>
) => {
window.alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
actions.resetForm();
}
Example #13
Source File: DiscoveryImageForm.tsx From assisted-ui-lib with Apache License 2.0 | 5 votes |
DiscoveryImageForm: React.FC<DiscoveryImageFormProps> = ({
cluster,
onCancel,
onSuccess,
}) => {
const { infraEnv, error: infraEnvError, isLoading } = useInfraEnv(cluster.id);
const cancelSourceRef = React.useRef<CancelTokenSource>();
const dispatch = useDispatch();
const ocmPullSecret = usePullSecret();
React.useEffect(() => {
cancelSourceRef.current = Axios.CancelToken.source();
return () => cancelSourceRef.current?.cancel('Image generation cancelled by user.');
}, []);
const handleCancel = () => {
dispatch(forceReload());
onCancel();
};
const handleSubmit = async (
formValues: DiscoveryImageFormValues,
formikActions: FormikHelpers<DiscoveryImageFormValues>,
) => {
if (cluster.id && infraEnv?.id) {
try {
const { updatedCluster } = await DiscoveryImageFormService.update(
cluster.id,
infraEnv.id,
cluster.kind,
formValues,
ocmPullSecret,
);
onSuccess();
dispatch(updateCluster(updatedCluster));
} catch (error) {
handleApiError(error, () => {
formikActions.setStatus({
error: {
title: 'Failed to download the discovery Image',
message: getErrorMessage(error),
},
});
});
}
}
};
if (isLoading) {
return <LoadingState></LoadingState>;
} else if (infraEnvError) {
return <ErrorState></ErrorState>;
}
return (
<DiscoveryImageConfigForm
onCancel={handleCancel}
handleSubmit={handleSubmit}
sshPublicKey={infraEnv?.sshAuthorizedKey}
httpProxy={infraEnv?.proxy?.httpProxy}
httpsProxy={infraEnv?.proxy?.httpsProxy}
noProxy={infraEnv?.proxy?.noProxy}
imageType={infraEnv?.type}
/>
);
}
Example #14
Source File: AdditionalNTPSourcesDialog.tsx From assisted-ui-lib with Apache License 2.0 | 4 votes |
AdditionalNTPSourcesForm: React.FC<AdditionalNTPSourcesFormProps> = ({
additionalNtpSource,
onClose,
onAdditionalNtpSource,
}) => {
const initialValues: V2ClusterUpdateParams = {
additionalNtpSource: additionalNtpSource || '',
};
const validationSchema = Yup.object().shape({
additionalNtpSource: ntpSourceValidationSchema.required(),
});
const handleSubmit = async (
values: V2ClusterUpdateParams,
formikHelpers: FormikHelpers<V2ClusterUpdateParams>,
) => {
formikHelpers.setStatus({ error: null });
if (onAdditionalNtpSource && values.additionalNtpSource) {
const onError = (message: string) =>
formikHelpers.setStatus({
error: {
title: 'Failed to add NTP sources',
message,
},
});
onAdditionalNtpSource(values.additionalNtpSource, onError);
}
onClose();
};
return (
<Formik
initialValues={initialValues}
initialTouched={{ additionalNtpSource: true }}
initialStatus={{ error: null }}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({ submitForm, status, setStatus, isSubmitting, isValid, dirty }) => {
return (
<>
<ModalBoxBody>
<Form>
{status.error && (
<Alert
variant={AlertVariant.danger}
title={status.error.title}
actionClose={
<AlertActionCloseButton onClose={() => setStatus({ error: null })} />
}
isInline
>
{status.error.message}
</Alert>
)}
<AdditionalNTPSourcesField
name="additionalNtpSource"
label="Additional NTP Sources"
helperText="A comma separated list of IP or domain names of the NTP pools or servers. Additional NTP sources are added to all hosts to ensure all hosts clocks are synchronized with a valid NTP server. It may take a few minutes for the new NTP sources to sync."
isRequired
/>
</Form>
</ModalBoxBody>
<ModalBoxFooter>
<Button
key="submit"
onClick={submitForm}
isDisabled={isSubmitting || !isValid || !dirty}
isLoading={isSubmitting}
>
{isSubmitting ? 'Adding...' : 'Add'}
</Button>
<Button key="cancel" variant="link" onClick={onClose}>
Cancel
</Button>
</ModalBoxFooter>
</>
);
}}
</Formik>
);
}
Example #15
Source File: ClusterDetailsForm.tsx From assisted-ui-lib with Apache License 2.0 | 4 votes |
ClusterDetailsForm: React.FC<ClusterDetailsFormProps> = (props) => {
const {
cluster,
infraEnv,
pullSecret,
managedDomains,
ocpVersions,
usedClusterNames = [],
moveNext,
handleClusterUpdate,
handleClusterCreate,
navigation,
} = props;
const featureSupportLevels = useFeatureSupportLevel();
const handleSubmit = React.useCallback(
async (values: OcmClusterDetailsValues) => {
const params = ClusterDetailsService.getClusterCreateParams(values);
if (cluster) {
await handleClusterUpdate(cluster.id, params);
} else {
await handleClusterCreate(params);
}
},
[cluster, handleClusterCreate, handleClusterUpdate],
);
const handleOnNext = (
dirty: boolean,
submitForm: FormikHelpers<unknown>['submitForm'],
cluster?: Cluster,
): (() => Promise<void> | void) => {
if (!dirty && !isUndefined(cluster) && canNextClusterDetails({ cluster })) {
return moveNext;
}
return submitForm;
};
const initialValues = React.useMemo(
() =>
ClusterDetailsService.getClusterDetailsInitialValues({
infraEnv,
cluster,
pullSecret,
managedDomains,
ocpVersions,
}),
[cluster, pullSecret, managedDomains, ocpVersions, infraEnv],
);
const validationSchema = getClusterDetailsValidationSchema({
usedClusterNames,
featureSupportLevels,
pullSecretSet: cluster?.pullSecretSet,
ocpVersions,
isOcm: true,
});
return (
<Formik
initialValues={initialValues}
validate={getRichTextValidation(validationSchema)}
onSubmit={handleSubmit}
>
{({ submitForm, isSubmitting, isValid, dirty, setFieldValue, errors, touched }) => {
const errorFields = getFormikErrorFields(errors, touched);
const toggleRedHatDnsService = (checked: boolean) =>
setFieldValue('baseDnsDomain', checked ? managedDomains.map((d) => d.domain)[0] : '');
const form = (
<>
<Grid hasGutter>
<GridItem>
<ClusterWizardStepHeader
extraItems={<ClusterWizardHeaderExtraActions cluster={cluster} />}
>
Cluster details
</ClusterWizardStepHeader>
</GridItem>
<GridItem span={12} lg={10} xl={9} xl2={7}>
<OcmClusterDetailsFormFields
toggleRedHatDnsService={toggleRedHatDnsService}
versions={ocpVersions}
canEditPullSecret={!cluster?.pullSecretSet}
forceOpenshiftVersion={cluster?.openshiftVersion}
defaultPullSecret={pullSecret}
isOcm={!!ocmClient}
managedDomains={managedDomains}
isPullSecretSet={cluster?.pullSecretSet ? cluster.pullSecretSet : false}
clusterExists={!!cluster}
/>
</GridItem>
</Grid>
</>
);
const footer = (
<ClusterWizardFooter
cluster={cluster}
errorFields={errorFields}
isSubmitting={isSubmitting}
isNextDisabled={
!(
!isSubmitting &&
isValid &&
(dirty || (cluster && canNextClusterDetails({ cluster })))
)
}
onNext={handleOnNext(dirty, submitForm, cluster)}
/>
);
return (
<ClusterWizardStep navigation={navigation} footer={footer}>
{form}
</ClusterWizardStep>
);
}}
</Formik>
);
}
Example #16
Source File: SupportForm.tsx From frontend with MIT License | 4 votes |
export default function SupportForm() {
const { t } = useTranslation()
const formRef = useRef<FormikProps<SupportFormData>>(null)
const [activeStep, setActiveStep] = useState<Steps>(Steps.ROLES)
const [failedStep, setFailedStep] = useState<Steps>(Steps.NONE)
const mutation = useMutation<
AxiosResponse<SupportRequestResponse>,
AxiosError<ApiErrors>,
SupportRequestInput
>({
mutationFn: createSupportRequest,
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
})
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1)
}
const handleSubmit = async (values: SupportFormData, actions: FormikHelpers<SupportFormData>) => {
if (isLastStep(activeStep, steps)) {
const errors = await actions.validateForm()
const hasErrors = !!Object.keys(errors).length
if (hasErrors) {
setFailedStep(Steps.PERSON)
return
}
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setFailedStep(Steps.NONE)
try {
const { person, ...supportData } = values
await mutation.mutateAsync({ person, supportData })
actions.resetForm()
if (window) {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
actions.setFieldError(property, t(matchValidator(constraints)))
})
}
}
return
}
actions.setTouched({})
actions.setSubmitting(false)
switch (activeStep) {
case Steps.ROLES:
{
const errors = await actions.validateForm()
if (errors.roles) {
setFailedStep(Steps.ROLES)
return
}
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setFailedStep(Steps.NONE)
}
break
case Steps.QUESTIONS:
{
const errors = await actions.validateForm()
let hasErrors = false
const questions = Object.entries(values.roles)
.filter(([, value]) => value)
.map(([key]) => key)
Object.keys(errors).forEach((error) => {
if (questions.includes(error)) {
hasErrors = true
}
})
if (hasErrors) {
setFailedStep(Steps.QUESTIONS)
return
}
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setFailedStep(Steps.NONE)
}
break
case Steps.PERSON:
{
const errors = await actions.validateForm()
if (errors.person) {
setFailedStep(Steps.PERSON)
return
}
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setFailedStep(Steps.NONE)
}
break
default:
return 'Unknown step'
}
}
const isStepFailed = (step: Steps | number): boolean => {
return step === failedStep
}
const isLastStep = (activeStep: number, steps: StepType[]): boolean => {
return activeStep === steps.length - 2
}
const isThankYouStep = (activeStep: number, steps: StepType[]): boolean => {
return activeStep === steps.length - 1
}
return (
<GenericForm<SupportFormData>
onSubmit={handleSubmit}
initialValues={initialValues}
validationSchema={validationSchema[activeStep]}
innerRef={formRef}>
<Hidden mdDown>
<Stepper
alternativeLabel
activeStep={activeStep}
connector={<StepConnector sx={{ mt: 1.5 }} />}>
{steps.map((step, index) => (
<Step key={index}>
<StepLabel error={isStepFailed(index)} StepIconComponent={StepIcon}>
{t(step.label)}
</StepLabel>
</Step>
))}
</Stepper>
</Hidden>
{isThankYouStep(activeStep, steps) ? (
steps[activeStep].component
) : (
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Grid container justifyContent="center">
<Grid item xs={12} sx={{ mt: 1, mb: 5 }}>
{steps[activeStep].component}
</Grid>
<Grid item xs={12} sx={(theme) => ({ '& button': { minWidth: theme.spacing(12) } })}>
<Actions
disableBack={activeStep === 0}
onBack={handleBack}
loading={mutation.isLoading}
nextLabel={
isLastStep(activeStep, steps) ? 'support:cta.submit' : 'support:cta.next'
}
/>
</Grid>
</Grid>
</Box>
)}
</GenericForm>
)
}
Example #17
Source File: AddBenefactorForm.tsx From frontend with MIT License | 4 votes |
export default function AddBenefactorForm({ initialValues = defaults }: BenefactorFormProps) {
const { t } = useTranslation('benefactor')
const mutation = useMutation<
AxiosResponse<BenefactorResponse>,
AxiosError<ApiErrors>,
BenefactorInput
>({
mutationFn: createBenefactor,
onError: () => AlertStore.show(t('alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('alerts.create'), 'success'),
})
const router = useRouter()
const onSubmit = async (
values: BenefactorFormData,
{ setFieldError, resetForm }: FormikHelpers<BenefactorFormData>,
) => {
try {
const data = {
// id: values.id,
extCustomerId: values.extCustomerId,
// createdAt: values.createdAt,
// updatedAt: values.updatedAt,
person: values.person,
}
await mutation.mutateAsync(data)
resetForm()
router.push(routes.admin.benefactor.index)
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid
container
direction="column"
component="section"
sx={{
maxWidth: '700px',
margin: '0 auto',
}}>
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Box sx={{ marginTop: '5%', height: '62.6vh' }}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h6">{t('form-heading')}</Typography>
</Grid>
{/* <Grid item xs={12} sm={4}>
<FormTextField
type="text"
label="auth:fields.id"
name="id"
autoComplete="id"
/>
</Grid> */}
<Grid item xs={12} sm={4}>
<FormTextField
type="text"
label={t('customerId')}
name="extCustomerId"
autoComplete="extCustomerId"
/>
</Grid>
<Grid item xs={12} sm={4}>
<FormTextField
type="text"
label={t('personId')}
name="person"
autoComplete="person"
/>
</Grid>
<Grid item xs={12}>
<SubmitButton fullWidth label={t('cta.submit')} />
</Grid>
<Grid item xs={6}>
<Link href={routes.admin.benefactor.index}>
<Button>{t('cta.cancel')}</Button>
</Link>
</Grid>
</Grid>
</Box>
</GenericForm>
</Grid>
)
}
Example #18
Source File: AddHostModal.tsx From assisted-ui-lib with Apache License 2.0 | 4 votes |
AddHostModal: React.FC<AddHostModalProps> = ({
isOpen,
onClose,
infraEnv,
agentClusterInstall,
onCreateBMH,
onSaveISOParams,
usedHostnames,
isBMPlatform,
}) => {
const hasDHCP = infraEnv.metadata?.labels?.networkType !== 'static';
const sshPublicKey = infraEnv.spec?.sshAuthorizedKey || agentClusterInstall?.spec?.sshPublicKey;
const { httpProxy, httpsProxy, noProxy } = infraEnv.spec?.proxy || {};
const areIsoDataAvailable = !!sshPublicKey || !!httpProxy || !!httpsProxy || !!noProxy;
const isoDialog = areIsoDataAvailable ? 'iso-download' : 'iso-config';
const [dialogType, setDialogType] = React.useState<AddHostModalStepType>(isoDialog);
const handleIsoConfigSubmit = async (
values: DiscoveryImageFormValues,
formikActions: FormikHelpers<DiscoveryImageFormValues>,
) => {
try {
await onSaveISOParams(values);
setDialogType('iso-download');
} catch (error) {
formikActions.setStatus({
error: {
title: 'Failed to download the discovery Image',
message: error, // TODO(mlibra): parse it better!!
},
});
}
};
return (
<Modal
aria-label="Add host dialog"
title="Add host"
isOpen={isOpen}
onClose={onClose}
variant={ModalVariant.small}
hasNoBodyWrapper
id="add-host-modal"
>
<ModalBoxHeader>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem>
<Radio
id="iso"
name="type"
label="Discovery ISO"
isChecked={dialogType !== 'bmc'}
onChange={(checked) => setDialogType(checked ? isoDialog : 'bmc')}
/>
</FlexItem>
<FlexItem spacer={{ default: isBMPlatform ? 'spacerXl' : 'spacerSm' }} />
<FlexItem>
<Tooltip
hidden={isBMPlatform}
content="To enable the host’s baseboard management controller (BMC) on the hub cluster,deploy the hub cluster on vSphere, BareMetal, OpenStack, or platform-agnostic (none type)."
>
<Radio
id="bmc"
name="type"
label="Baseboard Management Controller (BMC)"
isChecked={dialogType === 'bmc'}
onChange={(checked) => setDialogType(checked ? 'bmc' : isoDialog)}
isDisabled={!isBMPlatform}
/>
</Tooltip>
</FlexItem>
</Flex>
</ModalBoxHeader>
{dialogType === 'iso-config' && (
<DiscoveryImageConfigForm
onCancel={onClose}
handleSubmit={handleIsoConfigSubmit}
hideDiscoveryImageType={true} // So far configured by env variable on backend
imageType="full-iso" // So far the only option for CIM
sshPublicKey={sshPublicKey}
httpProxy={httpProxy}
httpsProxy={httpsProxy}
noProxy={noProxy}
hasDHCP={hasDHCP}
/>
)}
{dialogType === 'iso-download' && (
<DownloadIso
onClose={onClose}
downloadUrl={infraEnv?.status?.isoDownloadURL}
onReset={() => setDialogType('iso-config')}
hasDHCP={hasDHCP}
/>
)}
{dialogType === 'bmc' && (
<BMCForm
onCreateBMH={onCreateBMH}
onClose={onClose}
hasDHCP={hasDHCP}
infraEnv={infraEnv}
usedHostnames={usedHostnames}
/>
)}
</Modal>
);
}
Example #19
Source File: EditBenefactorForm.tsx From frontend with MIT License | 4 votes |
export default function EditBenefactorForm({ id, initialValues = defaults }: BenefactorFormProps) {
const { t } = useTranslation('benefactor')
const mutation = useMutation<
AxiosResponse<BenefactorResponse>,
AxiosError<ApiErrors>,
EditBenefactorProp
>({
mutationFn: editBenefactor,
onError: () => AlertStore.show(t('alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('alerts.create'), 'success'),
})
const router = useRouter()
const onSubmit = async (
values: BenefactorFormData,
{ setFieldError }: FormikHelpers<BenefactorFormData>,
) => {
try {
const data = {
extCustomerId: values.extCustomerId,
person: values.person,
}
await mutation.mutateAsync({
id,
data,
})
router.push(routes.admin.benefactor.index)
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid
container
direction="column"
component="section"
sx={{
maxWidth: '700px',
margin: '0 auto',
padding: '30px',
textAlign: 'center',
}}>
<GenericForm
enableReinitialize={true}
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Box sx={{ marginTop: '5%', height: '62.6vh' }}>
<Typography variant="h5" component="h2" sx={{ marginBottom: 2, textAlign: 'center' }}>
{t('edit-form-heading')}
</Typography>
<Grid container spacing={2} sx={{ width: 600, margin: '0 auto' }}>
<Grid item xs={12} />
<Grid item xs={12} sm={4}>
<FormTextField
type="text"
label={t('customerId')}
name="extCustomerId"
autoComplete="extCustomerId"
/>
</Grid>
<Grid item xs={12} sm={4}>
<FormTextField
type="text"
label={t('personId')}
name="person"
autoComplete="personId"
/>
</Grid>
<Grid item xs={6}>
<Button fullWidth variant="contained" type="submit" color="secondary">
{t('cta.submit')}
</Button>
</Grid>
<Grid item xs={6}>
<LinkButton
fullWidth
variant="contained"
color="primary"
href={routes.admin.benefactor.index}>
{t('cta.cancel')}
</LinkButton>
</Grid>
</Grid>
</Box>
</GenericForm>
</Grid>
)
}
Example #20
Source File: CampaignForm.tsx From frontend with MIT License | 4 votes |
export default function CampaignForm({ initialValues = defaults }: CampaignFormProps) {
const { t } = useTranslation()
const router = useRouter()
const [coordinator, setCoordinator] = useState<PersonFormData>()
const [beneficiary, setBeneficiary] = useState<PersonFormData>()
const [files, setFiles] = useState<File[]>([])
const [roles, setRoles] = useState<FileRole[]>([])
const mutation = useMutation<
AxiosResponse<CampaignResponse>,
AxiosError<ApiErrors>,
CampaignInput
>({
mutationFn: useCreateCampaign(),
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
})
const fileUploadMutation = useMutation<
AxiosResponse<CampaignUploadImage[]>,
AxiosError<ApiErrors>,
UploadCampaignFiles
>({
mutationFn: useUploadCampaignFiles(),
})
const onSubmit = async (
values: CampaignFormData,
{ setFieldError, resetForm }: FormikHelpers<CampaignFormData>,
) => {
try {
const response = await mutation.mutateAsync({
title: values.title,
slug: createSlug(values.title),
description: values.description,
targetAmount: values.targetAmount,
allowDonationOnComplete: values.allowDonationOnComplete,
startDate: values.startDate,
endDate: values.endDate,
essence: '',
campaignTypeId: values.campaignTypeId,
beneficiaryId: values.beneficiaryId,
coordinatorId: values.coordinatorId,
currency: Currency.BGN,
})
await fileUploadMutation.mutateAsync({
files,
roles,
campaignId: response.data.id,
})
resetForm()
router.push(routes.campaigns.viewCampaignBySlug(response.data.slug))
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid container direction="column" component="section">
<Grid item xs={12}>
<Typography
variant="h5"
component="h2"
sx={(theme) => ({
mb: 5,
color: theme.palette.primary.dark,
textAlign: 'center',
})}>
{t('campaigns:form-heading')}
</Typography>
</Grid>
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12}>
<FormTextField
type="text"
label="campaigns:campaign.title"
name="title"
autoComplete="title"
/>
</Grid>
<Grid item xs={12} sm={6}>
<CampaignTypeSelect />
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="number"
name="targetAmount"
autoComplete="target-amount"
label="campaigns:campaign.amount"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="startDate"
label="campaigns:campaign.start-date"
helperText={null}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="endDate"
label="campaigns:campaign.end-date"
helperText={null}
/>
</Grid>
<Grid item xs={12}>
<FormTextField
rows={5}
multiline
type="text"
name="description"
label="campaigns:campaign.description"
autoComplete="description"
sx={{ '& textarea': { resize: 'vertical' } }}
/>
</Grid>
<Grid item xs={12} sm={6}>
{coordinator ? (
<Typography fontWeight="bold" variant="body2">
{coordinator?.firstName} {coordinator?.lastName}
</Typography>
) : (
<PersonDialog
type="coordinator"
label={t('campaigns:campaign.coordinator.add')}
onSubmit={async (values: PersonFormData) => {
setCoordinator(values)
console.log('new coordinator', { values })
}}
/>
)}
<input type="hidden" name="coordinatorId" />
</Grid>
<Grid item xs={12} sm={6}>
{beneficiary ? (
<Typography fontWeight="bold" variant="body2">
{beneficiary?.firstName} {beneficiary?.lastName}
</Typography>
) : (
<PersonDialog
type="beneficiary"
label={t('campaigns:campaign.beneficiary.add')}
onSubmit={async (values: PersonFormData) => {
setBeneficiary(values)
console.log('new beneficiary', { values })
}}
/>
)}
<input type="hidden" name="beneficiaryId" />
</Grid>
<Grid item xs={12}>
<FileUpload
buttonLabel="Добави снимки"
onUpload={(newFiles) => {
setFiles((prevFiles) => [...prevFiles, ...newFiles])
setRoles((prevRoles) => [
...prevRoles,
...newFiles.map((file) => ({
file: file.name,
role: CampaignFileRole.background,
})),
])
}}
/>
<FileList
files={files}
filesRole={roles}
onDelete={(deletedFile) =>
setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
}
onSetFileRole={(file, role) => {
setRoles((filesRole) => [
...filesRole.filter((f) => f.file !== file.name),
{ file: file.name, role },
])
}}
/>
</Grid>
<Grid item xs={12}>
<AcceptTermsField name="terms" />
<AcceptPrivacyPolicyField name="gdpr" />
</Grid>
<Grid item xs={12}>
<SubmitButton
fullWidth
label="campaigns:cta.submit"
loading={mutation.isLoading}
color="info"
/>
</Grid>
</Grid>
</GenericForm>
</Grid>
)
}
Example #21
Source File: CreateForm.tsx From frontend with MIT License | 4 votes |
export default function CampaignForm({ initialValues = defaults }: CampaignFormProps) {
const router = useRouter()
const [files, setFiles] = useState<File[]>([])
const [roles, setRoles] = useState<FileRole[]>([])
const { t } = useTranslation()
const mutation = useMutation<
AxiosResponse<CampaignResponse>,
AxiosError<ApiErrors>,
CampaignInput
>({
mutationFn: useCreateCampaign(),
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
})
const fileUploadMutation = useMutation<
AxiosResponse<CampaignUploadImage[]>,
AxiosError<ApiErrors>,
UploadCampaignFiles
>({
mutationFn: useUploadCampaignFiles(),
})
const onSubmit = async (
values: CampaignFormData,
{ setFieldError }: FormikHelpers<CampaignFormData>,
) => {
try {
const response = await mutation.mutateAsync({
title: values.title,
slug: createSlug(values.title),
description: values.description,
targetAmount: values.targetAmount,
allowDonationOnComplete: values.allowDonationOnComplete,
startDate: values.startDate,
endDate: values.endDate,
essence: '',
campaignTypeId: values.campaignTypeId,
beneficiaryId: values.beneficiaryId,
coordinatorId: values.coordinatorId,
currency: Currency.BGN,
})
await fileUploadMutation.mutateAsync({
files,
roles,
campaignId: response.data.id,
})
router.push(routes.admin.campaigns.index)
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid container direction="column" component="section">
<Grid item xs={12}>
<Typography
variant="h5"
component="h2"
sx={(theme) => ({
mb: 5,
color: theme.palette.primary.dark,
textAlign: 'center',
})}>
{t('campaigns:form-heading')}
</Typography>
</Grid>
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12}>
<FormTextField
type="text"
label="campaigns:campaign.title"
name="title"
autoComplete="title"
/>
</Grid>
<Grid item xs={12} sm={6}>
<CampaignTypeSelect />
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="number"
name="targetAmount"
autoComplete="target-amount"
label="campaigns:campaign.amount"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="startDate"
label="campaigns:campaign.start-date"
helperText={null}
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="endDate"
label="campaigns:campaign.end-date"
helperText={null}
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={12}>
<FormTextField
rows={5}
multiline
type="text"
name="description"
label="campaigns:campaign.description"
autoComplete="description"
sx={{ '& textarea': { resize: 'vertical' } }}
/>
</Grid>
<Grid item xs={12} sm={6}>
<BeneficiarySelect />
</Grid>
<Grid item xs={12} sm={6}>
<CoordinatorSelect />
</Grid>
<Grid item xs={12}>
<FileUpload
onUpload={(newFiles) => {
setFiles((prevFiles) => [...prevFiles, ...newFiles])
setRoles((prevRoles) => [
...prevRoles,
...newFiles.map((file) => ({
file: file.name,
role: CampaignFileRole.background,
})),
])
}}
buttonLabel="Добави документи"
/>
<FileList
filesRole={roles}
files={files}
onDelete={(deletedFile) =>
setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
}
onSetFileRole={(file, role) => {
setRoles((prevRoles) => [
...prevRoles.filter((f) => f.file !== file.name),
{ file: file.name, role },
])
}}
/>
</Grid>
<Grid item xs={12}>
<AcceptTermsField name="terms" />
<AcceptPrivacyPolicyField name="gdpr" />
</Grid>
<Grid item xs={12}>
<SubmitButton fullWidth label="campaigns:cta.submit" loading={mutation.isLoading} />
</Grid>
<Link href={routes.admin.campaigns.index} passHref>
<Button fullWidth={true}>{t('Отказ')}</Button>
</Link>
</Grid>
</GenericForm>
</Grid>
)
}
Example #22
Source File: EditForm.tsx From frontend with MIT License | 4 votes |
export default function EditForm({ campaign }: { campaign: CampaignResponse }) {
const router = useRouter()
const [files, setFiles] = useState<File[]>([])
const [roles, setRoles] = useState<FileRole[]>([])
const { t } = useTranslation()
const initialValues: EditFormData = {
title: campaign?.title || '',
coordinatorId: campaign.coordinatorId,
campaignTypeId: campaign.campaignTypeId,
beneficiaryId: campaign.beneficiaryId,
targetAmount: campaign.targetAmount || 0,
allowDonationOnComplete: campaign.allowDonationOnComplete || false,
startDate: format(new Date(campaign.startDate ?? new Date()), formatString),
endDate: format(new Date(campaign.endDate ?? new Date()), formatString),
description: campaign.description || '',
}
const mutation = useMutation<
AxiosResponse<CampaignResponse>,
AxiosError<ApiErrors>,
CampaignInput
>({
mutationFn: useEditCampaign(campaign.id),
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
})
const fileUploadMutation = useMutation<
AxiosResponse<CampaignUploadImage[]>,
AxiosError<ApiErrors>,
UploadCampaignFiles
>({
mutationFn: useUploadCampaignFiles(),
})
const onSubmit = async (values: EditFormData, { setFieldError }: FormikHelpers<EditFormData>) => {
try {
await mutation.mutateAsync({
title: values.title,
slug: createSlug(values.title),
description: values.description,
targetAmount: values.targetAmount,
allowDonationOnComplete: campaign.allowDonationOnComplete,
startDate: values.startDate,
endDate: values.endDate,
essence: campaign.essence,
campaignTypeId: values.campaignTypeId,
beneficiaryId: values.beneficiaryId,
coordinatorId: values.coordinatorId,
currency: Currency.BGN,
})
await fileUploadMutation.mutateAsync({
files,
roles,
campaignId: campaign.id,
})
router.push(routes.admin.campaigns.index)
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid container direction="column" component="section">
<Grid item xs={12}>
<Typography
variant="h5"
component="h2"
sx={(theme) => ({
mb: 5,
color: theme.palette.primary.dark,
textAlign: 'center',
})}>
{t('campaigns:edit-form-heading')}
</Typography>
</Grid>
<GenericForm<EditFormData>
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12}>
<FormTextField
type="text"
label="campaigns:campaign.title"
name="title"
autoComplete="title"
/>
</Grid>
<Grid item xs={12} sm={6}>
<CampaignTypeSelect />
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="number"
name="targetAmount"
autoComplete="target-amount"
label="campaigns:campaign.amount"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="startDate"
label="campaigns:campaign.start-date"
helperText={null}
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="date"
name="endDate"
label="campaigns:campaign.end-date"
helperText={null}
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={12}>
<FormTextField
rows={5}
multiline
type="text"
name="description"
label="campaigns:campaign.description"
autoComplete="description"
sx={{ '& textarea': { resize: 'vertical' } }}
/>
</Grid>
<Grid item xs={12} sm={6}>
<CoordinatorSelect />
</Grid>
<Grid item xs={12} sm={6}>
<BeneficiarySelect />
</Grid>
<Grid item xs={12}>
<FileUpload
buttonLabel="Добави документи"
onUpload={(newFiles) => {
setFiles((prevFiles) => [...prevFiles, ...newFiles])
setRoles((prevRoles) => [
...prevRoles,
...newFiles.map((file) => ({
file: file.name,
role: CampaignFileRole.background,
})),
])
}}
/>
<FileList
files={files}
filesRole={roles}
onDelete={(deletedFile) =>
setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
}
onSetFileRole={(file, role) => {
setRoles((filesRole) => [
...filesRole.filter((f) => f.file !== file.name),
{ file: file.name, role },
])
}}
/>
</Grid>
<Grid item xs={12}>
<SubmitButton fullWidth label="campaigns:cta.submit" loading={mutation.isLoading} />
<Link href={routes.admin.campaigns.index}>
<Button fullWidth={true}>{t('Отказ')}</Button>
</Link>
</Grid>
</Grid>
</GenericForm>
</Grid>
)
}
Example #23
Source File: ContactForm.tsx From frontend with MIT License | 4 votes |
export default function ContactForm({ initialValues = defaults }: ContactFormProps) {
const { t } = useTranslation()
const mutationFn = createContactRequest
const mutation = useMutation<
AxiosResponse<ContactRequestResponse>,
AxiosError<ApiErrors>,
ContactRequestInput
>({
mutationFn,
onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
})
const onSubmit = async (
values: ContactFormData,
{ setFieldError, resetForm }: FormikHelpers<ContactFormData>,
) => {
try {
await mutation.mutateAsync(values)
resetForm()
} catch (error) {
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid container direction="column" component="section">
<Grid item xs={12}>
<Typography
variant="h5"
component="h2"
sx={(theme) => ({
mb: 5,
color: theme.palette.primary.dark,
textAlign: 'center',
})}>
{t('contact:form-heading')}
</Typography>
</Grid>
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormTextField
type="text"
label="auth:fields.first-name"
name="firstName"
autoComplete="first-name"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="text"
label="auth:fields.last-name"
name="lastName"
autoComplete="family-name"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
inputMode="email"
type="text"
label="auth:fields.email"
name="email"
autoComplete="email"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
type="tel"
name="phone"
inputMode="tel"
autoComplete="tel"
label="auth:fields.phone"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
type="text"
name="company"
label="auth:fields.company"
autoComplete="organization"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
rows={4}
multiline
type="text"
name="message"
label="auth:fields.message"
sx={{ '& textarea': { resize: 'vertical' } }}
/>
</Grid>
<Grid item xs={12}>
<AcceptTermsField name="terms" />
<AcceptPrivacyPolicyField name="gdpr" />
</Grid>
<Grid item xs={12}>
<SubmitButton fullWidth label="auth:cta.send" loading={mutation.isLoading} />
</Grid>
</Grid>
</GenericForm>
</Grid>
)
}
Example #24
Source File: CountryForm.tsx From frontend with MIT License | 4 votes |
export default function CountryForm({ initialValues = defaults, id }: CountryFormProps) {
//if (id) -> edit form, else -> create form
const { t } = useTranslation('countries')
const createMutation = useMutation<
AxiosResponse<CountryResponse>,
AxiosError<ApiErrors>,
CountryInput
>({
mutationFn: useCreateCountry(),
onError: () => AlertStore.show(t('alerts.new-row.error'), 'error'),
onSuccess: () => AlertStore.show(t('alerts.new-row.success'), 'success'),
})
const editMutation = useMutation<
AxiosResponse<CountryResponse>,
AxiosError<ApiErrors>,
CountryEditInput
>({
mutationFn: useEditCountry(),
onError: () => AlertStore.show(t('alerts.edit-row.error'), 'error'),
onSuccess: () => AlertStore.show(t('alerts.edit-row.success'), 'success'),
})
const router = useRouter()
const onSubmit = async (
values: CountryInput,
{ setFieldError, resetForm }: FormikHelpers<CountryInput>,
) => {
try {
const data = {
name: values.name,
countryCode: values.countryCode.toLocaleUpperCase(),
}
if (id) {
await editMutation.mutateAsync({ id, data })
} else {
await createMutation.mutateAsync(data)
resetForm()
}
router.push(routes.admin.countries.index)
} catch (error) {
console.error(error)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<Grid
container
direction="column"
component="section"
sx={{
maxWidth: '700px',
margin: '80px auto 0 auto',
}}>
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Grid container spacing={3}>
<Grid item xs={12} sm={8}>
<FormTextField
type="text"
label="countries:fields.name"
name="name"
autoComplete="name"
/>
</Grid>
<Grid item xs={12} sm={4}>
<FormTextField
type="text"
label="countries:fields.country-code"
name="countryCode"
autoComplete="country-code"
/>
</Grid>
{id ? (
<>
<Grid item xs={6}>
<Button fullWidth variant="contained" type="submit" color="secondary">
{t('btns.save')}
</Button>
</Grid>
</>
) : (
<Grid item xs={6}>
<SubmitButton fullWidth label="countries:btns.add" />
</Grid>
)}
<Grid item xs={6}>
<LinkButton
fullWidth
variant="contained"
color="primary"
href={routes.admin.countries.index}>
{t('btns.cancel')}
</LinkButton>
</Grid>
</Grid>
</GenericForm>
</Grid>
)
}
Example #25
Source File: Form.tsx From frontend with MIT License | 4 votes |
export default function Form() {
const queryClient = useQueryClient()
const router = useRouter()
const { t } = useTranslation('expenses')
let id = router.query.id
let data: ExpenseResponse | undefined
if (id) {
id = String(id)
data = useViewExpense(id).data
}
const initialValues: ExpenseInput = {
type: data?.type || ExpenseType.none,
status: data?.status || ExpenseStatus.pending,
currency: data?.currency || Currency.BGN,
amount: data?.amount || 0,
vaultId: data?.vaultId || '',
deleted: data?.deleted || false,
description: data?.description || '',
documentId: data?.documentId || '',
approvedById: data?.approvedById || '',
}
const mutationFn = id ? useEditExpense(id) : useCreateExpense()
const mutation = useMutation<AxiosResponse<ExpenseResponse>, AxiosError<ApiErrors>, ExpenseInput>(
{
mutationFn,
onError: () =>
AlertStore.show(id ? t('alerts.edit-row.error') : t('alerts.new-row.error'), 'error'),
onSuccess: () => {
queryClient.invalidateQueries(endpoints.expenses.listExpenses.url)
router.push(routes.admin.expenses.index)
AlertStore.show(id ? t('alerts.edit-row.success') : t('alerts.new-row.success'), 'success')
},
},
)
async function onSubmit(data: ExpenseInput, { setFieldError }: FormikHelpers<ExpenseInput>) {
try {
if (data.documentId == '') {
data.documentId = null
}
if (data.approvedById == '') {
data.approvedById = null
}
mutation.mutateAsync(data)
} catch (error) {
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
return (
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Box sx={{ marginTop: '5%', height: '62.6vh' }}>
<Typography variant="h5" component="h2" sx={{ marginBottom: 2, textAlign: 'center' }}>
{id ? t('headings.edit') : t('headings.add')}
</Typography>
<Grid container spacing={2} sx={{ width: 600, margin: '0 auto' }}>
<Grid item xs={6}>
<ExpenseTypeSelect />
</Grid>
<Grid item xs={6}>
<ExpenseStatusSelect />
</Grid>
<Grid item xs={6}>
<FormTextField type="number" name="amount" label="expenses:fields.amount" />
</Grid>
<Grid item xs={6}>
<CurrencySelect />
</Grid>
<Grid item xs={6}>
<VaultSelect />
</Grid>
<Grid item xs={6}>
<DocumentSelect />
</Grid>
<Grid item xs={12}>
<FormTextField
type="string"
name="description"
label="expenses:fields.description"
multiline
rows={5}
/>
</Grid>
<Grid item xs={id ? 10 : 12}>
<PersonSelect name="approvedById" namespace="expenses" />
</Grid>
{id && (
<Grid item xs={2}>
<DeletedCheckbox />
</Grid>
)}
<Grid item xs={6}>
<SubmitButton fullWidth label={id ? 'expenses:btns.save' : 'expenses:btns.submit'} />
</Grid>
<Grid item xs={6}>
<LinkButton
fullWidth
variant="contained"
color="primary"
href={routes.admin.expenses.index}>
{t('btns.cancel')}
</LinkButton>
</Grid>
</Grid>
</Box>
</GenericForm>
)
}
Example #26
Source File: IrregularityForm.tsx From frontend with MIT License | 4 votes |
export default function IrregularityForm({ campaign, person }: Props) {
const { t } = useTranslation('irregularity')
const classes = useStyles()
const formRef = useRef<FormikProps<IrregularityFormData>>(null)
const [fail, setFail] = useState(false)
const [success, setSuccess] = useState(false)
const [files, setFiles] = useState<File[]>([])
const [activeStep, setActiveStep] = useState<Steps>(Steps.GREETING)
const [failedStep, setFailedStep] = useState<Steps>(Steps.NONE)
const steps: StepType[] = [
{
component: <Greeting />,
},
{
component: <Contacts />,
},
{
component: <Info files={files} setFiles={setFiles} />,
},
]
const isStepFailed = (step: Steps | number): boolean => {
return step === failedStep
}
const mutation = useMutation<
AxiosResponse<IrregularityResponse>,
AxiosError<ApiErrors>,
IrregularityInput
>({
mutationFn: createIrregularity,
})
const fileUploadMutation = useMutation<
AxiosResponse<IrregularityUploadImage[]>,
AxiosError<ApiErrors>,
UploadIrregularityFiles
>({
mutationFn: uploadIrregularityFiles(),
})
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1)
}
const handleSubmit = async (
values: IrregularityFormData,
actions: FormikHelpers<IrregularityFormData>,
) => {
if (isLastStep(activeStep, steps)) {
const errors = await actions.validateForm(values)
const hasErrors = !!Object.keys(errors).length
if (hasErrors) {
setFailedStep(Steps.INFO)
return
}
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setFailedStep(Steps.NONE)
try {
const data: IrregularityInput = {
campaignId: values.info.campaignId,
description: values.info.description,
notifierType: values.info.notifierType,
reason: values.info.reason,
status: values.status,
person: {
firstName: values.person.firstName,
lastName: values.person.lastName,
email: values.person.email,
phone: values.person.phone,
},
}
const response = await mutation.mutateAsync(data)
await fileUploadMutation.mutateAsync({
files,
irregularityId: response.data.id,
})
actions.resetForm()
setSuccess(true)
} catch (error) {
console.error(error)
setFail(true)
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
actions.setFieldError(property, t(matchValidator(constraints)))
})
}
}
return
}
actions.setTouched({})
actions.setSubmitting(false)
initialValues.info.campaignId = campaign.id
initialValues.person.firstName = person?.firstName || ''
initialValues.person.lastName = person?.lastName || ''
initialValues.person.email = person?.email || ''
initialValues.person.phone = person?.phone || ''
await stepsHandler({ actions, activeStep, setActiveStep, setFailedStep })
}
if (success) {
return <Success />
}
if (fail) {
return <Fail setFail={setFail} setActiveStep={setActiveStep} />
}
return (
<>
<GenericForm<IrregularityFormData>
onSubmit={handleSubmit}
initialValues={initialValues}
validationSchema={validationSchema[activeStep]}
innerRef={formRef}>
<Stepper
alternativeLabel
activeStep={activeStep}
className={classes.stepper}
connector={<ColorlibConnector />}>
{steps.map((step, index) => (
<Step key={index}>
<StepLabel error={isStepFailed(index)} StepIconComponent={StepIcon} />
</Step>
))}
</Stepper>
<div className={classes.content}>
<Grid container spacing={5} justifyContent="center" className={classes.instructions}>
<Grid container item xs={12}>
{activeStep < steps.length && steps[activeStep].component}
</Grid>
<Grid container item spacing={3}>
<Actions
activeStep={activeStep}
disableBack={activeStep === 0}
onBack={handleBack}
loading={mutation.isLoading}
campaign={campaign}
nextLabel={isLastStep(activeStep, steps) ? 'cta.submit' : 'cta.next'}
backLabel={isFirstStep(activeStep, steps) ? 'cta.back-to-campaign' : 'cta.back'}
/>
</Grid>
</Grid>
</div>
</GenericForm>
{activeStep === Steps.GREETING && <Remark text={t('steps.greeting.remark')} />}
{activeStep === Steps.CONTACTS && <Remark text={t('steps.contacts.remark')} />}
</>
)
}
Example #27
Source File: Steps.tsx From frontend with MIT License | 4 votes |
export default function DonationStepper() {
const { t } = useTranslation('one-time-donation')
const router = useRouter()
const success = router.query.success === 'true' ? true : false
initialValues.amount = (router.query.price as string) || ''
const slug = String(router.query.slug)
const { data, isLoading } = useViewCampaign(slug)
if (!data || !data.campaign) return <NotFoundPage />
const { campaign } = data
const mutation = useDonationSession()
const donate = React.useCallback(
async (amount?: number, priceId?: string) => {
const { data } = await mutation.mutateAsync({
mode: 'payment',
amount,
priceId,
campaignId: campaign.id,
successUrl: `${baseUrl}${routes.campaigns.oneTimeDonation(campaign.slug)}?success=true`,
cancelUrl: `${baseUrl}${routes.campaigns.oneTimeDonation(campaign.slug)}?success=false`,
})
if (data.session.url) {
window.location.href = data.session.url
}
},
[mutation],
)
const onSubmit = async (
values: OneTimeDonation,
{ setFieldError, resetForm }: FormikHelpers<OneTimeDonation>,
) => {
try {
const data = {
currency: 'BGN',
priceId: values.amount !== 'other' ? values.amount : undefined,
amount:
values.amount === 'other'
? Math.round((values.otherAmount + Number.EPSILON) * 100)
: undefined,
}
await donate(data.amount, data.priceId)
resetForm()
} catch (error) {
if (isAxiosError(error)) {
const { response } = error as AxiosError<ApiErrors>
response?.data.message.map(({ property, constraints }) => {
setFieldError(property, t(matchValidator(constraints)))
})
}
}
}
const steps: StepType[] = [
{
label: 'First Step',
component: <FirstStep />,
validate: validateFirst,
},
{
label: 'Second Step',
component: <SecondStep />,
validate: validateSecond,
},
{
label: 'Third Step',
component: <ThirdStep />,
validate: validateThird,
},
{
label: 'Last Step',
component: success ? <Success /> : <Fail />,
validate: null,
},
]
const [step, setStep] = React.useState(0)
return (
<StepsContext.Provider value={{ step, setStep, campaign }}>
{isLoading ? (
<CircularProgress color="primary" />
) : (
<FormikStepper onSubmit={onSubmit} initialValues={initialValues}>
{steps.map(({ label, component, validate }) => (
<FormikStep key={label} validationSchema={validate}>
{component}
</FormikStep>
))}
</FormikStepper>
)}
</StepsContext.Provider>
)
}
Example #28
Source File: EntityForm.tsx From firecms with MIT License | 4 votes |
/**
* This is the form used internally by the CMS
* @param status
* @param path
* @param schemaOrResolver
* @param entity
* @param onEntitySave
* @param onDiscard
* @param onModified
* @param onValuesChanged
* @constructor
* @category Components
*/
export function EntityForm<M>({
status,
path,
schemaOrResolver,
entity,
onEntitySave,
onDiscard,
onModified,
onValuesChanged
}: EntityFormProps<M>) {
const classes = useStyles();
const dataSource = useDataSource();
/**
* Base values are the ones this view is initialized from, we use them to
* compare them with underlying changes in the datasource
*/
const entityId = status === "existing" ? entity?.id : undefined;
const initialResolvedSchema: ResolvedEntitySchema<M> = useMemo(() => computeSchema({
schemaOrResolver,
path,
entityId
}), [path, entityId]);
const baseDataSourceValues: Partial<EntityValues<M>> = useMemo(() => {
const properties = initialResolvedSchema.properties;
if ((status === "existing" || status === "copy") && entity) {
return entity.values ?? initWithProperties(properties, initialResolvedSchema.defaultValues);
} else if (status === "new") {
return initWithProperties(properties, initialResolvedSchema.defaultValues);
} else {
console.error({ status, entity });
throw new Error("Form has not been initialised with the correct parameters");
}
}, [status, initialResolvedSchema, entity]);
const formRef = React.useRef<HTMLDivElement>(null);
const [customId, setCustomId] = React.useState<string | undefined>(undefined);
const [customIdError, setCustomIdError] = React.useState<boolean>(false);
const [savingError, setSavingError] = React.useState<any>();
const initialValuesRef = React.useRef<EntityValues<M>>(entity?.values ?? baseDataSourceValues as EntityValues<M>);
const initialValues = initialValuesRef.current;
const [internalValue, setInternalValue] = useState<EntityValues<M> | undefined>(initialValues);
const schema: ResolvedEntitySchema<M> = useMemo(() => computeSchema({
schemaOrResolver,
path,
entityId,
values: internalValue,
previousValues: initialValues
}), [schemaOrResolver, path, entityId, internalValue]);
const mustSetCustomId: boolean = (status === "new" || status === "copy") && (!!schema.customId && schema.customId !== "optional");
const underlyingChanges: Partial<EntityValues<M>> = useMemo(() => {
if (initialValues && status === "existing") {
return Object.keys(schema.properties)
.map((key) => {
const initialValue = (initialValues as any)[key];
const latestValue = (baseDataSourceValues as any)[key];
if (!isEqual(initialValue, latestValue)) {
return { [key]: latestValue };
}
return {};
})
.reduce((a, b) => ({ ...a, ...b }), {}) as Partial<EntityValues<M>>;
} else {
return {};
}
}, [initialValues, baseDataSourceValues]);
const saveValues = useCallback((values: EntityValues<M>, formikActions: FormikHelpers<EntityValues<M>>) => {
if (mustSetCustomId && !customId) {
console.error("Missing custom Id");
setCustomIdError(true);
formikActions.setSubmitting(false);
return;
}
setSavingError(null);
setCustomIdError(false);
let savedEntityId: string | undefined;
if (status === "existing") {
if (!entity?.id) throw Error("Form misconfiguration when saving, no id for existing entity");
savedEntityId = entity.id;
} else if (status === "new" || status === "copy") {
if (schema.customId) {
if (schema.customId !== "optional" && !customId) {
throw Error("Form misconfiguration when saving, customId should be set");
}
savedEntityId = customId;
}
} else {
throw Error("New FormType added, check EntityForm");
}
if (onEntitySave)
onEntitySave({
schema: schema as EntitySchema,
path,
entityId: savedEntityId,
values,
previousValues: entity?.values
})
.then(_ => {
initialValuesRef.current = values;
formikActions.setTouched({});
})
.catch(e => {
console.error(e);
setSavingError(e);
})
.finally(() => {
formikActions.setSubmitting(false);
});
}, [status, path, schema, entity, onEntitySave, mustSetCustomId, customId]);
const uniqueFieldValidator: CustomFieldValidator = useCallback(({
name,
value,
property
}) => dataSource.checkUniqueField(path, name, value, property, entityId),
[dataSource, path, entityId]);
const validationSchema = useMemo(() => getYupEntitySchema(
schema.properties,
uniqueFieldValidator), [schema.properties]);
return (
<Formik
initialValues={initialValues}
onSubmit={saveValues}
validationSchema={validationSchema}
validate={(values) => console.debug("Validating", values)}
onReset={() => onDiscard && onDiscard()}
>
{({
values,
touched,
setFieldValue,
handleSubmit,
isSubmitting,
dirty
}) => {
return <FormInternal baseDataSourceValues={baseDataSourceValues}
values={values} onModified={onModified}
setInternalValue={setInternalValue}
onValuesChanged={onValuesChanged}
underlyingChanges={underlyingChanges}
entityId={entityId}
entity={entity}
touched={touched}
setFieldValue={setFieldValue}
schema={schema}
isSubmitting={isSubmitting}
classes={classes}
formRef={formRef}
status={status}
setCustomId={setCustomId}
customIdError={customIdError}
handleSubmit={handleSubmit}
savingError={savingError}/>;
}}
</Formik>
);
}
Example #29
Source File: SetPasswordForm.tsx From bada-frame with GNU General Public License v3.0 | 4 votes |
function SetPasswordForm(props: Props) {
const [loading, setLoading] = useState(false);
const onSubmit = async (
values: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
setLoading(true);
try {
const { passphrase, confirm } = values;
if (passphrase === confirm) {
await props.callback(passphrase, setFieldError);
} else {
setFieldError('confirm', constants.PASSPHRASE_MATCH_ERROR);
}
} catch (e) {
setFieldError('confirm', `${constants.UNKNOWN_ERROR} ${e.message}`);
} finally {
setLoading(false);
}
};
return (
<Container>
<Card style={{ maxWidth: '540px', padding: '20px' }}>
<Card.Body>
<div
className="text-center"
style={{ marginBottom: '40px' }}>
<p>{constants.ENTER_ENC_PASSPHRASE}</p>
{constants.PASSPHRASE_DISCLAIMER()}
</div>
<Formik<formValues>
initialValues={{ passphrase: '', confirm: '' }}
validationSchema={Yup.object().shape({
passphrase: Yup.string().required(
constants.REQUIRED
),
confirm: Yup.string().required(constants.REQUIRED),
})}
validateOnChange={false}
validateOnBlur={false}
onSubmit={onSubmit}>
{({
values,
touched,
errors,
handleChange,
handleSubmit,
}) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group>
<Form.Control
type="password"
placeholder={constants.PASSPHRASE_HINT}
value={values.passphrase}
onChange={handleChange('passphrase')}
isInvalid={Boolean(
touched.passphrase &&
errors.passphrase
)}
autoFocus
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.passphrase}
</Form.Control.Feedback>
</Form.Group>
<Form.Group>
<Form.Control
type="password"
placeholder={
constants.RE_ENTER_PASSPHRASE
}
value={values.confirm}
onChange={handleChange('confirm')}
isInvalid={Boolean(
touched.confirm && errors.confirm
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.confirm}
</Form.Control.Feedback>
</Form.Group>
<SubmitButton
buttonText={props.buttonText}
loading={loading}
/>
</Form>
)}
</Formik>
{props.back && (
<div
className="text-center"
style={{ marginTop: '20px' }}>
<Button variant="link" onClick={props.back}>
{constants.GO_BACK}
</Button>
</div>
)}
</Card.Body>
</Card>
</Container>
);
}