@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 vote down vote up
/**
 *
 * @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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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&apos;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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>;
}