formik#Field TypeScript Examples
The following examples show how to use
formik#Field.
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: form-field.component.tsx From MyWay-client with MIT License | 6 votes |
export default function FormField({
children,
name,
type = "text",
placeholder = "",
as = null,
}: {
children?: ReactNode | undefined;
name: string;
type?: string;
placeholder?: string;
as?: null | string;
}) {
return (
<Field
name={name}
type={type}
placeholder={placeholder}
as={as}
className="w-full my-2"
>
{children}
</Field>
);
}
Example #2
Source File: SignInProject.view.tsx From tezos-link with Apache License 2.0 | 6 votes |
SignInProjectView = ({ handleSubmitForm }: NewPostViewProps) => (
<SignInProjectCard>
<h1>Sign In</h1>
<Formik
initialValues={{
uuid: ''
}}
validationSchema={signInProjectValidator}
validateOnBlur={false}
onSubmit={values => handleSubmitForm(values)}
>
{formikProps => {
const { handleSubmit } = formikProps
return (
<form onSubmit={handleSubmit}>
<Field
InputType={Input}
component={FormInputField}
icon="user"
name="uuid"
placeholder="e4efba4d-47e6-42a5-905e-589d3f673853"
/>
<Button text="Sign in project" icon="login" type="submit" />
</form>
)
}}
</Formik>
</SignInProjectCard>
)
Example #3
Source File: CommentForm.tsx From End-to-End-Web-Testing-with-Cypress with MIT License | 6 votes |
CommentForm: React.FC<CommentFormProps> = ({ transactionId, transactionComment }) => {
const classes = useStyles();
const initialValues = { content: "" };
return (
<div>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
transactionComment({ transactionId, ...values });
}}
>
{() => (
<Form className={classes.form}>
<Field name="content">
{({ field, meta }: FieldProps) => (
<TextField
variant="outlined"
margin="dense"
fullWidth
id={`transaction-comment-input-${transactionId}`}
type="text"
placeholder="Write a comment..."
inputProps={{ "data-test": `transaction-comment-input-${transactionId}` }}
error={meta.touched && Boolean(meta.error)}
helperText={meta.touched ? meta.error : ""}
{...field}
/>
)}
</Field>
</Form>
)}
</Formik>
</div>
);
}
Example #4
Source File: NewProject.view.tsx From tezos-link with Apache License 2.0 | 6 votes |
NewProjectView = ({ handleSubmitForm, loading }: NewPostViewProps) => {
const [networkValue, setNetwork] = useState('MAINNET')
return (
<NewProjectCard>
<h1>New Project</h1>
<Formik
initialValues={{title: '', network: ''}}
validationSchema={newProjectValidator}
validateOnBlur={false}
onSubmit={(values, actions) => handleSubmitForm({ ...values, network: networkValue }, actions)}
>
{formikProps => {
const {handleSubmit} = formikProps
return (
<div>
<Select
options={['MAINNET', 'CARTHAGENET']}
defaultOption={networkValue}
selectCallback={(e: string) => setNetwork(e)}
/>
<form onSubmit={handleSubmit}>
<Field InputType={Input} component={FormInputField} icon="user" name="title"
placeholder="Project title"/>
<Button text="Create project" icon="sign-up" type="submit" loading={loading}/>
</form>
</div>
)
}}
</Formik>
</NewProjectCard>
)
}
Example #5
Source File: Input.tsx From panvala with Apache License 2.0 | 6 votes |
StyledInput = styled(Field)`
box-sizing: border-box;
display: block;
width: 100%;
font-size: 0.875em;
margin-top: 8px;
padding: 16px 8px;
border-radius: 8px;
${space};
${color};
${layout};
${typography};
${flexbox};
${border};
${background}
${shadow};
${position};
`
Example #6
Source File: InputBox.tsx From slice-machine with Apache License 2.0 | 6 votes |
InputBox: React.FunctionComponent<InputBoxProps> = ({ name, label, placeholder, error, dataCy, }) => ( <Box mb={3}> <Label htmlFor={name} mb={2}> {label} </Label> <Field name={name} type="text" placeholder={placeholder} as={Input} autoComplete="off" {...(dataCy ? { "data-cy": dataCy } : null)} /> {error ? ( <Text data-cy={dataCy ? `${dataCy}-error` : "input-error"} sx={{ color: "error", mt: 1 }} > {error} </Text> ) : null} </Box> )
Example #7
Source File: index.tsx From advanced-formik-validations-with-yup with MIT License | 6 votes |
FormikField: React.FC<FormikFieldProps> = ({ name, label, type = "text", required = false}) => {
return (
<div className="FormikField">
<Field
required={required}
autoComplete="off"
as={TextField}
label={label}
name={name}
fullWidth
type={type}
helperText={<ErrorMessage name={name} />}
/>
</div>
);
}
Example #8
Source File: index.tsx From Mokku with MIT License | 6 votes |
Input = styled(Field).attrs({ id: "mock-create-input" })<{
small?: boolean;
marginRight?: boolean;
}>`
border: 1px solid ${({ theme }) => theme.colors.border};
border-radius: 4px;
border-style: solid;
${({ small }) => small && `width: 124px;`};
${({ marginRight }) => marginRight && `margin-right: 8px;`};
`
Example #9
Source File: Autocomplete.test.tsx From abacus with GNU General Public License v2.0 | 6 votes |
test('it shows as loading data', () => {
const isLoading = true
const { container } = render(
<MockFormik initialValues={{ name: 'no_name' }}>
<Field
component={Autocomplete}
name='name'
id='name'
fullWidth
options={[]}
loading={isLoading}
renderInput={(params: AutocompleteRenderInputParams) => {
return (
<MuiTextField
{...params}
placeholder='wp_username'
helperText='Use WordPress.com username.'
variant='outlined'
required
label='Owner'
InputProps={{
...autocompleteInputProps(params, isLoading),
startAdornment: <InputAdornment position='start'>@</InputAdornment>,
}}
InputLabelProps={{
shrink: true,
}}
/>
)
}}
/>
</MockFormik>,
)
expect(container).toMatchSnapshot('loading')
})
Example #10
Source File: index.tsx From Account-Manager with MIT License | 6 votes |
FormInput: FC<ComponentProps> = ({
hideErrorBlock = false,
hideErrorText = false,
label,
required,
...baseInputProps
}) => {
const {className, name} = baseInputProps;
const {errors, touched} = useFormContext();
const error = !!errors[name] && !!touched[name];
return (
<div className={clsx('FormInput FormFieldComponent', className)}>
{renderFormLabel({className, label, name, required})}
<Field {...baseInputProps} as={Input} className="FormField" error={error} required={required} />
{hideErrorBlock ? null : renderFormError({className, hideErrorText, name})}
</div>
);
}
Example #11
Source File: add-training-goal-task.form.component.tsx From MyWay-client with MIT License | 6 votes |
export default function AddTrainingGoalTaskForm({
dogId,
goalId,
}: {
dogId: number;
goalId: number;
}) {
return (
<Formik
initialValues={{ description: "" }}
onSubmit={(values, actions) => {
axios.post(`/api/dogs/${dogId}/training-goals/${goalId}/tasks`, {
...values,
});
}}
>
<Form>
<Field name="description" placeholder="description" />
<ErrorMessage name="description" />
<button type="submit">Add Task</button>
</Form>
</Formik>
);
}
Example #12
Source File: Beginning.tsx From abacus with GNU General Public License v2.0 | 6 votes |
Beginning = (): JSX.Element => {
const classes = useStyles()
return (
<div className={classes.root}>
<Typography variant='h4' gutterBottom>
Design and Document Your Experiment
</Typography>
<Typography variant='body2'>
We think one of the best ways to prevent a failed experiment is by documenting what you hope to learn.{/* */}
<br />
<br />
</Typography>
<Alert severity='info'>
<Link underline='always' href='https://github.com/Automattic/experimentation-platform/wiki' target='_blank'>
Our wiki is a great place to start
</Link>
, it will instruct you on creating a P2 post.
</Alert>
<Field
className={classes.p2EntryField}
component={TextField}
id='experiment.p2Url'
name='experiment.p2Url'
placeholder='https://your-p2-post-here'
label={`Your Post's URL`}
variant='outlined'
InputLabelProps={{
shrink: true,
}}
/>
</div>
)
}
Example #13
Source File: index.tsx From youtube-2020-june-multi-step-form-formik with MIT License | 5 votes |
export default function Home() {
return (
<Card>
<CardContent>
<FormikStepper
initialValues={{
firstName: '',
lastName: '',
millionaire: false,
money: 0,
description: '',
}}
onSubmit={async (values) => {
await sleep(3000);
console.log('values', values);
}}
>
<FormikStep label="Personal Data">
<Box paddingBottom={2}>
<Field fullWidth name="firstName" component={TextField} label="First Name" />
</Box>
<Box paddingBottom={2}>
<Field fullWidth name="lastName" component={TextField} label="Last Name" />
</Box>
<Box paddingBottom={2}>
<Field
name="millionaire"
type="checkbox"
component={CheckboxWithLabel}
Label={{ label: 'I am a millionaire' }}
/>
</Box>
</FormikStep>
<FormikStep
label="Bank Accounts"
validationSchema={object({
money: mixed().when('millionaire', {
is: true,
then: number()
.required()
.min(
1_000_000,
'Because you said you are a millionaire you need to have 1 million'
),
otherwise: number().required(),
}),
})}
>
<Box paddingBottom={2}>
<Field
fullWidth
name="money"
type="number"
component={TextField}
label="All the money I have"
/>
</Box>
</FormikStep>
<FormikStep label="More Info">
<Box paddingBottom={2}>
<Field fullWidth name="description" component={TextField} label="Description" />
</Box>
</FormikStep>
</FormikStepper>
</CardContent>
</Card>
);
}
Example #14
Source File: index.tsx From Mokku with MIT License | 5 votes |
Input = styled(Field)<{ small?: boolean }>`
height: 25px;
border: 1px solid ${({ theme }) => theme.colors.border};
border-radius: 4px;
border-style: solid;
${({ small }) => small && `width: 124px;`};
`
Example #15
Source File: Login.tsx From krmanga with MIT License | 5 votes |
Login = ({ navigation, dispatch, isLogin, loading }: IProps) => {
const [disabled, setDisabled] = useState<boolean>(false);
useEffect(() => {
if (isLogin) {
setTimeout(() => {
navigation.goBack();
}, 100);
}
}, [isLogin]);
const onSubmit = (values: Values) => {
if (disabled || loading) {
return;
}
setDisabled(true);
dispatch({
type: "user/login",
payload: values,
callback: () => {
setDisabled(false);
}
});
};
const cancel = (form: FormikProps<string>, field: FieldInputProps<string>) => {
if (field.name === "account") {
form.setFieldValue("account", "");
} else if (field.name === "password") {
form.setFieldValue("password", "");
}
};
return (
<ScrollView keyboardShouldPersistTaps="handled" style={styles.container}>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={customerValidation}>
{({ handleSubmit }) => (
<View>
<Field
name="account"
placeholder="请输入用户名"
component={Input}
iconName={"icon-Account"}
cancel={cancel}
/>
<Field
name="password"
placeholder="请输入密码"
component={Input}
iconName={"icon-mima"}
secureTextEntry
cancel={cancel}
/>
<View style={styles.jumpView}>
<Text style={styles.jumpTitle}>忘记密码?</Text>
<Touchable onPress={() => navigation.navigate("Register")}>
<Text style={styles.jumpTitle}>注册账号</Text>
</Touchable>
</View>
<Touchable disabled={disabled} onPress={handleSubmit} style={styles.login}>
<Text style={styles.loginText}>登录</Text>
</Touchable>
</View>
)}
</Formik>
</ScrollView>
);
}
Example #16
Source File: SwarmSelect.tsx From bee-dashboard with BSD 3-Clause "New" or "Revised" License | 5 votes |
export function SwarmSelect({ defaultValue, formik, name, options, onChange, label }: Props): ReactElement {
const classes = useStyles()
if (formik) {
return (
<>
{label && <FormHelperText>{label}</FormHelperText>}
<Field
required
component={Select}
name={name}
fullWidth
variant="outlined"
defaultValue={defaultValue || ''}
className={classes.select}
placeholder={label}
MenuProps={{ MenuListProps: { disablePadding: true }, PaperProps: { square: true } }}
>
{options.map((x, i) => (
<MenuItem key={i} value={x.value} className={classes.option}>
{x.label}
</MenuItem>
))}
</Field>
</>
)
}
return (
<>
{label && <FormHelperText>{label}</FormHelperText>}
<SimpleSelect
required
name={name}
fullWidth
variant="outlined"
className={classes.select}
defaultValue={defaultValue || ''}
onChange={onChange}
placeholder={label}
MenuProps={{ MenuListProps: { disablePadding: true }, PaperProps: { square: true } }}
>
{options.map((x, i) => (
<MenuItem key={i} value={x.value} className={classes.option}>
{x.label}
</MenuItem>
))}
</SimpleSelect>
</>
)
}
Example #17
Source File: MetaFile.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
MetaFile = (props: Props) => {
const alert = useAlert();
const metaFieldRef = useRef<HTMLInputElement>(null);
const { file, className, onUpload, onDelete } = props;
const uploadMetaFile = () => {
metaFieldRef.current?.click();
};
const handleChangeMetaFile = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length) {
const isCorrectFormat = checkFileFormat(event.target.files[0]);
if (isCorrectFormat) {
onUpload(event.target.files[0]);
} else {
alert.error('Wrong file format');
}
event.target.value = '';
}
};
return (
<div className={clsx(styles.upload, className)}>
<label htmlFor="meta" className={styles.caption}>
Metadata file:
</label>
<div className={styles.block}>
<Field
id="meta"
name="meta"
className={styles.hidden}
type="file"
innerRef={metaFieldRef}
onChange={handleChangeMetaFile}
/>
{file ? (
<div className={clsx(styles.value, styles.filename)}>
{file.name}
<button type="button" onClick={onDelete}>
<Trash2 color="#ffffff" size="20" strokeWidth="1" />
</button>
</div>
) : (
<Button
text="Select file"
type="button"
color="secondary"
className={styles.button}
onClick={uploadMetaFile}
/>
)}
</div>
</div>
);
}
Example #18
Source File: TextArea.tsx From core with GNU Affero General Public License v3.0 | 5 votes |
TextArea: React.FC<TextAreaProps> = ({ name, placeholder, theme='auto', max, setValue, value }) => {
const ref = useRef()
const [ emojiPickerHidden, setEmojiPickerHidden ] = useState(true)
useOutsideClick(ref, () => {
setEmojiPickerHidden(true)
})
return <div className='border border-grey-light dark:border-transparent h-96 text-black dark:bg-very-black dark:text-white rounded px-4 py-3 inline-block relative w-full'>
<Field as='textarea' name={name} className='dark:border-transparent text-black dark:bg-very-black dark:text-white w-full relative h-full resize-none outline-none' placeholder={placeholder} />
<div ref={ref}>
<div className='absolute bottom-12 left-10 z-30'>
{
!emojiPickerHidden && <Picker title='선택해주세요' emoji='sunglasses' set='twitter' enableFrequentEmojiSort theme={theme} showSkinTones={false} onSelect={(e) => {
setEmojiPickerHidden(true)
setValue(value + ' ' + ((e as { native: string }).native || e.colons))
}} i18n={{
search: '검색',
notfound: '검색 결과가 없습니다.',
categories: {
search: '검색 결과',
recent: '최근 사용',
people: '사람',
nature: '자연',
foods: '음식',
activity: '활동',
places: '장소',
objects: '사물',
symbols: '기호',
flags: '국기',
custom: '커스텀'
}
}} custom={KoreanbotsEmoji}/>
}
</div>
<div className='absolute bottom-2 left-4 hidden sm:block'>
<div className='emoji-selector-button outline-none' onClick={() => setEmojiPickerHidden(false)} onKeyPress={() => setEmojiPickerHidden(false)} role='button' tabIndex={0} />
</div>
{
max && <span className={`absolute bottom-2 right-4 ${max < value.length ? ' text-red-400' : ''}`}>
{max-value.length}
</span>
}
</div>
</div>
}
Example #19
Source File: RecurrenceEditor.tsx From querybook with Apache License 2.0 | 5 votes |
RecurrenceEditorDatePicker: React.FunctionComponent<IDatePickerProps> = ({
label,
onKey,
options,
error,
recurrence,
setRecurrence,
}) => {
const formattedError = (error?.[onKey] || '').replace(
`recurrence.on.${onKey}`,
label
);
return (
<FormField label={`Recurrence ${label}`} error={formattedError}>
<Field
name={`recurrence.on.${onKey}`}
render={({ field }) => (
<Select<IOptionType, true>
menuPortalTarget={overlayRoot}
styles={recurrenceReactSelectStyle}
value={options.filter((option: { value: any }) =>
field.value?.includes(option.value)
)}
options={options}
onChange={(value) => {
const newRecurrence = {
...recurrence,
on: {
...recurrence.on,
[onKey]: value.map((v) => v.value),
},
};
setRecurrence(newRecurrence);
}}
isMulti
/>
)}
/>
</FormField>
);
}
Example #20
Source File: CheckBox.tsx From core with GNU Affero General Public License v3.0 | 5 votes |
CheckBox: React.FC<CheckBoxProps> = ({ name, ...props }) => {
return <Field type='checkbox' name={name} className='form-checkbox text-koreanbots-blue bg-gray-300 h-4 w-4 rounded' {...props} />
}
Example #21
Source File: TagFormFields.tsx From abacus with GNU General Public License v2.0 | 5 votes |
TagFormFields = (): JSX.Element => {
const classes = useStyles()
return (
<>
<div className={classes.row}>
<Field
component={TextField}
name='tag.namespace'
id='tag.namespace'
label='Tag namespace'
placeholder='tag_namespace'
helperText='Use snake_case.'
variant='outlined'
fullWidth
required
InputLabelProps={{
shrink: true,
}}
/>
</div>
<div className={classes.row}>
<Field
component={TextField}
name='tag.name'
id='tag.name'
label='Tag name'
placeholder='tag_name'
helperText='Use snake_case.'
variant='outlined'
fullWidth
required
InputLabelProps={{
shrink: true,
}}
/>
</div>
<div className={classes.row}>
<Field
component={TextField}
name='tag.description'
id='tag.description'
label='Tag description'
placeholder='Put your Tag description here!'
variant='outlined'
fullWidth
required
multiline
rows={4}
InputLabelProps={{
shrink: true,
}}
/>
</div>
</>
)
}
Example #22
Source File: dog-profile.component.tsx From MyWay-client with MIT License | 5 votes |
export default function DogProfile({ dog }: { dog: DogDto }) {
return (
<div>
<div>
<div>
<div>Dog{"'"}s picture</div>
<span></span>
</div>
<div>
<div>
Upload {dog.name}
{"'"}s photo
</div>
<div>
<button>Upload photo</button>
</div>
</div>
</div>
<Formik
initialValues={{
name: dog.name,
breed: dog.breed,
age_years: calculateDiffInYears(new Date(), new Date(dog.birthDate)),
age_months: calculateDiffInMonths(
new Date(),
new Date(dog.birthDate)
),
}}
onSubmit={async (values, actions) => {
axios
.patch(`/api/dogs/${dog.id}`, values)
.then((res) =>
actions.setStatus({
status: true,
message: "Changes were saved successfully.",
})
)
.catch((e) =>
actions.setStatus({ status: true, message: e.message })
)
.finally(() => actions.setSubmitting(false));
}}
validationSchema={DogProfileSchema}
>
{({ isSubmitting, status }) => (
<Form>
<Field name="name" type="text" placeholder="Name" />
<ErrorMessage name="name" />
<Field name="breed" type="text" placeholder="Breed" />
<ErrorMessage name="breed" />
<Field name="age_years" type="number" placeholder="Age (years)" />
<ErrorMessage name="age_years" />
<Field name="age_months" type="number" placeholder="Age (months)" />
<ErrorMessage name="age_months" />
{status && <>{status.message}</>}
<SubmitButton isSubmitting={isSubmitting} />
</Form>
)}
</Formik>
</div>
);
}
Example #23
Source File: index.tsx From core with GNU Affero General Public License v3.0 | 4 votes |
Bots: NextPage<BotsProps> = ({ data, desc, date, user, theme, csrfToken }) => {
const bg = checkBotFlag(data?.flags, 'trusted') && data?.banner
const router = useRouter()
const [ nsfw, setNSFW ] = useState<boolean>()
const [ reportModal, setReportModal ] = useState(false)
const [ reportRes, setReportRes ] = useState<ResponseProps<unknown>>(null)
useEffect(() => {
setNSFW(localStorage.nsfw)
}, [])
if (!data?.id) return <NotFound />
return <div style={bg ? { background: `linear-gradient(to right, rgba(34, 36, 38, 0.68), rgba(34, 36, 38, 0.68)), url("${data.bg}") center top / cover no-repeat fixed` } : {}}>
<Container paddingTop className='py-10'>
<NextSeo
title={data.name}
description={data.intro}
twitter={{
cardType: 'summary_large_image'
}}
openGraph={{
images: [
{
url: KoreanbotsEndPoints.OG.bot(data.id, data.name, data.intro, data.category, [formatNumber(data.votes), formatNumber(data.servers)]),
width: 2048,
height: 1170,
alt: 'Bot Preview Image'
}
]
}}
/>
{
data.state === 'blocked' ? <div className='pb-40'>
<Message type='error'>
<h2 className='text-lg font-black'>해당 봇은 관리자에 의해 삭제되었습니다.</h2>
</Message>
</div>
: data.category.includes('NSFW') && !nsfw ? <NSFW onClick={() => setNSFW(true)} onDisableClick={() => localStorage.nsfw = true} />
: <>
<div className='w-full pb-2'>
{
data.state === 'private' ? <Message type='info'>
<h2 className='text-lg font-black'>해당 봇은 특수목적 봇이므로 초대하실 수 없습니다.</h2>
<p>해당 봇은 공개 사용이 목적이 아닌 특수목적봇입니다. 따라서 따로 초대하실 수 없습니다.</p>
</Message> :
data.state === 'reported' ?
<Message type='error'>
<h2 className='text-lg font-black'>해당 봇은 신고가 접수되어, 관리자에 의해 잠금 상태입니다.</h2>
<p>해당 봇 사용에 주의해주세요.</p>
<p>봇 소유자분은 <Link href='/guidelines'><a className='text-blue-500 hover:text-blue-400'>가이드라인</a></Link>에 대한 위반사항을 확인해주시고 <Link href='/discord'><a className='text-blue-500 hover:text-blue-400'>디스코드 서버</a></Link>로 문의해주세요.</p>
</Message> : ''
}
</div>
<div className='lg:flex w-full'>
<div className='w-full text-center lg:w-2/12'>
<DiscordAvatar
userID={data.id}
size={256}
className='w-full'
/>
</div>
<div className='flex-grow px-5 py-12 w-full text-center lg:w-5/12 lg:text-left'>
<Tag
circular
text={
<>
<i className={`fas fa-circle text-${Status[data.status]?.color}`} />{' '}
{Status[data.status]?.text}
</>
}
/>
<h1 className='mb-2 mt-3 text-4xl font-bold' style={bg ? { color: 'white' } : {}}>
{data.name}{' '}
{checkBotFlag(data.flags, 'trusted') ? (
<Tooltip placement='bottom' overlay='해당 봇은 한국 디스코드 리스트에서 엄격한 기준을 통과한 봇입니다!'>
<span className='text-koreanbots-blue text-3xl'>
<i className='fas fa-award' />
</span>
</Tooltip>
) : ''}
</h1>
<p className={`${bg ? 'text-gray-300' : 'dark:text-gray-300 text-gray-800'} text-base`}>{data.intro}</p>
</div>
<div className='w-full lg:w-1/4'>
{
data.state === 'ok' && <LongButton
newTab
href={`/bots/${router.query.id}/invite`}
>
<h4 className='whitespace-nowrap'>
<i className='fas fa-user-plus text-discord-blurple' /> 초대하기
</h4>
</LongButton>
}
<Link href={`/bots/${router.query.id}/vote`}>
<LongButton>
<h4>
<i className='fas fa-heart text-red-600' /> 하트 추가
</h4>
<span className='ml-1 px-2 text-center text-black dark:text-gray-400 text-sm bg-little-white-hover dark:bg-very-black rounded-lg'>
{formatNumber(data.votes)}
</span>
</LongButton>
</Link>
{
((data.owners as User[]).find(el => el.id === user?.id) || checkUserFlag(user?.flags, 'staff')) && <LongButton href={`/bots/${data.id}/edit`}>
<h4>
<i className='fas fa-cogs' /> 관리하기
</h4>
</LongButton>
}
{
((data.owners as User[]).find(el => el.id === user?.id) || checkUserFlag(user?.flags, 'staff')) && <LongButton onClick={async() => {
const res = await Fetch(`/bots/${data.id}/stats`, { method: 'PATCH'} )
if(res.code !== 200) return alert(res.message)
else window.location.reload()
}}>
<h4>
<i className='fas fa-sync' /> 정보 갱신하기
</h4>
</LongButton>
}
</div>
</div>
<Divider className='px-5' />
<div className='hidden lg:block'>
<Advertisement />
</div>
<div className='lg:flex lg:flex-row-reverse' style={bg ? { color: 'white' } : {}}>
<div className='mb-1 w-full lg:w-1/4'>
<h2 className='3xl mb-2 font-bold'>정보</h2>
<div className='grid gap-4 grid-cols-2 px-4 py-4 text-black dark:text-gray-400 dark:bg-discord-black bg-little-white rounded-sm'>
<div>
<i className='far fa-flag' /> 접두사
</div>
<div className='markdown-body text-black dark:text-gray-400'>
<code>{data.prefix}</code>
</div>
<div>
<i className='fas fa-users' /> 서버수
</div>
<div>{data.servers || 'N/A'}</div>
{
data.shards && data.servers > 1500 && <>
<div>
<i className='fas fa-sitemap' /> 샤드수
</div>
<div>{data.shards}</div>
</>
}
<div>
<i className='fas fa-calendar-day' /> 봇 생성일
</div>
<div>{Day(date).fromNow(false)}</div>
{
checkBotFlag(data.flags, 'verified') ?
<Tooltip overlay='해당 봇은 디스코드측에서 인증된 봇입니다.'>
<div className='col-span-2'>
<i className='fas fa-check text-discord-blurple' /> 디스코드 인증됨
</div>
</Tooltip>
: ''
}
</div>
<h2 className='3xl mb-2 mt-2 font-bold'>카테고리</h2>
<div className='flex flex-wrap'>
{data.category.map(el => (
<Tag key={el} text={el} href={`/bots/categories/${el}`} />
))}
</div>
<h2 className='3xl mb-2 mt-2 font-bold'>제작자</h2>
{(data.owners as User[]).map(el => (
<Owner
key={el.id}
id={el.id}
tag={el.tag}
username={el.username}
/>
))}
<div className='list grid'>
<Link href={`/bots/${router.query.id}/report`}>
<a className='text-red-600 hover:underline cursor-pointer' aria-hidden='true'>
<i className='far fa-flag' /> 신고하기
</a>
</Link>
<Modal header={`${data.name}#${data.tag} 신고하기`} closeIcon isOpen={reportModal} onClose={() => {
setReportModal(false)
setReportRes(null)
}} full dark={theme === 'dark'}>
{
reportRes?.code === 200 ? <Message type='success'>
<h2 className='text-lg font-semibold'>성공적으로 신고하였습니다!</h2>
<p>더 자세한 설명이 필요할 수 있습니다! <a className='text-blue-600 hover:text-blue-500' href='/discord'>공식 디스코드</a>에 참여해주세요</p>
</Message> : <Formik onSubmit={async (body) => {
const res = await Fetch(`/bots/${data.id}/report`, { method: 'POST', body: JSON.stringify(body) })
setReportRes(res)
}} validationSchema={ReportSchema} initialValues={{
category: null,
description: '',
_csrf: csrfToken
}}>
{
({ errors, touched, values, setFieldValue }) => (
<Form>
<div className='mb-5'>
{
reportRes && <div className='my-5'>
<Message type='error'>
<h2 className='text-lg font-semibold'>{reportRes.message}</h2>
<ul className='list-disc'>
{reportRes.errors?.map((el, n) => <li key={n}>{el}</li>)}
</ul>
</Message>
</div>
}
<h3 className='font-bold'>신고 구분</h3>
<p className='text-gray-400 text-sm mb-1'>해당되는 항목을 선택해주세요.</p>
{
reportCats.map(el =>
<div key={el}>
<label>
<Field type='radio' name='category' value={el} className='mr-1.5 py-2' />
{el}
</label>
</div>
)
}
<div className='mt-1 text-red-500 text-xs font-light'>{errors.category && touched.category ? errors.category : null}</div>
<h3 className='font-bold mt-2'>설명</h3>
<p className='text-gray-400 text-sm mb-1'>신고하시는 내용을 자세하게 설명해주세요.</p>
<TextArea name='description' placeholder='최대한 자세하게 설명해주세요!' theme={theme === 'dark' ? 'dark' : 'light'} value={values.description} setValue={(value) => setFieldValue('description', value)} />
<div className='mt-1 text-red-500 text-xs font-light'>{errors.description && touched.description ? errors.description : null}</div>
</div>
<div className='text-right'>
<Button className='bg-gray-500 hover:opacity-90 text-white' onClick={()=> setReportModal(false)}>취소</Button>
<Button type='submit' className='bg-red-500 hover:opacity-90 text-white'>제출</Button>
</div>
</Form>
)
}
</Formik>
}
</Modal>
{data.discord && (
<a
rel='noopener noreferrer'
target='_blank'
className='text-discord-blurple hover:underline'
href={`https://discord.gg/${data.discord}`}
>
<i className='fab fa-discord' />
디스코드 서버
</a>
)}
{data.web && (
<a
rel='noopener noreferrer'
target='_blank'
className='text-blue-500 hover:underline'
href={data.web}
>
<i className='fas fa-globe' />
웹사이트
</a>
)}
{data.git && (
<a
rel='noopener noreferrer'
target='_blank'
className='hover:underline'
href={data.git}
>
<i className={`fab fa-${git[new URL(data.git).hostname]?.icon ?? 'git-alt'}`} />
{git[new URL(data.git).hostname]?.text ?? 'Git'}
</a>
)}
</div>
<Advertisement size='tall' />
</div>
<div className='w-full lg:pr-5 lg:w-3/4'>
{
checkBotFlag(data.flags, 'hackerthon') ? <Segment className='mt-10'>
<h1 className='text-3xl font-semibold'>
<i className='fas fa-trophy mr-4 my-2 text-yellow-300' /> 해당 봇은 한국 디스코드 리스트 해커톤 수상작품입니다!
</h1>
<p>해당 봇은 한국 디스코드 리스트 주최로 진행되었던 "한국 디스코드 리스트 제1회 해커톤"에서 우수한 성적을 거둔 봇입니다.</p>
<p>자세한 내용은 <a className='text-blue-500 hover:text-blue-400' href='https://blog.koreanbots.dev/first-hackathon-results/'>해당 글</a>을 확인해주세요.</p>
</Segment> : ''
}
<Segment className='my-4'>
<Markdown text={desc}/>
</Segment>
<Advertisement />
</div>
</div>
</>
}
</Container>
</div>
}
Example #24
Source File: index.tsx From formik-chakra-ui with MIT License | 4 votes |
App = () => {
return (
<ChakraProvider>
<Heading as="h1" size="xl" textAlign="center">
Formik Chakra UI
</Heading>
<Box as="p" textAlign="center">
Example using{' '}
<Link href="https://github.com/kgnugur/formik-chakra-ui" isExternal>
Formik Chakra UI{' '}
</Link>
</Box>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{({ handleSubmit, values, errors }) => (
<Stack
spacing={5}
borderWidth="1px"
rounded="lg"
shadow="1px 1px 3px rgba(0,0,0,0.3)"
maxWidth={800}
p={6}
m="10px auto"
as="form"
onSubmit={handleSubmit as any}
>
<InputControl name="firstName" label="First Name" />
<InputControl name="lastName" label="Last Name" />
<NumberInputControl
name="age"
label="Age"
helperText="Helper text"
/>
<CheckboxSingleControl name="employed">
Employed
</CheckboxSingleControl>
<RadioGroupControl name="favoriteColor" label="Favorite Color">
<Radio value="#ff0000">Red</Radio>
<Radio value="#00ff00">Green</Radio>
<Radio value="#0000ff">Blue</Radio>
</RadioGroupControl>
<CheckboxContainer name="toppings" label="Toppings">
<CheckboxControl name="toppings1" value="chicken">
Chicken
</CheckboxControl>
<CheckboxControl name="toppings" value="ham">
Ham
</CheckboxControl>
<CheckboxControl name="toppings" value="mushrooms">
Mushrooms
</CheckboxControl>
<CheckboxControl name="toppings" value="cheese">
Cheese
</CheckboxControl>
<CheckboxControl name="toppings" value="tuna">
Tuna
</CheckboxControl>
<CheckboxControl name="toppings" value="pineapple">
Pineapple
</CheckboxControl>
</CheckboxContainer>
<TextareaControl name="notes" label="Notes" />
<SwitchControl name="employedd" label="Employed" />
<SelectControl
label="Select label"
name="select"
selectProps={{ placeholder: 'Select option' }}
>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</SelectControl>
<SliderControl name="foo" sliderProps={{ max: 40 }} />
<PinInputControl
name="bar"
pinAmount={4}
pinInputProps={{ size: 'sm' }}
/>
<PercentComplete />
<FormControl
name="customField"
label="Custom FormControl"
helperText="Helper text"
>
<Field
as={Input}
name="customField"
placeholder="A custom field"
/>
</FormControl>
<InputControl
name="customElements"
label="Custom elements"
labelProps={{ color: 'blue' }}
errorMessageProps={{ fontWeight: 'bold' }}
helperText="Helper text"
helperTextProps={{ fontStyle: 'italic' }}
/>
<ButtonGroup>
<SubmitButton>Submit</SubmitButton>
<ResetButton>Reset</ResetButton>
</ButtonGroup>
<Box as="pre" marginY={10}>
{JSON.stringify(values, null, 2)}
<br />
{JSON.stringify(errors, null, 2)}
</Box>
</Stack>
)}
</Formik>
</ChakraProvider>
);
}
Example #25
Source File: AddAttachment.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
AddAttachment: React.FC<AddAttachmentPropTypes> = ({
setAttachment,
setAttachmentAdded,
setAttachmentURL,
setAttachmentType,
attachmentURL,
attachmentType,
uploadPermission,
}: AddAttachmentPropTypes) => {
const [errors, setErrors] = useState<any>(null);
const [uploading, setUploading] = useState(false);
const [fileName, setFileName] = useState<null | string>(null);
const [verifying, setVerifying] = useState(false);
const [uploadDisabled] = useState(!uploadPermission);
const { t } = useTranslation();
const [uploadMedia] = useMutation(UPLOAD_MEDIA, {
onCompleted: (data: any) => {
setAttachmentURL(data.uploadMedia);
setUploading(false);
},
onError: () => {
setUploading(false);
},
});
const validateURL = () => {
if (attachmentURL && attachmentType) {
setVerifying(true);
setErrors(null);
validateMedia(attachmentURL, attachmentType)
.then((response: any) => {
if (!response.data.is_valid) {
setVerifying(false);
setErrors(response.data.message);
} else if (response.data.is_valid) {
setVerifying(false);
setAttachmentAdded(true);
setErrors(null);
}
})
.catch((error) => {
setLogs(error, 'error');
});
}
};
useEffect(() => {
validateURL();
}, [attachmentURL, attachmentType]);
const helperText = (
<div className={styles.HelperText}>
{t('Please wait for the attachment URL verification')}
<CircularProgress className={styles.ProgressIcon} />
</div>
);
let timer: any = null;
const input = {
component: Input,
name: 'attachmentURL',
type: 'text',
placeholder: t('Attachment URL'),
helperText: verifying && helperText,
disabled: fileName !== null,
inputProp: {
onBlur: (event: any) => {
setAttachmentURL(event.target.value);
},
onChange: (event: any) => {
clearTimeout(timer);
timer = setTimeout(() => setAttachmentURL(event.target.value), 1000);
},
},
};
let formFieldItems: any = [
{
component: Dropdown,
options,
name: 'attachmentType',
placeholder: 'Type',
fieldValue: attachmentType,
fieldChange: (event: any) => {
setAttachmentType(event?.target.value);
setErrors(null);
},
},
];
formFieldItems = attachmentType !== '' ? [...formFieldItems, input] : formFieldItems;
const validationSchema = Yup.object().shape({
attachmentType: Yup.string().required(t('Type is required.')),
attachmentURL: Yup.string().required(t('URL is required.')),
});
const displayWarning = () => {
if (attachmentType === 'STICKER') {
return (
<div className={styles.FormHelperText}>
<ol>
<li>{t('Animated stickers are not supported.')}</li>
<li>{t('Captions along with stickers are not supported.')}</li>
</ol>
</div>
);
}
return (
<div className={styles.FormHelperText}>
<ol>
<li>{t('Captions along with audio are not supported.')}</li>
</ol>
</div>
);
};
const onSubmitHandle = (itemData: { attachmentURL: any; attachmentType: any }) => {
setAttachmentType(itemData.attachmentType);
setAttachmentURL(itemData.attachmentURL);
setAttachment(false);
};
const addAttachment = (event: any) => {
const media = event.target.files[0];
if (media) {
const mediaName = media.name;
const extension = mediaName.slice((Math.max(0, mediaName.lastIndexOf('.')) || Infinity) + 1);
const shortenedName = mediaName.length > 15 ? `${mediaName.slice(0, 15)}...` : mediaName;
setFileName(shortenedName);
setUploading(true);
uploadMedia({
variables: {
media,
extension,
},
});
}
};
const form = (
<Formik
enableReinitialize
initialValues={{ attachmentURL, attachmentType }}
validationSchema={validationSchema}
onSubmit={(itemData) => {
if (!errors) {
onSubmitHandle(itemData);
}
}}
>
{({ submitForm }) => (
<Form className={styles.Form} data-testid="formLayout" encType="multipart/form-data">
<DialogBox
titleAlign="left"
title={t('Add attachments to message')}
handleOk={() => {
submitForm();
}}
handleCancel={() => {
setAttachment(false);
setAttachmentType('');
setAttachmentURL('');
setAttachmentAdded(false);
}}
buttonOk={t('Add')}
alignButtons="left"
disableOk={verifying}
>
<div className={styles.DialogContent} data-testid="attachmentDialog">
{formFieldItems.map((field: any) => (
<Field {...field} key={field.name} validateURL={errors} />
))}
{attachmentType !== '' && (
<div className={styles.CrossIcon}>
<CrossIcon
data-testid="crossIcon"
onClick={() => {
setAttachmentType('');
setAttachmentURL('');
setAttachmentAdded(false);
setErrors(null);
setFileName(null);
}}
/>
</div>
)}
<div className={styles.FormError}>{errors}</div>
</div>
{attachmentType !== '' && (
<>
<div className={styles.UploadContainer}>
<label
className={`${uploadDisabled ? styles.UploadDisabled : styles.UploadEnabled} ${
fileName && attachmentURL ? styles.Uploaded : ''
}`}
htmlFor="uploadFile"
>
{!uploadPermission && <AlertIcon className={styles.AlertIcon} />}
<span>
{fileName !== null ? (
fileName
) : (
<>
<UploadIcon className={styles.UploadIcon} /> Upload File
</>
)}
<input
type="file"
id="uploadFile"
data-testid="uploadFile"
onClick={(event) => {
if (uploadDisabled) {
event.preventDefault();
}
}}
onChange={(event) => {
addAttachment(event);
}}
/>
</span>
</label>
</div>
{uploading && <div className={styles.WaitUpload}>Please wait for upload</div>}
</>
)}
{!uploadPermission && attachmentType !== '' && (
<div className={styles.FormHelperText}>
{t('Please integrate Google Cloud Storage to use the upload')}
</div>
)}
{attachmentType === 'STICKER' || attachmentType === 'AUDIO' ? displayWarning() : null}
</DialogBox>
</Form>
)}
</Formik>
);
return form;
}
Example #26
Source File: report.tsx From core with GNU Affero General Public License v3.0 | 4 votes |
ReportBot: NextPage<ReportBotProps> = ({ data, user, csrfToken }) => {
const [ reportRes, setReportRes ] = useState<ResponseProps<unknown>>(null)
if(!data?.id) return <NotFound />
if(!user) return <Login>
<NextSeo title='신고하기' />
</Login>
return <Container paddingTop className='py-10'>
<NextSeo title={`${data.name} 신고하기`} />
<Link href={makeBotURL(data)}>
<a className='text-blue-500 hover:opacity-80'><i className='fas fa-arrow-left mt-3 mb-3' /> <strong>{data.name}</strong>{getJosaPicker('로')(data.name)} 돌아가기</a>
</Link>
{
reportRes?.code === 200 ? <Message type='success'>
<h2 className='text-lg font-semibold'>성공적으로 제출하였습니다!</h2>
<p>더 자세한 설명이 필요할 수 있습니다. <strong>반드시 <a className='text-blue-600 hover:text-blue-500' href='/discord'>공식 디스코드</a>에 참여해주세요!!</strong></p>
</Message> : <Formik onSubmit={async (body) => {
const res = await Fetch(`/bots/${data.id}/report`, { method: 'POST', body: JSON.stringify(body) })
setReportRes(res)
}} validationSchema={ReportSchema} initialValues={{
category: null,
description: '',
_csrf: csrfToken
}}>
{
({ errors, touched, values, setFieldValue }) => (
<Form>
<div className='mb-5'>
{
reportRes && <div className='my-5'>
<Message type='error'>
<h2 className='text-lg font-semibold'>{reportRes.message}</h2>
<ul className='list-disc'>
{reportRes.errors?.map((el, n) => <li key={n}>{el}</li>)}
</ul>
</Message>
</div>
}
<h3 className='font-bold'>신고 구분</h3>
<p className='text-gray-400 text-sm mb-1'>해당되는 항목을 선택해주세요.</p>
{
reportCats.map(el =>
<div key={el}>
<label>
<Field type='radio' name='category' value={el} className='mr-1.5 py-2' />
{el}
</label>
</div>
)
}
<div className='mt-1 text-red-500 text-xs font-light'>{errors.category && touched.category ? errors.category : null}</div>
{
values.category && <>
{
{
[reportCats[2]]: <Message type='info'>
<h3 className='font-bold text-xl'>본인 혹은 다른 사람이 위험에 처해 있나요?</h3>
<p>당신은 소중한 사람입니다.</p>
<p className='list-disc list-item list-inside'>자살예방상담전화 1393 | 청소년전화 1388</p>
</Message>,
[reportCats[5]]: <DMCA values={values} errors={errors} touched={touched} setFieldValue={setFieldValue} />,
[reportCats[6]]: <Message type='warning'>
<h3 className='font-bold text-xl'>디스코드 약관을 위반사항을 신고하시려고요?</h3>
<p><a className='text-blue-400' target='_blank' rel='noreferrer' href='http://dis.gd/report'>디스코드 문의</a>를 통해 직접 디스코드에 신고하실 수도 있습니다.</p>
</Message>
}[values.category]
}
{
!['오픈소스 라이선스, 저작권 위반 등 권리 침해'].includes(values.category) && <>
<h3 className='font-bold mt-2'>설명</h3>
<p className='text-gray-400 text-sm mb-1'>최대한 자세하게 기재해주세요.</p>
<TextField values={values} errors={errors} touched={touched} setFieldValue={setFieldValue} />
</>
}
</>
}
</div>
</Form>
)
}
</Formik>
}
</Container>
}
Example #27
Source File: Billing.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
BillingForm: React.FC<BillingProps> = () => {
const stripe = useStripe();
const elements = useElements();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [loading, setLoading] = useState(false);
const [disable, setDisable] = useState(false);
const [paymentMethodId, setPaymentMethodId] = useState('');
const [cardError, setCardError] = useState<any>('');
const [alreadySubscribed, setAlreadySubscribed] = useState(false);
const [pending, setPending] = useState(false);
const [couponApplied, setCouponApplied] = useState(false);
const [coupon] = useState('');
const { t } = useTranslation();
const validationSchema = Yup.object().shape({
name: Yup.string().required(t('Name is required.')),
email: Yup.string().email().required(t('Email is required.')),
});
// get organization billing details
const {
data: billData,
loading: billLoading,
refetch,
} = useQuery(GET_ORGANIZATION_BILLING, {
fetchPolicy: 'network-only',
});
const [getCouponCode, { data: couponCode, loading: couponLoading, error: couponError }] =
useLazyQuery(GET_COUPON_CODE, {
onCompleted: ({ getCouponCode: couponCodeResult }) => {
if (couponCodeResult.code) {
setCouponApplied(true);
}
},
});
const [getCustomerPortal, { loading: portalLoading }] = useLazyQuery(GET_CUSTOMER_PORTAL, {
fetchPolicy: 'network-only',
onCompleted: (customerPortal: any) => {
window.open(customerPortal.customerPortal.url, '_blank');
},
});
const formFieldItems = [
{
component: Input,
name: 'name',
type: 'text',
placeholder: 'Your Organization Name',
disabled: alreadySubscribed || pending || disable,
},
{
component: Input,
name: 'email',
type: 'text',
placeholder: 'Email ID',
disabled: alreadySubscribed || pending || disable,
},
];
useEffect(() => {
// Set name and email if a customer is already created
if (billData && billData.getOrganizationBilling?.billing) {
const billing = billData.getOrganizationBilling?.billing;
setName(billing?.name);
setEmail(billing?.email);
if (billing?.stripeSubscriptionStatus === null) {
setPending(false);
}
}
}, [billData]);
const [updateBilling] = useMutation(UPDATE_BILLING);
const [createBilling] = useMutation(CREATE_BILLING);
const [createSubscription] = useMutation(CREATE_BILLING_SUBSCRIPTION, {
onCompleted: (data) => {
const result = JSON.parse(data.createBillingSubscription.subscription);
// needs additional security (3d secure)
if (result.status === 'pending') {
if (stripe) {
stripe
.confirmCardSetup(result.client_secret, {
payment_method: paymentMethodId,
})
.then((securityResult: any) => {
if (securityResult.error?.message) {
setNotification(securityResult.error?.message, 'warning');
setLoading(false);
refetch().then(({ data: refetchedData }) => {
updateBilling({
variables: {
id: refetchedData.getOrganizationBilling?.billing?.id,
input: {
stripeSubscriptionId: null,
stripeSubscriptionStatus: null,
},
},
}).then(() => {
refetch();
});
});
} else if (securityResult.setupIntent.status === 'succeeded') {
setDisable(true);
setLoading(false);
setNotification('Your billing account is setup successfully');
}
});
}
} // successful subscription
else if (result.status === 'active') {
refetch();
setDisable(true);
setLoading(false);
setNotification('Your billing account is setup successfully');
}
},
onError: (error) => {
refetch();
setNotification(error.message, 'warning');
setLoading(false);
},
});
if (billLoading || portalLoading) {
return <Loading />;
}
// check if the organization is already subscribed or in pending state
if (billData && !alreadySubscribed && !pending) {
const billingDetails = billData.getOrganizationBilling?.billing;
if (billingDetails) {
const { stripeSubscriptionId, stripeSubscriptionStatus } = billingDetails;
if (stripeSubscriptionId && stripeSubscriptionStatus === 'pending') {
setPending(true);
} else if (stripeSubscriptionId && stripeSubscriptionStatus === 'active') {
setAlreadySubscribed(true);
}
}
}
const stripePayment = async () => {
if (!stripe || !elements) {
// Stripe.js has not loaded yet. Make sure to disable
// form submission until Stripe.js has loaded.
return;
}
// Get a reference to a mounted CardElement. Elements knows how
// to find your CardElement because there can only ever be one of
// each type of element.
const cardElement: any = elements.getElement(CardElement);
// create a payment method
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
setLoading(false);
refetch();
setNotification(error.message ? error.message : 'An error occurred', 'warning');
} else if (paymentMethod) {
setPaymentMethodId(paymentMethod.id);
const variables: any = {
stripePaymentMethodId: paymentMethod.id,
};
if (couponApplied) {
variables.couponCode = couponCode.getCouponCode.id;
}
await createSubscription({
variables,
});
}
};
const handleSubmit = async (itemData: any) => {
const { name: billingName, email: billingEmail } = itemData;
setLoading(true);
if (billData) {
const billingDetails = billData.getOrganizationBilling?.billing;
if (billingDetails) {
// Check if customer needs to be updated
if (billingDetails.name !== billingName || billingDetails.email !== billingEmail) {
updateBilling({
variables: {
id: billingDetails.id,
input: {
name: billingName,
email: billingEmail,
currency: 'inr',
},
},
})
.then(() => {
stripePayment();
})
.catch((error) => {
setNotification(error.message, 'warning');
});
} else {
stripePayment();
}
} else {
// There is no customer created. Creating a customer first
createBilling({
variables: {
input: {
name: billingName,
email: billingEmail,
currency: 'inr',
},
},
})
.then(() => {
stripePayment();
})
.catch((error) => {
setNotification(error.message, 'warning');
});
}
}
};
const backLink = (
<div className={styles.BackLink}>
<Link to="/settings">
<BackIcon />
Back to settings
</Link>
</div>
);
const cardElements = (
<>
<CardElement
options={{ hidePostalCode: true }}
className={styles.Card}
onChange={(e) => {
setCardError(e.error?.message);
}}
/>
<div className={styles.Error}>
<small>{cardError}</small>
</div>
<div className={styles.Helper}>
<small>Once subscribed you will be charged on basis of your usage automatically</small>
</div>
</>
);
const subscribed = (
<div>
<div className={styles.Subscribed}>
<ApprovedIcon />
You have an active subscription
<div>
Please <span>contact us</span> to deactivate
<br />
*Note that we do not store your credit card details, as Stripe securely does.
</div>
</div>
<div
aria-hidden
className={styles.Portal}
data-testid="customerPortalButton"
onClick={() => {
getCustomerPortal();
}}
>
Visit Stripe portal <CallMadeIcon />
</div>
</div>
);
let paymentBody = alreadySubscribed || disable ? subscribed : cardElements;
if (pending) {
paymentBody = (
<div>
<div className={styles.Pending}>
<PendingIcon className={styles.PendingIcon} />
Your payment is in pending state
</div>
<div
aria-hidden
className={styles.Portal}
data-testid="customerPortalButton"
onClick={() => {
getCustomerPortal();
}}
>
Visit Stripe portal <CallMadeIcon />
</div>
</div>
);
}
const couponDescription = couponCode && JSON.parse(couponCode.getCouponCode.metadata);
const processIncomplete = !alreadySubscribed && !pending && !disable;
return (
<div className={styles.Form}>
<Typography variant="h5" className={styles.Title}>
<IconButton disabled className={styles.Icon}>
<Settingicon />
</IconButton>
Billing
</Typography>
{backLink}
<div className={styles.Description}>
<div className={styles.UpperSection}>
<div className={styles.Setup}>
<div>
<div className={styles.Heading}>One time setup</div>
<div className={styles.Pricing}>
<span>INR 15000</span> ($220)
</div>
<div className={styles.Pricing}>+ taxes</div>
<ul className={styles.List}>
<li>5hr consulting</li>
<li>1 hr onboarding session</li>
</ul>
</div>
<div>
<div className={styles.Heading}>Monthly Recurring</div>
<div className={styles.Pricing}>
<span>INR 7,500</span> ($110)
</div>
<div className={styles.Pricing}>+ taxes</div>
<ul className={styles.List}>
<li>upto 250k messages</li>
<li>1-10 users</li>
</ul>
</div>
</div>
<div className={styles.Additional}>
<div className={styles.Heading}>Variable charges as usage increases</div>
<div>For every staff member over 10 users – INR 150 ($2)</div>
<div>For every 1K messages upto 1Mn messages – INR 10 ($0.14)</div>
<div>For every 1K messages over 1Mn messages – INR 5 ($0.07)</div>
</div>
</div>
<div className={styles.DottedSpaced} />
<div className={styles.BottomSection}>
<div className={styles.InactiveHeading}>
Suspended or inactive accounts:{' '}
<span className={styles.Amount}> INR 4,500/mo + taxes</span>
</div>
</div>
</div>
{couponApplied && (
<div className={styles.CouponDescription}>
<div className={styles.CouponHeading}>Coupon Applied!</div>
<div>{couponDescription.description}</div>
</div>
)}
{processIncomplete && couponError && (
<div className={styles.CouponError}>
<div>Invalid Coupon!</div>
</div>
)}
<div>
<Formik
enableReinitialize
validateOnBlur={false}
initialValues={{
name,
email,
coupon,
}}
validationSchema={validationSchema}
onSubmit={(itemData) => {
handleSubmit(itemData);
}}
>
{({ values, setFieldError, setFieldTouched }) => (
<Form>
{processIncomplete && (
<Field
component={Input}
name="coupon"
type="text"
placeholder="Coupon Code"
disabled={couponApplied}
endAdornment={
<InputAdornment position="end">
{couponLoading ? (
<CircularProgress />
) : (
<div
aria-hidden
className={styles.Apply}
onClick={() => {
if (values.coupon === '') {
setFieldError('coupon', 'Please input coupon code');
setFieldTouched('coupon');
} else {
getCouponCode({ variables: { code: values.coupon } });
}
}}
>
{couponApplied ? (
<CancelOutlinedIcon
className={styles.CrossIcon}
onClick={() => setCouponApplied(false)}
/>
) : (
' APPLY'
)}
</div>
)}
</InputAdornment>
}
/>
)}
{formFieldItems.map((field, index) => {
const key = index;
return <Field key={key} {...field} />;
})}
{paymentBody}
{processIncomplete && (
<Button
variant="contained"
data-testid="submitButton"
color="primary"
type="submit"
className={styles.Button}
disabled={!stripe || disable}
loading={loading}
>
Subscribe for monthly billing
</Button>
)}
</Form>
)}
</Formik>
</div>
</div>
);
}
Example #28
Source File: report.tsx From core with GNU Affero General Public License v3.0 | 4 votes |
ReportUser: NextPage<ReportUserProps> = ({ data, user, csrfToken }) => {
const [ reportRes, setReportRes ] = useState<ResponseProps<unknown>>(null)
if(!data?.id) return <NotFound />
if(!user) return <Login>
<NextSeo title='신고하기' />
</Login>
if(user?.id === data.id) return <>
<div className='flex items-center justify-center h-screen select-none'>
<div className='container mx-auto px-20 md:text-left text-center'>
<h1 className='text-6xl font-semibold'>저런..!</h1>
<p className='text-gray-400 text-lg mt-2'>유감스럽게도 자기 자신은 신고할 수 없습니다.</p>
</div>
</div>
</>
return <Container paddingTop className='py-10'>
<NextSeo title={`${data.username} 신고하기`} />
<Link href={makeUserURL(data)}>
<a className='text-blue-500 hover:opacity-80'><i className='fas fa-arrow-left mt-3 mb-3' /> <strong>{data.username}</strong>{getJosaPicker('로')(data.username)} 돌아가기</a>
</Link>
{
reportRes?.code === 200 ? <Message type='success'>
<h2 className='text-lg font-semibold'>성공적으로 제출하였습니다!</h2>
<p>더 자세한 설명이 필요할 수 있습니다. <strong>반드시 <a className='text-blue-600 hover:text-blue-500' href='/discord'>공식 디스코드</a>에 참여해주세요!!</strong></p>
</Message> : <Formik onSubmit={async (body) => {
const res = await Fetch(`/users/${data.id}/report`, { method: 'POST', body: JSON.stringify(body) })
setReportRes(res)
}} validationSchema={ReportSchema} initialValues={{
category: null,
description: '',
_csrf: csrfToken
}}>
{
({ errors, touched, values, setFieldValue }) => (
<Form>
<div className='mb-5'>
{
reportRes && <div className='my-5'>
<Message type='error'>
<h2 className='text-lg font-semibold'>{reportRes.message}</h2>
<ul className='list-disc'>
{reportRes.errors?.map((el, n) => <li key={n}>{el}</li>)}
</ul>
</Message>
</div>
}
<h3 className='font-bold'>신고 구분</h3>
<p className='text-gray-400 text-sm mb-1'>해당되는 항목을 선택해주세요.</p>
{
reportCats.map(el =>
<div key={el}>
<label>
<Field type='radio' name='category' value={el} className='mr-1.5 py-2' />
{el}
</label>
</div>
)
}
<div className='mt-1 text-red-500 text-xs font-light'>{errors.category && touched.category ? errors.category : null}</div>
{
values.category && <>
{
values.category === '오픈소스 라이선스, 저작권 위반 등 권리 침해' ? <DMCA values={values} errors={errors} touched={touched} setFieldValue={setFieldValue} /> :
values.category === '괴롭힘, 모욕, 명예훼손' ? <>
<Message type='info'>
<h3 className='font-bold text-xl'>본인 혹은 다른 사람이 위험에 처해 있나요?</h3>
<p>당신은 소중한 사람입니다.</p>
<p className='list-disc list-item list-inside'>자살예방상담전화 1393 | 청소년전화 1388</p>
</Message>
</> : ''
}
{
!['오픈소스 라이선스, 저작권 위반 등 권리 침해'].includes(values.category) && <>
<h3 className='font-bold mt-2'>설명</h3>
<p className='text-gray-400 text-sm mb-1'>최대한 자세하게 기재해주세요.</p>
<TextField values={values} errors={errors} touched={touched} setFieldValue={setFieldValue} />
</>
}
</>
}
</div>
</Form>
)
}
</Formik>
}
</Container>
}
Example #29
Source File: Register.tsx From krmanga with MIT License | 4 votes |
function Register({ navigation, dispatch, isLogin, loading }: IProps) {
const [disabled, setDisabled] = useState<boolean>(false);
useEffect(() => {
if (isLogin) {
setTimeout(() => {
navigation.goBack();
}, 100);
}
}, [isLogin]);
const onSubmit = (values: Values) => {
if (disabled || loading) {
return;
}
setDisabled(true);
dispatch({
type: "user/register",
payload: values,
callback: () => {
setDisabled(false);
}
});
};
const cancel = (form: FormikProps<string>, field: FieldInputProps<string>) => {
if (field.name === "account") {
form.setFieldValue("account", "");
} else if (field.name === "password") {
form.setFieldValue("password", "");
} else if (field.name === "repeat_password") {
form.setFieldValue("repeat_password", "");
} else if (field.name === "phone") {
form.setFieldValue("phone", "");
}
};
return (
<ScrollView keyboardShouldPersistTaps="handled" style={styles.container}>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={customerValidation}>
{({ handleSubmit }) => (
<View>
<Field
name="account"
placeholder="请输入用户名"
component={Input}
iconName={"icon-Account"}
cancel={cancel}
/>
<Field
name="password"
placeholder="请输入密码"
component={Input}
iconName={"icon-mima"}
secureTextEntry
cancel={cancel}
/>
<Field
name="repeat_password"
placeholder="请再输入密码"
component={Input}
iconName={"icon-mima"}
secureTextEntry
cancel={cancel}
/>
<Field
name="phone"
placeholder="请输入手机号(选填)"
component={Input}
iconName={"icon-mobile-phone"}
cancel={cancel}
/>
<View style={styles.jumpView}>
<Text style={styles.jumpTitle}>忘记密码?</Text>
<Touchable onPress={() => navigation.navigate("Login")}>
<Text style={styles.jumpTitle}>立即登录</Text>
</Touchable>
</View>
<Touchable disabled={disabled} onPress={handleSubmit} style={styles.login}>
<Text style={styles.loginText}>注册</Text>
</Touchable>
</View>
)}
</Formik>
</ScrollView>
);
}