@chakra-ui/react#Switch TypeScript Examples
The following examples show how to use
@chakra-ui/react#Switch.
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: SwitchControl.tsx From openchakra with MIT License | 6 votes |
SwitchControl: React.FC<SwitchControlPropsType> = ({ name, label }) => {
const { setValue } = useForm()
const value = usePropsSelector(name)
return (
<FormControl label={label} htmlFor={name}>
<Switch
name={name}
id={name}
size="sm"
isChecked={value || false}
onChange={() => setValue(name, !value)}
/>
</FormControl>
)
}
Example #2
Source File: Setup.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
NavBar = (): JSX.Element => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Flex
height="20"
alignItems="center"
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent='space-between'
p={4}
pl={6}
>
<Flex alignItems="center" justifyContent='flex-start'>
<img src={logo} className="logo" alt="logo" height={48} />
<Text fontSize="1xl" ml={2}>BlueBubbles</Text>
</Flex>
<Flex justifyContent='flex-end'>
<HStack spacing={{ base: '0', md: '1' }}>
<Tooltip label="Website Home" aria-label="website-tip">
<Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
</Link>
</Tooltip>
<Tooltip label="BlueBubbles Web" aria-label="website-tip">
<Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
</Link>
</Tooltip>
<Tooltip label="Support Us" aria-label="donate-tip">
<Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
</Link>
</Tooltip>
<Tooltip label="Join our Discord" aria-label="discord-tip">
<Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
</Link>
</Tooltip>
<Tooltip label="Read our Source Code" aria-label="github-tip">
<Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
</Link>
</Tooltip>
<Spacer />
<Divider orientation="vertical" width={1} height={15} borderColor='gray' />
<Spacer />
<Spacer />
<Spacer />
<FormControl display='flex' alignItems='center'>
<Box mr={2}><MdOutlineDarkMode size={20} /></Box>
<Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
<Box ml={2}><MdOutlineLightMode size={20} /></Box>
</FormControl>
</HStack>
</Flex>
</Flex>
);
}
Example #3
Source File: index.tsx From formik-chakra-ui with MIT License | 5 votes |
SwitchControl: FC<SwitchControlProps> = React.forwardRef(
(props: SwitchControlProps, ref: React.ForwardedRef<HTMLInputElement>) => {
const { name, label, switchProps, ...rest } = props;
const [field, { error, touched }] = useField(name);
return (
<Box
css={css`
.chakra-form__label {
margin-bottom: 0;
}
.chakra-switch {
display: flex;
align-items: center;
margin-right: 0.75rem;
}
.chakra-form__error-message {
margin-top: 0;
}
`}
>
<FormControl
name={name}
label={label}
as={Flex}
alignItems="center"
{...rest}
>
<Switch
{...field}
id={name}
isInvalid={!!error && touched}
isChecked={field.value}
ref={ref}
{...switchProps}
/>
</FormControl>
</Box>
);
}
)
Example #4
Source File: TrackStreamOptionsSelector.tsx From takeout-app with MIT License | 5 votes |
TrackStreamOptionsSelector: React.FC<Props> = ({
track,
streamOptionsState: [options, setOptions],
instance,
}) => {
const handleOnChange = (key: "caption" | "interpretation") => {
return (e: React.ChangeEvent<HTMLInputElement>) => {
const newOptions = { ...options, [`${key}`]: e.target.checked };
setOptions(newOptions);
};
};
const enAndJa = (track.card?.topic?.labels?.indexOf("EN & JA") ?? -1) !== -1;
const interpretationLabel = enAndJa ? "English track" : "Japanese to English interpretation";
return (
<Box>
<Stack direction={["row", "row", "row", "column"]} spacing={0}>
<Tooltip label="Caption (English only)" aria-label="">
<FormControl display="flex" alignItems="center" h="30px">
<FormLabel htmlFor={`TrackStreamOptions_${instance}__CC`} aria-hidden="true" m={0} mr={1}>
<ClosedCaptionIcon w="24px" h="24px" />
</FormLabel>
<Switch
aria-label="Closed Caption"
id={`TrackStreamOptions_${instance}__CC`}
isChecked={options.caption}
onChange={handleOnChange("caption")}
/>
</FormControl>
</Tooltip>
{track.interpretation && track.card?.interpretation ? (
<Tooltip label={interpretationLabel} aria-label="">
<FormControl display="flex" alignItems="center" h="30px">
<FormLabel htmlFor={`TrackStreamOptions_${instance}__interpret`} aria-hidden="true" m={0} mr={1}>
<TranslateIcon w="24px" h="24px" />
</FormLabel>
<Switch
aria-label={interpretationLabel}
id={`TrackStreamOptions_${instance}__interpret`}
isChecked={options.interpretation}
onChange={handleOnChange("interpretation")}
/>
</FormControl>
</Tooltip>
) : null}
</Stack>
</Box>
);
}
Example #5
Source File: Navigation.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
MobileNav = ({ onOpen, onNotificationOpen, unreadCount, ...rest }: MobileProps) => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Flex
ml={{ base: 0, md: 60 }}
px={{ base: 4, md: 4 }}
height="20"
alignItems="center"
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent={{ base: 'space-between', md: 'flex-end' }}
{...rest}
>
<IconButton
display={{ base: 'flex', md: 'none' }}
onClick={onOpen}
variant="outline"
aria-label="open menu"
icon={<FiMenu />}
/>
<Text display={{ base: 'flex', md: 'none' }} fontSize="2xl" fontFamily="monospace" fontWeight="bold">
<img src={logo} className="logo-small" alt="logo" />
</Text>
<HStack spacing={{ base: '0', md: '1' }}>
<Tooltip label="Website Home" aria-label="website-tip">
<Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
</Link>
</Tooltip>
<Tooltip label="BlueBubbles Web" aria-label="website-tip">
<Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
</Link>
</Tooltip>
<Tooltip label="Sponsor Us" aria-label="sponsor-tip">
<Link href="https://github.com/sponsors/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<AiOutlineHeart />} />
</Link>
</Tooltip>
<Tooltip label="Support Us" aria-label="donate-tip">
<Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
</Link>
</Tooltip>
<Tooltip label="Join our Discord" aria-label="discord-tip">
<Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
</Link>
</Tooltip>
<Tooltip label="Read our Source Code" aria-label="github-tip">
<Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
</Link>
</Tooltip>
<Box position='relative' float='left'>
<IconButton
size="lg"
verticalAlign='middle'
zIndex={1}
variant="ghost"
aria-label="notifications"
icon={<FiBell />}
onClick={() => onNotificationOpen()}
/>
{(unreadCount > 0) ? (
<Badge
borderRadius='lg'
variant='solid'
colorScheme='red'
position='absolute'
margin={0}
top={1}
right={1}
zIndex={2}
>{unreadCount}</Badge>
) : null}
</Box>
<Spacer />
<Divider orientation="vertical" width={1} height={15} borderColor='gray' />
<Spacer />
<Spacer />
<Spacer />
<FormControl display='flex' alignItems='center'>
<Box mr={2}><MdOutlineDarkMode size={20} /></Box>
<Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
<Box ml={2}><MdOutlineLightMode size={20} /></Box>
</FormControl>
</HStack>
</Flex>
);
}
Example #6
Source File: FusePoolCreatePage.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
PoolConfiguration = () => {
const { t } = useTranslation();
const toast = useToast();
const { fuse, address } = useRari();
const navigate = useNavigate();
const { isOpen, onOpen, onClose } = useDisclosure();
const [name, setName] = useState("");
const [isWhitelisted, setIsWhitelisted] = useState(false);
const [whitelist, setWhitelist] = useState<string[]>([]);
const [closeFactor, setCloseFactor] = useState(50);
const [liquidationIncentive, setLiquidationIncentive] = useState(8);
const [isUsingMPO, setIsUsingMPO] = useState(true)
const [customOracleAddress, setCustomOracleAddress] = useState('')
const [isCreating, setIsCreating] = useState(false);
const [activeStep, setActiveStep] = useState<number>(0);
const increaseActiveStep = (step: string) => {
setActiveStep(steps.indexOf(step));
};
const [needsRetry, setNeedsRetry] = useState<boolean>(false);
const [retryFlag, setRetryFlag] = useState<number>(1);
const [deployedPriceOracle, setDeployedPriceOracle] = useState<string>("");
const postDeploymentHandle = (priceOracle: string) => {
setDeployedPriceOracle(priceOracle);
};
const deployPool = async (
bigCloseFactor: string,
bigLiquidationIncentive: string,
options: any,
priceOracle: string
) => {
const [poolAddress] = await fuse.deployPool(
name,
isWhitelisted,
bigCloseFactor,
bigLiquidationIncentive,
priceOracle,
{},
options,
isWhitelisted ? whitelist : null
);
return poolAddress;
};
const onDeploy = async () => {
let priceOracle = deployedPriceOracle;
if (name === "") {
toast({
title: "Error!",
description: "You must specify a name for your Fuse pool!",
status: "error",
duration: 2000,
isClosable: true,
position: "top-right",
});
return;
}
if (isWhitelisted && whitelist.length < 2 ) {
toast({
title: "Error!",
description: "You must add an address to your whitelist!",
status:"error",
duration: 2000,
isClosable: true,
position: "top-right",
})
return
}
if (!isUsingMPO && !fuse.web3.utils.isAddress(customOracleAddress)) {
toast({
title: "Error!",
description: "You must add an address for your oracle or use the default oracle.",
status:"error",
duration: 2000,
isClosable: true,
position: "top-right",
})
return
}
setIsCreating(true);
onOpen();
// 50% -> 0.5 * 1e18
const bigCloseFactor = new BigNumber(closeFactor)
.dividedBy(100)
.multipliedBy(1e18)
.toFixed(0);
// 8% -> 1.08 * 1e8
const bigLiquidationIncentive = new BigNumber(liquidationIncentive)
.dividedBy(100)
.plus(1)
.multipliedBy(1e18)
.toFixed(0);
let _retryFlag = retryFlag;
try {
const options = { from: address };
setNeedsRetry(false);
if (!isUsingMPO && _retryFlag === 1) {
_retryFlag = 2;
priceOracle = customOracleAddress
}
if (_retryFlag === 1) {
priceOracle = await fuse.deployPriceOracle(
"MasterPriceOracle",
{
underlyings: [],
oracles: [],
canAdminOverwrite: true,
defaultOracle:
Fuse.PUBLIC_PRICE_ORACLE_CONTRACT_ADDRESSES.MasterPriceOracle, // We give the MasterPriceOracle a default "fallback" oracle of the Rari MasterPriceOracle
},
options
);
postDeploymentHandle(priceOracle);
increaseActiveStep("Deploying Pool!");
_retryFlag = 2;
}
let poolAddress: string;
if (_retryFlag === 2) {
poolAddress = await deployPool(
bigCloseFactor,
bigLiquidationIncentive,
options,
priceOracle
);
const event = (
await fuse.contracts.FusePoolDirectory.getPastEvents(
"PoolRegistered",
{
fromBlock: (await fuse.web3.eth.getBlockNumber()) - 10,
toBlock: "latest",
}
)
).filter(
(event) =>
event.returnValues.pool.comptroller.toLowerCase() ===
poolAddress.toLowerCase()
)[0];
LogRocket.track("Fuse-CreatePool");
toast({
title: "Your pool has been deployed!",
description: "You may now add assets to it.",
status: "success",
duration: 2000,
isClosable: true,
position: "top-right",
});
let id = event.returnValues.index;
onClose();
navigate(`/fuse/pool/${id}/edit`);
}
} catch (e) {
handleGenericError(e, toast);
setRetryFlag(_retryFlag);
setNeedsRetry(true);
}
};
return (
<>
<TransactionStepperModal
handleRetry={onDeploy}
needsRetry={needsRetry}
activeStep={activeStep}
isOpen={isOpen}
onClose={onClose}
/>
<DashboardBox width="100%" mt={4}>
<Column mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
<Heading size="sm" px={4} py={4}>
{t("Create Pool")}
</Heading>
<ModalDivider />
<OptionRow>
<Text fontWeight="bold" mr={4}>
{t("Name")}
</Text>
<Input
width="20%"
value={name}
onChange={(event) => setName(event.target.value)}
/>
</OptionRow>
<ModalDivider />
<ModalDivider />
<OptionRow>
<SimpleTooltip
label={t(
"If enabled you will be able to limit the ability to supply to the pool to a select group of addresses. The pool will not show up on the 'all pools' list."
)}
>
<Text fontWeight="bold">
{t("Whitelisted")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<Switch
h="20px"
isChecked={isWhitelisted}
onChange={() => {
setIsWhitelisted((past) => !past);
// Add the user to the whitelist by default
if (whitelist.length === 0) {
setWhitelist([address]);
}
}}
className="black-switch"
colorScheme="#121212"
/>
</OptionRow>
{isWhitelisted ? (
<WhitelistInfo
whitelist={whitelist}
addToWhitelist={(user) => {
setWhitelist((past) => [...past, user]);
}}
removeFromWhitelist={(user) => {
setWhitelist((past) =>
past.filter(function (item) {
return item !== user;
})
);
}}
/>
) : null}
<ModalDivider />
<OptionRow>
<SimpleTooltip
label={t(
"The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing. Compound's close factor is 50%."
)}
>
<Text fontWeight="bold">
{t("Close Factor")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<SliderWithLabel
value={closeFactor}
setValue={setCloseFactor}
formatValue={formatPercentage}
min={5}
max={90}
/>
</OptionRow>
<ModalDivider />
<OptionRow>
<SimpleTooltip
label={t(
"The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. For example, if the liquidation incentive is 10%, liquidators receive an extra 10% of the borrowers collateral for every unit they close. Compound's liquidation incentive is 8%."
)}
>
<Text fontWeight="bold">
{t("Liquidation Incentive")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<SliderWithLabel
value={liquidationIncentive}
setValue={setLiquidationIncentive}
formatValue={formatPercentage}
min={0}
max={50}
/>
</OptionRow>
<ModalDivider />
<OptionRow>
<SimpleTooltip
label={t(
"We will deploy a price oracle for your pool. This price oracle will contain price feeds for popular ERC20 tokens."
)}
>
<Text fontWeight="bold">
{isUsingMPO ? t("Default Price Oracle") : t("Custom Price Oracle")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<Box display="flex" alignItems='flex-end' flexDirection="column">
<Checkbox
isChecked={isUsingMPO}
onChange={(e) => setIsUsingMPO(!isUsingMPO)}
marginBottom={3}
/>
{
!isUsingMPO ? (
<>
<Input
value={customOracleAddress}
onChange={(e) => setCustomOracleAddress(e.target.value)}
/>
<Text mt={3} opacity="0.6" fontSize="sm">
Please make sure you know what you're doing.
</Text>
</>
)
: null
}
</Box>
</OptionRow>
</Column>
</DashboardBox>
<DashboardBox
width="100%"
height="60px"
mt={4}
py={3}
fontSize="xl"
as="button"
onClick={useAuthedCallback(onDeploy)}
>
<Center expand fontWeight="bold">
{isCreating ? <Spinner /> : t("Create")}
</Center>
</DashboardBox>
</>
);
}
Example #7
Source File: FusePoolPage.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
AssetSupplyRow = ({
assets,
index,
comptrollerAddress,
supplyIncentives,
rewardTokensData,
isPaused,
}: {
assets: USDPricedFuseAsset[];
index: number;
comptrollerAddress: string;
supplyIncentives: CTokenRewardsDistributorIncentivesWithRates[];
rewardTokensData: TokensDataMap;
isPaused: boolean;
}) => {
const {
isOpen: isModalOpen,
onOpen: openModal,
onClose: closeModal,
} = useDisclosure();
const authedOpenModal = useAuthedCallback(openModal);
const asset = assets[index];
const { fuse, address } = useRari();
const tokenData = useTokenData(asset.underlyingToken);
const supplyAPY = convertMantissaToAPY(asset.supplyRatePerBlock, 365);
const queryClient = useQueryClient();
const toast = useToast();
const onToggleCollateral = async () => {
const comptroller = createComptroller(comptrollerAddress, fuse);
let call;
if (asset.membership) {
call = comptroller.methods.exitMarket(asset.cToken);
} else {
call = comptroller.methods.enterMarkets([asset.cToken]);
}
let response = await call.call({ from: address });
// For some reason `response` will be `["0"]` if no error but otherwise it will return a string number.
if (response[0] !== "0") {
if (asset.membership) {
toast({
title: "Error! Code: " + response,
description:
"You cannot disable this asset as collateral as you would not have enough collateral posted to keep your borrow. Try adding more collateral of another type or paying back some of your debt.",
status: "error",
duration: 9000,
isClosable: true,
position: "top-right",
});
} else {
toast({
title: "Error! Code: " + response,
description:
"You cannot enable this asset as collateral at this time.",
status: "error",
duration: 9000,
isClosable: true,
position: "top-right",
});
}
return;
}
await call.send({ from: address });
LogRocket.track("Fuse-ToggleCollateral");
queryClient.refetchQueries();
};
const isStakedOHM =
asset.underlyingToken.toLowerCase() ===
"0x04F2694C8fcee23e8Fd0dfEA1d4f5Bb8c352111F".toLowerCase();
const { data: stakedOHMApyData } = useQuery("sOHM_APY", async () => {
const data = (
await fetch("https://api.rari.capital/fuse/pools/18/apy")
).json();
return data as Promise<{ supplyApy: number; supplyWpy: number }>;
});
const isMobile = useIsMobile();
const { t } = useTranslation();
const hasSupplyIncentives = !!supplyIncentives.length;
const totalSupplyAPR =
supplyIncentives?.reduce((prev, incentive) => {
const apr = incentive.supplyAPR;
return prev + apr;
}, 0) ?? 0;
const [hovered, setHovered] = useState<number>(-1);
const handleMouseEnter = (index: number) => setHovered(index);
const handleMouseLeave = () => setHovered(-1);
const displayedSupplyAPR =
hovered >= 0 ? supplyIncentives[hovered].supplyAPR : totalSupplyAPR;
const displayedSupplyAPRLabel =
hovered >= 0
? `${supplyIncentives[hovered].supplyAPR.toFixed(2)} % APR in ${
rewardTokensData[supplyIncentives[hovered].rewardToken].symbol
} distributions.`
: `${displayedSupplyAPR.toFixed(
2
)}% total APR distributed in ${supplyIncentives
.map((incentive) => rewardTokensData[incentive.rewardToken].symbol)
.join(", ")}
`;
const _hovered = hovered > 0 ? hovered : 0;
const color =
rewardTokensData[supplyIncentives?.[_hovered]?.rewardToken]?.color ??
"white";
const symbol = getSymbol(tokenData, asset);
return (
<>
<PoolModal
defaultMode={Mode.SUPPLY}
comptrollerAddress={comptrollerAddress}
assets={assets}
index={index}
isOpen={isModalOpen}
onClose={closeModal}
isBorrowPaused={asset.isPaused}
/>
<Row
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
width="100%"
px={4}
py={1.5}
className="hover-row"
>
{/* Underlying Token Data */}
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
width="27%"
>
<Row
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
width="100%"
as="button"
onClick={authedOpenModal}
>
<Avatar
bg="#FFF"
boxSize="37px"
name={symbol}
src={
tokenData?.logoURL ??
"https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
}
/>
<Text fontWeight="bold" fontSize="lg" ml={2} flexShrink={0}>
{symbol}
</Text>
</Row>
{/* <Row
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
width="100%"
>
<Text fontSize="sm" ml={2} flexShrink={0}>
{shortUsdFormatter(asset.liquidityUSD)}
</Text>
</Row> */}
</Column>
{/* APY */}
{isMobile ? null : (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-end"
width="27%"
as="button"
onClick={authedOpenModal}
>
<Text
color={tokenData?.color ?? "#FF"}
fontWeight="bold"
fontSize="17px"
>
{isStakedOHM
? stakedOHMApyData
? (stakedOHMApyData.supplyApy * 100).toFixed(2)
: "?"
: supplyAPY.toFixed(2)}
%
</Text>
{/* Demo Supply Incentives */}
{hasSupplyIncentives && (
<Row
// ml={1}
// mb={.5}
crossAxisAlignment="center"
mainAxisAlignment="flex-end"
py={2}
>
<Text fontWeight="bold" mr={1}>
+
</Text>
<AvatarGroup size="xs" max={30} ml={2} mr={1} spacing={1}>
{supplyIncentives?.map((supplyIncentive, i) => {
return (
<SimpleTooltip label={displayedSupplyAPRLabel}>
<CTokenIcon
address={supplyIncentive.rewardToken}
boxSize="20px"
onMouseEnter={() => handleMouseEnter(i)}
onMouseLeave={() => handleMouseLeave()}
_hover={{
zIndex: 9,
border: ".5px solid white",
transform: "scale(1.3);",
}}
/>
</SimpleTooltip>
);
})}
</AvatarGroup>
<SimpleTooltip label={displayedSupplyAPRLabel}>
<Text color={color} fontWeight="bold" pl={1} fontSize="sm">
{/* {(supplyIncentive.supplySpeed / 1e18).toString()}% */}
{displayedSupplyAPR.toFixed(2)}% APR
</Text>
</SimpleTooltip>
</Row>
)}
{/* Incentives */}
{/* {hasSupplyIncentives && (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-end"
py={1}
>
{supplyIncentives?.map((supplyIncentive) => {
return (
<Row
ml={1}
py={0.5}
// mb={.5}
crossAxisAlignment="center"
mainAxisAlignment="flex-end"
>
<Text fontWeight="bold" mr={2}>
+
</Text>
<CTokenIcon
address={supplyIncentive.rewardToken}
boxSize="20px"
/>
<Text fontWeight="bold" mr={2}></Text>
<Text
color={
rewardTokensData[supplyIncentive.rewardToken].color ??
"white"
}
fontWeight="bold"
>
{(supplyIncentive.supplySpeed / 1e18).toString()}%
</Text>
</Row>
);
})}
</Column>
)} */}
<SimpleTooltip
label={t(
"The Collateral Factor (CF) ratio defines the maximum amount of tokens in the pool that can be borrowed with a specific collateral. It’s expressed in percentage: if in a pool ETH has 75% LTV, for every 1 ETH worth of collateral, borrowers will be able to borrow 0.75 ETH worth of other tokens in the pool."
)}
>
<Text fontSize="sm">{asset.collateralFactor / 1e16}% CF</Text>
</SimpleTooltip>
{/* Incentives under APY
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-end"
my={1}
>
{supplyIncentives?.map((supplyIncentive) => {
return (
<Row
mainAxisAlignment="space-between"
crossAxisAlignment="center"
w="100%"
>
<Avatar
src={
rewardTokensData[supplyIncentive.rewardToken].logoURL ?? ""
}
boxSize="20px"
/>
<Text
ml={2}
fontWeight="bold"
color={
rewardTokensData[supplyIncentive.rewardToken].color ?? ""
}
>
{(supplyIncentive.supplySpeed / 1e18).toString()}%
</Text>
</Row>
);
})}
</Column>
*/}
</Column>
)}
{/* Incentives */}
{/* <Column mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
{supplyIncentives?.map((supplyIncentive) => {
return (
<Row mainAxisAlignment="flex-start" crossAxisAlignment="center">
<Avatar
src={rewardTokensData[supplyIncentive.rewardToken].logoURL}
boxSize="15px"
/>
<Box>
{(supplyIncentive.supplySpeed / 1e18).toString()}% APY
</Box>
</Row>
);
})}
</Column> */}
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-end"
width={isMobile ? "40%" : "27%"}
as="button"
onClick={authedOpenModal}
>
<Text
color={tokenData?.color ?? "#FFF"}
fontWeight="bold"
fontSize="17px"
>
{smallUsdFormatter(asset.supplyBalanceUSD)}
</Text>
<Text fontSize="sm">
{smallUsdFormatter(
asset.supplyBalance / 10 ** asset.underlyingDecimals
).replace("$", "")}{" "}
{symbol}
</Text>
</Column>
{/* Set As Collateral */}
<Row
width={isMobile ? "34%" : "20%"}
mainAxisAlignment="flex-end"
crossAxisAlignment="center"
>
<SwitchCSS symbol={symbol} color={tokenData?.color} />
<Switch
isChecked={asset.membership}
className={symbol + "-switch"}
onChange={onToggleCollateral}
size="md"
mt={1}
mr={5}
/>
</Row>
</Row>
</>
);
}
Example #8
Source File: AmountSelect.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
AmountSelect = ({
onClose,
assets,
index,
mode,
setMode,
comptrollerAddress,
isBorrowPaused = false
}: {
onClose: () => any;
assets: USDPricedFuseAsset[];
index: number;
mode: Mode;
setMode: (mode: Mode) => any;
comptrollerAddress: string;
isBorrowPaused?: boolean;
}) => {
const asset = assets[index];
const { address, fuse } = useRari();
const toast = useToast();
const queryClient = useQueryClient();
const tokenData = useTokenData(asset.underlyingToken);
const [userAction, setUserAction] = useState(UserAction.NO_ACTION);
const [userEnteredAmount, _setUserEnteredAmount] = useState("");
const [amount, _setAmount] = useState<BigNumber | null>(
() => new BigNumber(0)
);
const showEnableAsCollateral = !asset.membership && mode === Mode.SUPPLY;
const [enableAsCollateral, setEnableAsCollateral] = useState(
showEnableAsCollateral
);
const { t } = useTranslation();
const updateAmount = (newAmount: string) => {
if (newAmount.startsWith("-")) {
return;
}
_setUserEnteredAmount(newAmount);
try {
BigNumber.DEBUG = true;
// Try to set the amount to BigNumber(newAmount):
const bigAmount = new BigNumber(newAmount);
_setAmount(bigAmount.multipliedBy(10 ** asset.underlyingDecimals));
} catch (e) {
// If the number was invalid, set the amount to null to disable confirming:
_setAmount(null);
}
setUserAction(UserAction.NO_ACTION);
};
const { data: amountIsValid } = useQuery(
(amount?.toString() ?? "null") + " " + mode + " isValid",
async () => {
if (amount === null || amount.isZero()) {
return false;
}
try {
const max = await fetchMaxAmount(mode, fuse, address, asset);
return amount.lte(max!.toString());
} catch (e) {
handleGenericError(e, toast);
return false;
}
}
);
let depositOrWithdrawAlert = null;
if (mode === Mode.BORROW && isBorrowPaused) {
depositOrWithdrawAlert = t("Borrowing is disabled for this asset.");
}
else if (amount === null || amount.isZero()) {
if (mode === Mode.SUPPLY) {
depositOrWithdrawAlert = t("Enter a valid amount to supply.");
} else if (mode === Mode.BORROW) {
depositOrWithdrawAlert = t("Enter a valid amount to borrow.");
} else if (mode === Mode.WITHDRAW) {
depositOrWithdrawAlert = t("Enter a valid amount to withdraw.");
} else {
depositOrWithdrawAlert = t("Enter a valid amount to repay.");
}
} else if (amountIsValid === undefined) {
depositOrWithdrawAlert = t("Loading your balance of {{token}}...", {
token: asset.underlyingSymbol,
});
} else if (!amountIsValid) {
if (mode === Mode.SUPPLY) {
depositOrWithdrawAlert = t("You don't have enough {{token}}!", {
token: asset.underlyingSymbol,
});
} else if (mode === Mode.REPAY) {
depositOrWithdrawAlert = t(
"You don't have enough {{token}} or are over-repaying!",
{
token: asset.underlyingSymbol,
}
);
} else if (mode === Mode.WITHDRAW) {
depositOrWithdrawAlert = t("You cannot withdraw this much!");
} else if (mode === Mode.BORROW) {
depositOrWithdrawAlert = t("You cannot borrow this much!");
}
} else {
depositOrWithdrawAlert = null;
}
const isMobile = useIsMobile();
const length = depositOrWithdrawAlert?.length ?? 0;
let depositOrWithdrawAlertFontSize;
if (length < 40) {
depositOrWithdrawAlertFontSize = !isMobile ? "xl" : "17px";
} else if (length < 50) {
depositOrWithdrawAlertFontSize = !isMobile ? "15px" : "11px";
} else if (length < 60) {
depositOrWithdrawAlertFontSize = !isMobile ? "14px" : "10px";
}
const onConfirm = async () => {
try {
setUserAction(UserAction.WAITING_FOR_TRANSACTIONS);
const isETH = asset.underlyingToken === ETH_TOKEN_DATA.address;
const isRepayingMax =
amount!.eq(asset.borrowBalance) && !isETH && mode === Mode.REPAY;
isRepayingMax && console.log("Using max repay!");
const max = new BigNumber(2).pow(256).minus(1).toFixed(0);
const amountBN = fuse.web3.utils.toBN(amount!.toFixed(0));
const cToken = new fuse.web3.eth.Contract(
isETH
? JSON.parse(
fuse.compoundContracts[
"contracts/CEtherDelegate.sol:CEtherDelegate"
].abi
)
: JSON.parse(
fuse.compoundContracts[
"contracts/CErc20Delegate.sol:CErc20Delegate"
].abi
),
asset.cToken
);
if (mode === Mode.SUPPLY || mode === Mode.REPAY) {
if (!isETH) {
const token = new fuse.web3.eth.Contract(
JSON.parse(
fuse.compoundContracts[
"contracts/EIP20Interface.sol:EIP20Interface"
].abi
),
asset.underlyingToken
);
const hasApprovedEnough = fuse.web3.utils
.toBN(
await token.methods
.allowance(address, cToken.options.address)
.call()
)
.gte(amountBN);
if (!hasApprovedEnough) {
await token.methods
.approve(cToken.options.address, max)
.send({ from: address });
}
LogRocket.track("Fuse-Approve");
}
if (mode === Mode.SUPPLY) {
// If they want to enable as collateral now, enter the market:
if (enableAsCollateral) {
const comptroller = createComptroller(comptrollerAddress, fuse);
// Don't await this, we don't care if it gets executed first!
comptroller.methods
.enterMarkets([asset.cToken])
.send({ from: address });
LogRocket.track("Fuse-ToggleCollateral");
}
if (isETH) {
const call = cToken.methods.mint();
if (
// If they are supplying their whole balance:
amountBN.toString() === (await fuse.web3.eth.getBalance(address))
) {
// Subtract gas for max ETH
const { gasWEI, gasPrice, estimatedGas } = await fetchGasForCall(
call,
amountBN,
fuse,
address
);
await call.send({
from: address,
value: amountBN.sub(gasWEI),
gasPrice,
gas: estimatedGas,
});
} else {
await call.send({
from: address,
value: amountBN,
});
}
} else {
await testForCTokenErrorAndSend(
cToken.methods.mint(amountBN),
address,
"Cannot deposit this amount right now!"
);
}
LogRocket.track("Fuse-Supply");
} else if (mode === Mode.REPAY) {
if (isETH) {
const call = cToken.methods.repayBorrow();
if (
// If they are repaying their whole balance:
amountBN.toString() === (await fuse.web3.eth.getBalance(address))
) {
// Subtract gas for max ETH
const { gasWEI, gasPrice, estimatedGas } = await fetchGasForCall(
call,
amountBN,
fuse,
address
);
await call.send({
from: address,
value: amountBN.sub(gasWEI),
gasPrice,
gas: estimatedGas,
});
} else {
await call.send({
from: address,
value: amountBN,
});
}
} else {
await testForCTokenErrorAndSend(
cToken.methods.repayBorrow(isRepayingMax ? max : amountBN),
address,
"Cannot repay this amount right now!"
);
}
LogRocket.track("Fuse-Repay");
}
} else if (mode === Mode.BORROW) {
await testForCTokenErrorAndSend(
cToken.methods.borrow(amountBN),
address,
"Cannot borrow this amount right now!"
);
LogRocket.track("Fuse-Borrow");
} else if (mode === Mode.WITHDRAW) {
await testForCTokenErrorAndSend(
cToken.methods.redeemUnderlying(amountBN),
address,
"Cannot withdraw this amount right now!"
);
LogRocket.track("Fuse-Withdraw");
}
queryClient.refetchQueries();
// Wait 2 seconds for refetch and then close modal.
// We do this instead of waiting the refetch because some refetches take a while or error out and we want to close now.
await new Promise((resolve) => setTimeout(resolve, 2000));
onClose();
} catch (e) {
handleGenericError(e, toast);
setUserAction(UserAction.NO_ACTION);
}
};
const symbol = getSymbol(tokenData, asset);
return (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
height={showEnableAsCollateral ? "575px" : "500px"}
>
{userAction === UserAction.WAITING_FOR_TRANSACTIONS ? (
<Column
expand
mainAxisAlignment="center"
crossAxisAlignment="center"
p={4}
>
<HashLoader size={70} color={tokenData?.color ?? "#FFF"} loading />
<Heading mt="30px" textAlign="center" size="md">
{t("Check your wallet to submit the transactions")}
</Heading>
<Text fontSize="sm" mt="15px" textAlign="center">
{t("Do not close this tab until you submit all transactions!")}
</Text>
</Column>
) : (
<>
<Row
width="100%"
mainAxisAlignment="center"
crossAxisAlignment="center"
p={4}
height="72px"
flexShrink={0}
>
<Box height="35px" width="35px">
<Image
width="100%"
height="100%"
borderRadius="50%"
src={
tokenData?.logoURL ??
"https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
}
alt=""
/>
</Box>
<Heading fontSize="27px" ml={3}>
{!isMobile && asset.underlyingName.length < 25
? asset.underlyingName
: symbol}
</Heading>
</Row>
<ModalDivider />
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
px={4}
pb={4}
pt={1}
height="100%"
>
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
width="100%"
>
<TabBar color={tokenData?.color} mode={mode} setMode={setMode} />
<DashboardBox width="100%" height="70px">
<Row
p={4}
mainAxisAlignment="space-between"
crossAxisAlignment="center"
expand
>
<AmountInput
color={tokenData?.color ?? "#FFF"}
displayAmount={userEnteredAmount}
updateAmount={updateAmount}
disabled={mode === Mode.BORROW && isBorrowPaused}
/>
<TokenNameAndMaxButton
comptrollerAddress={comptrollerAddress}
mode={mode}
symbol={symbol}
logoURL={
tokenData?.logoURL ??
"https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
}
asset={asset}
updateAmount={updateAmount}
/>
</Row>
</DashboardBox>
</Column>
<StatsColumn
symbol={symbol}
amount={parseInt(amount?.toFixed(0) ?? "0") ?? 0}
color={tokenData?.color ?? "#FFF"}
assets={assets}
index={index}
mode={mode}
enableAsCollateral={enableAsCollateral}
/>
{showEnableAsCollateral ? (
<DashboardBox p={4} width="100%" mt={4}>
<Row
mainAxisAlignment="space-between"
crossAxisAlignment="center"
width="100%"
>
<Text fontWeight="bold">{t("Enable As Collateral")}:</Text>
<SwitchCSS
symbol={asset.underlyingSymbol}
color={tokenData?.color}
/>
<Switch
h="20px"
className={asset.underlyingSymbol + "-switch"}
isChecked={enableAsCollateral}
onChange={() => {
setEnableAsCollateral((past) => !past);
}}
/>
</Row>
</DashboardBox>
) : null}
<Button
mt={4}
fontWeight="bold"
fontSize={
depositOrWithdrawAlert ? depositOrWithdrawAlertFontSize : "2xl"
}
borderRadius="10px"
width="100%"
height="70px"
bg={tokenData?.color ?? "#FFF"}
color={tokenData?.overlayTextColor ?? "#000"}
// If the size is small, this means the text is large and we don't want the font size scale animation.
className={
isMobile ||
depositOrWithdrawAlertFontSize === "14px" ||
depositOrWithdrawAlertFontSize === "15px"
? "confirm-button-disable-font-size-scale"
: ""
}
_hover={{ transform: "scale(1.02)" }}
_active={{ transform: "scale(0.95)" }}
onClick={onConfirm}
isDisabled={!amountIsValid}
>
{depositOrWithdrawAlert ?? t("Confirm")}
</Button>
</Column>
</>
)}
</Column>
);
}
Example #9
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 #10
Source File: Header.tsx From openchakra with MIT License | 4 votes |
Header = () => {
const showLayout = useSelector(getShowLayout)
const showCode = useSelector(getShowCode)
const dispatch = useDispatch()
return (
<DarkMode>
<Flex
justifyContent="space-between"
bg="#1a202c"
as="header"
height="3rem"
px="1rem"
>
<Flex
width="14rem"
height="100%"
backgroundColor="#1a202c"
color="white"
as="a"
fontSize="xl"
flexDirection="row"
alignItems="center"
aria-label="Chakra UI, Back to homepage"
>
<Box fontSize="2xl" as={AiFillThunderbolt} mr={1} color="teal.100" />{' '}
<Box fontWeight="bold">open</Box>chakra
</Flex>
<Flex flexGrow={1} justifyContent="space-between" alignItems="center">
<HStack spacing={4} justify="center" align="center">
<Box>
<HeaderMenu />
</Box>
<FormControl flexDirection="row" display="flex" alignItems="center">
<Tooltip
zIndex={100}
hasArrow
bg="yellow.100"
aria-label="Builder mode help"
label="Builder mode adds extra padding/borders"
>
<FormLabel
cursor="help"
color="gray.200"
fontSize="xs"
htmlFor="preview"
pb={0}
mb={0}
mr={2}
whiteSpace="nowrap"
>
Builder mode
</FormLabel>
</Tooltip>
<LightMode>
<Switch
isChecked={showLayout}
colorScheme="teal"
size="sm"
onChange={() => dispatch.app.toggleBuilderMode()}
id="preview"
/>
</LightMode>
</FormControl>
<FormControl display="flex" flexDirection="row" alignItems="center">
<FormLabel
color="gray.200"
fontSize="xs"
mr={2}
mb={0}
htmlFor="code"
pb={0}
whiteSpace="nowrap"
>
Code panel
</FormLabel>
<LightMode>
<Switch
isChecked={showCode}
id="code"
colorScheme="teal"
onChange={() => dispatch.app.toggleCodePanel()}
size="sm"
/>
</LightMode>
</FormControl>
</HStack>
<Stack direction="row">
<CodeSandboxButton />
<Popover>
{({ onClose }) => (
<>
<PopoverTrigger>
<Button
ml={4}
rightIcon={<SmallCloseIcon path="" />}
size="xs"
variant="ghost"
>
Clear
</Button>
</PopoverTrigger>
<LightMode>
<PopoverContent zIndex={100} bg="white">
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Are you sure?</PopoverHeader>
<PopoverBody fontSize="sm">
Do you really want to remove all components on the
editor?
</PopoverBody>
<PopoverFooter display="flex" justifyContent="flex-end">
<Button
size="sm"
variant="ghost"
colorScheme="red"
rightIcon={<CheckIcon path="" />}
onClick={() => {
dispatch.components.reset()
if (onClose) {
onClose()
}
}}
>
Yes, clear
</Button>
</PopoverFooter>
</PopoverContent>
</LightMode>
</>
)}
</Popover>
</Stack>
</Flex>
<Stack
justifyContent="flex-end"
width="13rem"
align="center"
direction="row"
spacing="2"
>
<Link isExternal href="https://github.com/premieroctet/openchakra">
<Box as={DiGithubBadge} size={32} color="gray.200" />
</Link>
<Box lineHeight="shorter" color="white" fontSize="xs">
by{' '}
<Link isExternal href="https://premieroctet.com" color="teal.100">
Premier Octet
</Link>
</Box>
</Stack>
</Flex>
</DarkMode>
)
}
Example #11
Source File: ChatForm.tsx From takeout-app with MIT License | 4 votes |
ChatForm: React.FC<Props> = ({ track, channel }) => {
const chat = useChat();
const { data: session } = Api.useSession();
const isStaff = session?.attendee?.is_staff;
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit, reset, setFocus, watch } = useForm<{
message: string;
asAdmin: boolean;
}>({
defaultValues: {
message: "",
asAdmin: false,
},
});
const asAdmin = watch("asAdmin");
const onSubmit = handleSubmit(async (data) => {
if (!chat.session || !channel) return;
if (isRequesting) return;
setIsRequesting(true);
setErrorAlert(null);
try {
if (data.asAdmin && isStaff) {
await Api.sendChatMessage(track.slug, data.message, true);
} else {
// Workaround: aws-sdk-v3 sigv4 fails to generate correct signature for payload containing emoji...
if (/\p{Extended_Pictographic}/u.test(data.message)) {
await Api.sendChatMessage(track.slug, data.message, false);
} else {
await chat.session.postMessage(channel, data.message);
}
}
reset({ message: "", asAdmin: false });
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setFocus("message");
setIsRequesting(false);
});
const shouldDisable = !session?.attendee || !chat.session || !channel;
// TODO: errorAlert to toast
return (
<Box p="16px" bgColor="#ffffff" borderTop="1px solid" borderColor={Colors.chatBorder}>
{errorAlert}
<form onSubmit={onSubmit}>
<VStack w="100%">
{session && !session.attendee?.is_ready ? (
<Box w="100%">
<Alert status="warning">
<AlertIcon />
<Text as="span">
Set your name at{" "}
<Link as={RouterLink} to="/attendee" textDecoration="underline">
Settings
</Link>{" "}
page
</Text>
</Alert>
</Box>
) : null}
<Box w="100%">
<Textarea
as={TextareaAutoSize}
{...register("message")}
size="sm"
placeholder={asAdmin ? "SAY SOMETHING AS ADMIN..." : "Send a message"}
isRequired
isDisabled={shouldDisable}
autoComplete="off"
rows={1}
minRows={1}
maxRows={4}
onKeyPress={(e) => {
if (e.key == "Enter") {
e.preventDefault();
onSubmit();
}
}}
css={{ resize: "none" }}
/>
</Box>
<Flex w="100%" alignItems="flex-end" direction="row-reverse" justifyContent="space-between">
<IconButton
icon={<SendIcon boxSize="14px" />}
minW="30px"
w="30px"
h="30px"
aria-label="Send"
type="submit"
isLoading={isRequesting}
isDisabled={shouldDisable}
/>
{isStaff ? (
<Tooltip label="Send as an official announcement" aria-label="">
<FormControl display="flex" alignSelf="center" h="30px">
<FormLabel htmlFor="ChatForm__asAdmin" aria-hidden="true" m={0} mr={1}>
<CampaignIcon w="24px" h="24px" />
</FormLabel>
<Switch
aria-label="Send as an official announcement"
id="ChatForm__asAdmin"
size="sm"
isChecked={asAdmin}
isDisabled={shouldDisable}
{...register("asAdmin")}
/>
</FormControl>
</Tooltip>
) : null}
</Flex>
</VStack>
</form>
</Box>
);
}