formik#useFormik JavaScript Examples
The following examples show how to use
formik#useFormik.
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: FormContext.js From ecommerce with MIT License | 6 votes |
FormProvider = ({ initialValues, validationSchema, onSubmit, children }) => {
const { handleChange, handleBlur, values, touched, errors, submitForm } = useFormik({
initialValues,
validationSchema,
onSubmit,
validateOnChange: true,
validateOnMount: true,
});
const defaultContext = useMemo(
() => ({
handleChange,
handleBlur,
values,
touched,
errors,
submitForm,
}),
[handleChange, handleBlur, values, touched, errors, submitForm]
);
return <FormContext.Provider value={defaultContext}>{children}</FormContext.Provider>;
}
Example #2
Source File: AppTasks.js From course-manager with MIT License | 6 votes |
export default function AppTasks() {
const formik = useFormik({
initialValues: {
checked: [TASKS[2]]
},
onSubmit: (values) => {
console.log(values);
}
});
const { values, handleSubmit } = formik;
return (
<Card>
<CardHeader title="Tasks" />
<Box sx={{ px: 3, py: 1 }}>
<FormikProvider value={formik}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
{TASKS.map((task) => (
<TaskItem
key={task}
task={task}
formik={formik}
checked={values.checked.includes(task)}
/>
))}
</Form>
</FormikProvider>
</Box>
</Card>
);
}
Example #3
Source File: about-us-title-edit-form.js From horondi_admin with MIT License | 5 votes |
AboutUsTitleEditForm = ({ businessPage }) => {
const dispatch = useDispatch();
const [updateTitle, { loading }] = useMutation(updateBusinessText, {
onCompleted: () => {
dispatch(showSuccessSnackbar(SUCCESS_UPDATE_STATUS));
},
onError: () => {
dispatch(showErrorSnackbar(ERROR_BOUNDARY_STATUS));
}
});
const onSubmit = (onSubmitValues) => {
const updatedBusinessPage = getBusinessPageWithUpdatedTitle(
businessPage,
onSubmitValues
);
updateTitle({
variables: setVariablesForUpdatingPage(updatedBusinessPage)
});
};
const { values, errors, touched, handleChange, handleBlur, submitForm } =
useFormik({
initialValues: getInitialValuesForTitleEditing(businessPage),
validationSchema: titleEditValidationSchema,
onSubmit
});
const inputOptions = {
errors,
touched,
handleChange,
handleBlur,
values,
inputs: [titleEditInput]
};
if (loading) {
return <LoadingBar />;
}
return (
<div>
<EditingButtonsPanel
pathBack={pathToAboutUs}
submitForm={submitForm}
values={values}
errors={errors}
/>
<form>
{languages.map((lang) => (
<LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
))}
</form>
</div>
);
}
Example #4
Source File: use-comment-validation.spec.js From horondi_client_fe with MIT License | 5 votes |
useFormik.mockImplementation(() => formik);
Example #5
Source File: LoginCard.js From bunk-manager-mern with MIT License | 5 votes |
LoginCard = (props) => {
const location = useLocation();
let { from } = location.state || { from: { pathname: "/" } };
//styles
const classes = useStyles(props);
//formik hook
const formik = useFormik({
initialValues: {
email: "",
password: "",
},
validationSchema: loginSchema,
onSubmit: (values) => {
props.loggingUser(values, from);
},
});
return (
<React.Fragment>
<Typography color="primary" className={classes.loginHeader} variant="h5">
Sign In
</Typography>
<form
autoComplete="off"
className={classes.form}
onSubmit={formik.handleSubmit}
>
{props.error ? <div>{props.error.msg}</div> : null}
<input
id="login-email"
label="Email"
value={formik.values.email}
onChange={formik.handleChange}
error={
formik.touched.email && Boolean(formik.errors.email).toString()
}
variant="outlined"
name="email"
placeholder="Username or Email"
type="text"
className={classes.input}
/>
{formik.errors.email ? <div>{formik.errors.email}</div> : null}
<input
name="password"
placeholder="Password"
type="password"
className={classes.input}
id="login-password"
value={formik.values.password}
onChange={formik.handleChange}
error={
formik.touched.password &&
Boolean(formik.errors.password).toString()
}
/>
{formik.errors.password ? <div>{formik.errors.password}</div> : null}
<Button
type="submit"
className={classes.button}
color="secondary"
variant="contained"
>
{props.auth.isLoading ? (
<CircularProgress color="primary" />
) : (
"Sign In"
)}
</Button>
</form>
</React.Fragment>
);
}
Example #6
Source File: index.js From website with MIT License | 5 votes |
WishesFilterBy = ({ onLatLngUpdated, items, currentRefinement, refine }) => {
const validationSchema = Yup.object().shape({
postalCode: Yup.string().matches(/\d{6}/, 'Invalid postal code'),
});
const formik = useFormik({
initialValues: {
postalCode: '',
},
validationSchema: validationSchema,
onSubmit: (values) => {
handleSubmitPostalCode(values);
},
});
const handleSubmitPostalCode = async (values) => {
try {
const { postalCode } = values;
if (postalCode.trim().length > 0) {
const postalCodeArray = [postalCode];
const locations = await getLocations(postalCodeArray);
if (locations.length > 0) {
const latLng = `${locations[0].latitude},${locations[0].longitude}`;
onLatLngUpdated(latLng);
} else {
onLatLngUpdated('');
}
} else {
onLatLngUpdated('');
}
} catch (error) {
console.error(error.message);
}
};
return (
<div>
<BlackText style={{ marginBottom: '10px' }} size="large">
Filter By
</BlackText>
<Separator />
<Stack>
{items.map((item, index) => {
return (
<Checkbox
label={item.label + ' (' + item.count + ') '}
value={item.value}
checked={item.isRefined}
key={item.value}
onChange={() => {
refine(item.value);
}}
/>
);
})}
<form onSubmit={formik.handleSubmit}>
<Stack>
<InputField
placeholder="postal code"
label="Nearest - Furthest"
error={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
{...formik.getFieldProps('postalCode')}
/>
<Button onClick={formik.handleSubmit}>Go</Button>
</Stack>
</form>
</Stack>
</div>
);
}
Example #7
Source File: questions-answers-form.js From horondi_admin with MIT License | 4 votes |
FormQNA = ({ id, editMode }) => {
const dispatch = useDispatch();
const { loading, questionsAnswers } = useSelector(({ QuestionsAnswers }) => ({
loading: QuestionsAnswers.loading,
questionsAnswers: QuestionsAnswers.currentPage
}));
const classes = useStyles();
const common = useCommonStyles();
const {
labels: { questionaAnswersLabel },
languages
} = config;
const { pathToBusinessPages } = config.routes;
const {
createQuestionsAnswers,
uaSetAnswer,
enSetAnswer,
uaSetQuestion,
enSetQuestion,
uaAnswer,
enAnswer,
enQuestion,
uaQuestion
} = useQuestionsAnswersHandlers();
useEffect(() => {
id && dispatch(getQuestionsAnswersById(id));
}, [dispatch, id]);
useEffect(() => {
const isEditingReady = !!questionsAnswers;
uaSetQuestion(uaSetQuestionsHandler(isEditingReady, questionsAnswers));
uaSetAnswer(uaSetAnswersHandler(isEditingReady, questionsAnswers));
enSetQuestion(enSetQuestionsHandler(isEditingReady, questionsAnswers));
enSetAnswer(enSetAnswersHandler(isEditingReady, questionsAnswers));
}, [
editMode,
questionsAnswers,
uaSetAnswer,
uaSetQuestion,
enSetAnswer,
enSetQuestion
]);
const {
values,
errors,
touched,
handleSubmit,
handleBlur,
handleChange,
setFieldValue
} = useFormik({
initialValues: {
uaQuestion,
enQuestion,
uaAnswer,
enAnswer
},
onSubmit: async (data) => {
const page = createQuestionsAnswers({
...data
});
questionsAnswersDispatchHandler(
editMode,
dispatch,
updateQuestionsAnswers,
addQuestionsAnswers,
{ id, page },
page
);
}
});
const changed = useChangedValuesChecker(values, errors);
const unblock = useUnsavedChangesHandler(values);
useMemo(() => {
values.uaQuestion = uaQuestion;
values.enQuestion = enQuestion;
values.uaAnswer = uaAnswer;
values.enAnswer = enAnswer;
}, [uaQuestion, enQuestion, uaAnswer, enAnswer]);
if (loading) {
return <LoadingBar />;
}
const inputOptions = {
errors,
touched,
handleChange,
handleBlur,
values,
inputs: questionaAnswersLabel,
setFieldValue
};
const eventPreventHandler = (e) => {
e.preventDefault();
};
return (
<div className={classes.container}>
<div className={classes.buttonContainer}>
<Grid container spacing={2} className={classes.fixedButtons}>
<Grid item className={classes.button}>
<BackButton pathBack={pathToBusinessPages} />
</Grid>
<Grid item className={classes.button}>
<SaveButton
id='save'
type='submit'
title='Зберегти'
data-cy='save-btn'
onClickHandler={handleSubmit}
unblockFunction={unblock}
values={{}}
errors={errors}
{...(id ? { disabled: !changed } : {})}
/>
</Grid>
</Grid>
</div>
<div className={common.adminHeader}>
<Typography
variant='h1'
className={common.materialTitle}
data-cy='add-header'
>
{config.titles.questionsAnswersTitles.addQuestionsAnswersTitle}
</Typography>
</div>
<form onSubmit={(e) => eventPreventHandler(e)}>
{languages.map((lang) => (
<LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
))}
</form>
</div>
);
}
Example #8
Source File: gift-certificate.js From horondi_client_fe with MIT License | 4 votes |
GiftCertificate = () => {
const { t } = useTranslation();
const styles = useStyles();
const appStyles = useAppStyles();
const [getPaymentCheckoutForCertificate] = useLazyQuery(getPaymentCheckoutForCertificates, {
onCompleted: (data) => {
const { paymentUrl, paymentToken, certificatesOrderId } =
data.getPaymentCheckoutForCertificates;
setToLocalStorage(orderDataToLS.certificatesOrderId, certificatesOrderId);
window.open(`${process.env.REACT_APP_ROOT_PATH}${pathToCertificateThanks}/${paymentToken}`);
window.open(paymentUrl);
}
});
const [generateCertificates] = useMutation(generateCertificate, {
onCompleted: (data) => {
const { certificates, certificatesPrice } = data.generateCertificate;
getPaymentCheckoutForCertificate({
variables: {
data: {
currency: getCurrentCurrency(currency),
amount: String(certificatesPrice),
certificates
}
}
});
}
});
const initialValues = {
email: ''
};
const { userData, currency } = useSelector(({ User, Currency }) => ({
userData: User.userData,
currency: Currency.currency
}));
const CHECKBOXES_STATE = [
{ value: 500, checked: false, count: INITIAL_CERTIFICATE_COUNT },
{ value: 1000, checked: true, count: INITIAL_CERTIFICATE_COUNT },
{ value: 1500, checked: false, count: INITIAL_CERTIFICATE_COUNT }
];
const [checkboxesArr, setCheckboxesArr] = useState(CHECKBOXES_STATE);
const { errors, values, touched, handleChange, handleSubmit, handleBlur, resetForm } = useFormik({
validationSchema,
initialValues,
onSubmit: () => {
const newCertificates = findCheckedCertificates(checkboxesArr);
generateCertificates({
variables: {
newCertificates,
email: values.email
}
});
}
});
useEffect(() => {
if (userData) {
resetForm({
values: {
email: userData.email
}
});
}
}, [userData, resetForm]);
const handleCheckboxChange = (value, checkboxIndex) => {
setCheckboxesArr(
checkboxesArr.map((checkbox, index) =>
index === checkboxIndex ? { ...checkbox, checked: value } : checkbox
)
);
};
const handleCountChange = (count, index) => {
setCheckboxesArr(
checkboxesArr.map((checkbox, key) => (key === index ? { ...checkbox, count } : checkbox))
);
};
const findCheckedCertificates = (certificates) =>
certificates
.filter((certificate) => certificate.checked === true)
.map(({ checked, ...keepAtrs }) => keepAtrs);
const checkboxContent = checkboxesArr.map((checkbox, index) => (
<CertificateCheckbox
handleAllCheckboxesChange={handleCheckboxChange}
handleAllCountChange={handleCountChange}
checked={checkbox.checked}
index={index}
key={checkbox.value}
value={checkbox.value}
/>
));
const certificateText = (index) => t(`certificate.certificateRules.${index}`);
const certificateRulesContent = certificateRules.map((_, index) => (
<React.Fragment key={index}>
{`${index + 1}. ${certificateText(index)}`}
<br />
</React.Fragment>
));
return (
<div className={appStyles.rootApp}>
<div className={appStyles.containerApp}>
<h1 className={styles.pageTitle}>{t('certificate.giftCertificate')}</h1>
<h2 className={styles.chooseCertificate}>{t('certificate.chooseCertificate')}</h2>
<div className={styles.checkboxWrapper}>{checkboxContent}</div>
<div className={styles.lowerWrapper}>
<div>{certificateRulesContent}</div>
<form onSubmit={handleSubmit}>
<div className={styles.formWrapper}>
<TextField
id='email'
data-testid='email'
fullWidth
label={t('checkout.checkoutTextFields.email')}
variant={TEXT_FIELD_VARIANT.OUTLINED}
className={styles.textField}
onBlur={handleBlur}
onChange={handleChange}
value={values.email}
color={MATERIAL_UI_COLOR.PRIMARY}
name='email'
error={touched.email && Boolean(t(errors.email))}
helperText={touched.email && t(errors.email)}
/>
<Button
data-testid='button'
className={styles.purchaseButton}
fullWidth
type='submit'
>
{t('buttons.buyButton')}
</Button>
</div>
</form>
</div>
</div>
</div>
);
}
Example #9
Source File: ContactForm.js From gatsby-theme-try-ghost with MIT License | 4 votes |
ContactForm = ({ topics, serviceConfig }) => {
const text = get(useLang())
const validate = useValidate(text)
const encodeFormData = (data) => {
if (serviceConfig.contentType === `application/json`) {
return JSON.stringify(data)
}
if (serviceConfig.contentType === `application/x-www-form-urlencoded`) {
return Object.keys(data)
.map(key => encodeURIComponent(key) + `=` + encodeURIComponent(data[key]))
.join(`&`)
}
return data
}
const formik = useFormik({
initialValues: {
name: ``,
email: ``,
subject: topics.length > 0 ? `topic` : ``,
message: ``,
'form-name': ``,
},
validate,
onSubmit: async (values, actions) => {
actions.setSubmitting(false)
values.source_url = window.location.href
values.subject = topics[values.subject]
if (typeof values[`form-name`] === `string` && values[`form-name`].length === 0) {
values[`form-name`] = `gatsby-theme-ghost-contact`
} else { //early return if robot
actions.resetForm()
actions.setStatus({ success: text(`MESSAGE_SENT`) })
return
}
const postURL = (serviceConfig.url || `/`)
// reset and show message as post can be slow!
actions.resetForm()
actions.setStatus({ success: text(`ONE_SECOND`) })
fetch(postURL, {
method: `POST`,
headers: { 'Content-Type': serviceConfig.contentType },
body: encodeFormData(values),
}).then(() => {
actions.resetForm()
actions.setStatus({ success: text(`MESSAGE_SENT`) })
//remove message after 10 seconds
window.setTimeout(() => actions.setStatus({ success: `` }), 10000)
}).catch((error) => {
actions.resetForm()
actions.setStatus({ success: `${text(`SENDING_FAILED`)}: ${error}.` })
//remove message after 10 seconds
window.setTimeout(() => actions.setStatus({ success: `` }), 10000)
})
},
})
return (
<>
<Span id="response">
<div>{printError(formik.touched, formik.errors)}</div>
</Span>
<Form
name="gatsby-theme-ghost-contact"
method="post"
action=""
onSubmit={formik.handleSubmit}
data-netlify="true"
data-netlify-honeypot="bot-field">
<Input
id="name"
name="name"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
placeholder={text(`FULL_NAME`)}
/>
<Input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
placeholder={text(`EMAIL_ADDRESS`)}
/>
{ topics.length > 0 &&
<Select
id="subject"
name="subject"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.subject}>
<option value="topic" hidden>{text(`PLEASE_SELECT`)}</option>
{ topics.map((topic, i) => (
<option num={i} value={i} key={`option-${i}`} >{topic}</option>
))}
</Select>
}
<Textarea
id="message"
name="message"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.message}
placeholder={text(`YOUR_MESSAGE`)}
rows="5"
/>
<Robot
type="hidden"
name="form-name"
onChange={formik.handleChange}
value={formik.values[`form-name`]}
/>
<Button id="submit" type="submit" value="Submit">{text(`SUBMIT`)}</Button>
<Response id="responsemsg">{formik.status && formik.status.success}</Response>
</Form>
</>
)
}
Example #10
Source File: demo.js From react-use-opentok with MIT License | 4 votes |
Demo = () => {
const [opentokProps, opentokMethods] = useOpenTok();
const [credentials, setCredentials] =
typeof window !== 'undefined'
? useLocalStorage('credentials', initialCredentials)
: [initialCredentials];
const {
connectionId,
isSessionConnected,
session,
connections,
streams,
subscribers,
publisher,
} = opentokProps;
const {
initSessionAndConnect,
disconnectSession,
publish,
unpublish,
subscribe,
unsubscribe,
sendSignal,
} = opentokMethods;
const credentialsFormik = useFormik({
initialValues: {
...JSON.parse(credentials),
},
onSubmit: async (values, { setSubmitting }) => {
const { apiKey, sessionId, token } = values;
setCredentials(
JSON.stringify({
...values,
})
);
await initSessionAndConnect({
apiKey,
sessionId,
token,
});
setSubmitting(false);
},
});
const signalFormik = useFormik({
initialValues: {
type: '',
data: '',
},
onSubmit: (values, { setSubmitting, resetForm }) => {
if (values.data.length === 0) {
console.warn('signal data is empty');
return;
}
sendSignal({
...values,
});
setTimeout(() => {
resetForm();
setSubmitting(false);
}, 400);
},
});
// Listener of `signal`
// References https://tokbox.com/developer/sdks/js/reference/SignalEvent.html
const handleSignal = useCallback(e => {
console.log('handleSignal', e);
}, []);
const handleSessionDisconnected = useCallback(e => {
console.log('handle session disconnected', e);
}, []);
useEffect(() => {
if (!isSessionConnected) {
return;
}
session.on('signal', handleSignal);
session.once('sessionDisconnected', handleSessionDisconnected);
return () => {
session.off('signal', handleSignal);
};
}, [handleSignal, handleSessionDisconnected, isSessionConnected, session]);
const streamGroups =
streams &&
streams.reduce((groups, stream) => {
const { connection } = stream;
groups[connection.connectionId] = groups[connection.connectionId] || [];
groups[connection.connectionId].push(stream);
return groups;
}, {});
if (typeof window === 'undefined') return null;
return (
<>
<div
sx={{
display: 'flex',
mb: 3,
}}
>
{/* Left Side */}
<div
sx={{
flex: 2,
}}
>
<div
sx={{
position: 'relative',
minHeight: 480,
backgroundColor: 'black',
width: `100%`,
}}
>
<div
id="subscriber"
sx={{
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
zIndex: 2,
}}
></div>
<div
id="camera"
sx={{
position: 'absolute',
width: 240,
height: 180,
right: 10,
bottom: 10,
zIndex: 3,
}}
></div>
<div
id="screen"
sx={{
position: 'absolute',
width: 240,
height: 180,
right: 10,
top: 10,
zIndex: 3,
}}
></div>
</div>
<div>
{isSessionConnected ? (
<>
<div
sx={{
mt: 3,
}}
>
<Button variant="primary" onClick={disconnectSession}>
Disconnect to Session
</Button>
{!publisher.camera ? (
<Button
variant="primary"
onClick={() => {
publish({
name: 'camera',
element: 'camera',
});
}}
>
Publish Camera Stream
</Button>
) : (
<Button
variant="secondary"
onClick={() => unpublish({ name: 'camera' })}
>
Stop Publish
</Button>
)}
{!publisher.screen ? (
<Button
variant="primary"
onClick={() =>
publish({
name: 'screen',
element: 'screen',
options: {
...defaultOpenTokOptions,
videoSource: 'screen',
},
})
}
>
Start Share Screen (Desktop)
</Button>
) : (
<Button
variant="secondary"
onClick={() => unpublish({ name: 'screen' })}
>
Stop Share Screen (Desktop)
</Button>
)}
</div>
<Box as="form" onSubmit={signalFormik.handleSubmit}>
<Label htmlFor="type" my={3}>
Signal
</Label>
<Input
name="type"
placeholder="Type"
onChange={signalFormik.handleChange}
value={signalFormik.values.type}
mb={3}
/>
<Textarea
name="data"
placeholder="Data"
onChange={signalFormik.handleChange}
value={signalFormik.values.data}
rows="6"
mb={3}
/>
<Button
variant="secondary"
type="submit"
sx={{
display: 'block',
marginLeft: 'auto',
}}
disabled={
!signalFormik.values.data.length ||
signalFormik.isSubmitting
}
>
Send Signal
</Button>
</Box>
</>
) : (
<Box as="form" onSubmit={credentialsFormik.handleSubmit}>
<Label htmlFor="apiKey" mt={3} mb={1}>
API Key
</Label>
<Input
name="apiKey"
mb={3}
onChange={credentialsFormik.handleChange}
value={credentialsFormik.values.apiKey}
/>
<Label htmlFor="sessionId" mb={1}>
Session ID
</Label>
<Input
name="sessionId"
mb={3}
onChange={credentialsFormik.handleChange}
value={credentialsFormik.values.sessionId}
/>
<Label htmlFor="apiKey" mb={1}>
Token
</Label>
<Input
name="token"
mb={3}
onChange={credentialsFormik.handleChange}
value={credentialsFormik.values.token}
/>
<Button
variant="secondary"
type="submit"
disabled={credentialsFormik.isSubmitting}
sx={{
display: 'block',
marginLeft: 'auto',
}}
>
Connect to Session
</Button>
</Box>
)}
<ConsoleFeed />
</div>
</div>
{/* Right Side */}
<div
sx={{
flex: 1,
px: 3,
}}
>
<div sx={{ pt: 3 }}>Connections</div>
<ul sx={{ pl: '1rem', mt: 2 }}>
{connections.map(c => (
<li key={c.connectionId}>
{c.connectionId}{' '}
{c.connectionId === connectionId && (
<Badge variant="outline" ml={1}>
You
</Badge>
)}
</li>
))}
</ul>
<div sx={{ pt: 3 }}>Streams</div>
<ul sx={{ pl: '1rem', mt: 2 }}>
{Object.entries(streamGroups).map(([groupId, streams]) => (
<li key={groupId}>
Connection ID: {groupId.split('-')[0]}{' '}
{groupId === connectionId && (
<Badge variant="outline" ml={1}>
You
</Badge>
)}
<ul sx={{ pl: '1rem', py: 2 }}>
{streams.map(stream => {
const { streamId, connection } = stream;
return (
<li key={streamId}>
{connection.connectionId === connectionId ? (
`Stream ID: ${streamId.split('-')[0]} (${
stream.videoType
})`
) : (
<>
{`Stream ID: ${streamId.split('-')[0]}`}{' '}
{subscribers.some(
subscriber => subscriber.streamId === streamId
) ? (
<Button
variant="secondary"
sx={{
p: 1,
fontSize: 0,
border: '1px solid',
mx: 1,
}}
onClick={() => unsubscribe({ stream })}
>
STOP
</Button>
) : (
<Button
variant="primary"
sx={{
p: 1,
fontSize: 0,
border: '1px solid',
mx: 1,
}}
onClick={() =>
subscribe({ stream, element: 'subscriber' })
}
>
Watch
</Button>
)}
</>
)}
</li>
);
})}
</ul>
</li>
))}
</ul>
</div>
</div>
</>
);
}
Example #11
Source File: LtiConfigForm.jsx From frontend-app-course-authoring with GNU Affero General Public License v3.0 | 4 votes |
function LtiConfigForm({ onSubmit, intl, formRef }) {
const dispatch = useDispatch();
const { selectedAppId, piiConfig } = useSelector((state) => state.discussions);
const appConfig = useModel('appConfigs', selectedAppId);
const app = useModel('apps', selectedAppId);
const providerName = intl.formatMessage(appMessages[`appName-${app?.id}`]);
const ltiAppConfig = {
consumerKey: appConfig?.consumerKey || '',
consumerSecret: appConfig?.consumerSecret || '',
launchUrl: appConfig?.launchUrl || '',
piiShareUsername: piiConfig.piiSharing ? piiConfig.piiShareUsername : undefined,
piiShareEmail: piiConfig.piiSharing ? piiConfig.piiShareEmail : undefined,
};
const user = getAuthenticatedUser();
const { externalLinks } = app;
const {
handleSubmit, handleChange, handleBlur, values, touched, errors,
} = useFormik({
initialValues: ltiAppConfig,
validationSchema: Yup.object().shape({
consumerKey: Yup.string().required(intl.formatMessage(messages.consumerKeyRequired)),
consumerSecret: Yup.string().required(intl.formatMessage(messages.consumerSecretRequired)),
launchUrl: Yup.string().required(intl.formatMessage(messages.launchUrlRequired)),
piiShareUsername: Yup.bool(),
piiShareEmail: Yup.bool(),
}),
onSubmit,
});
const isInvalidConsumerKey = Boolean(touched.consumerKey && errors.consumerKey);
const isInvalidConsumerSecret = Boolean(touched.consumerSecret && errors.consumerSecret);
const isInvalidLaunchUrl = Boolean(touched.launchUrl && errors.launchUrl);
const showLTIConfig = user.administrator;
const enablePIISharing = false;
const supportEmails = {
Yellowdig: '[email protected]',
'Ed Discussion': '[email protected]',
InScribe: '[email protected]',
Piazza: '[email protected]',
};
useEffect(() => {
dispatch(updateValidationStatus({ hasError: Object.keys(errors).length > 0 }));
}, [errors]);
return (
<Card className="mb-5 p-5" data-testid="ltiConfigForm">
<Form ref={formRef} onSubmit={handleSubmit}>
<h3 className="mb-3">{providerName}</h3>
<p>
<FormattedMessage
{...messages.staffOnlyConfigInfo}
values={{
providerName,
supportEmail: supportEmails[providerName] ? (
<MailtoLink to={supportEmails[providerName]}>{supportEmails[providerName]}</MailtoLink>
) : (
'support'
),
}}
/>
</p>
<p>
<FormattedMessage
{...messages.staffOnlyConfigGuide}
values={{
providerName,
supportEmail: supportEmails[providerName] ? (
<MailtoLink to={supportEmails[providerName]}>{supportEmails[providerName]}</MailtoLink>
) : (
'support'
),
}}
/>
</p>
{(showLTIConfig && piiConfig.piiSharing) && (
<>
<p>{intl.formatMessage(messages.formInstructions)}</p>
<Form.Group
controlId="consumerKey"
isInvalid={isInvalidConsumerKey}
className="mb-4"
data-testid="ltiConfigFields"
>
<Form.Control
floatingLabel={intl.formatMessage(messages.consumerKey)}
onChange={handleChange}
onBlur={handleBlur}
value={values.consumerKey}
/>
{isInvalidConsumerKey && (
<Form.Control.Feedback type="invalid" hasIcon={false}>
<span className="x-small">{errors.consumerKey}</span>
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group
controlId="consumerSecret"
isInvalid={isInvalidConsumerSecret}
className="mb-4"
>
<Form.Control
floatingLabel={intl.formatMessage(messages.consumerSecret)}
onChange={handleChange}
onBlur={handleBlur}
value={values.consumerSecret}
/>
{isInvalidConsumerSecret && (
<Form.Control.Feedback type="invalid" hasIcon={false}>
<span className="x-small">{errors.consumerSecret}</span>
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controlId="launchUrl" isInvalid={isInvalidLaunchUrl}>
<Form.Control
floatingLabel={intl.formatMessage(messages.launchUrl)}
onChange={handleChange}
onBlur={handleBlur}
value={values.launchUrl}
/>
{isInvalidLaunchUrl && (
<Form.Control.Feedback type="invalid" hasIcon={false}>
<span className="x-small">{errors.launchUrl}</span>
</Form.Control.Feedback>
)}
</Form.Group>
</>
)}
{(enablePIISharing) && (
<div data-testid="piiSharingFields">
<Form.Text className="my-2">{intl.formatMessage(messages.piiSharing)}</Form.Text>
<Form.Group controlId="piiSharing">
<Form.Check
type="checkbox"
name="piiShareUsername"
onChange={handleChange}
onBlur={handleBlur}
checked={values.piiShareUsername}
label={intl.formatMessage(messages.piiShareUsername)}
/>
<Form.Check
type="checkbox"
name="piiShareEmail"
onChange={handleChange}
onBlur={handleBlur}
checked={values.piiShareEmail}
label={intl.formatMessage(messages.piiShareEmail)}
/>
</Form.Group>
</div>
)}
</Form>
<AppExternalLinks
externalLinks={externalLinks}
providerName={providerName}
customClasses="small text-muted"
/>
</Card>
);
}
Example #12
Source File: checkout-form.js From muffinsplantshop with BSD Zero Clause License | 4 votes |
BillingForm = ({ setValues, shippingValues, setSection, sameAsShipping, setSameAsShipping, billingValues }) => {
const validationSchema = baseSchema.shape({
country: Yup.string().required("Required")
})
const { handleSubmit, handleChange, values, errors } = useFormik({
initialValues: {
firstName: billingValues ? billingValues.firstName : "",
lastName: billingValues ? billingValues.lastName : "",
addressOne: billingValues ? billingValues.addressOne : "",
addressTwo: billingValues ? billingValues.addressTwo : "",
municipality: billingValues ? billingValues.municipality : "",
provinceTerritory: billingValues ? billingValues.provinceTerritory : "",
postalCode: billingValues ? billingValues.postalCode : "",
country: billingValues ? billingValues.country : ""
},
validationSchema,
onSubmit(values) {
setValues(values);
setSection('payment');
}
});
return (
<div>
<div className={styles.checkoutForm__sameAsBilling}>
<input
checked={sameAsShipping}
id="sameAsShipping"
name="sameAsShipping"
onChange={(e) => setSameAsShipping(e.target.checked)}
type="checkbox" />
<label htmlFor="sameAsShipping">My billing address is the same as my shipping address</label>
</div>
{sameAsShipping ?
(<>
<Details values={shippingValues} section="billing" />
<div style={{ padding: `0 1rem` }}>
<button
className={styles.checkoutForm__submitButton}
data-testid="submit-billing-button"
onClick={() => setSection('payment')}
type="button">
Continue to payment
</button>
</div>
</>) :
(<form
className={styles.checkoutForm__form}
data-testid="billing-form"
onSubmit={handleSubmit}>
<div className={styles.checkoutForm__field}>
<label htmlFor="firstName">First Name<span className="required">*</span></label>
<input
id="firstName"
name="firstName"
onChange={handleChange}
type="text"
value={values.firstName} />
<span className={styles.checkoutForm__error}>{errors.firstName ? errors.firstName : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="lastName">Last Name<span className="required">*</span></label>
<input
id="lastName"
name="lastName"
onChange={handleChange}
type="text"
value={values.lastName} />
<span className={styles.checkoutForm__error}>{errors.lastName ? errors.lastName : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="country">Country<span className="required">*</span></label>
<input
id="country"
name="country"
onChange={handleChange}
type="text"
value={values.country} />
<span className={styles.checkoutForm__error}>{errors.addressOne ? errors.addressOne : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="addressOne">Address Line 1<span className="required">*</span></label>
<input
id="addressOne"
name="addressOne"
onChange={handleChange}
type="text"
value={values.addressOne} />
<span className={styles.checkoutForm__error}>{errors.addressOne ? errors.addressOne : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="addressTwo">Address Line 2</label>
<input
id="addressTwo"
name="addressTwo"
onChange={handleChange}
type="text"
value={values.addressTwo} />
<span className={styles.checkoutForm__error}>{errors.addressTwo ? errors.addressTwo : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="municipality">Municipality<span className="required">*</span></label>
<input
id="municipality"
name="municipality"
onChange={handleChange}
type="text"
value={values.municipality} />
<span className={styles.checkoutForm__error}>{errors.municipality ? errors.municipality : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="provinceTerritory">Province/Territory<span className="required">*</span></label>
<select
value={values.provinceTerritory}
id="provinceTerritory"
name="provinceTerritory"
onChange={handleChange}>
<option value="">Select</option>
<option value="AB">Alberta</option>
<option value="BC">British Columbia</option>
<option value="MB">Manitoba</option>
<option value="NB">New Brunswick</option>
<option value="NL">Newfoundland and Labrador</option>
<option value="NS">Nova Scotia</option>
<option value="NT">Northwest Territories</option>
<option value="NU">Nunavut</option>
<option value="ON">Ontario</option>
<option value="PE">Prince Edward Island</option>
<option value="QC">Quebec</option>
<option value="SK">Saskatchewan</option>
<option value="YT">Yukon</option>
</select>
<span className={styles.checkoutForm__error}>{errors.provinceTerritory ? errors.provinceTerritory : null}</span>
</div>
<div className={styles.checkoutForm__field}>
<label htmlFor="postalCode">Postal Code<span className="required">*</span></label>
<input
id="postalCode"
name="postalCode"
onChange={handleChange}
type="text"
value={values.postalCode} />
<span className={styles.checkoutForm__error}>{errors.postalCode ? errors.postalCode : null}</span>
</div>
<button
className={styles.checkoutForm__submitButton}
data-testid="submit-billing-button"
type="submit">continue to payment</button>
</form>)
}
</div >
)
}
Example #13
Source File: RuleForm.jsx From acid-tabs-extension with MIT License | 4 votes |
RuleForm = (props) => {
const { groupRules, saveGroupRules, handleUpdate, handleCollapseGroups, showConfirm, handleConfirm } = props;
const [isDirty, setIsDirty] = useState(false);
const [isBulkMode, setIsBulkMode] = useState(false);
const [bulkValue, setBulkValue] = useState(groupRules.map(ruleToText).join('\n'));
const [newestRule, setNewestRule] = useState(null);
const [isCollapsed, setIsCollapsed] = useState(false);
const [showBottomRow, setShowBottomRow] = useState(false);
const [movedRule, setMovedRule] = useState({});
const formik = useFormik({
initialValues: {
groupRules
},
onSubmit: (values) => {
saveGroupRules(values.groupRules)
},
});
const removeRule = (index) => {
formik.values.groupRules.splice(index, 1)
formik.setFieldValue(formik.values.groupRules);
setIsDirty(true);
saveGroupRules(formik.values.groupRules)
}
const updateRuleOrder = (index, change) => {
const otherIndex = index + change;
setMovedRule({ [index]: change > 0 ? 'down' : 'up' })
setTimeout(() => {
formik.values.groupRules[index].key = otherIndex;
formik.values.groupRules[otherIndex].key = index;
formik.setFieldValue(formik.values.groupRules.sort((a, b) => a.key - b.key));
setIsDirty(true)
setMovedRule({})
saveGroupRules(formik.values.groupRules)
}, 100)
}
const getNewColor = () => {
const colorCounts = Object.keys(COLORS).reduce((curr, prev) => ({ ...curr, [prev]: 0 }), {})
formik.values.groupRules
.filter(rule => rule.color && Number.isInteger(colorCounts[rule.color]))
.forEach(rule => { colorCounts[rule.color] = colorCounts[rule.color] + 1 });
const colorsSortedByUse = Object.entries(colorCounts)
.sort((a, b) => a[1] - b[1])
.map(c => c[0]);
return colorsSortedByUse[0];
}
const addNewRule = () => {
const newRule = {
name: '',
pattern: '',
key: formik.values.groupRules.length,
color: getNewColor(),
}
formik.setFieldValue(formik.values.groupRules.push(newRule));
setNewestRule(formik.values.groupRules.length)
}
const allowUp = index => index > 0;
const allowDown = index => index < (formik.values.groupRules && formik.values.groupRules.length - 1);
const allValid = formik.values.groupRules.every(rule => rule.name.length > 0 && rule.pattern.length > 0)
const changed = formik.dirty || isDirty;
const textToRules = (rawText) => {
const lines = rawText.split('\n');
const rules = lines.map((line, i) => lineToRule(line, i)).filter(r => !!r)
return rules;
}
const lineToRule = (text, key) => {
const fields = text.split(',').map(f => f.replace(' ', '\n').trim())
if (text.trim().length === 0) return null;
if (fields.length < 2 || fields.length > 3 || fields.slice(0, 2).some(f => f.length === 0)) {
return { error: 'Invalid format' }
}
const color = fields.length > 2 && Object.keys(COLORS).includes(fields[2]) ? fields[2] : getNewColor();
return { key, name: fields[0], pattern: fields[1], color }
}
const handleCollapse = (state) => {
setIsCollapsed(state)
handleCollapseGroups(state)
}
const updateCollapsed = async() => {
const newIsCollapsed = await isAnyAcidTabGroupCollapsed();
setIsCollapsed(newIsCollapsed);
}
const toggleCollapseListener = async (command) => {
if (command === 'toggle-collapse') {
setTimeout(updateCollapsed, 100);
}
};
useEffect(() => {
if (allValid) {
saveGroupRules(formik.values.groupRules)
setBulkValue(formik.values.groupRules.map(ruleToText).join('\n'))
}
}, [formik.values.groupRules])
useEffect(() => {
updateCollapsed();
setTimeout(() => setShowBottomRow(true), 10)
chrome.commands.onCommand.addListener(toggleCollapseListener);
return () => chrome.commands.onCommand.removeListener(toggleCollapseListener);
}, [])
if (showConfirm) {
return <TabDemo onConfirm={handleConfirm} />;
}
if (isBulkMode) {
const parsedRules = textToRules(bulkValue);
const isBulkValid = parsedRules.every(r => !r.error)
const confirmBulk = (rules) => {
if (!isBulkValid) return;
saveGroupRules(parsedRules, true)
setIsBulkMode(false)
}
return (
<Wrapper style={{ marginTop: '1rem', padding: '0 1rem' }}>
<TextField
fullWidth
key={`bulkValue`}
name={`bulkValue`}
label='Raw Text Rules (per line: "name, pattern")'
value={bulkValue}
error={!isBulkValid}
multiline
placeholder='name, pattern'
onChange={(e) => setBulkValue(e.target.value)}
/>
<Row style={{ flex: 10, marginTop: '1rem', marginBottom: '1rem' }} alignItems='flex-end' justifyContent='center' alwaysShow>
<Button disabled={!isBulkValid} variant='contained' color="primary" onClick={confirmBulk}>
<DoneIcon style={{ paddingRight: '0.5rem' }} />
Confirm
</Button>
</Row>
</Wrapper>
)
}
const getMove = (i) => {
if (movedRule[i]) {
return movedRule[i];
}
if (movedRule[i-1] == 'down') {
if (i === 1) return 'fade';
return 'up'
}
if (movedRule[i+1] == 'up') {
if (i === 0) return 'fade';
return 'down'
}
}
const indirectlyMoved = i => getMove(i) && !movedRule[i];
const shouldShowLabel = (i) => i === 0;
return (
<Wrapper style={{}}>
<br />
<form onSubmit={formik.handleSubmit}>
{/* <Icon style={{ position: 'absolute' }}><ArrowBackIcon /></Icon> */}
{formik.values.groupRules.length === 0 && (
<FillColumn style={{ justifyContent: 'center', fontSize: '1.1rem' }}>
<FilterListIcon style={{ fontSize: '2.5rem' }} />
No rules yet, add one to start!
</FillColumn>
)}
{/* {formik.values.groupRules.length > 0 && (
<Row className={'special-hide'} key={'null'} alignItems='flex-end' style={{ paddingLeft: '1rem', boxSizing: 'border-box' }}>
<TextField
style={{ minWidth: '8rem' }}
key={`groupRules.${0}.name`}
name={`groupRules.${0}.name`}
label={shouldShowLabel(0) ? "Name" : null}
value
required
placeholder='Group Name'
/>
<TextField
fullWidth
key={`groupRules.${0}.pattern`}
name={`groupRules.${0}.pattern`}
label={shouldShowLabel(0) ? "URL Pattern (space separated for multiple)" : null}
required
multiline
placeholder='URL Pattern ("google.com")'
/>
<Select
key={`groupRules.${0}.color`}
name={`groupRules.${0}.color`}
displayEmpty
>
{Object.entries(COLORS).map(([colorKey, colorVal]) => (
<MenuItem value={colorKey}><ColorCircle value={colorVal} /></MenuItem>
))}
</Select>
</Row>
)} */}
{formik.values.groupRules.map((groupRule, i) => (
<Row className={getMove(i) ? `moving moving--${getMove(i)} ${indirectlyMoved(i) ? 'moving--indirect' : ''}` : ''} key={groupRule.key || '0'} alignItems='flex-end' style={{ paddingLeft: '1rem', boxSizing: 'border-box' }}>
<TextField
style={{ minWidth: '8rem' }}
key={`groupRules.${i}.name`}
name={`groupRules.${i}.name`}
label={shouldShowLabel(i) ? "Name" : null}
value={groupRule.name}
error={formik.dirty && groupRule.name.length === 0}
autoFocus={i === newestRule - 1}
required
placeholder='Group Name'
onChange={formik.handleChange}
/>
<TextField
fullWidth
key={`groupRules.${i}.pattern`}
name={`groupRules.${i}.pattern`}
label={shouldShowLabel(i) ? "URL Pattern (space separated for multiple)" : null}
value={groupRule.pattern}
error={formik.dirty && groupRule.pattern.length === 0}
required
multiline
placeholder='URL Pattern ("google.com")'
onChange={formik.handleChange}
/>
<Select
key={`groupRules.${i}.color`}
name={`groupRules.${i}.color`}
value={groupRule.color}
onChange={formik.handleChange}
displayEmpty
renderValue={(val) => (
<ColorCircle value={COLORS[groupRule.color]} displayMode />
)}
>
{Object.entries(COLORS).map(([colorKey, colorVal]) => (
<MenuItem value={colorKey}><ColorCircle value={colorVal} /></MenuItem>
))}
</Select>
<PostCol>
<ArrowUpwardIcon className={`icon ${!allowUp(i) ? 'disabled' : ''}`} onClick={() => allowUp(i) && updateRuleOrder(i, -1)} />
<ArrowDownwardIcon className={`icon ${!allowDown(i) ? 'disabled' : ''}`} onClick={() => allowDown(i) && updateRuleOrder(i, 1)} />
<DeleteIcon className='icon icon--delete' onClick={() => removeRule(i)} />
</PostCol>
</Row>
))}
<Row className={`bottom-row ${showBottomRow ? 'bottom-row--show' : ''}`} style={{ flex: 10, marginBottom: '1rem', marginTop: '1rem' }} alignItems='flex-end' justifyContent='space-between' alwaysShow>
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'flex-start' }}>
<Tooltip title="Hotkey: Alt+Shift+C">
<Button onClick={() => handleCollapse(!isCollapsed)} style={{ marginLeft: '1rem', minWidth: '8rem' }}>
{isCollapsed ? (
<>
<ClearAllIcon style={{ paddingRight: '1.25rem' }} />
<div>Expand</div>
</>
) : (
<>
<SortIcon style={{ paddingRight: '0.5rem' }} />
<div>Collapse</div>
</>
)}
</Button>
</Tooltip>
<Button onClick={() => setIsBulkMode(true)} style={{ marginLeft: '0.5rem' }}>
<EditIcon style={{ paddingRight: '0.75rem' }} />
<div>Bulk Edit</div>
</Button>
</div>
<Fab color="primary" aria-label="add" style={{ marginRight: '7rem' }} onClick={addNewRule}>
<AddIcon />
</Fab>
</Row>
</form>
</Wrapper>
);
}
Example #14
Source File: profile-page.js From horondi_client_fe with MIT License | 4 votes |
ProfilePage = () => {
const [userImageUrl, setUserImageUrl] = useState(null);
const [upload, setUpload] = useState(null);
const [deleteAvatar, setDeleteAvatar] = useState(false);
const [shouldValidate, setShouldValidate] = useState(false);
const { t, i18n } = useTranslation();
const language = i18n.language === 'ua' ? 0 : 1;
const classes = useStyles();
const appStyles = useAppStyles();
const dispatch = useDispatch();
const {
userData,
userLoading,
confirmationEmailSent,
userRecovered,
confirmationLoading,
recoveryLoading
} = useSelector(({ User }) => ({
userData: User.userData,
userLoading: User.userLoading,
confirmationEmailSent: User.confirmationEmailSent,
userRecovered: User.userRecovered,
confirmationLoading: User.confirmationLoading,
recoveryLoading: User.recoveryLoading
}));
const handleSaveUser = ({ firstName, lastName, email, phoneNumber, ...address }) => {
if (phoneNumber === null) {
phoneNumber = '';
}
const user = { firstName, lastName, email, phoneNumber, address };
Object.keys(address).forEach((key) => {
if (address[key] === null) {
address[key] = '';
}
});
dispatch(updateUser({ user, id: userData._id, upload, deleteAvatar }));
setShouldValidate(false);
};
const { errors, values, touched, handleBlur, resetForm, handleSubmit, handleChange } = useFormik({
initialValues,
onSubmit: handleSaveUser,
validationSchema,
validateOnChange: shouldValidate,
validateOnBlur: shouldValidate
});
const handleConfirmation = () => {
dispatch(sendConfirmationEmail({ email: userData.email, language }));
};
const handlePasswordChange = () => {
dispatch(recoverUser({ email: userData.email, language }));
};
useEffect(() => {
if (userData) {
const { firstName, lastName, email, phoneNumber, address } = userData;
resetForm({
values: {
firstName,
lastName,
email,
phoneNumber,
...address
}
});
}
if (userData.images && userData.images.thumbnail) {
setUserImageUrl(IMG_URL + userData.images.thumbnail);
}
}, [userData, resetForm]);
const getTextFields = (textFields) =>
Object.keys(textFields).map((name) => (
<TextField
key={name}
type='text'
name={name}
variant={TEXT_FIELD_VARIANT.OUTLINED}
value={values[name]?.startsWith('+380') ? values[name].slice(4) : values[name]}
InputProps={
name === 'phoneNumber'
? {
maxLength: 9,
startAdornment: <InputAdornment position='start'>+380</InputAdornment>
}
: {}
}
label={t(`profilePage.labels.${name}`)}
fullWidth
color={MATERIAL_UI_COLOR.PRIMARY}
onChange={handleChange}
error={touched[name] && !!errors[name]}
helperText={t(errors[name])}
className={handleClassName(classes.dataInput, classes.nameInputs, name)}
/>
));
const emailSent = (titleText) => (
<div className={classes.emailSent} data-testid='emailSent'>
<OpenedLetterIcon className={classes.openedLetterIcon} />
<h3 className={classes.formTitle}>{titleText}</h3>
<p>{t('profilePage.checkEmailText')}</p>
</div>
);
const passwordChange = () =>
userRecovered ? (
emailSent(t('profilePage.passwordChange.heading'))
) : (
<>
<h3 className={classes.formTitle}>{t('profilePage.passwordChange.heading')}</h3>
<span className={classes.userActionsText}>{t('profilePage.passwordChange.text')}</span>
<Button
className={`${classes.button} ${classes.userActionsButton}`}
onClick={handlePasswordChange}
data-testid='passwordChangeBtn'
>
{t('profilePage.passwordChange.btnTitle')}
</Button>
</>
);
const confirmEmail = () =>
confirmationEmailSent ? (
emailSent(t('profilePage.emailConfirm.heading'))
) : (
<>
<h3 className={classes.formTitle}>{t('profilePage.emailConfirm.heading')}</h3>
<TextField
data-cy='confirmEmail'
id='confirmEmail'
label={t('profilePage.labels.confirmEmail')}
className={classes.userActionsInput}
fullWidth
variant={TEXT_FIELD_VARIANT.OUTLINED}
color={MATERIAL_UI_COLOR.PRIMARY}
value={values.email}
name='confirmEmail'
onChange={handleChange}
onBlur={handleBlur}
error={Boolean(touched.confirmEmail && t(errors.confirmEmail))}
helperText={touched.confirmEmail && t(errors.confirmEmail)}
/>
<span className={classes.userActionsText}>
{!confirmationEmailSent && t('profilePage.emailConfirm.text')}
</span>
<Button
className={`${classes.button} ${classes.userActionsButton}`}
onClick={handleConfirmation}
data-testid='emailConfirmBtn'
>
{t('profilePage.emailConfirm.btnTitle')}
</Button>
</>
);
return (
<div className={appStyles.rootApp}>
<div className={appStyles.containerApp}>
<div className={classes.profileTitleInfo}>
<h2 className={classes.profileTitle}>{t('profilePage.titles.mainTitle')}</h2>
<div className={classes.titleLine} />
</div>
<div className={classes.profile}>
<div>
{userLoading ? (
<div className={classes.userForm}>
<Loader gridColumn='span 3' />
</div>
) : (
<div className={classes.userFormControl}>
<form onSubmit={handleSubmit} className={classes.userForm} data-testid='userForm'>
<Avatar
userImageUrl={userImageUrl}
setUserImageUrl={setUserImageUrl}
setUpload={setUpload}
setDeleteAvatar={setDeleteAvatar}
t={t}
/>
<h3 className={classes.formTitle}>{t('profilePage.titles.contactTitle')}</h3>
{getTextFields(PROFILE_USER_CONTACT_DATA)}
<h3 className={classes.formTitle}>{t('profilePage.titles.addressTitle')}</h3>
{getTextFields(PROFILE_USER_ADDRESS_DATA)}
<Button
fullWidth
className={`${classes.button} ${classes.saveBtn}`}
type='submit'
onClick={() => setShouldValidate(true)}
data-testid='submitBtn'
>
{t('profilePage.labels.saveBtnTitle')}
</Button>
</form>
</div>
)}
</div>
<div className={classes.userActions}>
<div className={classes.newPassword}>
{recoveryLoading ? <Loader /> : passwordChange()}
</div>
{!userData.confirmed && (
<div className={classes.confirmUser}>
{confirmationLoading ? <Loader /> : confirmEmail()}
</div>
)}
</div>
</div>
</div>
</div>
);
}
Example #15
Source File: user-form.js From horondi_admin with MIT License | 4 votes |
UserForm = ({ user, id, edit }) => {
const styles = useStyles();
const dispatch = useDispatch();
const { createUser, setUserImage, setUpload, upload } = useUserHandlers();
const userValidationSchema = Yup.object().shape({
userFirstName: Yup.string()
.min(2, USER_FIRSTNAME_MIN_LENGTH_MESSAGE)
.max(30, USER_FIRSTNAME_MAX_LENGTH_MESSAGE)
.required(USER_ERROR_MESSAGE)
.matches(firstName, USER_FIRSTNAME_MESSAGE),
userLastName: Yup.string()
.min(2, USER_LASTNAME_MIN_LENGTH_MESSAGE)
.max(30, USER_LASTNAME_MAX_LENGTH_MESSAGE)
.required(USER_ERROR_MESSAGE)
.matches(lastName, USER_LASTNAME_MESSAGE),
email: Yup.string()
.required(USER_EMAIL_MESSAGE)
.matches(email, USER_INVALID_EMAIL_MESSAGE),
phoneNumber: Yup.string()
.required(USER_PHONE_NUMBER_MESSAGE)
.matches(phoneNumber, USER_INVALID_PHONE_NUMBER_MESSAGE),
country: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
region: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
city: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
street: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
house: Yup.string().matches(uaNameCreation, USER_INVALID_ADDRESS_MESSAGE),
flat: Yup.string().matches(categoryCode, USER_INVALID_ADDRESS_MESSAGE),
zipcode: Yup.string().matches(postCode, USER_INVALID_ADDRESS_MESSAGE),
userImage: Yup.string()
});
const {
values,
handleSubmit,
handleChange,
handleBlur,
touched,
errors,
setFieldValue
} = useFormik({
validationSchema: userValidationSchema,
initialValues: getUserInitialValues(user, edit, IMG_URL),
onSubmit: () => {
const editedUser = createUser(values);
const editAndUpload = edit && upload instanceof File;
if (editAndUpload || edit) {
userFormOnSubmit(
editAndUpload,
dispatch,
updateUserById,
{
id,
user: editedUser,
image: upload
},
edit,
{
id,
user: editedUser
}
);
}
}
});
const unblock = useUnsavedChangesHandler(values);
const handleImageLoad = (files) => {
if (files && files[0]) {
const reader = new FileReader();
reader.onload = (data) => {
setFieldValue('userImage', data.target.result);
setUserImage(data.target.result);
};
reader.readAsDataURL(files[0]);
setUpload(files[0]);
}
};
const eventPreventHandler = (e) => {
e.preventDefault();
};
return (
<div>
<form onSubmit={(e) => eventPreventHandler(e)}>
<div className={styles.buttonContainer}>
<Grid container spacing={2} className={styles.fixedButtons}>
<Grid item className={styles.button}>
<BackButton
className={styles.returnButton}
pathBack={pathToUsers}
/>
</Grid>
<Grid item className={styles.button}>
<SaveButton
className={styles.saveButton}
data-cy='save'
type='submit'
title={SAVE_TITLE}
values={values}
errors={errors}
onClickHandler={handleSubmit}
unblockFunction={unblock}
/>
</Grid>
</Grid>
</div>
<Paper className={styles.colorPaper}>
<Grid item xs={12}>
<Paper>
<span className={styles.userImage}>Фото користувача</span>
<div className={styles.userImage}>
<ImageUploadContainer
handler={handleImageLoad}
src={values.userImage}
/>
</div>
</Paper>
</Grid>
{Object.keys(labels).map((fieldName) => (
<React.Fragment key={fieldName}>
<TextField
id={fieldName}
data-cy={fieldName}
className={styles.textField}
variant='outlined'
label={labels[fieldName]}
value={values[fieldName]}
onChange={handleChange}
onBlur={handleBlur}
error={touched[fieldName] && !!errors[fieldName]}
/>
{touched[fieldName] && errors[fieldName] && (
<div className={styles.inputError}>{errors[fieldName]}</div>
)}
</React.Fragment>
))}
</Paper>
</form>
</div>
);
}
Example #16
Source File: checkout-form.js From horondi_client_fe with MIT License | 4 votes |
CheckoutForm = ({ cartItems, cartOperations, promoCode }) => {
const { currency } = useContext(CurrencyContext);
const styles = useStyles();
const appStyles = useAppStyles();
const userData = useSelector(({ User }) => User.userData);
const { t, i18n } = useTranslation();
const language = i18n.language === 'ua' ? 0 : 1;
const { clearCart } = cartOperations;
const dispatch = useDispatch();
const [deliveryType, setDeliveryType] = useState(
getFromSessionStorage(SESSION_STORAGE.DELIVERY_TYPE) || deliveryTypes.SELFPICKUP
);
const [countryOption, setCountryOption] = useState(countryOptions.WITHIN_UKRAINE);
const [initialValues, setInitialValues] = useState(stateInitialValues);
const [pricesFromQuery, setPricesFromQuery] = useState([]);
const handleCountryOption = (_, newTabValue) => setCountryOption(newTabValue);
const { discount, categories } = promoCode?.getPromoCodeByCode || {};
const totalPriceToPay = pricesFromQuery
.map((item, index) => {
const canUsePromoCode = categories?.includes(item.category?.code);
const priceWithPromoCode = calcPriceForCart(item.price, cartItems[index]?.quantity, discount);
const priceWithoutPromoCode = calcPriceForCart(item.price, cartItems[index]?.quantity);
return canUsePromoCode ? priceWithPromoCode : priceWithoutPromoCode;
})
.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
const consentLink = (
<div className={styles.consentMessage}>
{' '}
{t('checkout.checkoutAdditionalInfo.consent.0')}
<Link
className={styles.consentLink}
to={pathToUserAgreement}
target='_blank'
rel='noreferrer'
>
{' '}
{t('checkout.checkoutAdditionalInfo.consent.1')}{' '}
</Link>{' '}
{t('checkout.checkoutAdditionalInfo.consent.2')}
<Link className={styles.consentLink} to={pathToTerms} target='_blank' rel='noreferrer'>
{' '}
{t('checkout.checkoutAdditionalInfo.consent.3')}{' '}
</Link>
</div>
);
const { values, handleSubmit, handleChange, setFieldValue, touched, errors } = useFormik({
enableReinitialize: true,
validationSchema: validationSchema(deliveryType, countryOption, t),
initialValues,
onSubmit: (data) => {
if (data.paymentMethod === checkoutPayMethod.card) {
dispatch(addPaymentMethod(checkoutPayMethod.card));
dispatch(
getFondyData({
order: orderInputData(data, deliveryType, cartItems, countryOption),
currency
})
);
} else {
dispatch(addOrder(orderInputData(data, deliveryType, cartItems, countryOption)));
dispatch(addPaymentMethod(checkoutPayMethod.cash));
}
clearSessionStorage();
clearCart();
}
});
useEffect(() => {
setToSessionStorage(SESSION_STORAGE.CHECKOUT_FORM, values);
}, [values]);
useEffect(() => {
if (userData) {
setInitialValues(updateInitialValues(userData, deliveryType));
}
}, [userData, deliveryType]);
return (
<div className={appStyles.rootApp}>
<form onSubmit={handleSubmit} className={appStyles.containerApp}>
<Grid item className={styles.checkoutFormContainer}>
<div className={styles.checkoutTitleInfo}>
<div className={styles.checkoutTitleInfoData}>
<Link to={pathToCart} className={styles.backBtn}>
<KeyboardBackspaceIcon color={getThemeColor()} className={styles.backBtnLine} />
</Link>
</div>
<h2 className={styles.checkoutTitle}>{t('checkout.checkoutTitles.checkoutTitle')}</h2>
<div className={styles.checkoutTitleLine} />
</div>
<Grid item className={styles.userInfoContainer}>
<div>
<h3 className={styles.title}>{t('checkout.checkoutTitles.contactInfo')}</h3>
<div className={styles.contactInfoFields}>
{userContactLabels.map((field) => (
<div key={field.name} className={styles.inputData}>
<TextField
data-testid={field.name}
size={TEXT_FIELDS.SMALL}
data-cy={field.name}
name={field.name}
className={styles.textField}
variant={TEXT_FIELD_VARIANT.OUTLINED}
label={field.label}
value={values[field.name]}
onChange={handleChange}
error={handleError(touched[field.name], errors[field.name])}
InputProps={
field.name === 'phoneNumber' && {
maxLength: 9,
startAdornment: <InputAdornment position='start'>+380</InputAdornment>
}
}
/>
{touched[field.name] && errors[field.name] && (
<div data-cy={CY_CODE_ERR} className={styles.error}>
{t(errors[field.name])}
</div>
)}
</div>
))}
</div>
</div>
<h3 className={styles.deliveryTitle}>{t('checkout.checkoutTitles.delivery')}</h3>
<Tabs
className={styles.tabs}
value={countryOption}
TabIndicatorProps={{ style: { display: 'none' } }}
onChange={handleCountryOption}
variant='fullWidth'
scrollButtons='auto'
aria-label='delivery type'
>
<Tab
className={styles.tab}
label={t('checkout.tabs.withinUkraineDelivery')}
value={countryOptions.WITHIN_UKRAINE}
/>
<Tab
className={styles.tab}
label={t('checkout.tabs.worldWideDelivery')}
value={countryOptions.WORLDWIDE}
/>
</Tabs>
<Delivery
deliveryType={deliveryType}
countryOption={countryOption}
language={language}
values={values}
errors={errors}
touched={touched}
handleChange={handleChange}
setFieldValue={setFieldValue}
setDeliveryType={setDeliveryType}
/>
<div>
<h2 className={styles.title}>{t('checkout.checkoutTitles.payment')}</h2>
<FormControl
error={touched.paymentMethod && !!errors.paymentMethod}
variant={TEXT_FIELD_VARIANT.OUTLINED}
className={styles.formControl}
>
<InputLabel variant={TEXT_FIELD_VARIANT.OUTLINED}>
{t('checkout.checkoutTextFields.paymentMethod')}
</InputLabel>
<Select
data-testid='paymentMetod'
label={t('checkout.checkoutTextFields.paymentMethod')}
className={styles.paymentSelect}
data-cy='paymentMethod'
name='paymentMethod'
value={values.paymentMethod}
onChange={handleChange}
>
{countryOption === countryOptions.WORLDWIDE ? (
<MenuItem value={checkoutPayMethod.card}>
{t(`checkout.checkoutPayment.${checkoutPayMethod.card}`)}
</MenuItem>
) : (
Object.values(checkoutPayMethod).map((value) => (
<MenuItem key={value} value={value}>
{t(`checkout.checkoutPayment.${value}`)}
</MenuItem>
))
)}
</Select>
{touched.paymentMethod && errors.paymentMethod && (
<div data-cy={CY_CODE_ERR} className={styles.error}>
{t(errors.paymentMethod)}
</div>
)}
</FormControl>
</div>
<div className={styles.contactPaymentInfo}>
<h2 className={styles.title}>{t('checkout.checkoutTitles.orderComment')}</h2>
<div>
<TextField
size={TEXT_FIELDS.SMALL}
data-cy='userComment'
name='userComment'
multiline
rows={4}
className={styles.textAreaField}
variant={TEXT_FIELD_VARIANT.OUTLINED}
value={values.userComment}
onChange={handleChange}
error={handleError(touched.userComment, errors.userComment)}
/>
{touched.userComment && errors.userComment && (
<div data-cy={CY_CODE_ERR} className={styles.error}>
{t(errors.userComment)}
</div>
)}
</div>
<p className={styles.contactInfoAdditional}>
{t('checkout.checkoutAdditionalInfo.additionalInfo')}
</p>
</div>
</Grid>
<Grid item className={styles.deliveryContainer}>
<YourOrder
checkoutFormBtnValue={checkoutFormBtnValue}
consentLink={consentLink}
t={t}
currency={currency}
totalPriceToPay={totalPriceToPay}
values={values}
language={language}
styles={styles}
deliveryType={deliveryType}
setPricesFromQuery={setPricesFromQuery}
promoCode={promoCode}
/>
</Grid>
</Grid>
</form>
</div>
);
}
Example #17
Source File: register-user.js From horondi_admin with MIT License | 4 votes |
RegisterUser = ({ handleClose }) => {
const styles = useStyles();
const dispatch = useDispatch();
const { loading } = useSelector(({ Users }) => ({
loading: Users.adminLoading
}));
const { adminId } = useSelector(({ Auth }) => ({
adminId: Auth.adminId
}));
const formSchema = Yup.object().shape({
email: Yup.string()
.required(ENTER_EMAIL_MESSAGE)
.email(INVALID_EMAIL_MESSAGE),
role: Yup.string().required(SELECT_ROLE_MESSAGE),
otp_code: Yup.string().when('role', {
is: superadmin,
then: Yup.string().required(ENTER_CODE)
})
});
const { handleSubmit, handleChange, values, touched, errors } = useFormik({
initialValues: {
role: admin,
email: '',
otp_code: ''
},
validationSchema: formSchema,
validateOnBlur: true,
onSubmit: (data) => {
dispatch(registerAdmin(data));
handleClose();
}
});
const roles = userRoles.filter((item) =>
allowedforRegistrationRoles.includes(item.role)
);
if (loading) {
return <LoadingBar />;
}
const rolesList = roles.map((item, idx) => (
<MenuItem key={idx} id={item.role} data-cy={item.role} value={item.role}>
{item.label}
</MenuItem>
));
const handleSendCode = () => {
dispatch(confirmSuperadmin({ _id: adminId }));
};
return (
<Grid className={styles.detailsContainer}>
<Grid className={styles.userDetails}>
<form onSubmit={handleSubmit}>
<Paper className={styles.userInputPanel}>
<FormControl
className={styles.formControl}
error={touched.email && !!errors.email}
>
<TextField
onChange={handleChange}
value={values.email}
id='email'
variant={outlined}
label='Пошта'
name='email'
data-cy='email'
type={text}
onBlur={handleChange}
error={touched.email && !!errors.email}
/>
<FormHelperText data-cy='email-error-label'>
{touched.email && errors.email}
</FormHelperText>
</FormControl>
<FormControl
className={styles.formControl}
error={touched.role && !!errors.role}
>
<InputLabel id='role-label'>Роль</InputLabel>
<Select
labelId='role-label'
id='role'
name='role'
type={text}
onBlur={handleChange}
value={values.role}
onChange={handleChange}
className={styles.formSelect}
data-cy='role'
error={touched.role && !!errors.role}
>
{rolesList}
</Select>
<FormHelperText data-cy='role-error-label'>
{touched.role && errors.role}
</FormHelperText>
</FormControl>
{values.role !== admin && (
<FormControl
className={styles.formControl}
error={touched.otp_code && !!errors.otp_code}
>
<Button
id='send-otp_code-button'
data-cy='add-user-admin-button'
onClick={handleSendCode}
variant={contained}
className={styles.sendButton}
color={primary}
>
{SEND_CODE}
</Button>
<TextField
onChange={handleChange}
value={values.otp_code}
id='otp_code'
variant={outlined}
label='Код'
name='otp_code'
data-cy='otp_code'
type={text}
onBlur={handleChange}
error={touched.otp_code && !!errors.otp_code}
/>
<FormHelperText data-cy='otp_code-error-label'>
{touched.otp_code && errors.otp_code}
</FormHelperText>
</FormControl>
)}
<FormControl className={styles.formControl}>
<SaveButton
type={submit}
title='Створити'
data-cy='submit-admin-register'
className={styles.saveButton}
errors={errors}
/>
</FormControl>
</Paper>
</form>
</Grid>
</Grid>
);
}
Example #18
Source File: index.js From website with MIT License | 4 votes |
RegisterNpoDetails = () => {
const dispatch = useDispatch();
const [openTnC, setOpenTnC] = useState(false);
const [tnc, setTnC] = useState('');
const [values, setValues] = useState({});
const organization = useSelector(getOrganization);
const router = useRouter();
const [alertTitle, setAlertTitle] = useState('');
const [showAlert, setShowAlert] = useState(false);
const [alertType, setAlertType] = useState('');
const [alertDescription, setAlertDescription] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isPasswordSecure, setIsPasswordSecure] = useState(false);
useEffect(() => {
api.legal.get('tnc_npo').then((doc) => {
setTnC(doc.data().content);
});
}, []);
const handleBackToNpoRegisterOnClick = () => {
dispatch(setIsBackToNpoRegister());
};
const displayAlert = (title, description, type) => {
setShowAlert(true);
setAlertTitle(title);
setAlertDescription(description);
setAlertType(type);
};
const handleFormSubmission = async () => {
handleModal();
setIsLoading(true);
setShowAlert(false);
dispatch(setNpoDetails(values.name, values.mobileNumber));
try {
let name = values.name;
let contact = values.mobileNumber;
let email = values.email;
let password = values.password;
let organizationName = organization.name;
let registrationNumber = organization.registrationNumber;
let activities = organization.activities;
const [token, user, userDoc] = await api.auth.registerNPO(
name,
contact,
email,
password,
organizationName,
registrationNumber,
activities
);
await api.auth.sendVerificationEmail();
displayAlert(
'Successfully Registered!',
`A verification email has been sent to ${user.email}. Remember to check your junk email too!`,
'success'
);
let response = await client.post('/api/sessionLogin', { token });
if (response.status === 200) {
await timeout(1000);
router.push('/?next=onboarding');
} else {
throw response.error;
}
} catch (error) {
console.error(error);
await api.auth.logout();
setIsLoading(false);
formik.setSubmitting(false);
if (error.code === 'auth/email-already-in-use') {
displayAlert('Email already in use', error.message, 'critical');
} else if (error.code === 'auth/invalid-email') {
displayAlert('Invalid Email', error.message, 'critical');
} else if (error.code === 'auth/unable-to-create-user') {
displayAlert('Error', error.message, 'critical');
} else {
displayAlert('Error', error.message, 'critical');
}
}
};
const handleModal = () => {
if (openTnC) {
setOpenTnC(false);
} else {
setOpenTnC(true);
}
};
const validationSchema = Yup.object().shape({
name: Yup.string().required('Required'),
mobileNumber: Yup.string()
.required('Required')
.matches(/^[6|8|9]\d{7}$/, 'Phone number is not valid'),
email: Yup.string().email('Email must be a valid email').required('Required'),
password: Yup.string()
.required('Required')
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\!\@\#\$%\^&\*\-\+\=\?\;\:\[\]\{\}\|\`\~\"\'\_\.])(?=.{12,})/,
'Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase letters, numbers and symbols'
),
passwordConfirmation: Yup.string()
.required('Required')
.oneOf([Yup.ref('password'), null], 'Passwords must match'),
});
const formik = useFormik({
initialValues: {
name: '',
mobileNumber: '',
email: '',
password: '',
passwordConfirmation: '',
},
validationSchema: validationSchema,
onSubmit: (values) => {
handleModal();
setValues(values);
},
});
return (
<div>
<Button
type="secondary"
circled
iconLeft={<ChevronLeft />}
onClick={handleBackToNpoRegisterOnClick}
spaceAfter="normal"
/>
<form onSubmit={formik.handleSubmit}>
<Stack spacing="loose">
<InputField
disabled={formik.isSubmitting}
label="Name"
name="name"
placeholder="Your full name"
error={formik.touched.name && formik.errors.name ? formik.errors.name : ''}
{...formik.getFieldProps('name')}
help={
<Tooltip
content="Use your own name even though there might be multiple people sharing a single account."
enabled
preferredAlign="start"
preferredPosition="bottom"
size="medium"
>
<span>Not sure whose name to put?</span>
</Tooltip>
}
/>
<InputField
prefix="+65"
disabled={formik.isSubmitting}
label="Mobile Number"
name="mobileNumber"
placeholder="Mobile Number or Your desk number"
error={formik.touched.mobileNumber && formik.errors.mobileNumber ? formik.errors.mobileNumber : ''}
{...formik.getFieldProps('mobileNumber')}
/>
<InputField
disabled={formik.isSubmitting}
type="email"
value="[email protected]"
label="Email"
name="email"
autoComplete="email"
placeholder="e.g. [email protected]"
help="Please use your work email"
error={formik.touched.email && formik.errors.email ? formik.errors.email : ''}
{...formik.getFieldProps('email')}
/>
<Stack spacing="none">
<InputField
disabled={formik.isSubmitting}
type="password"
label="Create a password"
name="password"
autoComplete="new-password"
error={formik.touched.password && formik.errors.password ? true : false}
{...formik.getFieldProps('password')}
suffix={
isPasswordSecure ? (
<CheckIconWrapper>
<Check />
</CheckIconWrapper>
) : null
}
/>
{formik.touched.password && formik.errors.password ? (
<Text size="small" type="critical" weight="bold">
{formik.errors.password}
</Text>
) : (
<Text size="small" type="secondary">
Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase
letters, numbers and symbols
</Text>
)}
</Stack>
<PasswordStrength
password={formik.values.password}
show={formik.errors.password && formik.values.password.length > 0 ? true : false}
onSecure={() => {
setIsPasswordSecure(true);
}}
onNotSecure={() => {
setIsPasswordSecure(false);
}}
/>
<InputField
disabled={formik.isSubmitting}
type="password"
label="Confirm password"
name="passwordConfirm"
autoComplete="new-password"
error={
formik.touched.passwordConfirmation && formik.errors.passwordConfirmation
? formik.errors.passwordConfirmation
: ''
}
{...formik.getFieldProps('passwordConfirmation')}
/>
{showAlert ? (
<Alert icon title={alertTitle} type={alertType}>
{alertDescription}
</Alert>
) : null}
<Button submit fullWidth={true} asComponent={BlueButton} loading={isLoading}>
Register
</Button>
<Text align="center" type="secondary">
By joining, you agree to the{' '}
<TextLink type="secondary" external href="https://www.giftforgood.io/privacy-policy">
Privacy Policy
</TextLink>{' '}
and our{' '}
<TextLink type="secondary" external href="https://www.giftforgood.io/terms-and-conditions">
Terms and Conditions
</TextLink>
.
</Text>
</Stack>
</form>
{openTnC ? <TermsAndConditionModal onClose={handleModal} tnc={tnc} onSubmit={handleFormSubmission} /> : null}
</div>
);
}
Example #19
Source File: Edit.js From course-manager with MIT License | 4 votes |
// ----------------------------------------------------------------------
export default function Edit() {
const navigate = useNavigate();
const { id } = useParams();
const [course, setCourse] = useState();
const [videos, setVideos] = useState([]);
const [isVideoModelOpen, setVideoModelOpen] = useState(false);
const [thumbnailUrl, setThumbnailUrl] = useState('');
useEffect(() => {
async function fetchCourse() {
const queryString = RequestQueryBuilder.create({
join: {
field: 'videos'
}
});
const course = await apis.course.findOne(id, queryString.query());
if (!course) navigate('/dashboard/courses', { replace: true });
formik.initialValues = {
title: course.title,
description: course.description
};
setCourse(course);
setVideos(course.videos);
setThumbnailUrl(course.thumbnailUrl);
}
fetchCourse();
}, []);
const CourseSchema = Yup.object().shape({
title: Yup.string().required('Full name is required'),
description: Yup.string().required('Username is required')
});
const formik = useFormik({
initialValues: course,
enableReinitialize: true,
validationSchema: CourseSchema,
onSubmit: async (values) => {
const data = {
...values,
thumbnailUrl
};
const updatedCourse = await apis.course.update(id, data);
if (!updatedCourse) {
return;
}
navigate('/dashboard/courses', { replace: true });
}
});
const { errors, touched, isSubmitting, handleSubmit, getFieldProps } = formik;
const closeVideoForm = (e, reason) => {
if (reason !== 'backdropClick') setVideoModelOpen(false);
};
const videoCreatedHandler = (newVideo) => {
setVideos([...videos, newVideo]);
};
return (
<Page title="List | Minimal-UI">
<Container>
<VideoCreateForm
open={isVideoModelOpen}
onClose={closeVideoForm}
onDataCreated={videoCreatedHandler}
/>
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
<Typography variant="h4" gutterBottom>
Edit Course
</Typography>
</Stack>
{course && (
<FormikProvider value={formik}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
<Stack spacing={3}>
<TextField
fullWidth
autoComplete="title"
type="text"
label="Title"
{...getFieldProps('title')}
error={Boolean(touched.title && errors.title)}
helperText={touched.title && errors.title}
/>
<TextField
fullWidth
autoComplete="description"
type="text"
label="Description"
{...getFieldProps('description')}
error={Boolean(touched.description && errors.description)}
helperText={touched.description && errors.description}
/>
<FileUploader
initUrl={thumbnailUrl}
type={COURSE_THUMBNAIL_TYPE}
setUrl={setThumbnailUrl}
title="Upload thumbnail"
name="edit-course-thumb"
/>
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
<Typography variant="h5" gutterBottom>
Videos
</Typography>
<Button
variant="contained"
onClick={() => setVideoModelOpen(true)}
startIcon={<Icon icon={plusFill} />}
>
Add video
</Button>
</Stack>
{videos && (
<Grid container spacing={3}>
{videos.map((video) => (
<Grid key={video.id} item xs={12} sm={6} md={3}>
<VideoCard video={video} />
</Grid>
))}
</Grid>
)}
<LoadingButton
fullWidth
size="large"
type="submit"
variant="contained"
loading={isSubmitting}
>
Submit
</LoadingButton>
</Stack>
</Form>
</FormikProvider>
)}
<Card />
</Container>
</Page>
);
}
Example #20
Source File: index.js From website with MIT License | 4 votes |
NpoEditProfilePanel = () => {
const user = useUser();
const [profileImage, setProfileImage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const router = useRouter();
const [alertTitle, setAlertTitle] = useState('');
const [showAlert, setShowAlert] = useState(false);
const [alertType, setAlertType] = useState('');
const [alertDescription, setAlertDescription] = useState('');
const displayAlert = (title, description, type) => {
setShowAlert(true);
setAlertTitle(title);
setAlertDescription(description);
setAlertType(type);
};
const handleFormSubmission = async (values) => {
setIsLoading(true);
setShowAlert(false);
const { name, contactNumber, profileImage } = values;
try {
const npoDoc = await api.users.updateNPO(name, contactNumber, profileImage);
setIsLoading(false);
router.reload();
} catch (error) {
setIsLoading(true);
formik.setSubmitting(false);
displayAlert('Error', error.message, 'critical');
}
};
const validationSchema = Yup.object().shape({
name: Yup.string().required('Required'),
contactNumber: Yup.string()
.required('Required')
.matches(/^[6|8|9]\d{7}$/, 'Phone number is not valid'),
profileImage: Yup.mixed(),
});
const formik = useFormik({
initialValues: {
name: user ? user.name : '',
contactNumber: user ? user.contactNumber : '',
profileImage: null,
},
enableReinitialize: true,
validationSchema: validationSchema,
onSubmit: (values) => {
handleFormSubmission(values);
},
});
const handleUploadProfileImage = (file) => {
if (!file) {
return;
}
if (file.size <= MAXIMUM_FILE_SIZE_LIMIT) {
formik.setFieldValue('profileImage', file);
} else {
formik.setFieldError('profileImage', 'Unable to upload images that are more than 25mb');
}
};
useEffect(() => {
if (formik.values.profileImage) {
const file = formik.values.profileImage;
const reader = new FileReader();
reader.onload = (ev) => {
setProfileImage(ev.target.result);
};
reader.readAsDataURL(file);
}
}, [formik]);
if (!user) {
return null;
}
return (
<Container>
<Card>
<CardSection>
<form onSubmit={formik.handleSubmit}>
<Stack spacing="loose">
<Heading>Edit Profile</Heading>
<Stack>
<Heading type="title2">Profile Picture</Heading>
<ProfileAvatar imageUrl={profileImage || user.profileImageUrl.raw} height={100} width={100} />
<InputFile
buttonLabel="Upload picture"
allowedFileTypes={['image/*']}
{...formik.getFieldProps('profileImage')}
error={formik.touched.profileImage && formik.errors.profileImage ? formik.errors.profileImage : ''}
fileName={formik.values.profileImage ? formik.values.profileImage.name : ''}
onChange={(event) => handleUploadProfileImage(event.currentTarget.files[0])}
/>
</Stack>
<Stack>
<Heading type="title2">Public Profile</Heading>
<Stack spacing="loose" spaceAfter="normal">
<InputField
disabled={formik.isSubmitting}
{...formik.getFieldProps('name')}
label="Your Name"
name="name"
placeholder="Your full name"
error={formik.touched.name && formik.errors.name ? formik.errors.name : ''}
/>
<InputField
disabled={formik.isSubmitting}
{...formik.getFieldProps('contactNumber')}
label="Your Contact"
name="contactNumber"
placeholder="Your contact"
error={
formik.touched.contactNumber && formik.errors.contactNumber ? formik.errors.contactNumber : ''
}
/>
<InputField
disabled
label="Your Email"
name="email"
placeholder="Your email"
value={user.email}
help={
<div>
Looking to change your email?{' '}
<TextLink external href="/contact">
Contact the administrators
</TextLink>
</div>
}
/>
<InputField
disabled
label="Organization Name"
name="name"
placeholder="Your full name"
value={user.organization.name}
/>
<InputField
disabled
label="Organization Address"
name="address"
placeholder="Address"
value={user.organization.address}
/>
<div>
<Text size="small">
Looking to change the fields above?{' '}
<TextLink external href="/contact">
Contact the administrators
</TextLink>
</Text>
</div>
<Button
asComponent={SaveChangesButton}
submit
fullWidth={true}
disabled={formik.isSubmitting || !formik.dirty}
loading={isLoading}
>
Save changes
</Button>
</Stack>
</Stack>
{showAlert ? (
<Alert icon title={alertTitle} type={alertType}>
{alertDescription}
</Alert>
) : null}
</Stack>
</form>
</CardSection>
</Card>
</Container>
);
}
Example #21
Source File: Create.js From course-manager with MIT License | 4 votes |
// ----------------------------------------------------------------------
export default function Create() {
const navigate = useNavigate();
const [isAdmin, setIsAdmin] = useState(false);
const [isMod, setIsMod] = useState(false);
const [isSupporter, setIsSupporter] = useState(false);
const UserSchema = Yup.object().shape({
fullName: Yup.string().required('Full name is required'),
username: Yup.string().required('Username is required'),
email: Yup.string().email('Email must be a valid email address').required('Email is required')
});
const formik = useFormik({
initialValues: {
fullName: '',
username: '',
email: ''
},
validationSchema: UserSchema,
onSubmit: async (values) => {
const roles = [];
if (isAdmin) roles.push('ADMIN');
if (isSupporter) roles.push('SUPPORTER');
if (isMod) roles.push('MOD');
const newUser = await apis.user.create({
...values,
roles
});
console.log(`New user ${newUser.username}`);
navigate('/dashboard/user', { replace: true });
}
});
const handleChange = (event) => {
switch (event.target.name) {
case 'isAdmin':
setIsAdmin(event.target.checked);
if (event.target.checked) {
setIsMod(false);
setIsSupporter(false);
}
break;
case 'isMod':
setIsMod(event.target.checked);
break;
case 'isSupporter':
setIsSupporter(event.target.checked);
break;
default:
break;
}
};
const { errors, touched, isSubmitting, handleSubmit, getFieldProps } = formik;
return (
<Page title="List | Minimal-UI">
<Container>
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
<Typography variant="h4" gutterBottom>
Edit User
</Typography>
<Button
variant="contained"
component={RouterLink}
to="#"
startIcon={<Icon icon={plusFill} />}
>
New List
</Button>
</Stack>
<FormikProvider value={formik}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
<Stack spacing={3}>
<TextField
fullWidth
autoComplete="username"
type="text"
label="Username"
{...getFieldProps('username')}
error={Boolean(touched.username && errors.username)}
helperText={touched.username && errors.username}
/>
<TextField
fullWidth
autoComplete="fullName"
type="text"
label="Full name"
{...getFieldProps('fullName')}
error={Boolean(touched.fullName && errors.fullName)}
helperText={touched.fullName && errors.fullName}
/>
<TextField
fullWidth
autoComplete="email"
type="email"
label="Email"
{...getFieldProps('email')}
error={Boolean(touched.email && errors.email)}
helperText={touched.email && errors.email}
/>
<FormControlLabel
control={<ODCheckbox checked={isAdmin} onChange={handleChange} name="isAdmin" />}
label="Is Admin"
/>
<FormGroup row>
<FormControlLabel
disabled={isAdmin}
control={<ODCheckbox checked={isMod} onChange={handleChange} name="isMod" />}
label="Is Mod"
/>
<FormControlLabel
disabled={isAdmin}
control={
<ODCheckbox checked={isSupporter} onChange={handleChange} name="isSupporter" />
}
label="Is Supporter"
/>
</FormGroup>
<LoadingButton
fullWidth
size="large"
type="submit"
variant="contained"
loading={isSubmitting}
>
Submit
</LoadingButton>
</Stack>
</Form>
</FormikProvider>
<Card />
</Container>
</Page>
);
}
Example #22
Source File: index.js From website with MIT License | 4 votes |
RegisterDonor = () => {
const dispatch = useDispatch();
const router = useRouter();
const [alertTitle, setAlertTitle] = useState('');
const [showAlert, setShowAlert] = useState(false);
const [alertType, setAlertType] = useState('');
const [alertDescription, setAlertDescription] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [googleLoading, setGoogleLoading] = useState(false);
const [isPasswordSecure, setIsPasswordSecure] = useState(false);
const handleBackToLandingOnClick = () => {
dispatch(setIsBackToLanding());
};
const displayAlert = (title, description, type) => {
setShowAlert(true);
setAlertTitle(title);
setAlertDescription(description);
setAlertType(type);
};
const handleFormSubmission = async (values) => {
try {
setIsLoading(true);
const [token, user, userDoc] = await api.auth.registerDonorWithEmailAndPassword(values.email, values.password);
await api.auth.sendVerificationEmail();
displayAlert('Successfully Registered!', `A verification email has been sent to ${user.email}`, 'success');
let response = await client.post('/api/sessionLogin', { token });
if (response.status === 200) {
await timeout(1000);
router.push('/?next=onboarding');
} else {
throw response.error;
}
} catch (error) {
console.error(error);
await api.auth.logout();
setIsLoading(false);
formik.setSubmitting(false);
if (error.code === 'auth/email-already-in-use') {
displayAlert('Email already in use', error.message, 'critical');
} else if (error.code === 'auth/invalid-email') {
displayAlert('Invalid Email', error.message, 'critical');
} else if (error.code === 'auth/unable-to-create-user') {
displayAlert('Error', error.message, 'critical');
} else {
displayAlert('Error', error.message, 'critical');
}
}
};
const handleGoogleRegister = async () => {
try {
setGoogleLoading(true);
const [token, user, userDoc] = await api.auth.registerDonorWithGoogle();
let response = await client.post('/api/sessionLogin', { token });
if (response.status === 200) {
await timeout(1000);
router.push('/');
} else {
throw response.error;
}
} catch (error) {
console.error(error);
await api.auth.logout();
setGoogleLoading(false);
if (error.code === 'auth/unable-to-create-user') {
displayAlert('Error', error.message, 'critical');
} else {
displayAlert('Error', error.message, 'critical');
}
}
};
const validationSchema = Yup.object().shape({
email: Yup.string().email('Email must be a valid email').required('Required'),
password: Yup.string()
.required('Required')
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\!\@\#\$%\^&\*\-\+\=\?\;\:\[\]\{\}\|\`\~\"\'\_\.])(?=.{12,})/,
'Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase letters, numbers and symbols'
),
passwordConfirmation: Yup.string()
.required('Required')
.oneOf([Yup.ref('password'), null], 'Passwords must match'),
});
const formik = useFormik({
initialValues: {
email: '',
password: '',
passwordConfirmation: '',
},
validationSchema: validationSchema,
onSubmit: (values) => {
handleFormSubmission(values);
},
});
return (
<div>
<Button
type="secondary"
circled
iconLeft={<ChevronLeft />}
onClick={handleBackToLandingOnClick}
spaceAfter="normal"
/>
<Text align="center" as="div" spaceAfter="largest">
<Stack direction="row" align="center" justify="center">
<Heading size="large" weight="bold">
I am a
</Heading>
<Heading size="large" weight="bold">
<HeadingColor>Donor</HeadingColor>
</Heading>
</Stack>
</Text>
<SocialButton
type="google"
fullWidth={true}
spaceAfter="normal"
onClick={handleGoogleRegister}
loading={googleLoading}
disabled={isLoading}
>
Sign in with Google
</SocialButton>
<Text align="center" spaceAfter="normal">
OR
</Text>
<form onSubmit={formik.handleSubmit}>
<Stack spacing="comfy" spaceAfter="normal">
<InputField
disabled={formik.isSubmitting}
type="email"
value="[email protected]"
label="Email"
name="email"
autoComplete="email"
placeholder="e.g. [email protected]"
error={formik.touched.email && formik.errors.email ? formik.errors.email : ''}
{...formik.getFieldProps('email')}
/>
<Stack spacing="none">
<InputField
disabled={formik.isSubmitting}
type="password"
label="Create a password"
name="password"
autoComplete="new-password"
error={formik.touched.password && formik.errors.password ? true : false}
{...formik.getFieldProps('password')}
suffix={
isPasswordSecure ? (
<CheckIconWrapper>
<Check />
</CheckIconWrapper>
) : null
}
/>
{formik.touched.password && formik.errors.password ? (
<Text size="small" type="critical" weight="bold">
{formik.errors.password}
</Text>
) : (
<Text size="small" type="secondary">
Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase
letters, numbers and symbols
</Text>
)}
</Stack>
<PasswordStrength
password={formik.values.password}
show={formik.errors.password && formik.values.password.length > 0 ? true : false}
onSecure={() => {
setIsPasswordSecure(true);
}}
onNotSecure={() => {
setIsPasswordSecure(false);
}}
/>
<InputField
disabled={formik.isSubmitting}
type="password"
label="Confirm password"
name="passwordConfirm"
autoComplete="new-password"
error={
formik.touched.passwordConfirmation && formik.errors.passwordConfirmation
? formik.errors.passwordConfirmation
: ''
}
{...formik.getFieldProps('passwordConfirmation')}
/>
<Button
submit
fullWidth={true}
asComponent={RedButton}
disabled={formik.isSubmitting}
loading={isLoading}
disabled={googleLoading}
>
Register
</Button>
<Text align="center" type="secondary">
By joining, you agree to the{' '}
<TextLink type="secondary" external href="https://www.giftforgood.io/privacy-policy">
Privacy Policy
</TextLink>{' '}
and our{' '}
<TextLink type="secondary" external href="https://www.giftforgood.io/terms-and-conditions">
Terms and Conditions
</TextLink>
.
</Text>
</Stack>
</form>
{showAlert ? (
<Alert icon title={alertTitle} type={alertType}>
{alertDescription}
</Alert>
) : null}
</div>
);
}
Example #23
Source File: index.js From flame-coach-web with MIT License | 4 votes |
CustomersView = ({ customerIdentifier }) => {
const classes = useStyles();
const isMobile = useIsMediumMobile();
const options = {
filterType: "dropdown",
selectableRows: "none",
tableBodyMaxHeight: "70vh",
sortOrder: {
name: "Name",
direction: "asc"
},
print: false
};
const [notification, setNotification] = useState({
enable: false,
message: "",
level: "INFO"
});
const queryClient = useQueryClient();
const [clientLoading, setClientLoading] = useState(false);
const [isClientLoading, setIsClientLoading] = useState(null);
const { mutate: inviteClient } = useInviteClient();
const resetNotificationHandler = () => {
setNotification(update(notification,
{
enable: { $set: false }
}));
};
const updateNotificationHandler = (enable, message, level) => {
setNotification({
enable,
message,
level
});
};
const formikSendInviteClient = useFormik({
initialValues: {
email: ""
},
validationSchema,
validateOnBlur: false,
validateOnChange: false,
onSubmit: (values) => {
inviteClient({
coachIdentifier: customerIdentifier,
clientEmail: values.email
}, {
onError: (error) => {
logError("Customer",
"useMutation inviteClient",
"Error:", error.response);
logError("Customer", "useMutation inviteClient", "Error Details:", error.response.data.detail);
const errorCode = ErrorMessage.fromCode(error.response.data.code);
updateNotificationHandler(true, errorCode.msg, errorCode.level);
},
onSuccess: (data) => {
queryClient.invalidateQueries(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier]);
const successMessage = data.registrationInvite ? InfoMessage.CODE_0004
: InfoMessage.CODE_0003;
updateNotificationHandler(true, successMessage.msg, successMessage.level);
}
});
}
});
const {
isError,
isLoading,
data
} = useQuery(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier],
() => getClientsCoachPlusClientsAvailableForCoaching(customerIdentifier), {
onError: async (err) => {
logError("Customer",
"useQuery getClientsCoachPlusClientsAvailableForCoaching",
"Error:", err);
},
select: (data) => {
const filteredClients = data.clientsCoach.filter((client) => client.status === "PENDING"
|| client.status === "ACCEPTED");
return {
identifier: data.identifier,
clientsCoach: filteredClients
};
}
});
const unlinkClient = useMutation(
({
clientIdentifier,
// eslint-disable-next-line no-unused-vars
coachIdentifier
}) => enrollmentProcessBreak(clientIdentifier),
{
onMutate: async ({ clientIdentifier }) => {
setClientLoading(clientIdentifier);
setIsClientLoading(true);
resetNotificationHandler();
},
onError: async (error) => {
logError("Customer",
"useMutation enrollmentProcessBreak",
"Error:", error.response);
setIsClientLoading(false);
logError("Customer", "useMutation enrollmentProcessBreak", "Error Details:", error.response.data.detail);
const errorCode = ErrorMessage.fromCode(error.response.data.code);
updateNotificationHandler(true, errorCode.msg, errorCode.level);
},
onSuccess: async (data, variables) => {
await queryClient.cancelQueries(["getClientsCoachPlusClientsAvailableForCoaching", variables.coachIdentifier]);
queryClient.setQueryData(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier], (oldData) => {
const index = oldData.clientsCoach.findIndex(
(customer) => customer.identifier === variables.clientIdentifier
);
return update(oldData, {
clientsCoach: {
[index]: {
status: { $set: data.status }
}
}
});
});
setIsClientLoading(false);
}
}
);
const unlinkClientHandler = (client) => {
unlinkClient.mutate({
clientIdentifier: client.identifier,
coachIdentifier: customerIdentifier
});
};
const getStatus = (status) => {
switch (status) {
case "AVAILABLE":
return "Available";
case "PENDING":
return "Pending";
case "ACCEPTED":
return "My client";
default:
return "Unknown";
}
};
const columnActions = {
label: "Actions",
options: {
filter: false,
sort: false,
setCellHeaderProps: () => {
return {
className: clsx({
[classes.rightTableHead]: true
})
};
},
// eslint-disable-next-line react/display-name
customBodyRender: (value) => {
const disableButtonMinus = value.client.identifier === value.clientLoading
? value.isClientLoading || !(value.client.status !== "AVAILABLE")
: !(value.client.status !== "AVAILABLE");
return (
<Grid
container
justifyContent={isMobile ? "flex-start" : "flex-end"}
spacing={1}
className={clsx({
[classes.actionColumnTable]: true
})}
>
<Grid item>
<Button
className={classes.minusUserButton}
variant="contained"
disabled={disableButtonMinus}
onClick={() => unlinkClientHandler(value.client)}
>
<SvgIcon
fontSize="small"
color="inherit"
>
<UserMinusIcon />
</SvgIcon>
</Button>
</Grid>
</Grid>
);
}
}
};
const columns = ["Name", "Email", "Registration date", "Status", columnActions];
return (
<Page
title="Customers"
isError={isError}
isLoading={isLoading}>
<Grid
direction="row"
container
>
<Grid item xs={12}>
<Box marginBottom={2}>
<form onSubmit={formikSendInviteClient.handleSubmit}>
<Card>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Send Invite
</Typography>
<Box className={classes.sendCard}>
<TextField
error={Boolean(formikSendInviteClient.errors.email)}
fullWidth
helperText={formikSendInviteClient.errors.email}
label="Email"
margin="normal"
name="email"
onBlur={formikSendInviteClient.handleBlur}
onChange={formikSendInviteClient.handleChange}
value={formikSendInviteClient.values.email}
variant="outlined"
/>
<Button
className={classes.sendInviteButton}
variant="contained"
type="submit"
>
<SvgIcon
fontSize="small"
color="inherit"
>
<SendIcon />
</SvgIcon>
</Button>
</Box>
</CardContent>
</Card>
</form>
</Box>
</Grid>
<Grid item xs={12}>
<Table
title="Clients List"
data={data ? data.clientsCoach.map((client) => ([
`${client.firstname} ${client.lastname}`,
client.email,
client.registrationDate,
getStatus(client.status),
{
client,
clientLoading,
isClientLoading
}
])) : null}
columns={columns}
options={options}
themeTable={outerTheme => outerTheme}
/>
</Grid>
{notification.enable
? (
<Grid item xs={12}>
<Notification
collapse
open={notification.enable}
openHandler={resetNotificationHandler}
level={notification.level}
message={notification.message}
/>
</Grid>
)
: null}
</Grid>
</Page>
);
}
Example #24
Source File: Reviews.js From Next.js-e-commerce-online-store with MIT License | 4 votes |
export default function Reviews({ id, reviewList }) {
const [ isEditorReadOnly, setIsEditorReadOnly ] = useState(false)
const [ sameEmailError, setSameEmailError ] = useState(false)
const formik = useFormik({
initialValues: { name: '', email: '', message: '' },
onSubmit: async (values, { resetForm }) => {
setIsEditorReadOnly(true)
await fetch(`/api/postReview?productId=${id}&name=${values.name}&email=${values.email}&reviewText=${encodeURIComponent(values.message)}`)
.then(res => {
if (res.status >= 400) {
if (res.status === 400) {
console.log(res.status, res)
setSameEmailError(res.statusText)
const err = new Error(res.statustext)
setIsEditorReadOnly(false)
throw err
} else if (res.status > 400) {
setSameEmailError(false)
const err = new Error('Error')
setIsEditorReadOnly(false)
throw err
}
}
return res.json()
})
.then(data => {
resetForm()
setEditorState(EditorState.push(editorState, ContentState.createFromText('')))
setSameEmailError(false)
const publishedReview = data.data.createReview.data
reviewList.push(publishedReview)
setIsEditorReadOnly(false)
const headingElement = document.getElementById('heading')
headingElement.scrollIntoView({ behavior: 'smooth' })
})
.catch(err => console.error(err))
},
validationSchema: schema
})
const [ reviews, setReviews ] = useState(reviewList)
const value = formik.values.message
const prepareDraft = value => {
const draft = htmlToDraft(value)
const contentState = ContentState.createFromBlockArray(draft.contentBlocks)
const editorState = EditorState.createWithContent(contentState)
return editorState
}
const setFieldValue = val => formik.setFieldValue('message', val)
const [ editorState, setEditorState ] = useState(value ? prepareDraft(value) : EditorState.createEmpty())
const onEditorStateChange = editorState => {
const forFormik = draftToHtml(
convertToRaw(editorState.getCurrentContent())
)
setFieldValue(forFormik)
setEditorState(editorState)
}
return (
<ReviewsDiv>
<div className="heading" id="heading">
{
reviews.length === 0
? 'No reviews so far. Be the first!'
: 'Reviews'
}
</div>
<div className="reviews">
{
reviews
.sort((a, b) => (
// sort by date, newest first ↓
new Date(b.attributes.createdAt).getTime() - new Date(a.attributes.createdAt).getTime()
))
.map(review => (
<div className="review" key={review.id}>
<div>
Reviewed at <b>{review.attributes.createdAt.slice(0, 10)}</b> by <b>{review.attributes.name}</b>:
</div>
<div dangerouslySetInnerHTML={{__html: review.attributes.reviewText}} className="review-text"></div>
</div>
))
}
</div>
<form className="form" onSubmit={formik.handleSubmit}>
<div className="input-group">
<div className="input-group-prepend">
<span className="input-group-text" id="inputGroup-sizing-default">Name</span>
</div>
<input
type="text"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
pattern="[A-Za-z ]{1,32}"
title="1 to 32 letters, no special symbols, except space"
minLength="1"
name="name"
id="name"
required
className="form-control"
value={formik.values.name}
onChange={formik.handleChange}
/>
</div>
{formik.errors.name && <h1 className="feedback-msgs">{formik.errors.name}</h1>}
<div className="input-group">
<div className="input-group-prepend">
<span className="input-group-text" id="inputGroup-sizing-default">E-mail</span>
</div>
<input
type="email"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
minLength="3"
name="email"
id="email"
required
className="form-control"
value={formik.values.email}
onChange={formik.handleChange}
/>
</div>
{formik.errors.email && <h1 className="feedback-msgs">{formik.errors.email}</h1>}
<div className="editor-top-wrapper">
<Editor
editorState={editorState}
readOnly={isEditorReadOnly}
toolbarHidden={isEditorReadOnly}
toolbarClassName="toolbar"
wrapperClassName="wrapper"
editorClassName="editor"
onEditorStateChange={onEditorStateChange}
toolbar={{
options: ['inline', 'blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'link', 'embedded', 'emoji', 'image', 'remove', 'history'],
colorPicker: { popupClassName: 'colorPickerPopup' },
link: { popupClassName: 'linkPopup' },
emoji: { popupClassName: 'emojiPopup' },
embedded: { popupClassName: 'embeddedPopup' },
image: { popupClassName: 'imagePopup' }
}}
/>
</div>
{formik.errors.message && <div className="feedback-msgs">{formik.errors.message}</div>}
{
sameEmailError
? <div className="feedback-msgs">{sameEmailError}</div>
: null
}
<button type="submit" className="post-button btn btn-primary" disabled={isEditorReadOnly}>
Post Review
</button>
</form>
</ReviewsDiv>
)
}
Example #25
Source File: index.js From atendimento-e-agilidade-medica-AAMed with MIT License | 4 votes |
Login = () => {
const [showPass, setShowPass] = useState(true);
const [press, setPress] = useState(false);
const [errorMsg, setErrorMsg] = useState(false);
const navigation = useNavigation();
const [auth, { login }] = useAuth();
const formik = useFormik({
initialValues: {
cpf: '',
password: '',
},
onSubmit: async values => {
try {
const response = await api.post('/login/user', values);
login(response.data);
console.log(response.data); //debug
} catch (error) {
// Error
if (error.response) {
setErrorMsg(error.response.data.error);
console.log(error.response.data);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
// setErrorMsg(error.message); // depois vejo isso
console.log('Erro fora dos ifs ', error); // depois de 2min que vai aparecer
}
},
});
function toggleShowPass() {
if (!press) {
setShowPass(false);
setPress(true);
} else {
setShowPass(true);
setPress(false);
}
}
navigation.setOptions({
headerRight: () => (
<Button
onPress={() => navigation.navigate('SignUp')}
title="Cadastre-se"
color="#0277BD"
/>
),
headerRightContainerStyle: {
padding: 15,
},
title: 'Bem-Vindo',
});
return (
<SafeAreaView style={{ flex: 1 }}>
<ImageBackground source={screen} style={{ flex: 1 }}>
<KeyboardAvoidingView
keyboardVerticalOffset={0}
enabled={false}
behavior="padding"
style={{ flex: 1 }}
>
<ImageContainer>
<Image source={logo} resizeMode="contain" />
</ImageContainer>
{!!errorMsg && <ErrorText>{errorMsg}</ErrorText>}
<LoginBox>
<InputBox>
{/* <Icon name="user" /> */}
<Label>CPF</Label>
<InputMask
name="cpf"
type={'cpf'}
placeholder="000.000.000-00"
placeholderTextColor="#00000066"
returnKeyType="next"
selectionColor="#006bad66"
value={formik.values.cpf}
onChangeText={formik.handleChange('cpf')}
/>
</InputBox>
<InputBox>
{/* <Icon name="lock" /> */}
<Label>Senha</Label>
<Input
name="password"
secureTextEntry={showPass}
placeholder="************"
placeholderTextColor="#00000066"
returnKeyType="done"
selectionColor="#006bad66"
value={formik.values.password}
onChangeText={formik.handleChange('password')}
/>
<TouchEye onPress={toggleShowPass}>
<IconEye name={press ? 'eye-off-outline' : 'eye-outline'} />
</TouchEye>
</InputBox>
<MainButton
onPress={formik.handleSubmit}
flag={formik.isSubmitting}
label={'ENTRAR'}
>
<ActivityIndicator size="small" color="#FFF" />
</MainButton>
<Option
onPress={() => {
navigation.navigate('ForgotPassword');
}}
>
Esqueceu a senha?
</Option>
</LoginBox>
</KeyboardAvoidingView>
</ImageBackground>
</SafeAreaView>
);
}
Example #26
Source File: business-page-form.js From horondi_admin with MIT License | 4 votes |
BusinessPageForm = ({ editMode, codePath }) => {
const dispatch = useDispatch();
const { loading, businessPage } = useSelector(({ BusinessPages }) => ({
loading: BusinessPages.loading,
businessPage: BusinessPages.currentPage
}));
const classes = useStyles();
const common = useCommonStyles();
const {
labels: { businessPageLabel },
languages,
businessPageErrorMessages: {
ENTER_CODE_ERROR_MESSAGE,
ENTER_TITLE_ERROR_MESSAGE,
ENTER_TEXT_ERROR_MESSAGE,
MIN_TEXT_LENGTH_MESSAGE
},
commonErrorMessages: {
UA_NAME_MESSAGE,
EN_NAME_MESSAGE,
MIN_LENGTH_MESSAGE
}
} = config;
const {
createBusinessPage,
createBusinessTextTranslationFields,
uaSetText,
enSetText,
uaSetTitle,
enSetTitle,
uaText,
enText,
enTitle,
uaTitle,
code,
setCode,
files,
setFiles
} = useBusinessHandlers();
useEffect(() => {
codePath && dispatch(getBusinessPageByCode(codePath));
}, [dispatch, codePath]);
useEffect(() => {
const isEditingReady = businessPage && editMode;
setCode(setCodeHandler(isEditingReady, businessPage));
uaSetTitle(uaSetTitleHandler(isEditingReady, businessPage));
uaSetText(uaSetTextHandler(isEditingReady, businessPage));
enSetTitle(enSetTitleHandler(isEditingReady, businessPage));
enSetText(enSetTextHandler(isEditingReady, businessPage));
}, [
code,
setCode,
editMode,
businessPage,
uaSetText,
uaSetTitle,
enSetText,
enSetTitle
]);
const formSchema = Yup.object().shape({
code: Yup.string()
.matches(config.formRegExp.pageCode, ENTER_CODE_ERROR_MESSAGE)
.required(ENTER_CODE_ERROR_MESSAGE),
uaTitle: Yup.string()
.min(2, MIN_LENGTH_MESSAGE)
.matches(config.formRegExp.uaNameCreation, EN_NAME_MESSAGE)
.required(ENTER_TITLE_ERROR_MESSAGE),
enTitle: Yup.string()
.min(2, MIN_LENGTH_MESSAGE)
.matches(config.formRegExp.enNameCreation, UA_NAME_MESSAGE)
.required(ENTER_TITLE_ERROR_MESSAGE),
enText: Yup.string()
.min(17, MIN_TEXT_LENGTH_MESSAGE)
.matches(config.formRegExp.enDescription, EN_NAME_MESSAGE)
.required(ENTER_TEXT_ERROR_MESSAGE),
uaText: Yup.string()
.min(17, MIN_TEXT_LENGTH_MESSAGE)
.required(ENTER_TEXT_ERROR_MESSAGE)
});
const {
values,
errors,
touched,
handleSubmit,
handleBlur,
handleChange,
setFieldValue
} = useFormik({
initialValues: {
code,
uaTitle,
enTitle,
uaText,
enText
},
validationSchema: formSchema,
onSubmit: async () => {
const uniqueFiles = files.filter((file, i) => {
const { name, size } = file;
return indexFinder(i, files, name, size);
});
const newUaText = values.uaText.replace(/src="data:image.*?"/g, 'src=""');
const newEnText = values.enText.replace(/src="data:image.*?"/g, 'src=""');
const page = createBusinessPage(values);
const businessTextTranslationFields = createBusinessTextTranslationFields(
{
...values,
uaText: newUaText,
enText: newEnText
}
);
businessPageDispatchHandler(
editMode,
dispatch,
updateBusinessPage,
addBusinessPage,
{
id: businessPage._id,
page,
businessTextTranslationFields,
files: uniqueFiles
},
{ page, files: uniqueFiles }
);
}
});
const changed = useChangedValuesChecker(values, errors);
const unblock = useUnsavedChangesHandler(values);
useMemo(() => {
values.code = code;
values.uaTitle = uaTitle;
values.enTitle = enTitle;
values.uaText = uaText;
values.enText = enText;
}, [code, uaTitle, enTitle, uaText, enText]);
if (loading) {
return <LoadingBar />;
}
businessPageLabel[1].setFiles = setFiles;
const inputOptions = {
errors,
touched,
handleChange,
handleBlur,
values,
inputs: businessPageLabel,
setFieldValue
};
const eventPreventHandler = (e) => {
e.preventDefault();
};
return (
<div className={classes.container}>
<div className={classes.buttonContainer}>
<Grid container spacing={2} className={classes.fixedButtons}>
<Grid item className={classes.button}>
<SaveButton
id='save'
type='submit'
title='Зберегти'
data-cy='save-btn'
onClickHandler={handleSubmit}
unblockFunction={unblock}
values={{
code: values.code,
uaTitle: values.uaTitle,
enTitle: values.enTitle
}}
errors={errors}
{...(businessPage?._id ? { disabled: !changed } : {})}
/>
</Grid>
</Grid>
</div>
<div className={common.adminHeader}>
<Typography
variant='h1'
className={common.materialTitle}
data-cy='add-header'
>
{config.titles.businessPageTitles.addBusinessPageTitle}
</Typography>
</div>
<form onSubmit={(e) => eventPreventHandler(e)}>
<Grid item xs={12}>
<Paper className={classes.businessPageForm}>
<TextField
id='code'
className={classes.textField}
variant='outlined'
label='Код сторінки'
value={values.code}
onChange={handleChange}
onBlur={handleBlur}
error={touched.code && !!errors.code}
data-cy='page-code'
/>
</Paper>
{touched.code && errors.code && (
<div data-cy='code-error' className={classes.errorMessage}>
{errors.code}
</div>
)}
</Grid>
{languages.map((lang) => (
<LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
))}
</form>
</div>
);
}
Example #27
Source File: RegisterForm.js From Django-REST-Framework-React-BoilerPlate with MIT License | 4 votes |
// ----------------------------------------------------------------------
export default function RegisterForm() {
const dispatch = useDispatch();
const navigate = useNavigate();
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const userRgister = useSelector((state) => state.userRgister);
const { error: registerError, loading: registerLoading } = userRgister;
const [showPassword, setShowPassword] = useState(false);
const RegisterSchema = Yup.object().shape({
firstName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('First name required'),
lastName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('Last name required'),
email: Yup.string().email('Email must be a valid email address').required('Email is required'),
password: Yup.string().required('Password is required'),
});
const formik = useFormik({
initialValues: {
firstName: '',
lastName: '',
email: '',
password: '',
},
validationSchema: RegisterSchema,
onSubmit: () => {
dispatch(register(values.firstName, values.lastName, values.email, values.password));
},
});
const { errors, touched, values, handleSubmit, isSubmitting, getFieldProps } = formik;
useEffect(() => {
if (userInfo) {
navigate('/dashboard/app', { replace: true });
}
}, [navigate, userInfo]);
return (
<FormikProvider value={formik}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
<Stack spacing={3}>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
<TextField
fullWidth
label="First name"
{...getFieldProps('firstName')}
error={Boolean(touched.firstName && errors.firstName)}
helperText={touched.firstName && errors.firstName}
/>
<TextField
fullWidth
label="Last name"
{...getFieldProps('lastName')}
error={Boolean(touched.lastName && errors.lastName)}
helperText={touched.lastName && errors.lastName}
/>
</Stack>
<TextField
fullWidth
autoComplete="username"
type="email"
label="Email address"
{...getFieldProps('email')}
error={Boolean(touched.email && errors.email)}
helperText={touched.email && errors.email}
/>
<TextField
fullWidth
autoComplete="current-password"
type={showPassword ? 'text' : 'password'}
label="Password"
{...getFieldProps('password')}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton edge="end" onClick={() => setShowPassword((prev) => !prev)}>
<Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
</IconButton>
</InputAdornment>
),
}}
error={Boolean(touched.password && errors.password)}
helperText={touched.password && errors.password}
/>
{registerError ? (
<Alert severity="error">
<AlertTitle>Register Error</AlertTitle>
{registerError}
</Alert>
) : null}
<LoadingButton
fullWidth
size="large"
type="submit"
variant="contained"
loading={registerLoading ? isSubmitting : null}
>
Register
</LoadingButton>
</Stack>
</Form>
</FormikProvider>
);
}
Example #28
Source File: category-form.js From horondi_admin with MIT License | 4 votes |
CategoryForm = ({ category, id, edit }) => {
const styles = useStyles();
const dispatch = useDispatch();
const { createCategory, setUpload, upload, categoryImage, setCategoryImage } =
useCategoryHandlers();
const { pathToCategories } = config.routes;
const categoryValidationSchema = Yup.object().shape({
code: Yup.string()
.min(2, CATEGORY_VALIDATION_ERROR)
.max(30, CATEGORY_VALIDATION_ERROR)
.required(ERROR_MESSAGE)
.matches(categoryCode, CATEGORY_CODE_MESSAGE),
uaName: Yup.string()
.min(2, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
.max(50, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
.required(ERROR_MESSAGE)
.matches(uaNameCreation, UA_NAME_MESSAGE),
enName: Yup.string()
.min(2, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
.max(50, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
.required(ERROR_MESSAGE)
.matches(enNameCreation, EN_NAME_MESSAGE)
});
const {
values,
handleSubmit,
handleChange,
handleBlur,
touched,
errors,
setFieldValue
} = useFormik({
validationSchema: categoryValidationSchema,
initialValues: getCategoryInitialValues(edit, IMG_URL, category),
onSubmit: (data) => {
const newCategory = createCategory(data);
const uploadCondition = upload instanceof File;
onSubmitCategoryHandler(edit, dispatch, updateCategory, {
id,
category: newCategory,
upload
});
onSubmitCategoryHandler(uploadCondition, dispatch, addCategory, {
category: newCategory,
upload
});
if (!uploadCondition && !category.images.thumbnail) {
dispatch(showErrorSnackbar(CATEGORY_ERROR));
}
}
});
const unblock = useUnsavedChangesHandler(values);
const handleImageLoad = (files) => {
if (files && files[0]) {
const reader = new FileReader();
reader.onload = (event) => {
setFieldValue('categoryImage', event.target.result);
setCategoryImage(event.target.result);
};
reader.readAsDataURL(files[0]);
setUpload(files[0]);
}
};
const inputs = [
{ label: config.labels.categories.categoryName, name: 'name' }
];
const inputOptions = {
errors,
touched,
handleChange,
handleBlur,
values,
inputs
};
const eventPreventHandler = (e) => {
e.preventDefault();
};
return (
<div>
<form onSubmit={(e) => eventPreventHandler(e)}>
<div className={styles.buttonContainer}>
<Grid container spacing={2} className={styles.fixedButtons}>
<Grid item className={styles.button}>
<BackButton pathBack={pathToCategories} />
</Grid>
<Grid item className={styles.button}>
<SaveButton
data-cy='save'
type={materialUiConstants.types.submit}
title={SAVE_TITLE}
onClickHandler={handleSubmit}
unblockFunction={unblock}
errors={errors}
values={{
uaName: values.uaName,
enName: values.enName,
code: values.code
}}
/>
</Grid>
</Grid>
</div>
<Grid item xs={12}>
<Paper className={styles.categoryItemUpdate}>
<span className={styles.imageUpload}>
{config.labels.avatarText}
</span>
<div className={styles.imageUploadAvatar}>
<ImageUploadContainer
handler={handleImageLoad}
src={edit ? values.categoryImage : categoryImage}
/>
</div>
<TextField
data-cy='code'
name='code'
className={styles.textField}
variant='outlined'
placeholder={config.labels.categories.categoryCode}
value={values.code}
onChange={handleChange}
onBlur={handleBlur}
error={touched.code && !!errors.code}
/>
{touched.code && errors.code && (
<div data-cy='code-error' className={styles.error}>
{errors.code}
</div>
)}
</Paper>
</Grid>
{languages.map((lang) => (
<LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
))}
</form>
</div>
);
}
Example #29
Source File: register.jsx From UpStats with MIT License | 4 votes |
Register = (props) => {
const toast = useToast();
const register = async (creds) => {
try {
const { data: jwt } = await http.post("/users/create", { ...creds });
window.localStorage.setItem(tokenKey, jwt);
window.location = "/admin";
toast({
title: "Success",
description: "Redirecting...",
status: "success",
duration: 9000,
isClosable: true,
});
} catch (ex) {
toast({
title: "Error",
description: "Cannot Login to Account",
status: "error",
duration: 9000,
isClosable: true,
});
}
};
useEffect(() => {
const token = window.localStorage.getItem("token");
if (token) {
window.location = "/admin";
}
}, []);
const formik = useFormik({
initialValues: {
name: "",
email: "",
password: "",
},
validationSchema: Yup.object({
name: Yup.string().label("Name").required(),
email: Yup.string().email().label("Email").required(),
password: Yup.string().label("Password").required(),
}),
onSubmit: (values) => {
register(values);
//alert(JSON.stringify(values, null, 2));
},
});
return (
<div className="w-full max-w-sm mx-auto overflow-hidden rounded-lg">
<div className="px-6 py-4">
<h2 className="mt-1 text-3xl font-medium text-center">Welcome Back</h2>
<p className="mt-1 text-center">Login to continue</p>
<form onSubmit={formik.handleSubmit}>
<Stack>
<Text>Name</Text>
<Input
id="name"
name="name"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
placeholder="Enter here"
isInvalid={
formik.touched.name && formik.errors.name ? true : false
}
/>
{formik.touched.name && formik.errors.name ? (
<Alert status="error">
<AlertIcon />
{formik.errors.name}
</Alert>
) : null}
</Stack>
<Stack>
<Text>Email</Text>
<Input
id="email"
name="email"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
placeholder="Enter here"
isInvalid={
formik.touched.email && formik.errors.email ? true : false
}
/>
{formik.touched.email && formik.errors.email ? (
<Alert status="error">
<AlertIcon />
{formik.errors.email}
</Alert>
) : null}
</Stack>
<Stack>
<Text>Password</Text>
<Input
id="password"
name="password"
type="password"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.password}
placeholder="Enter here"
isInvalid={
formik.touched.password && formik.errors.password ? true : false
}
/>
{formik.touched.password && formik.errors.password ? (
<Alert status="error">
<AlertIcon />
{formik.errors.password}
</Alert>
) : null}
</Stack>
{/* Register */}
<div className="flex items-center mt-4">
<button
style={{ backgroundColor: "#3747D4" }}
className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
type="submit"
>
Register
</button>
</div>
</form>
</div>
</div>
);
}