@chakra-ui/react#Spinner TypeScript Examples
The following examples show how to use
@chakra-ui/react#Spinner.
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: Loader.tsx From calories-in with MIT License | 6 votes |
function Loader({ label }: Props) {
return (
<Center height="200px" spacing={2}>
<Flex flexDirection="column" alignItems="center">
<Spinner size="lg" color="teal" />
<Text mt={4} fontSize="lg" fontWeight="medium">
{label}
</Text>
</Flex>
</Center>
)
}
Example #2
Source File: SpinnerMessage.tsx From dope-monorepo with GNU General Public License v3.0 | 6 votes |
SpinnerMessage = ({ text }: { text: string }) => {
return (
<SpinnerContainer>
<div>
<Spinner size="xs" />
</div>
<div>{text}</div>
</SpinnerContainer>
);
}
Example #3
Source File: create.tsx From coindrop with GNU General Public License v3.0 | 6 votes |
CreateFirstCoindrop: NextPage = () => {
const { user } = useUser();
const [isCreateTriggered, setIsCreateTriggered] = useState(false);
const [candidatePiggybankPath, setCandidatePiggybankPath] = useState('');
useCreatePiggybank(candidatePiggybankPath, setCandidatePiggybankPath, user, isCreateTriggered, setIsCreateTriggered);
useEffect(() => {
const pendingLoginCreatePiggybankPath = cookies.get('pendingLoginCreatePiggybankPath');
if (pendingLoginCreatePiggybankPath) {
setCandidatePiggybankPath(pendingLoginCreatePiggybankPath);
setIsCreateTriggered(true);
}
}, []);
return (
<Flex
direction="column"
align="center"
justify="center"
my={6}
>
<Spinner size="lg" mb={3} />
<Heading size="lg">
Creating Coindrop...
</Heading>
</Flex>
);
}
Example #4
Source File: EventWelcome.tsx From dope-monorepo with GNU General Public License v3.0 | 6 votes |
export default function EventWelcome(props: Props) {
const [ loading, setLoading ] = useState(false);
useEffect(() => {
props.manager.events.on('game', () => setLoading(true));
}, []);
return (
<ChakraProvider theme={theme}>
<Center style={{
height: "100vh",
backdropFilter: "brightness(50%)",
}}>
{loading ? <Spinner size="xl" color="white" /> : <Container style={{
padding: "1rem",
borderStyle: "solid",
boxShadow: "0px 0px 15px rgba(0,0,0,1)",
borderColor: "black",
borderWidth: "0px",
backgroundColor: "white",
borderRadius: "7px",
}}>
{
<Stepper
manager={props.manager}
/>
}
</Container>}
</Center>
</ChakraProvider>
);
}
Example #5
Source File: FirebaseAuth.tsx From coindrop with GNU General Public License v3.0 | 6 votes |
FirebaseAuth: FunctionComponent = () => {
// Do not SSR FirebaseUI, because it is not supported.
// https://github.com/firebase/firebaseui-web/issues/213
const [renderAuth, setRenderAuth] = useState(false);
useEffect(() => {
if (typeof window !== 'undefined') {
setRenderAuth(true);
}
}, []);
return (
<div>
{renderAuth ? (
<StyledFirebaseAuth
uiConfig={firebaseAuthConfig}
firebaseAuth={firebase.auth()}
/>
) : <Spinner />}
</div>
);
}
Example #6
Source File: PoolPortal.tsx From rari-dApp with GNU Affero General Public License v3.0 | 6 votes |
CurrentAPY = () => {
const { t } = useTranslation();
const poolType = usePoolType();
const poolAPY = usePoolAPY(poolType);
return (
<Row expand mainAxisAlignment="center" crossAxisAlignment="center">
<Heading
mt="5px"
fontFamily={`'Baloo 2', ${theme.fonts.heading}`}
fontSize="54px"
fontWeight="extrabold"
>
{poolAPY ? (
(poolAPY.startsWith("0.") ? poolAPY : poolAPY.slice(0, -1)) + "%"
) : (
<Spinner size="lg" mr={4} />
)}
</Heading>
<Text ml={3} width="65px" fontSize="sm" textTransform="uppercase">
{t("Current APY")}
</Text>
</Row>
);
}
Example #7
Source File: UI.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
loadingSpinner = () => <ChakraProvider theme={theme}>
<Spinner size="xl" color="white" style={{
position: 'absolute',
bottom: '5%',
right: '5%',
boxShadow: '0px 0px 60px black',
}} />
</ChakraProvider>
Example #8
Source File: FuseLiquidationsPage.tsx From rari-dApp with GNU Affero General Public License v3.0 | 5 votes |
LiquidationEventsList = ({
liquidations,
totalLiquidations,
setLiquidationsToShow,
}: {
liquidations?: LiquidationEvent[];
totalLiquidations: number;
setLiquidationsToShow: React.Dispatch<React.SetStateAction<number>>;
}) => {
const { t } = useTranslation();
const isMobile = useIsMobile();
return (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
expand
>
<Row
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
height="45px"
width="100%"
flexShrink={0}
pl={4}
pr={1}
>
<Text fontWeight="bold" width={isMobile ? "100%" : "30%"}>
{t("Recent Liquidations")}
</Text>
{isMobile ? null : (
<>
<Text fontWeight="bold" textAlign="center" width="23%">
{t("Collateral Seized")}
</Text>
<Text fontWeight="bold" textAlign="center" width="23%">
{t("Borrow Repaid")}
</Text>
<Text fontWeight="bold" textAlign="center" width="25%">
{t("Timestamp")}
</Text>
</>
)}
</Row>
<ModalDivider />
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
width="100%"
>
{liquidations ? (
<>
{liquidations.map((liquidation, index) => {
return (
<LiquidationRow
key={liquidation.transactionHash}
liquidation={liquidation}
noBottomDivider={index === liquidations.length - 1}
/>
);
})}
<RowsControl
totalAmount={totalLiquidations}
setAmountToShow={setLiquidationsToShow}
/>
</>
) : (
<Spinner my={8} />
)}
</Column>
</Column>
);
}
Example #9
Source File: Hustlers.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
Hustlers = () => {
const [hustlers, setHustlers] = React.useState<any>();
useEffect(() => {
if (!(window.ethereum as any)?.selectedAddress) return;
fetch(`https://api.dopewars.gg/wallets/${ethers.utils.getAddress(
(window.ethereum as any).selectedAddress,
)}/hustlers`).then(res => res.json()).then(res => setHustlers(res));
}, []);
return (
<div>
{hustlers ? <SimpleGrid columns={2} spacing={5} paddingBottom="8">
{
hustlers.map((hustler: any, i: number) =>
<VStack key={i}>
<Text paddingBottom="0px">
{hustler.id} {hustler.name ? " - " + hustler.name : ""}
</Text>
<object width="70%" type="image/svg+xml" data={hustler.svg} />
{ localStorage.getItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`) !== hustler.id ? <Popover>
<PopoverTrigger>
<Button variant="primary">
Set as selected hustler
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Are you sure?</PopoverHeader>
<PopoverBody>The game needs to be reloaded in order to modify your selected hustler</PopoverBody>
<PopoverFooter>
<Button variant="primary" onClick={() => {
localStorage.setItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`, hustler.id);
window.location.reload();
}}>
Confirm
</Button>
</PopoverFooter>
</PopoverContent>
</Popover> : undefined }
</VStack>
)
}
</SimpleGrid> : <Center padding="4">
<Spinner size="lg"/>
</Center>
}
<Center>
<a href="/inventory">
<Button variant="primary">
Details
</Button>
</a>
</Center>
</div>
)
}
Example #10
Source File: LoadingSpinner.tsx From ksana.in with Apache License 2.0 | 5 votes |
export function LoadingSpinner() {
return (
<Spinner thickness="4px" speed="0.65s" emptyColor="gray.200" color="orange.400" size="xl" />
)
}
Example #11
Source File: PiggybankListItem.tsx From coindrop with GNU General Public License v3.0 | 5 votes |
PiggybankListItem: FunctionComponent<Props> = ({ id }) => {
const { colors } = useTheme();
const [isLoading, setIsLoading] = useState(false);
const hoverBg = useColorModeValue(colors.gray['100'], colors.gray['600']);
const activeBg = useColorModeValue(colors.gray['200'], colors.gray['700']);
return (
<Box
onClick={() => setIsLoading(true)}
cursor="pointer"
mt={3}
bg={isLoading ? hoverBg : undefined}
_hover={{
bg: hoverBg,
textDecoration: "none",
}}
_active={{
bg: activeBg,
}}
>
<NextLink href={`/${id}`} passHref>
<a id={`link-to-coindrop-${id}`}>
<Box
py={5}
shadow="md"
borderWidth="1px"
borderRadius="10px"
>
{isLoading ? (
<Flex align="center" justify="center">
<Spinner boxSize="32px" />
<Heading ml={2} fontSize="xl">
Loading
</Heading>
</Flex>
) : (
<Flex
justify="space-between"
align="center"
mx={4}
>
<Heading fontSize="xl" wordBreak="break-word">
coindrop.to/
{id}
</Heading>
<ChevronRightIcon boxSize="32px" />
</Flex>
)}
</Box>
</a>
</NextLink>
</Box>
);
}
Example #12
Source File: IRMChart.tsx From rari-dApp with GNU Affero General Public License v3.0 | 5 votes |
IRMChart = ({
curves,
tokenData,
modal
}: {
curves: any;
tokenData: TokenData;
modal?: boolean;
}) => {
const { t } = useTranslation();
return (
<Box
height="170px"
width="100%"
color="#000000"
overflow="hidden"
px={modal ? 0 : 3}
className="hide-bottom-tooltip"
flexShrink={0}
>
{curves ? (
<Chart
options={
{
...FuseIRMDemoChartOptions,
colors: ["#FFFFFF", tokenData.color! ?? "#282727"],
} as any
}
type="line"
width="100%"
height="100%"
series={[
{
name: "Borrow Rate",
data: curves.borrowerRates,
},
{
name: "Deposit Rate",
data: curves.supplierRates,
},
]}
/>
) : curves === undefined ? (
<Center expand color="#FFF">
<Spinner my={8} />
</Center>
) : (
<Center expand color="#FFFFFF">
<Text>
{t("No graph is available for this asset's interest curves.")}
</Text>
</Center>
)}
</Box>
);
}
Example #13
Source File: DeleteAccount.tsx From coindrop with GNU General Public License v3.0 | 5 votes |
DeleteAccount: FC = () => {
const { user, logout } = useUser();
const id = user?.id;
const email = user?.email;
const [status, setStatus] = useState<Status>('initial');
const [confirmingInput, setConfirmingInput] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const onSubmit = (event: React.FormEvent) => {
event.preventDefault();
handleDelete(logout, setIsSubmitting, user, setStatus);
};
if (!id || !email) {
return <Spinner data-testid="no-user-spinner" />;
}
if (status === 'initial') {
return (
<Box>
<Button
colorScheme="red"
variant="outline"
onClick={() => setStatus('user-confirmation')}
>
Delete Account
</Button>
</Box>
);
}
if (status === 'user-confirmation') {
return (
<form
onSubmit={onSubmit}
>
<Text mb={1}>
Type your e-mail address to confirm account deletion:
</Text>
<Input
placeholder={email}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setConfirmingInput(event.target.value)}
value={confirmingInput}
type="text"
/>
{confirmingInput === email && (
<Text mt={2}>
All your Coindrops will be deleted. This cannot be undone!
</Text>
)}
<Box>
<Button
type="submit"
colorScheme="red"
leftIcon={isSubmitting ? <Spinner size="sm" /> : undefined}
isDisabled={confirmingInput !== email || isSubmitting}
mt={2}
>
{isSubmitting ? 'Deleting' : 'Delete Account'}
</Button>
</Box>
</form>
);
}
if (status === 'success') {
return (
<Text textAlign="center">
✔️ Account deleted. Redirecting to homepage...
</Text>
);
}
if (status === 'error') {
return (
<Text textAlign="center">
⚠️ Error deleting account. Please try again and contact support if you continue to receive this error.
</Text>
);
}
return null;
}
Example #14
Source File: AppDomains.tsx From ledokku with MIT License | 4 votes |
AppDomains = ({ appId }: AppDomainProps) => {
const toast = useToast();
const { data, loading /* error */ } = useAppByIdQuery({
variables: {
appId,
},
ssr: false,
skip: !appId,
});
const {
data: domainsData,
loading: domainsDataLoading,
refetch: appDomainsRefetch,
} = useDomainsQuery({
variables: {
appId,
},
});
const [
removeDomainMutation,
{ loading: removeDomainMutationLoading },
] = useRemoveDomainMutation();
const handleRemoveDomain = async (domain: string) => {
try {
await removeDomainMutation({
variables: {
input: {
appId,
domainName: domain,
},
},
refetchQueries: [{ query: DomainsDocument, variables: { appId } }],
});
toast.success('Domain removed successfully');
} catch (error) {
toast.error(error.message);
}
};
if (!data) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
return (
<>
<Box py="5">
<Heading as="h2" size="md">
Domain management
</Heading>
<Text fontSize="sm" color="gray.400">
List of domains you have added to {app.name} app
</Text>
</Box>
<Grid templateColumns={{ sm: 'repeat(1, 1fr)', md: 'repeat(3, 1fr)' }}>
<GridItem colSpan={2}>
<Box mb="8">
{domainsDataLoading ? <Spinner /> : null}
{domainsData?.domains.domains.length === 0 ? (
<Text fontSize="sm" color="gray.400">
Currently you haven't added any custom domains to your app
</Text>
) : null}
{domainsData?.domains.domains.map((domain: any) => (
<Flex
key={domain}
justifyContent="space-between"
alignItems="center"
>
<Link
href={`http://${domain}`}
isExternal
display="flex"
alignItems="center"
>
{domain} <Icon as={FiExternalLink} mx="2" />
</Link>
<IconButton
aria-label="Delete"
variant="ghost"
colorScheme="red"
icon={<FiTrash2 />}
disabled={removeDomainMutationLoading}
onClick={() => handleRemoveDomain(domain)}
/>
</Flex>
))}
</Box>
<AddAppDomain appId={appId} appDomainsRefetch={appDomainsRefetch} />
</GridItem>
</Grid>
</>
);
}
Example #15
Source File: Login.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
export default function Login(props: Props) {
const toast = createStandaloneToast(theme);
const [ loading, setLoading ] = useState(false);
const [ loggedIn, setLoggedIn ] = useState(false);
useEffect(() => {
props.manager.events.on('loggedIn', () => setLoading(true));
}, []);
const login = () => {
if ((window.ethereum as any).chainId !== '0x1') {
toast({
title: "Wrong network",
description: "Please switch to the main Ethereum network",
status: "error",
...toastStyle,
});
return;
}
props.authenticator.login()
.then(() => {
setLoggedIn(true)
toast({
title: "Success",
description: "You have successfully logged in!",
status: "success",
...toastStyle
});
})
.catch((err) => {
setLoggedIn(false);
toast({
title: "Error " + (err.code ?? ""),
description: err.message ?? err,
status: "error",
...toastStyle
});
});
}
return (
<ChakraProvider theme={theme}>
<Center style={{
height: "100vh",
backdropFilter: "brightness(50%)",
}}>
{loading ? <Spinner size="xl" color="white" /> : <Container style={{
padding: "1rem",
borderStyle: "solid",
boxShadow: "0px 0px 15px rgba(0,0,0,1)",
borderColor: "black",
borderWidth: "0px",
backgroundColor: "white",
borderRadius: "7px",
}}>
<VStack>
<Heading>
Please login before accessing the game
</Heading>
<br />
<Text>
To login, you need to sign a message using your wallet provider. Our personal favorite is Metamask but you can use any other extension or wallet provider.
</Text>
<UnorderedList spacing={4} style={{
paddingLeft: "1rem",
}}>
<ListItem>
Click on this button to trigger the sign message
<br />
<Button variant="primary" onClick={login}>
Sign
</Button>
</ListItem>
<ListItem>Your wallet provider will popup a dialog and you will need to press `Sign`</ListItem>
<ListItem>
Wait for this to show as logged in
<HStack style={{
paddingLeft: "1rem",
paddingRight: "1rem",
}}>
{loggedIn ? <CheckIcon /> : <Spinner color='red.500' />}
<Text style={{
paddingTop: "1rem",
}}>{loggedIn ? 'Logged in' : 'Not logged in'}</Text>
</HStack>
</ListItem>
<ListItem>Press continue</ListItem>
</UnorderedList>
<Button
disabled={!loggedIn}
onClick={() => props.manager.events.emit('loggedIn')}
style={{
position: "relative",
top: "30px"
}}
variant="primary"
>
Continue
</Button>
</VStack>
</Container>}
</Center>
</ChakraProvider>
);
}
Example #16
Source File: index.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
UserDataForm: FC<UserDataFormProps> = ({ userData, mutate, userId }) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const toast = useToast();
const { register, handleSubmit, formState: { isDirty }, reset } = useForm();
const email_lists = userData?.email_lists;
const onSubmit = async (rawFormData) => {
setIsSubmitting(true);
const userDataForDb = {
email_lists: [],
};
Object.keys(optionalEmailLists).forEach(emailListId => {
if (rawFormData.email_lists[emailListId]) {
userDataForDb.email_lists.push(emailListId);
}
});
try {
await updateUserData({ data: userDataForDb, userId });
mutate(userDataForDb);
reset();
toast({
title: "Account updated",
status: "success",
duration: 6000,
isClosable: true,
});
} catch (err) {
toast({
title: "Error updating account",
description: "Please try again or contact support",
status: "error",
duration: 9000,
isClosable: true,
});
} finally {
setIsSubmitting(false);
}
};
return (
<SectionContainer>
<form onSubmit={handleSubmit(onSubmit)} data-testid="settings-form">
<SectionHeading size="md">
E-mail
</SectionHeading>
<Box
id="email-preferences-content"
m={4}
>
<FormLabel>Newsletters</FormLabel>
<Flex wrap="wrap">
{Object.entries(optionalEmailLists).map(([emailListId, emailListDisplayName]: [EmailListIds, string]) => {
return (
<Checkbox
key={emailListId}
mr={6}
name={`email_lists.${emailListId}`}
colorScheme="orange"
defaultChecked={email_lists?.includes(emailListId)}
ref={register()}
>
{emailListDisplayName}
</Checkbox>
);
})}
{alwaysEnabledEmailLists.map(listName => (
<Checkbox
key={listName}
mr={6}
colorScheme="orange"
defaultChecked
isDisabled
>
{listName}
</Checkbox>
))}
</Flex>
</Box>
<Box>
<Button
colorScheme="green"
type="submit"
isDisabled={!isDirty || isSubmitting}
leftIcon={isSubmitting ? <Spinner size="sm" /> : undefined}
>
{isSubmitting ? 'Saving' : 'Save'}
</Button>
</Box>
</form>
</SectionContainer>
);
}
Example #17
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>
);
}
Example #18
Source File: AccountButton.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
Buttons = ({
openModal,
openClaimRGTModal,
hasClaimableRewards,
}: {
openModal: () => any;
openClaimRGTModal: () => any;
hasClaimableRewards: boolean;
}) => {
const { address, isAuthed, login, isAttemptingLogin } = useRari();
const { t } = useTranslation();
const isMobile = useIsSmallScreen();
const handleAccountButtonClick = useCallback(() => {
if (isAuthed) {
openModal();
} else login();
}, [isAuthed, login, openModal]);
return (
<Row mainAxisAlignment="center" crossAxisAlignment="center">
{isMobile ? null : (
<>
{hasClaimableRewards ? (
<DarkGlowingButton
label={t("Claim")}
onClick={openClaimRGTModal}
height="40px"
flexShrink={0}
width="95px"
fontSize="15px"
fontWeight="bold"
/>
) : (
<DashboardBox
ml={1}
as="button"
height="40px"
flexShrink={0}
width="95px"
fontSize="15px"
fontWeight="bold"
onClick={openClaimRGTModal}
>
<Center expand>{t("Claim")}</Center>
</DashboardBox>
)}
</>
)}
{/* Connect + Account button */}
<DashboardBox
ml={isMobile ? 0 : 4}
as="button"
height="40px"
flexShrink={0}
flexGrow={0}
width="133px"
onClick={handleAccountButtonClick}
>
<Row
expand
mainAxisAlignment="space-around"
crossAxisAlignment="center"
px={3}
py={1}
>
{/* Conditionally display Connect button or Account button */}
{!isAuthed ? (
isAttemptingLogin ? (
<Spinner />
) : (
<Text fontWeight="semibold">{t("Connect")}</Text>
)
) : (
<>
<Jazzicon diameter={23} seed={jsNumberForAddress(address)} />
<Text ml={2} fontWeight="semibold">
{shortAddress(address)}
</Text>
</>
)}
</Row>
</DashboardBox>
</Row>
);
}
Example #19
Source File: RenderDetail.tsx From ke with MIT License | 4 votes |
RenderDetail = (props: RenderDetailProps): JSX.Element => {
/*
Entry point for displaying components in https://myspa.com/some-url/100500 route format.
Here we fetch data from the backend using the url that we specified in a
admin class.
After that we mounts the widgets of a particular view type. At the moment there are two:
- Detail View (see mountDetailFields for detail)
- Wizard View (see mountWizards for detail)
*/
const [mainDetailObject, setMainDetailObject] = useState<Model>()
const [needRefreshDetailObject, setNeedRefreshDetailObject] = useState<boolean>(true)
const { id } = useParams<{ id: string }>()
const { resourceName, admin, provider, notifier } = props
const toast = useToast()
const detailNotifier = notifier || new ChakraUINotifier(toast)
const [isLoading, setIsLoading] = useState<boolean>(true)
const [loadError, setLoadError] = useState<LoadError | null>(null)
const activeWizardRef = useRef<WizardControl>()
let title = `${admin.verboseName} # ${id}`
if (admin.getPageTitle) {
const pageTitle = admin.getPageTitle(mainDetailObject)
if (pageTitle) {
title = pageTitle
}
}
document.title = title
let favicon = admin.favicon || ''
if (admin.getPageFavicon) {
const favIconSource = admin.getPageFavicon(mainDetailObject)
if (favIconSource) {
favicon = favIconSource
}
}
setFavicon(favicon)
const refreshMainDetailObject = (): void => {
setNeedRefreshDetailObject(true)
}
useEffect(() => {
const backendResourceUrl = admin.getResource(id)
if (needRefreshDetailObject) {
provider
.getObject(backendResourceUrl)
.then(async (res) => {
setNeedRefreshDetailObject(false)
setMainDetailObject(res)
if (admin?.onDetailObjectLoaded !== undefined) {
await admin.onDetailObjectLoaded({
mainDetailObject: res,
provider,
context: containerStore,
setInitialValue,
})
}
})
.catch((er: LoadError) => {
setLoadError(er)
})
.finally(() => setIsLoading(false))
}
}, [id, provider, admin, needRefreshDetailObject, props, mainDetailObject])
const { getDataTestId } = useCreateTestId({ name: admin.name })
useEffect(() => {
admin.onMount()
return () => admin.onUnmount()
}, [admin])
return (
<SaveEventProvider>
<Row>
<Col xs={12} xsOffset={0} md={10} mdOffset={1}>
<Box padding="8px 0px">
<ToListViewLink name={resourceName} />
</Box>
</Col>
</Row>
<Row {...getDataTestId()}>
<Col xs={12} xsOffset={0} md={10} mdOffset={1}>
{isLoading ? <Spinner /> : ''}
{!isLoading && !loadError
? Object.entries(getContainersToMount()).map(([elementsKey, container]: [string, Function]) => {
const elements = admin[elementsKey as keyof typeof admin]
if (!elements) return []
return (
<ErrorBoundary>
{container({
mainDetailObject,
setMainDetailObject,
ViewType,
elements,
elementsKey,
refreshMainDetailObject,
activeWizardRef,
...props,
notifier: detailNotifier,
})}
</ErrorBoundary>
)
})
: ''}
{!isLoading && loadError ? (
<Alert status="error" {...getDataTestId({ postfix: '--loadingError' })}>
<AlertIcon />
<AlertTitle mr={2}>Ошибка при выполнении запроса</AlertTitle>
<AlertDescription>{loadError.response?.data?.message}</AlertDescription>
</Alert>
) : (
''
)}
</Col>
</Row>
</SaveEventProvider>
)
}
Example #20
Source File: InterestRatesView.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
export default function InterestRatesView() {
// name of table in view (current)
const [tableName, setTableName] = useState<InterestRatesTableOptions>(
InterestRatesTableOptions.Lending
);
// search term in TokenSearch component
const [tokenSearchValue, setTokenSearchValue] = useState("");
// information about each token
const [tokenData, setTokenData] = useState<TokenData[]>([]);
// Aave
const aaveReserves = useReserves();
// Compound
const compoundMarkets = useCompoundMarkets();
// Fuse
const { pools: fusePools, markets: fuseMarkets } = useFuseMarkets();
useEffect(() => {
let isUnmounting = false;
async function getTokenData() {
// gather list of all tokens
const allTokens = [
...aaveReserves.map((reserve) => reserve.tokenAddress),
...compoundMarkets.map((market) => market.tokenAddress),
];
// add fuse pools if available
if (fusePools)
allTokens.push(
...fusePools.map((pool) => pool.underlyingTokens).flat()
);
// isolate unique tokens only
const tokenAddresses = [...new Set(allTokens)];
// fetch token data asynchronously
const tokenDataList: TokenData[] = [];
await Promise.all(
tokenAddresses.map(async (address) => {
tokenDataList.push(await fetchTokenDataWithCache(address));
})
);
// sort token data
tokenDataList.sort(
(a, b) =>
tokenAddresses.indexOf(a.address!) -
tokenAddresses.indexOf(b.address!)
);
// set list in state if conditions are met
if (!isUnmounting && tokenDataList.length === tokenAddresses.length)
setTokenData(tokenDataList);
}
getTokenData();
// set isUnmounting to true when unmounting
return () => {
isUnmounting = false;
};
}, [aaveReserves, compoundMarkets, setTokenData, fusePools]);
// token list filtered by search term
const filteredTokenData = useMemo(
() =>
tokenSearchValue === ""
? tokenData
: tokenData // filter token by search term
.filter(
(token) =>
token
.name!.toLowerCase()
.includes(tokenSearchValue.toLowerCase()) ||
token
.symbol!.toLowerCase()
.includes(tokenSearchValue.toLowerCase())
),
[tokenSearchValue, tokenData]
);
const { t } = useTranslation();
return (
<InterestRatesContext.Provider
value={{
selectedTable: tableName,
tokens: filteredTokenData,
fusePools: fusePools,
markets: {
aave: aaveReserves,
compound: compoundMarkets,
fuse: fuseMarkets,
},
marketDataLoaded: aaveReserves.length > 0 && compoundMarkets.length > 0,
}}
>
<Column
width="100%"
mainAxisAlignment="center"
crossAxisAlignment="flex-start"
mt="3"
p={15}
>
{/* TODO (Zane): Add i18n */}
<Heading size="lg" mb="5">
Interest Rates
</Heading>
{tokenData.length === 0 ||
!fusePools ||
!fuseMarkets ||
!aaveReserves ||
!compoundMarkets ? (
<Center w="100%" h="100px">
<Spinner size="xl" />
</Center>
) : (
<>
<Flex w="100%">
<Box flex="3">
<MultiPicker
options={{
lending: t("Lending Rates"),
borrowing: t("Borrowing Rates"),
}}
// set table on change
onChange={(value) =>
setTableName(value as InterestRatesTableOptions)
}
/>
</Box>
<Spacer flex="2" />
<Box flex="3">
<TokenSearch onChange={setTokenSearchValue} />
</Box>
</Flex>
<Box mt="4" w="100%" position="relative">
<InterestRatesTable />
</Box>
</>
)}
</Column>
</InterestRatesContext.Provider>
);
}