@chakra-ui/react#FormHelperText TypeScript Examples
The following examples show how to use
@chakra-ui/react#FormHelperText.
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: AutoInstallUpdatesField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
AutoInstallUpdatesField = ({ helpText }: AutoInstallUpdatesFieldProps): JSX.Element => {
const autoInstall: boolean = (useAppSelector(state => state.config.auto_install_updates) ?? false);
return (
<FormControl>
<Checkbox id='auto_install_updates' isChecked={autoInstall} onChange={onCheckboxToggle}>Auto Install / Apply Updates</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
When enabled, BlueBubbles will auto-install the latest available version when an update is detected
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #2
Source File: AutoStartField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
AutoStartField = ({ helpText }: AutoStartFieldProps): JSX.Element => {
const autoStart: boolean = (useAppSelector(state => state.config.auto_start) ?? false);
return (
<FormControl>
<Checkbox id='auto_start' isChecked={autoStart} onChange={onCheckboxToggle}>Startup with macOS</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
When enabled, BlueBubbles will start automatically when you login.
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #3
Source File: CheckForUpdatesField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
CheckForUpdatesField = ({ helpText }: CheckForUpdatesFieldProps): JSX.Element => {
const checkForUpdates: boolean = (useAppSelector(state => state.config.check_for_updates) ?? false);
return (
<FormControl>
<Checkbox id='check_for_updates' isChecked={checkForUpdates} onChange={onCheckboxToggle}>Check for Updates on Startup</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
When enabled, BlueBubbles will automatically check for updates on startup
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #4
Source File: EncryptCommunicationsField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
EncryptCommunicationsField = ({ helpText }: EncryptCommunicationsFieldProps): JSX.Element => {
const encryption: boolean = (useAppSelector(state => state.config.encrypt_coms) ?? false);
return (
<FormControl>
<Checkbox id='encrypt_coms' isChecked={encryption} onChange={onCheckboxToggle}>Encrypt Messages</Checkbox>
<FormHelperText>
{helpText ?? 'Enabling this will add an additional layer of security to the app communications by encrypting messages with a password-based AES-256-bit algorithm'}
</FormHelperText>
</FormControl>
);
}
Example #5
Source File: AutoCaffeinateField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
AutoCaffeinateField = ({ helpText }: AutoCaffeinateFieldProps): JSX.Element => {
const keepAwake: boolean = (useAppSelector(state => state.config.auto_caffeinate) ?? false);
return (
<FormControl>
<Checkbox id='auto_caffeinate' isChecked={keepAwake} onChange={onCheckboxToggle}>Keep macOS Awake</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
When enabled, you mac will not fall asleep due to inactivity or a screen screen saver.
However, your computer lid's close action may override this.
Make sure your computer does not go to sleep when the lid is closed.
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #6
Source File: index.tsx From formik-chakra-ui with MIT License | 6 votes |
FormControl: FC<BaseProps> = (props: BaseProps) => {
const {
children,
name,
label,
labelProps,
helperText,
helperTextProps,
errorMessageProps,
...rest
} = props;
const [, { error, touched }] = useField(name);
return (
<ChakraFormControl isInvalid={!!error && touched} {...rest}>
{label && (
<FormLabel htmlFor={name} {...labelProps}>
{label}
</FormLabel>
)}
{children}
{error && (
<FormErrorMessage {...errorMessageProps}>{error}</FormErrorMessage>
)}
{helperText && (
<FormHelperText {...helperTextProps}>{helperText}</FormHelperText>
)}
</ChakraFormControl>
);
}
Example #7
Source File: NgrokRegionField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
NgrokRegionField = ({ helpText }: NgrokRegionFieldProps): JSX.Element => {
const ngrokRegion: string = (useAppSelector(state => state.config.ngrok_region) ?? '');
return (
<FormControl>
<FormLabel htmlFor='ngrok_region'>Ngrok Region</FormLabel>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Select
id='ngrok_region'
placeholder='Select your Ngrok Region'
maxWidth="15em"
mr={3}
value={ngrokRegion}
onChange={(e) => {
if (!e.target.value || e.target.value.length === 0) return;
onSelectChange(e);
}}
>
<option value='us'>North America</option>
<option value='eu'>Europe</option>
<option value='ap'>Asia/Pacific</option>
<option value='au'>Australia</option>
<option value='sa'>South America</option>
<option value='jp'>Japan</option>
<option value='in'>India</option>
</Select>
</Flex>
<FormHelperText>
{helpText ?? 'Select the region closest to you. This will ensure latency is at its lowest when connecting to the server.'}
</FormHelperText>
</FormControl>
);
}
Example #8
Source File: OledDarkThemeField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
UseOledDarkModeField = ({ helpText }: UseOledDarkModeFieldProps): JSX.Element => {
const oledDark: boolean = (useAppSelector(state => state.config.use_oled_dark_mode) ?? false);
return (
<FormControl>
<Checkbox id='use_oled_dark_mode' isChecked={oledDark} onChange={onCheckboxToggle}>Use OLED Black Dark Mode</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
Enabling this will set the dark mode theme to OLED black
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #9
Source File: UseHttpsField.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
UseHttpsField = ({ helpText }: UseHttpsFieldProps): JSX.Element => {
const useHttps: boolean = (useAppSelector(state => state.config.use_custom_certificate) ?? false);
return (
<FormControl>
<Checkbox id='use_custom_certificate' isChecked={useHttps} onChange={onCheckboxToggle}>Use Custom Certificate</Checkbox>
<FormHelperText>
{helpText ?? (
<Text>
This will install a self-signed certificate at: <Code>~/Library/Application Support/bluebubbles-server/Certs</Code>
<br />
Note: Only use this this option if you have your own certificate! Replace the certificates in the <Code>Certs</Code> directory
</Text>
)}
</FormHelperText>
</FormControl>
);
}
Example #10
Source File: Login.tsx From takeout-app with MIT License | 5 votes |
LoginForm: React.FC = () => {
const history = useHistory();
const { data: conferenceData } = Api.useConference();
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit } = useForm<{
email: string;
reference: string;
}>({ defaultValues: { email: "", reference: "" } });
const onSubmit = handleSubmit(async (data) => {
if (isRequesting) return;
setIsRequesting(true);
try {
const resp = await Api.createSession(data.email, data.reference);
setErrorAlert(null);
if (resp.attendee.is_ready) {
if (conferenceData) {
history.push(`/tracks/${encodeURIComponent(conferenceData.conference.default_track)}`);
} else {
location.href = "/";
}
} else {
history.push("/attendee");
}
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setIsRequesting(false);
});
// TODO: link to registration page and support email
return (
<Box maxW="360px" w="100%">
<form onSubmit={onSubmit}>
<FormControl mt={4} id="login_email" isRequired>
<FormLabel>Email Address</FormLabel>
<FormHelperText color={Colors.textMuted} my={1}>
Must be identital to the one registered to your ticket
</FormHelperText>
<Input {...register("email")} type="email" autoFocus backgroundColor="white" />
</FormControl>
<FormControl mt={4} id="login_reference" isRequired>
<FormLabel>Ticket ID (Reference Code)</FormLabel>
<FormHelperText color={Colors.textMuted} my={1}>
Code should be shown at{" "}
<Link href="/assets/ticket-email.png" isExternal target="_blank" textDecoration="underline">
the upper right of the confirmation email
</Link>{" "}
you received.
</FormHelperText>
<Input
{...register("reference")}
type="password"
placeholder="e.g. ABCD-1, XY1N-10, ..."
backgroundColor="white"
/>
</FormControl>
<Flex direction="row" justifyContent="space-around" w="100%" mt="30px">
<Button type="submit" w="160px" h="46px" colorScheme="rk" isLoading={isRequesting}>
Log in
</Button>
</Flex>
</form>
{errorAlert}
</Box>
);
}
Example #11
Source File: FeatureSettings.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
FeatureSettings = (): JSX.Element => {
const hideDockIcon = (useAppSelector(state => state.config.hide_dock_icon) ?? false);
const useTerminal = (useAppSelector(state => state.config.start_via_terminal) ?? false);
return (
<section>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Features</Text>
<Divider orientation='horizontal' />
<Spacer />
<PrivateApiField />
<Spacer />
<AutoCaffeinateField />
<Spacer />
<AutoStartField />
<Spacer />
<FormControl>
<Checkbox id='hide_dock_icon' isChecked={hideDockIcon} onChange={onCheckboxToggle}>Hide Dock Icon</Checkbox>
<FormHelperText>
Hiding the dock icon will not close the app. You can open the app again via the status bar icon.
</FormHelperText>
</FormControl>
<Spacer />
<Accordion allowMultiple>
<AccordionItem>
<AccordionButton>
<Box flex='1' textAlign='left' width="15em">
Advanced Feature Settings
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4}>
<FormControl>
<Checkbox id='start_via_terminal' isChecked={useTerminal} onChange={onCheckboxToggle}>Always Start via Terminal</Checkbox>
<FormHelperText>
When BlueBubbles starts up, it will auto-reload itself in terminal mode.
When in terminal, type "help" for command information.
</FormHelperText>
</FormControl>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
</section>
);
}
Example #12
Source File: ServerPasswordField.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
ServerPasswordField = ({ helpText }: ServerPasswordFieldProps): JSX.Element => {
const dispatch = useAppDispatch();
const password: string = (useAppSelector(state => state.config.password) ?? '');
const [showPassword, setShowPassword] = useBoolean();
const [newPassword, setNewPassword] = useState(password);
const [passwordError, setPasswordError] = useState('');
const hasPasswordError: boolean = (passwordError?? '').length > 0;
useEffect(() => { setNewPassword(password); }, [password]);
/**
* A handler & validator for saving a new password.
*
* @param theNewPassword - The new password to save
*/
const savePassword = (theNewPassword: string): void => {
// Validate the port
if (theNewPassword.length < 8) {
setPasswordError('Your password must be at least 8 characters!');
return;
} else if (theNewPassword === password) {
setPasswordError('You have not changed the password since your last save!');
return;
}
dispatch(setConfig({ name: 'password', value: theNewPassword }));
if (hasPasswordError) setPasswordError('');
showSuccessToast({
id: 'settings',
description: 'Successfully saved new password!'
});
};
return (
<FormControl isInvalid={hasPasswordError}>
<FormLabel htmlFor='password'>Server Password</FormLabel>
<Input
id='password'
type={showPassword ? 'text' : 'password'}
maxWidth="20em"
value={newPassword}
onChange={(e) => {
if (hasPasswordError) setPasswordError('');
setNewPassword(e.target.value);
}}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='View password'
icon={showPassword ? <AiFillEye /> : <AiFillEyeInvisible />}
onClick={() => setShowPassword.toggle()}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='Save password'
icon={<AiOutlineSave />}
onClick={() => savePassword(newPassword)}
/>
{!hasPasswordError ? (
<FormHelperText>
{helpText ?? 'Enter a password to use for clients to authenticate with the server'}
</FormHelperText>
) : (
<FormErrorMessage>{passwordError}</FormErrorMessage>
)}
</FormControl>
);
}
Example #13
Source File: PrivateApiField.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
PrivateApiField = ({ helpText }: PrivateApiFieldProps): JSX.Element => {
const privateApi: boolean = (useAppSelector(state => state.config.enable_private_api) ?? false);
const alertRef = useRef(null);
const [requiresConfirmation, confirm] = useState((): string | null => {
return null;
});
return (
<Box mt={1}>
<PrivateApiRequirements />
<FormControl mt={5}>
<Stack direction='row'>
<Checkbox
id='enable_private_api'
isChecked={privateApi}
onChange={onCheckboxToggle}
>
Private API
</Checkbox>
<Button
size='xs'
onClick={() => confirm('reinstall')}
>
Re-install Helper
</Button>
</Stack>
<FormHelperText>
{helpText ?? (
<Text>
If you have set up the Private API features (via MacForge or MySIMBL),
enable this option to allow the server to communicate with the iMessage Private API.
</Text>
)}
</FormHelperText>
</FormControl>
<ConfirmationDialog
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
onAccept={() => {
confirmationActions[requiresConfirmation as string].func();
}}
isOpen={requiresConfirmation !== null}
/>
</Box>
);
}
Example #14
Source File: PollIntervalField.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
PollIntervalField = ({ helpText }: PollIntervalFieldProps): JSX.Element => {
const dispatch = useAppDispatch();
const pollInterval: number = useAppSelector(state => state.config.db_poll_interval) ?? 1000;
const [newInterval, setNewInterval] = useState(pollInterval);
const [intervalError, setIntervalError] = useState('');
const hasIntervalError: boolean = (intervalError?? '').length > 0;
useEffect(() => { setNewInterval(pollInterval); }, [pollInterval]);
/**
* A handler & validator for saving a new poll interval
*
* @param theNewInterval - The new interval to save
*/
const saveInterval = (theNewInterval: number): void => {
// Validate the interval
if (theNewInterval < 500) {
setIntervalError('The interval must be at least 500ms or else database locks can occur');
return;
}
dispatch(setConfig({ name: 'db_poll_interval', value: theNewInterval }));
if (hasIntervalError) setIntervalError('');
showSuccessToast({
id: 'settings',
duration: 4000,
description: 'Successfully saved new poll interval! Restarting DB listeners...'
});
};
return (
<FormControl isInvalid={hasIntervalError}>
<FormLabel htmlFor='db_poll_interval'>Database Poll Interval (ms)</FormLabel>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Input
id='db_poll_interval'
type='number'
maxWidth="5em"
value={newInterval}
onChange={(e) => {
if (hasIntervalError) setIntervalError('');
setNewInterval(Number.parseInt(e.target.value));
}}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='Save poll interval'
icon={<AiOutlineSave />}
onClick={() => saveInterval(newInterval)}
/>
</Flex>
{!hasIntervalError ? (
<FormHelperText>
{helpText ?? 'Enter how often (in milliseconds) you want the server to check for new messages in the database'}
</FormHelperText>
) : (
<FormErrorMessage>{intervalError}</FormErrorMessage>
)}
</FormControl>
);
}
Example #15
Source File: LocalPortField.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
LocalPortField = ({ helpText }: LocalPortFieldProps): JSX.Element => {
const dispatch = useAppDispatch();
const port: number = useAppSelector(state => state.config.socket_port) ?? 1234;
const [newPort, setNewPort] = useState(port);
const [portError, setPortError] = useState('');
const hasPortError: boolean = (portError?? '').length > 0;
useEffect(() => { setNewPort(port); }, [port]);
/**
* A handler & validator for saving a new port.
*
* @param theNewPort - The new port to save
*/
const savePort = (theNewPort: number): void => {
// Validate the port
if (theNewPort < 1024 || theNewPort > 65635) {
setPortError('Port must be between 1,024 and 65,635');
return;
} else if (theNewPort === port) {
setPortError('You have not changed the port since your last save!');
return;
}
dispatch(setConfig({ name: 'socket_port', value: theNewPort }));
if (hasPortError) setPortError('');
showSuccessToast({
id: 'settings',
duration: 4000,
description: 'Successfully saved new port! Restarting Proxy & HTTP services...'
});
};
return (
<FormControl isInvalid={hasPortError}>
<FormLabel htmlFor='socket_port'>Local Port</FormLabel>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Input
id='socket_port'
type='number'
maxWidth="5em"
value={newPort}
onChange={(e) => {
if (hasPortError) setPortError('');
setNewPort(Number.parseInt(e.target.value));
}}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='Save port'
icon={<AiOutlineSave />}
onClick={() => savePort(newPort)}
/>
</Flex>
{!hasPortError ? (
<FormHelperText>
{helpText ?? 'Enter the local port for the socket server to run on'}
</FormHelperText>
) : (
<FormErrorMessage>{portError}</FormErrorMessage>
)}
</FormControl>
);
}
Example #16
Source File: ProxyServiceField.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
ProxyServiceField = ({ helpText, showAddress = true }: ProxyServiceFieldProps): JSX.Element => {
const dispatch = useAppDispatch();
const dnsRef = useRef(null);
const alertRef = useRef(null);
const proxyService: string = (useAppSelector(state => state.config.proxy_service) ?? '').toLowerCase().replace(' ', '-');
const address: string = useAppSelector(state => state.config.server_address) ?? '';
const port: number = useAppSelector(state => state.config.socket_port) ?? 1234;
const [dnsModalOpen, setDnsModalOpen] = useBoolean();
const [requiresConfirmation, confirm] = useState((): string | null => {
return null;
});
return (
<FormControl>
<FormLabel htmlFor='proxy_service'>Proxy Service</FormLabel>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Select
id='proxy_service'
placeholder='Select Proxy Service'
maxWidth="15em"
mr={3}
value={proxyService}
onChange={(e) => {
if (!e.target.value || e.target.value.length === 0) return;
onSelectChange(e);
if (e.target.value === 'dynamic-dns') {
setDnsModalOpen.on();
} else if (e.target.value === 'cloudflare') {
confirm('confirmation');
}
}}
>
<option value='ngrok'>Ngrok</option>
<option value='cloudflare'>Cloudflare</option>
<option value='dynamic-dns'>Dynamic DNS</option>
</Select>
{(proxyService === 'dynamic-dns')
? (
<IconButton
mr={3}
aria-label='Set address'
icon={<AiOutlineEdit />}
onClick={() => setDnsModalOpen.on()}
/>
) : null}
{(showAddress) ? (
<>
<Text fontSize="md" color="grey">Address: {address}</Text>
<IconButton
ml={3}
aria-label='Copy address'
icon={<BiCopy />}
onClick={() => copyToClipboard(address)}
/>
</>
) : null}
</Flex>
<FormHelperText>
{helpText ?? 'Select a proxy service to use to make your server internet-accessible. Without one selected, your server will only be accessible on your local network'}
</FormHelperText>
<DynamicDnsDialog
modalRef={dnsRef}
onConfirm={(address) => dispatch(setConfig({ name: 'server_address', value: address }))}
isOpen={dnsModalOpen}
port={port as number}
onClose={() => setDnsModalOpen.off()}
/>
<ConfirmationDialog
title="Notice"
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
acceptText="OK"
declineText={null}
onAccept={() => {
confirmationActions[requiresConfirmation as string].func();
}}
isOpen={requiresConfirmation !== null}
/>
</FormControl>
);
}
Example #17
Source File: NgrokAuthTokenField.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
NgrokAuthTokenField = ({ helpText }: NgrokAuthTokenFieldProps): JSX.Element => {
const dispatch = useAppDispatch();
const ngrokToken: string = (useAppSelector(state => state.config.ngrok_key) ?? '');
const [showNgrokToken, setShowNgrokToken] = useBoolean();
const [newNgrokToken, setNewNgrokToken] = useState(ngrokToken);
const [ngrokTokenError, setNgrokTokenError] = useState('');
const hasNgrokTokenError: boolean = (ngrokTokenError ?? '').length > 0;
useEffect(() => { setNewNgrokToken(ngrokToken); }, [ngrokToken]);
/**
* A handler & validator for saving a new Ngrok auth token.
*
* @param theNewNgrokToken - The new auth token to save
*/
const saveNgrokToken = (theNewNgrokToken: string): void => {
theNewNgrokToken = theNewNgrokToken.trim();
// Validate the port
if (theNewNgrokToken === ngrokToken) {
setNgrokTokenError('You have not changed the token since your last save!');
return;
} else if (theNewNgrokToken.includes(' ')) {
setNgrokTokenError('Invalid Ngrok Auth Token! Please check that you have copied it correctly.');
return;
}
dispatch(setConfig({ name: 'ngrok_key', value: theNewNgrokToken }));
setNgrokTokenError('');
showSuccessToast({
id: 'settings',
duration: 4000,
description: 'Successfully saved new Ngrok Auth Token! Restarting Proxy service...'
});
};
return (
<FormControl isInvalid={hasNgrokTokenError}>
<FormLabel htmlFor='ngrok_key'>Ngrok Auth Token (Optional)</FormLabel>
<Input
id='password'
type={showNgrokToken ? 'text' : 'password'}
maxWidth="20em"
value={newNgrokToken}
onChange={(e) => {
if (hasNgrokTokenError) setNgrokTokenError('');
setNewNgrokToken(e.target.value);
}}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='View Ngrok token'
icon={showNgrokToken ? <AiFillEye /> : <AiFillEyeInvisible />}
onClick={() => setShowNgrokToken.toggle()}
/>
<IconButton
ml={3}
verticalAlign='top'
aria-label='Save Ngrok token'
icon={<AiOutlineSave />}
onClick={() => saveNgrokToken(newNgrokToken)}
/>
{!hasNgrokTokenError ? (
<FormHelperText>
{helpText ?? (
<Text>
Using an Auth Token will allow you to use the benefits of the upgraded Ngrok
service. This can improve connection stability and reliability. If you do not have
an Ngrok Account, sign up for free here:
<Box as='span' color={baseTheme.colors.brand.primary}>
<Link href='https://dashboard.ngrok.com/get-started/your-authtoken' target='_blank'>ngrok.com</Link>
</Box>
</Text>
)}
</FormHelperText>
) : (
<FormErrorMessage>{ngrokTokenError}</FormErrorMessage>
)}
</FormControl>
);
}
Example #18
Source File: index.tsx From ksana.in with Apache License 2.0 | 4 votes |
export function UrlForm({ user, onSuccess }: IUrlFormProps) {
const { showAlert, hideAlert } = useAlertContext()
const [url, setUrl] = useState<string>('')
const [slug, setSlug] = useState<string>('')
const [isCheckPass, setIsCheckPass] = useState<boolean>(false)
const [isDynamic, setIsDynamic] = useState<boolean>(false)
const [errorUrl, setErrorUrl] = useState<boolean | string>(false)
const [errorSlug, setErrorSlug] = useState<boolean | string>(false)
const [loading, setLoading] = useState<boolean>(false)
const handleChangeUrl = (e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setUrl(value)
setErrorUrl('')
}
const handleChangeSlug = (e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setSlug(value)
setErrorSlug('')
}
const handleChangeIsDynamic = (e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.checked
setIsDynamic(value)
}
const resetErrorMessage = () => {
setErrorUrl('')
setErrorSlug('')
}
const checkIsEmpty = () => {
if (url === '') {
setErrorUrl('URL dan slug tidak bisa dikosongkan')
return true
}
if (url.indexOf('http://') === -1 && url.indexOf('https://') === -1) {
setErrorUrl('Pastikan URL dimulai dengan http:// atau https://')
return true
}
if (slug === '') {
setErrorSlug('URL dan slug tidak bisa dikosongkan')
return true
}
return false
}
const checkParamRequired = () => {
const params = url.match(/{param}/g) || []
if (isDynamic && !params.length) {
setErrorUrl('Tautan dinamis membutuhkan teks {param} di dalamnya')
return false
}
if (isDynamic && params.length > 1) {
setErrorUrl('Teks {param} cukup satu saja')
return false
}
return true
}
const handleCheckAvailability = async () => {
setLoading(true)
resetErrorMessage()
const isEmpty = checkIsEmpty()
const hasParam = checkParamRequired()
if (!isEmpty && hasParam) {
const response = await checkSlug({ slug: sanitizeSlug(slug) })
if (response.error) {
setIsCheckPass(true)
resetErrorMessage()
} else {
setErrorSlug(`Slug ${slug} telah digunakan, coba slug lain`)
}
}
setLoading(false)
}
const handleSaveNew = async () => {
setLoading(true)
const isEmpty = checkIsEmpty()
if (!isEmpty) {
const { error: errorInsert } = await saveUrl({
url: url,
slug: sanitizeSlug(slug),
is_dynamic: isDynamic,
userId: user?.id
})
if (!errorInsert) {
showAlert({
title: 'Sukses menyimpan tautan baru',
message: 'Tautan telah disimpan dalam basis data kami, silahkan mulai bagikan',
onClose: () => {
hideAlert()
mutate(apiUrlsGet(user?.id))
setUrl('')
setSlug('')
setIsCheckPass(false)
resetErrorMessage()
onSuccess()
}
})
} else {
showAlert({
title: 'Terjadi galat pada saat berusaha menyimpan data',
message: `Pesan: ${errorInsert.message}`,
onClose: () => {
hideAlert()
setIsCheckPass(false)
resetErrorMessage()
}
})
}
}
setLoading(false)
}
return (
<Box width={{ base: '100%' }}>
<Stack spacing={4} direction={{ base: 'column' }}>
<FormControl id="url" isRequired>
<Input
isRequired
isInvalid={Boolean(errorUrl)}
size="lg"
name="url"
placeholder={'Tautan yang akan dipercantik'}
variant="filled"
value={url}
onChange={handleChangeUrl}
/>
{errorUrl && <FormHelperText color="red.500">Error: {errorUrl}</FormHelperText>}
<FormHelperText>
Membutuhkan tautan dalam bentuk utuh, termasuk awalan https://
</FormHelperText>
{isDynamic && (
<FormHelperText>
Sisipkan teks <code>{'{param}'}</code> pada tautan
</FormHelperText>
)}
</FormControl>
<FormControl display="flex" alignItems="center">
<FormLabel htmlFor="is-dynamic" mb="0" display="flex">
Tautan dinamis{' '}
<Tooltip
label="Kamu bisa membuat tautan dinamis macam: https://mazipan.space/{param}"
placement="bottom"
>
<i>
<HiQuestionMarkCircle />
</i>
</Tooltip>
</FormLabel>
<Switch id="is-dynamic" onChange={handleChangeIsDynamic} />
</FormControl>
<FormControl id="slug" isRequired>
<InputGroup size="lg">
<InputLeftAddon
color={'orange.400'}
fontWeight="bold"
px={2}
children={HOME?.replace('https://', '').replace('http://', '')}
fontSize="xs"
/>
<Input
isRequired
isInvalid={Boolean(errorSlug)}
size="lg"
name="slug"
placeholder={'Slug cantik dambaanmu'}
variant="filled"
value={slug}
onChange={handleChangeSlug}
/>
</InputGroup>
{errorSlug && <FormHelperText color="red.500">Error: {errorSlug}</FormHelperText>}
<FormHelperText>
Hanya diperbolehkan menggunakan huruf, angka, karakter titik dan strip saja
</FormHelperText>
</FormControl>
{isCheckPass ? (
<Button
isLoading={loading}
loadingText="Processing"
size="lg"
px={6}
mt="4"
color={'white'}
bg={'green.400'}
_hover={{
bg: 'green.500'
}}
_focus={{
bg: 'green.500'
}}
onClick={handleSaveNew}
>
Simpan sekarang
</Button>
) : (
<Button
isLoading={loading}
loadingText="Processing"
size="lg"
px={6}
my="4"
color={'white'}
bg={'orange.400'}
_hover={{
bg: 'orange.500'
}}
_focus={{
bg: 'orange.500'
}}
onClick={handleCheckAvailability}
>
Cek ketersediaan
</Button>
)}
</Stack>
</Box>
)
}
Example #19
Source File: Inspector.tsx From openchakra with MIT License | 4 votes |
Inspector = () => {
const dispatch = useDispatch()
const component = useSelector(getSelectedComponent)
const { isOpen, onOpen, onClose } = useDisclosure()
const [componentName, onChangeComponentName] = useState('')
const componentsNames = useSelector(getComponentNames)
const { clearActiveProps } = useInspectorUpdate()
const saveComponent = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
dispatch.components.setComponentName({
componentId: component.id,
name: componentName,
})
onClose()
onChangeComponentName('')
}
const isValidComponentName = useMemo(() => {
return (
!!componentName.match(/^[A-Z]\w*$/g) &&
!componentsNames.includes(componentName) &&
// @ts-ignore
!componentsList.includes(componentName)
)
}, [componentName, componentsNames])
const { type, rootParentType, id, children } = component
const isRoot = id === 'root'
const parentIsRoot = component.parent === 'root'
const docType = rootParentType || type
const componentHasChildren = children.length > 0
useEffect(() => {
clearActiveProps()
}, [clearActiveProps])
return (
<>
<Box bg="white">
<Box
fontWeight="semibold"
fontSize="md"
color="yellow.900"
py={2}
px={2}
boxShadow="sm"
bg="yellow.100"
display="flex"
justifyContent="space-between"
flexDir="column"
>
{isRoot ? 'Document' : type}
{!!component.componentName && (
<Text fontSize="xs" fontWeight="light">
{component.componentName}
</Text>
)}
</Box>
{!isRoot && (
<Stack
direction="row"
py={2}
spacing={2}
align="center"
zIndex={99}
px={2}
flexWrap="wrap"
justify="flex-end"
>
<CodeActionButton />
{!component.componentName && (
<ActionButton
label="Name component"
icon={<EditIcon path="" />}
onClick={onOpen}
/>
)}
<ActionButton
label="Duplicate"
onClick={() => dispatch.components.duplicate()}
icon={<CopyIcon path="" />}
/>
<ActionButton
label="Reset props"
icon={<IoMdRefresh />}
onClick={() => dispatch.components.resetProps(component.id)}
/>
<ActionButton
label="Chakra UI Doc"
as={Link}
onClick={() => {
window.open(
`https://chakra-ui.com/${docType.toLowerCase()}`,
'_blank',
)
}}
icon={<GoRepo />}
/>
<ActionButton
bg="red.500"
label="Remove"
onClick={() => dispatch.components.deleteComponent(component.id)}
icon={<FiTrash2 />}
/>
</Stack>
)}
</Box>
<Box pb={1} bg="white" px={3}>
<Panels component={component} isRoot={isRoot} />
</Box>
<StylesPanel
isRoot={isRoot}
showChildren={componentHasChildren}
parentIsRoot={parentIsRoot}
/>
<Modal onClose={onClose} isOpen={isOpen} isCentered>
<ModalOverlay>
<ModalContent>
<form onSubmit={saveComponent}>
<ModalHeader>Save this component</ModalHeader>
<ModalCloseButton />
<ModalBody>
<FormControl isInvalid={!isValidComponentName}>
<FormLabel>Component name</FormLabel>
<Input
size="md"
autoFocus
variant="outline"
isFullWidth
focusBorderColor="blue.500"
errorBorderColor="red.500"
value={componentName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChangeComponentName(e.target.value)
}
/>
{!isValidComponentName && (
<FormErrorMessage>
Component name must start with a capital character and
must not contain space or special character, and name
should not be already taken (including existing chakra-ui
components).
</FormErrorMessage>
)}
<FormHelperText>
This will name your component that you will see in the code
panel as a separated component.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="blue"
mr={3}
type="submit"
isDisabled={!isValidComponentName}
>
Save
</Button>
<Button onClick={onClose}>Cancel</Button>
</ModalFooter>
</form>
</ModalContent>
</ModalOverlay>
</Modal>
</>
)
}
Example #20
Source File: AttendeeEdit.tsx From takeout-app with MIT License | 4 votes |
AttendeeEdit: React.FC = () => {
const { data: conferenceData } = Api.useConference();
const { data: session, error: sessionError } = Api.useSession();
const history = useHistory();
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit, reset } = useForm<{
name: string;
gravatar_email: string;
}>({
defaultValues: {
name: React.useMemo(() => session?.attendee?.name, [session]),
gravatar_email: "",
},
});
React.useEffect(() => {
if (session?.attendee) reset({ name: session.attendee.name, gravatar_email: "" });
}, [session?.attendee]);
const onSubmit = handleSubmit(async (data) => {
//const wasReady = session!.attendee?.is_ready;
if (isRequesting) return;
setIsRequesting(true);
try {
await Api.updateAttendee(data.name, data.gravatar_email);
setErrorAlert(null);
if (conferenceData) {
history.push(`/tracks/${encodeURIComponent(conferenceData.conference.default_track)}`);
} else {
location.href = "/";
}
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setIsRequesting(false);
});
if (!session?.attendee) {
return (
<Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
<VStack>
{sessionError ? (
<Box my={2}>
<ErrorAlert error={sessionError} />
</Box>
) : null}
<Spinner size="xl" />
</VStack>
</Container>
);
}
return (
<Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
<VStack justify="start" alignItems="start" spacing="30px">
<Heading as="h2" color={Colors.main}>
Settings
</Heading>
<HStack spacing="30px">
<Avatar size="xl" bg={Colors.defaultAvatarBg} src={session.attendee.avatar_url} loading="lazy" />
<Box maxW="750px">
<Text mb={2}>
Confirm your name and avatar used at live chat. These informations may be shared with other attendees once
submitted.
</Text>
<Text>
Be remember to abide by{" "}
<Link href="https://rubykaigi.org/2021-takeout/policies" isExternal textDecoration="underline">
our policies
</Link>
.
</Text>
</Box>
</HStack>
<form onSubmit={onSubmit}>
<VStack justify="start" alignItems="start" spacing="30px">
<FormControl id="login_reference" isRequired>
<FormLabel>Name</FormLabel>
<FormHelperText my={1}>Feel free to use nicknames, usernames, or handles :)</FormHelperText>
<Input {...register("name")} maxW="460px" autoFocus />
</FormControl>
<FormControl id="login_email">
<FormLabel>Gravatar Email Address</FormLabel>
<FormHelperText my={1}>
We use avatar images registered on{" "}
<Link href="https://www.gravatar.com" isExternal textDecoration="underline">
Gravatar
</Link>
. Fill the following field if you desire to choose different email address for your Gravatar image.
</FormHelperText>
<Input
{...register("gravatar_email")}
type="email"
maxW="460px"
placeholder="(leave empty to remain unchanged)"
/>
</FormControl>
<Button type="submit" w="160px" h="46px" colorScheme="rk" isLoading={isRequesting}>
{session.attendee.is_ready ? "Save" : "Continue"}
</Button>
</VStack>
</form>
{errorAlert}
</VStack>
</Container>
);
}