@chakra-ui/react#InputLeftAddon TypeScript Examples
The following examples show how to use
@chakra-ui/react#InputLeftAddon.
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: InputLeftAddonPreview.tsx From openchakra with MIT License | 6 votes |
InputLeftAddonPreview: React.FC<{ component: IComponent }> = ({
component,
}) => {
const { props, ref } = useInteractive(component)
const boxProps: any = {}
return (
<Box {...boxProps} ref={ref}>
<InputLeftAddon {...props} />
</Box>
)
}
Example #2
Source File: index.tsx From engine with MIT License | 5 votes |
Details = () => (
<AccordionItem>
<h2>
<AccordionButton _expanded={{ bg: "gray.300", color: "white" }}>
<Box flex="1" textAlign="left">
Details
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<InputGroup size="sm">
<InputLeftAddon children="Name" w="24" />
<Input defaultValue="DoThingsFoo" />
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children="File path" w="24" />
<Input defaultValue="src/producers/domain/computation.ts" />
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children="Author" w="24" />
<Input defaultValue="John Doe" isReadOnly />
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children="Created on" w="24" />
<Input defaultValue="19/02/2022" isReadOnly />
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children="Version" w="24" />
<Select placeholder="Select a version">
<option value="option1" selected>
V2 22/02/2022 14:23 - John a2a2b227a7 (latest)
</option>
<option value="option2">V1 20/02/2022 13:23 Jane 9c32e516af</option>
</Select>
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children="Description" w="24" />
<Textarea defaultValue="Does what it needs to do in terms of computation"></Textarea>
</InputGroup>
</AccordionPanel>
</AccordionItem>
)
Example #3
Source File: index.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
PlayerPanel = (props: {player: Player}) => {
const player = props.player;
return (
<Accordion>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
Basic info
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<InputGroup size="sm">
<InputLeftAddon children='Name' />
<Input onChange={(e) => player.name = e.target.value} placeholder={player.name} />
</InputGroup>
<div>
<Position object={player} />
</div>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
Quests
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
{player.questManager.quests.map((quest, i) => {
<Text>
{quest.name}: {quest.description}
</Text>
})}
</AccordionPanel>
</AccordionItem>
</Accordion>
)
}
Example #4
Source File: index.tsx From engine with MIT License | 4 votes |
Header = () => (
<AccordionItem>
<Heading>
<AccordionButton _expanded={{ bg: "gray.300", color: "white" }}>
<Box flex="1" textAlign="left">
Header
</Box>
<AccordionIcon />
</AccordionButton>
</Heading>
<AccordionPanel pb={4}>
<HStack mb="3">
<Box w="70%">
Fill values from a past runtime call, a unit test or auto determine
values based on observe and update dependencies
</Box>
<Box w="30%">
<Button size="sm" mr="3" mb="2" color="teal">
Auto
</Button>
<Popover>
<PopoverTrigger>
<Button size="sm" mr="3" mb="2" color="purple">
From call
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverHeader>Runtime call history (5)</PopoverHeader>
<PopoverCloseButton />
<PopoverBody>
<OrderedList>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
23/02/2022 14:15:10.123
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
23/02/2022 14:13:2.130
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
23/02/2022 14:12:41.500
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
23/02/2022 13:21:20.341
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
23/02/2022 12:40:19.983
</ListItem>
</OrderedList>
</PopoverBody>
</PopoverContent>
</Popover>
<Popover>
<PopoverTrigger>
<Button size="sm" color="blue">
From test
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverHeader>Tests (100% coverage)</PopoverHeader>
<PopoverCloseButton />
<PopoverBody>
<OrderedList>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
should ensure guards work (30% coverage)
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
should do computation when y is less (70% coverage)
</ListItem>
<ListItem
cursor="pointer"
_hover={{
color: "teal.500",
}}
>
should reject if y is greater than (64% coverage)
</ListItem>
</OrderedList>
</PopoverBody>
</PopoverContent>
</Popover>
</Box>
</HStack>
<Divider mb="4" />
<Box mb="4">
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="pie" w="32" />
<Input defaultValue="3.14" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="http" w="32" />
<Input defaultValue={`axios from "axios"`} />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input defaultValue="[mock]" bg="black.100" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="operation" w="32" />
<Input defaultValue="prop.operation" />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input defaultValue="sum" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="foo" w="32" />
<Input defaultValue="observe.foo.value" />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input defaultValue="123" bg="teal.800" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="bam" w="32" />
<Input defaultValue="observe.bar.internal.something" />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input defaultValue="321" bg="teal.800" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="updateSome" w="32" />
<Input defaultValue="update.a.value.somewhere" />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input defaultValue="444" bg="yellow.700" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
<HStack>
<InputGroup size="sm" w="70%">
<InputLeftAddon children="" w="32" />
<Input placeholder="enter something..." />
</InputGroup>
<InputGroup size="sm" w="30%">
<Input placeholder="sample value" />
<InputRightAddon children={<SettingsIcon />} cursor="pointer" />
</InputGroup>
</HStack>
</Box>
<HStack>
<Text w="70%" size="sm">
Last run took 14ms
</Text>
<ButtonGroup variant="outline" spacing="4">
<Button size="sm" colorScheme="black">
Save as test
</Button>
<Button size="sm" colorScheme="green" variant="solid">
Run
</Button>
</ButtonGroup>
</HStack>
</AccordionPanel>
</AccordionItem>
)
Example #5
Source File: index.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
HustlersPanel = (props: { hustlers: Hustler[] }) => {
const hustlers = props.hustlers;
return (
<Accordion allowToggle>
{hustlers.map((hustler, i) =>
<AccordionItem key={i}>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
{hustler.name}: {hustler.hustlerId ?? 'No Hustler'}
<br/>
Citizen: {hustler instanceof Citizen ? '✅' : '❌'}
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<InputGroup size="sm">
<InputLeftAddon children='Name' />
<Input onChange={(e) => hustler.name = e.target.value} placeholder={hustler.name} />
</InputGroup>
<div>
<Position object={hustler} />
</div>
<br />
<Accordion allowToggle>
{hustler instanceof Citizen ? <div>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
Path
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Repeat path:
<Checkbox defaultChecked={hustler.repeatPath} onChange={(e) => hustler.repeatPath = e.target.checked} />
<br />
Follow path:
<Checkbox defaultChecked={hustler.shouldFollowPath} onChange={(e) => hustler.shouldFollowPath = e.target.checked} />
<br />
<br />
{
hustler.path.map((p, i) =>
<div key={i}>
PathPoint #{i}
<Position object={p.position} />
<br />
</div>
)
}
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
Conversations
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
{
hustler.conversations.map((c, i) =>
<div key={i}>
<Accordion>
{
c.texts.map((t, i) =>
<AccordionItem key={i}>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
{t.text}
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<InputGroup size="sm">
<InputLeftAddon children='Text' />
<Input onChange={(e) => t.text = e.target.value} placeholder={t.text} />
</InputGroup>
<Text>
Choices
</Text>
{
t.choices ? t.choices.map((c, i) =>
<div key={i}>
<InputGroup size="sm">
<InputLeftAddon children='Text' />
<Input onChange={(e) => (t.choices!)[i] = e.target.value} placeholder={c} />
</InputGroup>
</div>
) : undefined
}
</AccordionPanel>
</AccordionItem>
)
}
</Accordion>
</div>
)
}
</AccordionPanel>
</AccordionItem>
</div> : undefined}
</Accordion>
</AccordionPanel>
</AccordionItem>
)}
</Accordion>
)
}
Example #6
Source File: index.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
LightsPanel = (props: { player: Player, lights: Phaser.GameObjects.LightsManager }) => {
const [, forceUpdate] = useReducer(x => x + 1, 0);
const player = props.player;
const lights = props.lights;
return (
<>
<div style={{
paddingLeft: '1rem',
}}>
Enabled: <Checkbox onChange={(e) => lights.active = e.target.checked} defaultChecked={lights.active}/>
<br/>
Number of lights: {lights.getLightCount()}
<br/>
Ambient color:
<input
type="color"
onChange={(e) => {
const value = e.target.value;
const color = value.substring(1);
const r = parseInt(color.substring(0, 2), 16) / 255;
const g = parseInt(color.substring(2, 4), 16) / 255;
const b = parseInt(color.substring(4, 6), 16) / 255;
lights.ambientColor.set(r, g, b);
}}
defaultValue={'#' +
(lights.ambientColor.r * 255).toString(16) +
(lights.ambientColor.g * 255).toString(16) +
(lights.ambientColor.b * 255).toString(16)}
/>
<br/>
<br />
<Button onClick={(e) => {
lights.addLight(player.x, player.y);
forceUpdate();
}}>
Add light
</Button>
<br />
<Button onClick={(e) => {
let layer: Phaser.GameObjects.Layer;
if (!(layer = (lights as any).pointLightLayer))
layer = (lights as any).pointLightLayer = player.scene.add.layer();
layer.add(lights.addPointLight(player.x, player.y));
forceUpdate();
}}>
Add pointlight
</Button>
</div>
<br/>
<Accordion defaultIndex={0}>
{
// getLights doesnt actually return an array of the lights... it returns an object with the dist and light
lights.getLights(player.scene.cameras.main).map((light, i) => {
const distance = (light as any).distance;
light = (light as any).light;
return <AccordionItem key={i}>
<h2>
<AccordionButton>
<Box flex='1' textAlign='left'>
Light: {light.x} {light.y}
<br />
PointLight: {light instanceof Phaser.GameObjects.PointLight ? '✅' : '❌'}
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<Position object={light}/>
<InputGroup size="sm">
<InputLeftAddon children='Radius' />
<Input onChange={(e) => light.radius = Number.parseFloat(e.target.value) ?? 0} placeholder={light.radius.toString()} />
</InputGroup>
<InputGroup size="sm">
<InputLeftAddon children='Intensity' />
<Input onChange={(e) => light.intensity = Number.parseFloat(e.target.value) ?? 0} placeholder={light.intensity.toString()} />
</InputGroup>
<br/>
Visible: <Checkbox onChange={(e) => light.visible = e.target.checked} defaultChecked={light.visible}/>
<div>
Color:
<input
type="color"
onChange={(e) => {
const value = e.target.value;
const color = value.substring(1);
const r = parseInt(color.substring(0, 2), 16) / 255;
const g = parseInt(color.substring(2, 4), 16) / 255;
const b = parseInt(color.substring(4, 6), 16) / 255;
light.color.set(r, g, b);
}}
defaultValue={'#' +
((light.color as any).r * 255).toString(16).padStart(2, '0') +
((light.color as any).g * 255).toString(16).padStart(2, '0') +
((light.color as any).b * 255).toString(16).padStart(2, '0')}
/>
</div>
<br/>
<Button variant="cny" onClick={(e) => {
if (light instanceof Phaser.GameObjects.PointLight)
(light as any).layer.remove(light);
else
lights.removeLight(light);
forceUpdate();
}}>
Remove light
</Button>
</AccordionPanel>
</AccordionItem>
})
}
</Accordion>
</>
)
}
Example #7
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 #8
Source File: CreatePiggybankInput.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
CreatePiggybankInput: FunctionComponent<Props> = ({
buttonText,
instanceId,
onCancel,
createButtonColorScheme,
placeholder,
}) => {
const { user } = useUser();
const router = useRouter();
const inputRef = createRef<HTMLInputElement>();
useEffect(() => {
if (router.pathname === '/dashboard') {
inputRef.current.focus();
}
}, []);
const [candidatePiggybankPath, setCandidatePiggybankPath] = useState('');
const [isCandidatePiggybankPathInvalid, setIsCandidatePiggybankPathInvalid] = useState(false);
const [isCreateTriggered, setIsCreateTriggered] = useState(false);
const { submitStatus, error, setError } = useCreatePiggybank(candidatePiggybankPath, setCandidatePiggybankPath, user, isCreateTriggered, setIsCreateTriggered);
async function handleCreateUrl() {
const isInvalid = !candidatePiggybankPath.match(piggybankPathRegex);
if (isInvalid) {
setIsCandidatePiggybankPathInvalid(true);
} else if (user) {
setIsCreateTriggered(true);
} else if (router.pathname === '/') {
cookies.set('pendingLoginCreatePiggybankPath', candidatePiggybankPath);
router.push('/?auth=1', undefined, { shallow: true });
}
}
function onSubmit(event) {
event.preventDefault();
handleCreateUrl();
}
const inputName = `create-coindrop-input-${instanceId}`;
return (
<form id={`create-coindrop-form-${instanceId}`} onSubmit={onSubmit}>
<Flex
align="center"
justify="center"
wrap="wrap"
>
<BoxMargin>
<InputGroup>
<InputLeftAddon>
coindrop.to/
</InputLeftAddon>
<Input
aria-label="Enter custom URL path"
name={inputName}
id={inputName}
maxLength={32}
roundedLeft="0"
placeholder={placeholder}
onChange={(e) => {
setError(null);
setCandidatePiggybankPath(e.target.value);
setIsCandidatePiggybankPathInvalid(false);
}}
value={candidatePiggybankPath}
isInvalid={isCandidatePiggybankPathInvalid || !!error}
ref={inputRef}
/>
</InputGroup>
</BoxMargin>
<BoxMargin>
<Button
ml={1}
colorScheme={createButtonColorScheme}
isDisabled={isCandidatePiggybankPathInvalid || submitStatus === 'submitting' || submitStatus === 'success'}
isLoading={submitStatus === 'submitting' || submitStatus === 'success'}
loadingText="Creating"
onClick={onSubmit}
type="submit"
>
{buttonText}
</Button>
</BoxMargin>
{onCancel && (
<BoxMargin>
<Button
onClick={onCancel}
ml={1}
>
Cancel
</Button>
</BoxMargin>
)}
</Flex>
{error && (
<CreateCoindropError
error={error}
/>
)}
{isCandidatePiggybankPathInvalid && (
<CoindropRequirements />
)}
</form>
);
}
Example #9
Source File: EditUrlInput.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
EditUrlInput: FunctionComponent<Props> = ({ register, value }) => {
const { query: { piggybankName }} = useRouter();
const currentPiggybankId = Array.isArray(piggybankName) ? piggybankName[0] : piggybankName;
const [isValidating, setIsValidating] = useState(false);
const [isValid, setIsValid] = useState(false);
const [error, setError] = useState<'Invalid input' | 'Id taken' | 'Network error'>();
const debouncedValue = useDebounce(value, 1500);
const { setIsPiggybankIdAvailable } = useContext(AdditionalValidation);
const isUrlUnchanged = value === currentPiggybankId;
const isInvalid = !debouncedValue.match(piggybankPathRegex);
const validateIsAvailable = async () => {
if (isUrlUnchanged) {
setIsValid(true);
setIsPiggybankIdAvailable(true);
setError(null);
setIsValidating(false);
return;
}
if (isInvalid) {
setIsValid(false);
setIsPiggybankIdAvailable(false);
setError('Invalid input');
setIsValidating(false);
return;
}
try {
const isAvailable = await isCoindropUrlAvailable(debouncedValue);
setIsValid(isAvailable && !isInvalid);
setIsPiggybankIdAvailable(isAvailable && !isInvalid);
if (!isAvailable) {
setError('Id taken');
}
} catch (err) {
setIsValid(false);
setIsPiggybankIdAvailable(false);
setError('Network error');
} finally {
setIsValidating(false);
}
};
useEffect(() => {
validateIsAvailable();
}, [debouncedValue]);
useEffect(() => {
setIsValidating(true);
setError(null);
}, [value]);
useEffect(() => {
setIsValidating(false);
}, []);
return (
<>
<InputGroup>
<InputLeftAddon>
coindrop.to/
</InputLeftAddon>
<Input
id="input-piggybankId"
maxLength={32}
roundedLeft="0"
isInvalid={!isValid && !isValidating && value === debouncedValue && !isUrlUnchanged}
ref={register}
name="piggybankId"
/>
<InputRightElement>
<StatusIcon
value={value}
debouncedValue={debouncedValue}
currentPiggybankId={currentPiggybankId}
isValid={isValid}
isValidating={isValidating}
/>
</InputRightElement>
</InputGroup>
{error === 'Invalid input' && (
<CoindropRequirements />
)}
{error === 'Id taken' && (
<CreateCoindropError
error="URL is taken, try another!"
/>
)}
{error === 'Network error' && (
<CreateCoindropError
error="Error checking availability, please try again"
/>
)}
</>
);
}