@mui/material#CircularProgress TypeScript Examples
The following examples show how to use
@mui/material#CircularProgress.
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: CircularProgressCenter.tsx From firecms with MIT License | 6 votes |
/**
*
* @param props
* @constructor
* @ignore
*/
export function CircularProgressCenter(props: CircularProgressProps) {
return (
<Box
display="flex"
width={"100%"}
maxHeight={"100%"}
height={"100vh"}>
<Box m="auto">
<CircularProgress {...props}/>
</Box>
</Box>
);
}
Example #2
Source File: Logout.tsx From your_spotify with GNU General Public License v3.0 | 6 votes |
export default function Logout() {
const navigate = useNavigate();
const dispatch = useAppDispatch();
useEffect(() => {
async function dologout() {
dispatch(logout());
try {
await api.logout();
} catch (e) {
console.error(e);
}
navigate('/login');
}
dologout();
}, [navigate, dispatch]);
return (
<div>
<Text element="h3">You are being logged out</Text>
<CircularProgress />
</div>
);
}
Example #3
Source File: BlogEntryPreview.tsx From firecms with MIT License | 6 votes |
function ProductGroupPreview({ references }: { references: EntityReference[] }) {
const [products, setProducts] = useState<Entity<Product>[] | undefined>();
const dataSource = useDataSource();
/**
* Fetch the products determined by the references, using the datasource
* and the products schema
*/
useEffect(() => {
if (references) {
Promise.all(references.map((ref) => dataSource.fetchEntity({
path: ref.path,
entityId: ref.id,
schema: productSchema
})))
.then((results) => results.filter(r => !!r) as Entity<Product>[])
.then((results) => setProducts(results));
}
}, [references, dataSource]);
if (!references)
return <></>;
if (!products) return <CircularProgress/>;
return <Box>
{products.map((p, index) => <ProductPreview
key={`products_${index}`}
productValues={p.values as EntityValues<Product>}/>)}
</Box>;
}
Example #4
Source File: PrivateRoute.tsx From your_spotify with GNU General Public License v3.0 | 6 votes |
export default function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
const user = useSelector(selectUser);
const accounts = useSelector(selectAccounts);
const loaded = useSelector(selectLoaded);
const navigate = useNavigate();
useEffect(() => {
if (loaded && !user) {
navigate('/login');
}
}, [loaded, navigate, user]);
if (!loaded) {
return <CircularProgress />;
}
if (!user || !accounts || accounts.length === 0) {
return <div />;
}
return children;
}
Example #5
Source File: index.tsx From ExpressLRS-Configurator with GNU General Public License v3.0 | 6 votes |
Loader: FunctionComponent<LoaderProps> = ({ loading, sx = {} }) => {
return (
<>
{loading && (
<Box sx={{ ...styles.root, ...sx }}>
<CircularProgress />
</Box>
)}
</>
);
}
Example #6
Source File: NativeUsage.tsx From GTAV-NativeDB with MIT License | 6 votes |
function NativeUsage({ nativeHash, onNotFound }: NativeUsageProps) {
const [usageCode, setUsageCode] = useState<string | null>(null)
useEffect(() => {
(async () => {
setUsageCode(null)
const response = await fetch(`https://raw.githubusercontent.com/DottieDot/gta5-additional-nativedb-data/main/usages/${nativeHash}.cpp`)
if (response.ok) {
const code = await response.text();
setUsageCode(code)
}
else {
onNotFound && onNotFound()
setUsageCode('')
}
})()
}, [nativeHash, setUsageCode, onNotFound])
if (usageCode === null) {
return (
<Box sx={{ p: 2, justifyContent: 'center', display: 'flex' }}>
<CircularProgress size={36} />
</Box>
)
}
return (
<SyntaxHighlighter language="cpp">
{usageCode}
</SyntaxHighlighter>
)
}
Example #7
Source File: Loading.tsx From NekoMaid with MIT License | 6 votes |
CircularLoading: React.FC<CircularProgressProps & { loading?: boolean, background?: boolean }> =
({ loading, background = true, ...props }) => <Box sx={{
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: loading ? 2 : -1,
backgroundColor: background ? theme => theme.palette.mode === 'dark' ? 'rgba(0, 0, 0, 0.65)' : 'rgba(255, 255, 255, 0.4)' : undefined,
backdropFilter: background && loading ? 'blur(1px)' : undefined,
transition: '.5s',
opacity: loading ? '1' : '0',
userSelect: 'none',
pointerEvents: loading ? undefined : 'none'
}}>
<CircularProgress {...props} />
</Box>
Example #8
Source File: items-page.tsx From sdk with MIT License | 6 votes |
export function ItemsPage() {
const connection = useContext(ConnectorContext)
const { items, fetching, error } = useFetchItems(connection.sdk, connection.walletAddress)
return (
<Page header="My Items">
<CommentedBlock sx={{ my: 2 }} comment={<GetItemsComment/>}>
{
error && <CommentedBlock sx={{ my: 2 }}>
<Alert severity="error">
<AlertTitle>Items fetch error</AlertTitle>
{error.message || error.toString()}
</Alert>
</CommentedBlock>
}
{
fetching ? <Box sx={{
my: 4,
display: 'flex',
justifyContent: "center",
}}>
<CircularProgress/>
</Box> : ( items && <Box sx={{my: 2}}>
<ItemsList items={items}/>
</Box> )
}
</CommentedBlock>
</Page>
)
}
Example #9
Source File: index.tsx From mui-toolpad with MIT License | 6 votes |
function EditorContent({ appId }: EditorContentProps) {
const domLoader = useDomLoader();
return (
<EditorRoot>
{domLoader.dom ? (
<FileEditor appId={appId} />
) : (
<Box flex={1} display="flex" alignItems="center" justifyContent="center">
{domLoader.error ? (
<Alert severity="error">{domLoader.error}</Alert>
) : (
<CircularProgress />
)}
</Box>
)}
</EditorRoot>
);
}
Example #10
Source File: SubmitButton.tsx From frontend with MIT License | 6 votes |
export default function SubmitButton({
label = 'Submit',
loading = false,
loadingColor,
...props
}: SubmitButtonProps) {
const { t } = useTranslation()
const guessColor = props.color === 'primary' ? 'secondary' : 'primary'
const progressColor = loadingColor ? loadingColor : guessColor
return (
<Button
type="submit"
color="primary"
variant="contained"
disabled={loading}
sx={(theme) => ({ minWidth: theme.spacing(12) })}
{...props}>
{loading ? <CircularProgress color={progressColor} size="1.5rem" /> : t(label)}
</Button>
)
}
Example #11
Source File: transaction-info.tsx From example with MIT License | 6 votes |
export function TransactionPending({ transaction }: ITransactionInfoProps) {
const [state, setState] = useState<"resolve" | "reject" | "pending">("pending")
useEffect( () => {
transaction.wait()
.then(() => setState("resolve"))
.catch(() => setState("reject"))
}, [transaction])
return <Box sx={{ my: 1 }}>
<>
{ state === "pending" && <><CircularProgress size={14}/> Processing</> }
{ state === "resolve" && <Chip
label="Confirmed"
icon={<Icon icon={faCheckDouble}/>}
variant="outlined"
color="success"
size="small"
/> }
{ state === "reject" && <Chip
label="Rejected"
icon={<Icon icon={faTimes}/>}
variant="outlined"
color="error"
size="small"
/> }
</>
</Box>
}
Example #12
Source File: MessageList.tsx From airmessage-web with Apache License 2.0 | 5 votes |
function HistoryLoadingProgress() {
return (
<div className={styles.progressContainer}>
<CircularProgress />
</div>
);
}
Example #13
Source File: ImportHistory.tsx From your_spotify with GNU General Public License v3.0 | 5 votes |
export default function ImportHistory() {
const dispatch = useAppDispatch();
const imports = useSelector(selectImportStates);
const cleanImport = useCallback(
async (id: string) => {
dispatch(cleanupImport(id));
},
[dispatch],
);
const onImport = useCallback(
async (id: string) => {
await dispatch(startImportPrivacy({ id }));
},
[dispatch],
);
if (!imports) {
return <CircularProgress />;
}
return (
<div className={s.importhistory}>
<Text element="h3">Import history</Text>
{imports.map((st) => (
<SettingLine
key={st._id}
left={
<Text>
Import of {dateToListenedAt(new Date(st.createdAt))}
<Text className={s.importertype}>from {st.type}</Text>
</Text>
}
right={
<div className={s.right}>
<Text>
{statusToString[st.status]} ({st.current}/{st.total})
</Text>
<ThreePoints
items={compact([
st.status === 'failure'
? { label: 'Retry', onClick: () => onImport(st._id) }
: undefined,
st.status === 'failure'
? {
label: 'Clean up',
onClick: () => cleanImport(st._id),
style: 'destructive',
}
: undefined,
])}
/>
</div>
}
/>
))}
</div>
);
}
Example #14
Source File: DetailThread.tsx From airmessage-web with Apache License 2.0 | 5 votes |
render() {
//Creating the body view (use a loading spinner while conversation details aren't available)
let body: React.ReactNode;
if(this.state.display.type === DisplayType.Messages) {
body = <MessageList conversation={this.props.conversation} items={this.state.display.data} messageSubmitEmitter={this.messageSubmitEmitter} showHistoryLoader={this.state.historyLoadState === "loading"} onRequestHistory={this.handleRequestHistory} />;
} else if(this.state.display.type === DisplayType.Loading) {
body = (
<div className={styles.centerContainer}>
<CircularProgress />
</div>
);
} else if(this.state.display.type === DisplayType.Error) {
body = (
<div className={styles.centerContainer}>
<Typography color="textSecondary" gutterBottom>Couldn't load this conversation</Typography>
<Button onClick={this.requestMessages}>Retry</Button>
</div>
);
}
let inputPlaceholder: string;
if(this.props.conversation.service === appleServiceAppleMessage) {
inputPlaceholder = "iMessage";
} else {
inputPlaceholder = "Text message";
}
//Returning the element
return (
<DetailFrame
title={this.state.title ?? ""}
ref={this.dragDropRef}
showCall={this.state.isFaceTimeSupported}
onClickCall={this.startCall}>
<div className={styles.body}>{body}</div>
<div className={styles.input}>
<MessageInput placeholder={inputPlaceholder} message={this.state.message} attachments={this.state.attachments}
onMessageChange={this.handleMessageChange.bind(this)} onMessageSubmit={this.handleMessageSubmit.bind(this)}
onAttachmentAdd={this.handleAttachmentAdd.bind(this)} onAttachmentRemove={this.handleAttachmentRemove.bind(this)} />
</div>
</DetailFrame>
);
}
Example #15
Source File: Importer.tsx From your_spotify with GNU General Public License v3.0 | 5 votes |
export default function Importer() {
const dispatch = useAppDispatch();
const imports = useSelector(selectImportStates);
const [importType, setImportType] = useState<ImporterStateTypes>(ImporterStateTypes.privacy);
const fetch = useCallback(
async (force = false) => {
dispatch(getImports(force));
},
[dispatch],
);
useEffect(() => {
fetch();
}, [fetch]);
const running = useMemo(() => imports?.find((st) => st.status === 'progress'), [imports]);
const Component = useMemo(
() => (importType ? ImportTypeToComponent[importType] : null),
[importType],
);
if (!imports) {
return <CircularProgress />;
}
return (
<div>
<div>
{running && (
<div>
<Text>Importing...</Text>
<div className={s.progress}>
<Text>
{running.current} / {running.total}
</Text>
</div>
<LinearProgress
style={{ width: '100%' }}
variant="determinate"
value={(running.current / running.total) * 100}
/>
</div>
)}
</div>
{!running && (
<div>
<FormControl className={s.selectimport}>
<InputLabel id="import-type-select">Import type</InputLabel>
<Select
labelId="import-type-select"
value={importType}
label="Import type"
onChange={(ev) => setImportType(ev.target.value as ImporterStateTypes)}>
{Object.values(ImporterStateTypes).map((typ) => (
<MenuItem value={typ} key={typ}>
{typ}
</MenuItem>
))}
</Select>
</FormControl>
{Component && <Component />}
</div>
)}
{imports.length > 0 && <ImportHistory />}
</div>
);
}
Example #16
Source File: GameCanvas.tsx From rewind with MIT License | 5 votes |
GameCanvas = () => {
const canvas = useRef<HTMLCanvasElement | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const analysisApp = useAnalysisApp();
const { status } = useObservable(() => analysisApp.scenarioManager.scenario$, { status: "DONE" });
const showOverlay = status !== "DONE";
useEffect(() => {
if (containerRef.current) {
containerRef.current.append(analysisApp.stats());
}
}, [analysisApp]);
useEffect(() => {
if (status === "INIT") {
analysisApp.stats().hidden = true;
} else {
analysisApp.stats().hidden = false;
}
}, [status, analysisApp]);
useEffect(() => {
if (canvas.current) {
console.log("Initializing renderer to the canvas");
analysisApp.onEnter(canvas.current);
}
return () => analysisApp.onHide();
}, [analysisApp]);
return (
<Box ref={containerRef} sx={{ borderRadius: 2, overflow: "hidden", position: "relative", flex: 1 }}>
{status === "DONE" && (
<Tooltip title={"Close replay"}>
<IconButton
sx={{ position: "absolute", right: "0", top: "0" }}
onClick={() => analysisApp.scenarioManager.clearReplay()}
onFocus={ignoreFocus}
>
<CloseIcon />
</IconButton>
</Tooltip>
)}
<canvas
style={{
width: "100%",
height: "100%",
// , pointerEvents: "none"
}}
ref={canvas}
// This does not work
/>
{/*Overlay*/}
{showOverlay && (
<Box
sx={{
position: "absolute",
display: "flex",
alignItems: "center",
justifyContent: "center",
top: "0",
left: "0",
height: "100%",
width: "100%",
backgroundColor: "rgba(0,0,0,0.7)",
}}
>
{status === "INIT" && <EmptyState />}
{status === "LOADING" && <CircularProgress />}
{status === "ERROR" && <Typography>Something wrong happened...</Typography>}
</Box>
)}
</Box>
);
}
Example #17
Source File: MessageAttachmentDownloadable.tsx From airmessage-web with Apache License 2.0 | 5 votes |
export default function MessageAttachmentDownloadable(props: { data?: ArrayBuffer | Blob, name: string | undefined, type: string, size: number, guid: string, onDataAvailable: (result: FileDownloadResult) => void, onDataClicked: (data: ArrayBuffer | Blob) => void, partProps: MessagePartProps, tapbacks?: TapbackItem[], stickers?: StickerItem[]} ) { //State const [isDownloading, setIsDownloading] = useState(false); const [sizeAvailable, setSizeAvailable] = useState(props.size); const [sizeDownloaded, setSizeDownloaded] = useState<number | undefined>(undefined); const displaySnackbar = useContext(SnackbarContext); //Display the file name if it is available, otherwise just display the file type const nameDisplay = props.name ?? mimeTypeToPreview(props.type); function startDownload() { //Checking if data is already available if(props.data) { props.onDataClicked(props.data); return; } //Setting the state as downloading setIsDownloading(true); //Sending the request and setting the state to downloading ConnectionManager.fetchAttachment(props.guid) .progress((progress) => { if(progress.type === "size") { setSizeAvailable(progress.value); } else { setSizeDownloaded(progress.value); } }) .then((fileData) => { //Calling the listener props.onDataAvailable(fileData); //Resetting the state setIsDownloading(false); setSizeDownloaded(undefined); }) .catch((error: AttachmentRequestErrorCode) => { //Resetting the state setIsDownloading(false); setSizeDownloaded(undefined); //Notifying the user with a snackbar displaySnackbar({message: "Failed to download attachment: " + errorCodeToMessage(error)}); }); } return ( <DecorativeMessageBubble element={ButtonBase} className={`${styles.textBubble} ${stylesAttachment.root}`} style={props.partProps} disabled={isDownloading} onClick={startDownload} tapbacks={props.tapbacks} stickers={props.stickers}> <div className={stylesAttachment.icon}> { isDownloading ? <CircularProgress size={24} variant={sizeDownloaded === undefined ? "indeterminate" : "determinate"} value={(sizeDownloaded ?? 0) / sizeAvailable * 100} style={{color: props.partProps.color}} /> : <GetAppRounded /> } </div> <div className={stylesAttachment.description}> <span>{nameDisplay}</span> <br /> <span className={stylesAttachment.descriptionSecondary}>{ isDownloading ? formatFileSize(sizeDownloaded ?? 0) + " of " + formatFileSize(sizeAvailable): formatFileSize(sizeAvailable) + " • Click to download"} </span> </div> </DecorativeMessageBubble> ); }
Example #18
Source File: Require.tsx From multi-downloader-nx with MIT License | 5 votes |
Require = <T, >(props: React.PropsWithChildren<RequireType<T>>) => {
return props.value === undefined ? <Backdrop open>
<CircularProgress />
</Backdrop> : <Box>{props.children}</Box>
}
Example #19
Source File: CampaignFilter.tsx From frontend with MIT License | 5 votes |
export default function CampaignFilter() {
const { t } = useTranslation()
const { mobile } = useMobile()
const { data: campaigns, isLoading } = useCampaignList()
const [selectedCategory, setSelectedCategory] = useState<string | undefined>()
const campaignToShow = useMemo<CampaignResponse[]>(() => {
return (
campaigns?.filter((campaign) => {
if (selectedCategory) {
return campaign.campaignType.category === selectedCategory
}
return campaign
}) ?? []
)
}, [campaigns, selectedCategory])
return (
<Root>
<ImageList
cols={mobile ? 2 : 6}
rowHeight={164}
sx={{ maxWidth: 'lg', margin: '0 auto', my: 6 }}>
{Object.values(CampaignTypeCategory).map((category) => {
const count =
campaigns?.filter((campaign) => campaign.campaignType.category === category).length ?? 0
return (
<IconButton
key={category}
disabled={count === 0}
className={classes.filterButtons}
onClick={() => setSelectedCategory(category)}>
{categories[category].icon ?? <Category fontSize="large" />}
<Typography>
{t(`campaigns:filters.${category}`)} ({count})
</Typography>
</IconButton>
)
})}
<IconButton
disabled={!selectedCategory}
className={classes.filterButtons}
onClick={() => setSelectedCategory(undefined)}>
<FilterNone fontSize="large" />
<Typography>
{t(`campaigns:filters.all`)} ({campaigns?.length ?? 0})
</Typography>
</IconButton>
</ImageList>
{isLoading ? (
<Box textAlign="center">
<CircularProgress size="3rem" />
</Box>
) : (
<CampaignsList campaignToShow={campaignToShow} />
)}
</Root>
)
}
Example #20
Source File: CustomIframe.tsx From fluttertemplates.dev with MIT License | 5 votes |
export default function CustomIframe(props: CustomIframeProps) {
const [isLoading, setIsLoading] = React.useState(true);
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 10000);
}, []);
return (
<div
style={{
position: "relative",
width: "100%",
height: "100%",
}}
>
{isLoading && props.showLoadingIndicator && (
<Grid
container
direction="column"
justifyContent="center"
alignItems="center"
style={{
height: "100%",
width: "100%",
position: "absolute",
}}
>
<CircularProgress size="1.5rem" thickness={8} color="secondary" />
</Grid>
)}
<iframe
src={props.url}
style={{
height: "100%",
width: "100%",
position: "absolute",
border: "none",
...props.style,
}}
></iframe>
</div>
);
}
Example #21
Source File: AppEditorShell.tsx From mui-toolpad with MIT License | 5 votes |
export default function AppEditorShell({ appId, ...props }: ToolpadAppShellProps) {
const domLoader = useDomLoader();
const [createReleaseDialogOpen, setCreateReleaseDialogOpen] = React.useState(false);
return (
<ToolpadAppShell
appId={appId}
actions={
<React.Fragment>
{domLoader.saving ? (
<Box display="flex" flexDirection="row" alignItems="center">
<CircularProgress size={16} color="inherit" sx={{ mr: 1 }} />
</Box>
) : null}
<Typography>{domLoader.unsavedChanges} unsaved change(s).</Typography>
<IconButton
aria-label="Create release"
color="inherit"
sx={{ ml: 1 }}
onClick={() => setCreateReleaseDialogOpen(true)}
>
<RocketLaunchIcon />
</IconButton>
</React.Fragment>
}
{...props}
>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
overflow: 'hidden',
height: '100%',
}}
>
<PagePanel
appId={appId}
sx={{
width: 250,
borderRight: 1,
borderColor: 'divider',
}}
/>
<Box
sx={{
flex: 1,
overflow: 'hidden',
position: 'relative',
}}
>
<Outlet />
</Box>
<CreateReleaseDialog
appId={appId}
open={createReleaseDialogOpen}
onClose={() => setCreateReleaseDialogOpen(false)}
/>
</Box>
</ToolpadAppShell>
);
}
Example #22
Source File: Songs.tsx From your_spotify with GNU General Public License v3.0 | 5 votes |
export default function Songs() {
const user = useSelector(selectUser);
const accounts = useSelector(selectAccounts);
const { mode } = useParams();
const [query] = useSearchParams();
const idsQuery = query.get('ids');
const ids = useMemo(() => idsQuery?.split(',') ?? [], [idsQuery]);
const {
interval: { start, end },
} = useOldestListenedAtFromUsers(ids, AFFINITY_PREFIX);
const result = useAPI(api.collaborativeBestSongs, ids, start, end, mode as CollaborativeMode);
if (!result || !user) {
return (
<div className={s.loading}>
<CircularProgress size={18} />
<Text element="div">Loading your data</Text>
</div>
);
}
const accountsDict = accounts.reduce<Record<string, AdminAccount>>((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
const realIds = [user._id, ...ids];
return (
<div className={s.root}>
<Header
title="Affinity by song"
subtitle={`Affinity computed between ${realIds
.map((id) => accountsDict[id].username)
.join(', ')} in ${mode} mode, from ${intervalToDisplay(start, end)}`}
hideInterval
/>
<div className={s.content}>
{result?.map((res, index) => {
const listened = realIds.map((id) => res[id]);
let maxIndex = 0;
let max = 0;
for (let i = 0; i < listened.length; i += 1) {
if (listened[i] > max) {
maxIndex = i;
max = listened[i];
}
}
return (
<div key={res.track.id} className={s.track}>
<Text element="strong" className={s.ranking}>
#{index + 1}
</Text>
<PlayButton id={res.track.id} />
<img alt="cover" src={getImage(res.album)} className={s.trackimage} />
<div className={s.trackname}>
<Text element="div">{res.track.name}</Text>
<Text className={s.artist}>
<InlineArtist artist={res.artist} />
</Text>
</div>
<div className={s.enjoyed}>
<Text>
Most enjoyed by{' '}
<Text element="strong">{accountsDict[realIds[maxIndex]].username}</Text>
</Text>
</div>
</div>
);
})}
</div>
</div>
);
}
Example #23
Source File: Loadbox.tsx From Cromwell with MIT License | 5 votes |
LoadBox = (props: { size?: number }) => {
const classes = useStylesLoadBox();
return (
<div className={classes.loadBox} >
<CircularProgress size={(props.size ? props.size : 150)} />
</div>
)
}
Example #24
Source File: Loading.tsx From abrechnung with GNU Affero General Public License v3.0 | 5 votes |
export default function Loading() {
return (
<Grid container direction="row" justifyContent="center" alignItems="center">
<CircularProgress />
</Grid>
);
}
Example #25
Source File: Loader.tsx From your_spotify with GNU General Public License v3.0 | 5 votes |
export default function Loader() {
return (
<div className={s.root}>
<CircularProgress />
</div>
);
}
Example #26
Source File: Deposit.tsx From wrap.scrt.network with MIT License | 4 votes |
export default function Deposit({
token,
secretAddress,
onSuccess,
onFailure,
}: {
token: Token;
secretAddress: string;
onSuccess: (txhash: string) => any;
onFailure: (error: any) => any;
}) {
const [sourceAddress, setSourceAddress] = useState<string>("");
const [availableBalance, setAvailableBalance] = useState<string>("");
const [loadingTx, setLoading] = useState<boolean>(false);
const [sourceCosmJs, setSourceCosmJs] =
useState<SigningStargateClient | null>(null);
const [selectedChainIndex, setSelectedChainIndex] = useState<number>(0);
const [fetchBalanceInterval, setFetchBalanceInterval] = useState<any>(null);
const inputRef = useRef<any>();
const maxButtonRef = useRef<any>();
const sourceChain =
chains[token.deposits[selectedChainIndex].source_chain_name];
const targetChain = chains["Secret Network"];
const fetchSourceBalance = async (sourceAddress: string) => {
const url = `${
chains[token.deposits[selectedChainIndex].source_chain_name].lcd
}/bank/balances/${sourceAddress}`;
try {
const response = await fetch(url);
const result: {
height: string;
result: Array<{ denom: string; amount: string }>;
} = await response.json();
const balance =
result.result.find(
(c) => c.denom === token.deposits[selectedChainIndex].from_denom
)?.amount || "0";
setAvailableBalance(balance);
} catch (e) {
console.error(`Error while trying to query ${url}:`, e);
setAvailableBalance("Error");
}
};
useEffect(() => {
setAvailableBalance("");
if (!sourceAddress) {
return;
}
if (fetchBalanceInterval) {
clearInterval(fetchBalanceInterval);
}
fetchSourceBalance(sourceAddress);
const interval = setInterval(
() => fetchSourceBalance(sourceAddress),
10_000
);
setFetchBalanceInterval(interval);
return () => clearInterval(interval);
}, [sourceAddress]);
useEffect(() => {
(async () => {
while (!window.keplr || !window.getOfflineSignerOnlyAmino) {
await sleep(100);
}
if (["LUNA", "UST"].includes(token.name.toUpperCase())) {
await suggestTerraToKeplr(window.keplr);
}
// Initialize cosmjs on the target chain, because it has sendIbcTokens()
const { chain_id, rpc, bech32_prefix } =
chains[token.deposits[selectedChainIndex].source_chain_name];
await window.keplr.enable(chain_id);
const sourceOfflineSigner = window.getOfflineSignerOnlyAmino(chain_id);
const depositFromAccounts = await sourceOfflineSigner.getAccounts();
setSourceAddress(depositFromAccounts[0].address);
const cosmjs = await SigningStargateClient.connectWithSigner(
rpc,
sourceOfflineSigner,
{ prefix: bech32_prefix, broadcastPollIntervalMs: 10_000 }
);
setSourceCosmJs(cosmjs);
})();
}, [selectedChainIndex]);
return (
<>
<div style={{ padding: "1.5em" }}>
<div
style={{
display: "flex",
placeItems: "center",
gap: token.deposits.length === 1 ? "0.3em" : "0.5em",
}}
>
<Typography>
Deposit <strong>{token.name}</strong> from
</Typography>
<If condition={token.deposits.length === 1}>
<Then>
<Typography>
<strong>
{token.deposits[selectedChainIndex].source_chain_name}
</strong>
</Typography>
</Then>
<Else>
<FormControl>
<Select
value={selectedChainIndex}
onChange={(e) =>
setSelectedChainIndex(Number(e.target.value))
}
>
{token.deposits.map((chain, index) => (
<MenuItem value={index} key={index}>
<div
style={{
display: "flex",
gap: "0.5em",
placeItems: "center",
}}
>
<Avatar
src={chains[chain.source_chain_name].chain_image}
sx={{
marginLeft: "0.3em",
width: "1em",
height: "1em",
boxShadow: "rgba(0, 0, 0, 0.15) 0px 6px 10px",
}}
/>
<strong>{chain.source_chain_name}</strong>
</div>
</MenuItem>
))}
</Select>
</FormControl>
</Else>
</If>
<Typography>
to <strong>Secret Network</strong>
</Typography>
</div>
<br />
<div
style={{
display: "flex",
placeContent: "space-between",
placeItems: "center",
gap: "1em",
}}
>
<Typography sx={{ fontWeight: "bold" }}>From:</Typography>
<CopyableAddress
address={sourceAddress}
explorerPrefix={sourceChain.explorer_account}
/>
</div>
<div
style={{
display: "flex",
placeContent: "space-between",
placeItems: "center",
gap: "1em",
}}
>
<Typography sx={{ fontWeight: "bold" }}>To:</Typography>
<CopyableAddress
address={secretAddress}
explorerPrefix={targetChain.explorer_account}
/>
</div>
<br />
<div
style={{
display: "flex",
placeItems: "center",
gap: "0.3em",
marginBottom: "0.8em",
}}
>
<Typography sx={{ fontSize: "0.8em", fontWeight: "bold" }}>
Available to Deposit:
</Typography>
<Typography
sx={{
fontSize: "0.8em",
opacity: 0.8,
cursor: "pointer",
}}
onClick={() => {
maxButtonRef.current.click();
}}
>
{(() => {
if (availableBalance === "") {
return <CircularProgress size="0.6em" />;
}
const prettyBalance = new BigNumber(availableBalance)
.dividedBy(`1e${token.decimals}`)
.toFormat();
if (prettyBalance === "NaN") {
return "Error";
}
return `${prettyBalance} ${token.name}`;
})()}
</Typography>
</div>
<FormControl sx={{ width: "100%" }} variant="standard">
<InputLabel htmlFor="Amount to Deposit">Amount to Deposit</InputLabel>
<Input
autoFocus
id="Amount to Deposit"
fullWidth
type="text"
inputRef={inputRef}
startAdornment={
<InputAdornment position="start">
<Avatar
src={token.image}
sx={{
width: "1em",
height: "1em",
boxShadow: "rgba(0, 0, 0, 0.15) 0px 6px 10px",
}}
/>
</InputAdornment>
}
endAdornment={
<InputAdornment position="end">
<Button
ref={maxButtonRef}
style={{
padding: "0.1em 0.5em",
minWidth: 0,
}}
onClick={() => {
if (availableBalance === "") {
return;
}
const prettyBalance = new BigNumber(availableBalance)
.dividedBy(`1e${token.decimals}`)
.toFormat();
if (prettyBalance === "NaN") {
return;
}
inputRef.current.value = prettyBalance;
}}
>
MAX
</Button>
</InputAdornment>
}
/>
</FormControl>
</div>
<div
style={{
display: "flex",
placeContent: "center",
marginBottom: "0.4em",
}}
>
<LoadingButton
variant="contained"
sx={{
padding: "0.5em 0",
width: "10em",
fontWeight: "bold",
fontSize: "1.2em",
}}
loading={loadingTx}
onClick={async () => {
if (!sourceCosmJs) {
console.error("No cosmjs");
return;
}
if (!inputRef?.current?.value) {
console.error("Empty deposit");
return;
}
const normalizedAmount = (inputRef.current.value as string).replace(
/,/g,
""
);
if (!(Number(normalizedAmount) > 0)) {
console.error(`${normalizedAmount} not bigger than 0`);
return;
}
setLoading(true);
const amount = new BigNumber(normalizedAmount)
.multipliedBy(`1e${token.decimals}`)
.toFixed(0, BigNumber.ROUND_DOWN);
const { deposit_channel_id, deposit_gas } =
chains[token.deposits[selectedChainIndex].source_chain_name];
try {
const { transactionHash } = await sourceCosmJs.sendIbcTokens(
sourceAddress,
secretAddress,
{
amount,
denom: token.deposits[selectedChainIndex].from_denom,
},
"transfer",
deposit_channel_id,
undefined,
Math.floor(Date.now() / 1000) + 15 * 60, // 15 minute timeout
gasToFee(deposit_gas)
);
inputRef.current.value = "";
onSuccess(transactionHash);
} catch (e) {
onFailure(e);
} finally {
setLoading(false);
}
}}
>
Deposit
</LoadingButton>
</div>
</>
);
}
Example #27
Source File: FirebaseLoginView.tsx From firecms with MIT License | 4 votes |
function PhoneLoginForm({
onClose,
authDelegate
}: {
onClose: () => void,
authDelegate: FirebaseAuthDelegate,
}) {
useRecaptcha();
const [phone, setPhone] = useState<string>();
const [code, setCode] = useState<string>();
const [isInvalidCode, setIsInvalidCode] = useState(false);
const handleSubmit = async (event: any) => {
event.preventDefault();
if (code && authDelegate.confirmationResult) {
setIsInvalidCode(false);
authDelegate.confirmationResult.confirm(code).catch((e: FirebaseError) => {
if (e.code === "auth/invalid-verification-code") {
setIsInvalidCode(true)
}
});
} else {
if (phone) {
authDelegate.phoneLogin(phone, window.recaptchaVerifier);
}
}
}
return (
<form onSubmit={handleSubmit}>
{isInvalidCode &&
<Box p={2}>
<ErrorView
error={"Invalid confirmation code"}/>
</Box>}
<div id={RECAPTCHA_CONTAINER_ID} />
<Grid container spacing={1}>
<Grid item xs={12}>
<IconButton
onClick={onClose}>
<ArrowBackIcon sx={{ width: 20, height: 20 }}/>
</IconButton>
</Grid>
<Grid item xs={12} sx={{
p: 1,
display: "flex"
}}>
<Typography align={"center"}
variant={"subtitle2"}>{"Please enter your phone number"}</Typography>
</Grid>
<Grid item xs={12}>
<TextField placeholder="" fullWidth
value={phone}
disabled={Boolean(phone && (authDelegate.authLoading || authDelegate.confirmationResult))}
type="phone"
required
onChange={(event) => setPhone(event.target.value)}/>
</Grid>
{Boolean(phone && authDelegate.confirmationResult) &&
<>
<Grid item xs={12} sx={{
mt: 2,
p: 1,
display: "flex"
}}>
<Typography align={"center"}
variant={"subtitle2"}>{"Please enter the confirmation code"}</Typography>
</Grid>
<Grid item xs={12}>
<TextField placeholder="" fullWidth
value={code}
type="text"
required
onChange={(event) => setCode(event.target.value)}/>
</Grid>
</>
}
<Grid item xs={12}>
<Box sx={{
display: "flex",
justifyContent: "end",
alignItems: "center",
width: "100%"
}}>
{authDelegate.authLoading &&
<CircularProgress sx={{ p: 1 }} size={16}
thickness={8}/>
}
<Button type="submit">
{"Ok"}
</Button>
</Box>
</Grid>
</Grid>
</form>
);
}
Example #28
Source File: InlineDonation.tsx From frontend with MIT License | 4 votes |
export default function InlineDonation({ campaign }: Props) {
const { t } = useTranslation()
const router = useRouter()
const [showDonationPriceList, setDonationPriceList] = useState(false)
const onClick = () => setDonationPriceList(true)
const target = campaign.targetAmount
const summary = campaign.summary.find(() => true)
const reached = summary?.reachedAmount ?? 0
const donors = summary?.donors ?? 0
const { data: prices } = useSinglePriceList()
const {
data: donations,
error: donationHistoryError,
isLoading: isDonationHistoryLoading,
} = useCampaignDonationHistory(campaign.id)
const sortedPrices = useMemo(() => {
if (!prices) return []
return prices?.sort((a, b) => {
if (a.unit_amount === null || b.unit_amount === null) return 0
return a.unit_amount - b.unit_amount
})
}, [prices])
return (
<StyledGrid item xs={12} mt={5} p={3} className={classes.inlineDonationWrapper}>
<Grid mb={2}>
<Typography component="span" className={classes.reachedMoney}>
{money(reached)}
</Typography>{' '}
{t('campaigns:campaign.from')}{' '}
<Typography component="span" className={classes.targetMoney}>
{money(target)}
</Typography>
</Grid>
<CampaignProgress raised={reached} target={target} />
<Grid display="inline-block" m={3} ml={0}>
<Typography className={classes.donorsSharesCount}>{donors}</Typography>
<Typography>{t('campaigns:campaign.donors')}</Typography>
</Grid>
<Grid display="inline-block" m={3} ml={0}>
<Typography className={classes.donorsSharesCount}>{0}</Typography>
<Typography>{t('campaigns:campaign.shares')}</Typography>
</Grid>
<Grid container gap={2}>
<LinkButton
fullWidth
href="#"
variant="outlined"
startIcon={<ShareIcon />}
color="secondary">
{t('campaigns:cta.share')}
</LinkButton>
<LinkButton
fullWidth
href="#"
onClick={onClick}
variant="contained"
color="secondary"
startIcon={<Favorite color="action" />}>
{t('common:support')}
</LinkButton>
{showDonationPriceList && (
<List className={classes.donationPriceList}>
{sortedPrices.map((price, index) => {
if (!price) return null
return (
<ListItem button key={index}>
<ListItemText
onClick={() =>
router.push({
pathname: routes.campaigns.oneTimeDonation(campaign.slug),
query: {
price: price.id,
},
})
}
primary={`${(price.unit_amount ?? 100) / 100} лв.`}
secondary={price.metadata.title}
/>
</ListItem>
)
})}
</List>
)}
</Grid>
{donationHistoryError ? (
'Error fetching donation history'
) : isDonationHistoryLoading ? (
<CircularProgress sx={{ display: 'block', margin: `${theme.spacing(3)} auto` }} />
) : (
<DonorsAndDonations donations={donations} />
)}
{/* <pre>{JSON.stringify(prices, null, 2)}</pre> */}
</StyledGrid>
)
}
Example #29
Source File: EntityView.tsx From firecms with MIT License | 4 votes |
export function EntityView<M extends { [Key: string]: any }, UserType>({
path,
entityId,
callbacks,
selectedSubpath,
copy,
permissions,
schema: schemaOrResolver,
subcollections,
onModifiedValues,
width
}: EntityViewProps<M, UserType>) {
const resolvedWidth: string | undefined = typeof width === "number" ? `${width}px` : width;
const classes = useStylesSide({ containerWidth: resolvedWidth ?? CONTAINER_WIDTH });
const dataSource = useDataSource();
const sideEntityController = useSideEntityController();
const snackbarContext = useSnackbarController();
const context = useFireCMSContext();
const authController = useAuthController<UserType>();
const [status, setStatus] = useState<EntityStatus>(copy ? "copy" : (entityId ? "existing" : "new"));
const [currentEntityId, setCurrentEntityId] = useState<string | undefined>(entityId);
const [readOnly, setReadOnly] = useState<boolean>(false);
const [tabsPosition, setTabsPosition] = React.useState(-1);
const [modifiedValues, setModifiedValues] = useState<EntityValues<any> | undefined>();
const {
entity,
dataLoading,
// eslint-disable-next-line no-unused-vars
dataLoadingError
} = useEntityFetch({
path,
entityId: currentEntityId,
schema: schemaOrResolver,
useCache: false
});
const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
const resolvedSchema:ResolvedEntitySchema<M> = useMemo(() => computeSchema({
schemaOrResolver,
path,
entityId,
values: modifiedValues,
previousValues: usedEntity?.values
}), [schemaOrResolver, path, entityId, modifiedValues]);
useEffect(() => {
function beforeunload(e: any) {
if (modifiedValues) {
e.preventDefault();
e.returnValue = `You have unsaved changes in this ${resolvedSchema.name}. Are you sure you want to leave this page?`;
}
}
if (typeof window !== "undefined")
window.addEventListener("beforeunload", beforeunload);
return () => {
if (typeof window !== "undefined")
window.removeEventListener("beforeunload", beforeunload);
};
}, [modifiedValues, window]);
const customViews = resolvedSchema.views;
const customViewsCount = customViews?.length ?? 0;
useEffect(() => {
setUsedEntity(entity);
if (entity)
setReadOnly(!canEdit(permissions, entity, authController, path, context));
}, [entity, permissions]);
const theme = useTheme();
const largeLayout = useMediaQuery(theme.breakpoints.up("lg"));
useEffect(() => {
if (!selectedSubpath)
setTabsPosition(-1);
if (customViews) {
const index = customViews
.map((c) => c.path)
.findIndex((p) => p === selectedSubpath);
setTabsPosition(index);
}
if (subcollections && selectedSubpath) {
const index = subcollections
.map((c) => c.path)
.findIndex((p) => p === selectedSubpath);
setTabsPosition(index + customViewsCount);
}
}, [selectedSubpath]);
const onPreSaveHookError = useCallback((e: Error) => {
snackbarContext.open({
type: "error",
title: "Error before saving",
message: e?.message
});
console.error(e);
}, []);
const onSaveSuccessHookError = useCallback((e: Error) => {
snackbarContext.open({
type: "error",
title: `${resolvedSchema.name}: Error after saving (entity is saved)`,
message: e?.message
});
console.error(e);
}, []);
const onSaveSuccess = useCallback((updatedEntity: Entity<M>) => {
setCurrentEntityId(updatedEntity.id);
snackbarContext.open({
type: "success",
message: `${resolvedSchema.name}: Saved correctly`
});
setUsedEntity(updatedEntity);
setStatus("existing");
onModifiedValues(false);
if (tabsPosition === -1)
sideEntityController.close();
}, []);
const onSaveFailure = useCallback((e: Error) => {
snackbarContext.open({
type: "error",
title: `${resolvedSchema.name}: Error saving`,
message: e?.message
});
console.error("Error saving entity", path, entityId);
console.error(e);
}, []);
const onEntitySave = useCallback(async ({
schema,
path,
entityId,
values,
previousValues
}: {
schema: EntitySchema<M>,
path: string,
entityId: string | undefined,
values: EntityValues<M>,
previousValues?: EntityValues<M>,
}): Promise<void> => {
console.log("onEntitySave", path)
if (!status)
return;
return saveEntityWithCallbacks({
path,
entityId,
callbacks,
values,
previousValues,
schema,
status,
dataSource,
context,
onSaveSuccess,
onSaveFailure,
onPreSaveHookError,
onSaveSuccessHookError
});
}, [status, callbacks, dataSource, context, onSaveSuccess, onSaveFailure, onPreSaveHookError, onSaveSuccessHookError]);
const onDiscard = useCallback(() => {
if (tabsPosition === -1)
sideEntityController.close();
}, [sideEntityController, tabsPosition]);
const body = !readOnly
? (
<EntityForm
key={`form_${path}_${usedEntity?.id ?? "new"}`}
status={status}
path={path}
schemaOrResolver={schemaOrResolver}
onEntitySave={onEntitySave}
onDiscard={onDiscard}
onValuesChanged={setModifiedValues}
onModified={onModifiedValues}
entity={usedEntity}/>
)
: (usedEntity &&
<EntityPreview
entity={usedEntity}
path={path}
schema={schemaOrResolver}/>
)
;
const customViewsView: JSX.Element[] | undefined = customViews && customViews.map(
(customView, colIndex) => {
return (
<Box
className={classes.subcollectionPanel}
key={`custom_view_${customView.path}_${colIndex}`}
role="tabpanel"
flexGrow={1}
height={"100%"}
width={"100%"}
hidden={tabsPosition !== colIndex}>
<ErrorBoundary>
{customView.builder({
schema: resolvedSchema,
entity: usedEntity,
modifiedValues: modifiedValues ?? usedEntity?.values
})}
</ErrorBoundary>
</Box>
);
}
);
const subCollectionsViews = subcollections && subcollections.map(
(subcollection, colIndex) => {
const absolutePath = usedEntity ? `${usedEntity?.path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.path)}` : undefined;
return (
<Box
className={classes.subcollectionPanel}
key={`subcol_${subcollection.name}_${colIndex}`}
role="tabpanel"
flexGrow={1}
hidden={tabsPosition !== colIndex + customViewsCount}>
{usedEntity && absolutePath
? <EntityCollectionView
path={absolutePath}
collection={subcollection}/>
: <Box m={3}
display={"flex"}
alignItems={"center"}
justifyContent={"center"}>
<Box>
You need to save your entity before
adding additional collections
</Box>
</Box>
}
</Box>
);
}
);
const getSelectedSubpath = useCallback((value: number) => {
if (value === -1) return undefined;
if (customViews && value < customViewsCount) {
return customViews[value].path;
}
if (subcollections) {
return subcollections[value - customViewsCount].path;
}
throw Error("Something is wrong in getSelectedSubpath");
}, [customViews]);
const onSideTabClick = useCallback((value: number) => {
setTabsPosition(value);
if (entityId) {
sideEntityController.open({
path,
entityId,
selectedSubpath: getSelectedSubpath(value),
overrideSchemaRegistry: false
});
}
}, []);
const loading = dataLoading || (!usedEntity && status === "existing");
const header = (
<Box sx={{
paddingLeft: 2,
paddingRight: 2,
paddingTop: 2,
display: "flex",
alignItems: "center",
backgroundColor: theme.palette.mode === "light" ? theme.palette.background.default : theme.palette.background.paper
}}
>
<IconButton onClick={(e) => sideEntityController.close()}
size="large">
<CloseIcon/>
</IconButton>
<Tabs
value={tabsPosition === -1 ? 0 : false}
indicatorColor="secondary"
textColor="inherit"
scrollButtons="auto"
>
<Tab
label={resolvedSchema.name}
classes={{
root: classes.tab
}}
wrapped={true}
onClick={() => {
onSideTabClick(-1);
}}/>
</Tabs>
<Box flexGrow={1}/>
{loading &&
<CircularProgress size={16} thickness={8}/>}
<Tabs
value={tabsPosition >= 0 ? tabsPosition : false}
indicatorColor="secondary"
textColor="inherit"
onChange={(ev, value) => {
onSideTabClick(value);
}}
className={classes.tabBar}
variant="scrollable"
scrollButtons="auto"
>
{customViews && customViews.map(
(view) =>
<Tab
classes={{
root: classes.tab
}}
wrapped={true}
key={`entity_detail_custom_tab_${view.name}`}
label={view.name}/>
)}
{subcollections && subcollections.map(
(subcollection) =>
<Tab
classes={{
root: classes.tab
}}
wrapped={true}
key={`entity_detail_collection_tab_${subcollection.name}`}
label={subcollection.name}/>
)}
</Tabs>
</Box>
);
return <div
className={clsx(classes.container, { [classes.containerWide]: tabsPosition !== -1 })}>
{
loading
? <CircularProgressCenter/>
: <>
{header}
<Divider/>
<div className={classes.tabsContainer}>
<Box
role="tabpanel"
hidden={!largeLayout && tabsPosition !== -1}
className={classes.form}>
{body}
</Box>
{customViewsView}
{subCollectionsViews}
</div>
</>
}
</div>;
}