@material-ui/core/styles#useTheme TypeScript Examples

The following examples show how to use @material-ui/core/styles#useTheme. 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: NavigationContainer.tsx    From Demae with MIT License 6 votes vote down vote up
ListView = (props: BoxProps) => {
	const theme = useTheme()
	const matches = useMediaQuery(theme.breakpoints.down("sm"));
	const maxWidth = props.maxWidth || (matches ? "100%" : "380px")
	return (
		<Box
			width="100%"
			maxWidth={maxWidth}
			height="100%"
		>
			<Box
				position="fixed"
				width="inherit"
				maxWidth="inherit"
				style={{
					paddingTop: NavigationBarHeight
				}}
				{...props}
			>
				<Paper
					elevation={0}
					style={{
						height: "100%",
						width: "100%",
						paddingTop: NavigationBarHeight,
						background: "inherit"
					}}>
					<ListViewProvider>
						<ListHeaderProvider>
							{props.children}
						</ListHeaderProvider>
					</ListViewProvider>
				</Paper>
			</Box>
		</Box>
	)
}
Example #2
Source File: Drawer.tsx    From dashboard-layout with MIT License 6 votes vote down vote up
CustomDrawer = () => {
  const classes = useStyles();
  const { isOpened, toggleIsOpened } = useDrawerContext();
  const theme = useTheme();
  const isLargeScreen = useMediaQuery(theme.breakpoints.up("sm"));

  return (
    <Drawer
      variant={isLargeScreen ? "permanent" : "temporary"}
      open={!isLargeScreen && isOpened ? true : false}
      onClose={() => toggleIsOpened(!isOpened)}
      classes={{
        paper: clsx(classes.drawer, {
          [classes.closed]: !isOpened,
          [classes.opened]: isOpened,
        }),
      }}
    >
      <MenuItemsList />
    </Drawer>
  );
}
Example #3
Source File: ChartType.tsx    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
ChartType: React.FC<ChartTypeProps> = ({
  typeTexts,
  chartTypes,
  chartType,
  setChartType,
}) => {
  const classes = useStyles();
  const { palette } = useTheme();

  return (
    <Box display='flex' alignItems='center'>
      {chartTypes.map((value, index) => (
        <Box
          key={index}
          className={classes.chartType}
          bgcolor={chartType === value ? palette.grey.A400 : 'transparent'}
          onClick={() => setChartType(value)}
        >
          <Typography variant='caption'>{typeTexts[index]}</Typography>
        </Box>
      ))}
    </Box>
  );
}
Example #4
Source File: LinearGauge.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
export function LinearGauge(props: Props) {
  const { value, getColor = getProgressColor } = props;
  const { palette } = useTheme<BackstageTheme>();
  if (isNaN(value)) {
    return null;
  }
  let percent = Math.round(value * 100 * 100) / 100;
  if (percent > 100) {
    percent = 100;
  }
  const strokeColor = getColor({
    palette,
    value: percent,
    inverse: false,
    max: 100,
  });
  return (
    <Tooltip title={`${percent}%`}>
      <span>
        <Line
          percent={percent}
          strokeWidth={4}
          trailWidth={4}
          strokeColor={strokeColor}
        />
      </span>
    </Tooltip>
  );
}
Example #5
Source File: AppDynamicPage.tsx    From clearflask with Apache License 2.0 6 votes vote down vote up
BoardPanel = (props: {
  className?: string,
  server: Server,
  panel: Client.PagePanelWithHideIfEmpty,
  PanelPostProps?: Partial<React.ComponentProps<typeof PanelPost>>;
}) => {
  const classes = useStyles();
  const theme = useTheme();
  return (
    <PanelPost
      key={getSearchKey(props.panel.search)}
      className={classNames(props.className, classes.boardPanel)}
      maxHeight={theme.vh(80)}
      direction={Direction.Vertical}
      panel={props.panel}
      server={props.server}
      displayDefaults={{
        titleTruncateLines: 1,
        descriptionTruncateLines: 0,
        showCommentCount: false,
        showCategoryName: false,
        showCreated: false,
        showAuthor: false,
        showStatus: false,
        showTags: false,
        showVoting: false,
        showVotingCount: false,
        showFunding: false,
        showExpression: false,
      }}
      {...props.PanelPostProps}
    />
  );
}
Example #6
Source File: DailyStatsChart.tsx    From asynqmon with MIT License 6 votes vote down vote up
export default function DailyStatsChart(props: Props) {
  const data = makeChartData(props.data, props.numDays);
  const theme = useTheme<Theme>();
  return (
    <ResponsiveContainer>
      <LineChart data={data}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis
          dataKey="date"
          minTickGap={10}
          stroke={theme.palette.text.secondary}
        />
        <YAxis stroke={theme.palette.text.secondary} />
        <Tooltip />
        <Legend />
        <Line
          type="monotone"
          dataKey="succeeded"
          stroke={theme.palette.success.main}
        />
        <Line
          type="monotone"
          dataKey="failed"
          stroke={theme.palette.error.main}
        />
      </LineChart>
    </ResponsiveContainer>
  );
}
Example #7
Source File: Login.tsx    From ra-enterprise-demo with MIT License 6 votes vote down vote up
LoginWithTheme = (props: any): ReactElement => {
    const theme = useTheme();
    const { lightTheme } = getThemes(theme);
    return (
        <ThemeProvider theme={createMuiTheme(lightTheme)}>
            <Login {...props} />
        </ThemeProvider>
    );
}
Example #8
Source File: index.tsx    From Demae with MIT License 5 votes vote down vote up
OrderList = () => {
	const theme = useTheme()
	const [user, isLoading] = useUser()
	const ref = user?.orders.collectionReference
	const [orders, isDataLoading] = useDataSourceListen<Order>(Order, {
		path: ref?.path,
		orderBy: OrderBy("createdAt", "desc"),
		limit: 100
	}, isLoading)

	if (isDataLoading) {
		return (
			<Paper>
				<DataLoading />
			</Paper>
		)
	}

	if (orders.length === 0) {
		return <Box padding={3} display="flex" justifyContent="center" fontWeight={600} fontSize={20}>There are no orders.</Box>
	}

	return (
		<Paper>
			<List style={{
				height: "100%"
			}}>
				{orders.map(data => {
					const orderedDate = Dayjs(data.createdAt.toDate())
					return (
						<ListItem key={data.id} button alignItems="flex-start" component={Link} to={`/account/orders/${data.id}`}>
							<ListItemAvatar>
								<Avatar variant="rounded" src={data.imageURLs()[0]} style={{
									height: theme.spacing(5),
									width: theme.spacing(5)
								}}>
									<ImageIcon />
								</Avatar>
							</ListItemAvatar>
							<ListItemText primary={
								<>
									<Typography variant="subtitle1">
										{data.title}
									</Typography>
									<Typography variant="body2">
										{`ID: ${data.id}`}
									</Typography>
									<Typography variant="caption">
										{orderedDate.format("YYYY-MM-DD HH:mm:ss")}
									</Typography>
									<Box display="flex" paddingY={1}>
										{data.salesMethod === "online" && <Label color="gray" fontSize={12}>{DeliveryStatusLabel[data.deliveryStatus]}</Label>}
										<Label color="gray" fontSize={12}>{PaymentStatusLabel[data.paymentStatus]}</Label>
									</Box>
								</>
							} />
						</ListItem>
					)
				})}
			</List>
		</Paper>
	)
}
Example #9
Source File: CodeEditor.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
export default function CodeEditor({
  onChange,
  value,
  height = 400,
  wrapperProps,
  disabled,
  editorOptions,
}: ICodeEditorProps) {
  const theme = useTheme();
  const [initialEditorValue] = useState(value ?? "");
  const { tableState } = useFiretableContext();
  const classes = useStyles();
  const monacoInstance = useMonaco();

  const editorRef = useRef<any>();

  function handleEditorDidMount(_, editor) {
    editorRef.current = editor;
  }

  const themeTransformer = (theme: string) => {
    switch (theme) {
      case "dark":
        return "vs-dark";
      default:
        return theme;
    }
  };

  useMemo(async () => {
    if (!monacoInstance) {
      // useMonaco returns a monaco instance but initialisation is done asynchronously
      // dont execute the logic until the instance is initialised
      return;
    }

    try {
      monacoInstance.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
        {
          noSemanticValidation: true,
          noSyntaxValidation: false,
        }
      );
      // compiler options
      monacoInstance.languages.typescript.javascriptDefaults.setCompilerOptions(
        {
          target: monacoInstance.languages.typescript.ScriptTarget.ES5,
          allowNonTsExtensions: true,
        }
      );
    } catch (error) {
      console.error(
        "An error occurred during initialization of Monaco: ",
        error
      );
    }
  }, [tableState?.columns]);

  return (
    <div
      {...wrapperProps}
      className={clsx(classes.editorWrapper, wrapperProps?.className)}
    >
      <Editor
        theme={themeTransformer(theme.palette.type)}
        height={height}
        onMount={handleEditorDidMount}
        language="javascript"
        value={initialEditorValue}
        options={{
          readOnly: disabled,
          fontFamily: theme.typography.fontFamilyMono,
          ...editorOptions,
        }}
        onChange={onChange as any}
      />
    </div>
  );
}
Example #10
Source File: SubList.tsx    From GitNotes with MIT License 5 votes vote down vote up
export default function SubList(props: Props) {
    const theme = useTheme()
    const indent = props.indent ? props.indent : 2
    const f = props.folder

    const [opens, setOpens] = React.useState(
        Array(typeof (f.folders) === 'function' ? 0 : f.folders.length).fill(false) as boolean[]
    )

    function handleClick(index: number) {
        setOpens(opens.map((value, i) => index === i ? !value : value))
    }

    if (typeof (f.folders) === 'function') {
        f.folders(f, (folders, files) => {
            f.folders = folders
            f.files = files
            setOpens(Array(f.folders.length).fill(false))
            if (props.onLoad) {
                props.onLoad(files)
            }
            props.fresh()
        })
        return (
            <List component="div" disablePadding>
                <ListItem button style={{ paddingLeft: theme.spacing(indent) }}>
                    <Skeleton variant="text" width={300} height={30} />
                </ListItem>
            </List>
        )
    } else {
        return (
            <List component="div" disablePadding>
                {
                    flatten2d(f.folders.map((folder, index) => [
                        <ListItem button
                            onClick={() => handleClick(index)}
                            key={index}
                            style={{ paddingLeft: theme.spacing(indent) }}>
                            <ListItemIcon>
                                <FolderIcon />
                            </ListItemIcon>
                            <ListItemText primary={folder.name} />
                            {opens[index] ? <ExpandLess /> : <ExpandMore />}
                        </ListItem>,
                        <Collapse key={f.folders.length + index} in={opens[index]} timeout="auto" unmountOnExit>
                            <SubList indent={indent + 4} folder={folder} fresh={props.fresh} onClick={props.onClick} />
                        </Collapse>
                    ]))
                }
                {
                    f.files.map((file, index) => (
                        <ListItem button
                            onClick={() => {props.onClick(file)}}
                            key={2 * f.folders.length + index}
                            style={{ paddingLeft: theme.spacing(indent) }}>
                            <ListItemIcon>
                                {isMarkdown(file.name) ? <MdIcon /> : <FileIcon />}
                            </ListItemIcon>
                            <ListItemText primary={file.name} />
                        </ListItem>
                    ))
                }
            </List>
        )
    }
}
Example #11
Source File: TransactionInfiniteList.tsx    From End-to-End-Web-Testing-with-Cypress with MIT License 5 votes vote down vote up
TransactionInfiniteList: React.FC<TransactionListProps> = ({
  transactions,
  loadNextPage,
  pagination,
}) => {
  const classes = useStyles();
  const theme = useTheme();
  const isXsBreakpoint = useMediaQuery(theme.breakpoints.down("xs"));
  const isMobile = useMediaQuery(theme.breakpoints.down("sm"));

  const itemCount = pagination.hasNextPages ? transactions.length + 1 : transactions.length;

  const loadMoreItems = () => {
    return new Promise((resolve) => {
      return resolve(pagination.hasNextPages && loadNextPage(pagination.page + 1));
    });
  };

  const isRowLoaded = (params: Index) =>
    !pagination.hasNextPages || params.index < transactions.length;

  // @ts-ignore
  function rowRenderer({ key, index, style }) {
    const transaction = get(index, transactions);

    if (index < transactions.length) {
      return (
        <div key={key} style={style}>
          <TransactionItem transaction={transaction} />
          <Divider variant={isMobile ? "fullWidth" : "inset"} />
        </div>
      );
    }
  }

  return (
    <InfiniteLoader
      isRowLoaded={isRowLoaded}
      loadMoreRows={loadMoreItems}
      rowCount={itemCount}
      threshold={2}
    >
      {({ onRowsRendered, registerChild }) => (
        <div data-test="transaction-list" className={classes.transactionList}>
          <List
            rowCount={itemCount}
            ref={registerChild}
            onRowsRendered={onRowsRendered}
            height={isXsBreakpoint ? theme.spacing(74) : theme.spacing(88)}
            width={isXsBreakpoint ? theme.spacing(38) : theme.spacing(110)}
            rowHeight={isXsBreakpoint ? theme.spacing(28) : theme.spacing(16)}
            rowRenderer={rowRenderer}
          />
        </div>
      )}
    </InfiniteLoader>
  );
}
Example #12
Source File: BuyFiatModal.tsx    From interface-v2 with GNU General Public License v3.0 5 votes vote down vote up
BuyFiatModal: React.FC<BuyFiatModalProps> = ({
  open,
  onClose,
  buyMoonpay,
}) => {
  const classes = useStyles();
  const { account } = useActiveWeb3React();
  const { breakpoints } = useTheme();
  const mobileWindowSize = useMediaQuery(breakpoints.down('sm'));
  const { initTransak } = useInitTransak();

  return (
    <CustomModal open={open} onClose={onClose}>
      <Box padding={3}>
        <Box display='flex' justifyContent='space-between' alignItems='center'>
          <Typography variant='subtitle2' color='textPrimary'>
            Fiat gateway providers
          </Typography>
          <CloseIcon style={{ cursor: 'pointer' }} onClick={onClose} />
        </Box>
        <Box className={classes.paymentBox}>
          <img src={Moonpay} alt='moonpay' />
          <Box className={classes.buyButton} onClick={buyMoonpay}>
            Buy
          </Box>
        </Box>
        <Box className={classes.paymentBox}>
          <img src={Transak} alt='transak' />
          <Box
            className={classes.buyButton}
            onClick={() => {
              onClose();
              initTransak(account, mobileWindowSize);
            }}
          >
            Buy
          </Box>
        </Box>
        <Box mt={3} display='flex'>
          <Box display='flex' mt={0.3}>
            <HelpIcon />
          </Box>
          <Box ml={1.5} width='calc(100% - 32px)'>
            <Typography variant='body2'>
              Fiat services on Quickswap are provided by third-parties.
              Quickswap is not associated with, responsible or liable for the
              performance of these third-party services. Any claims & questions
              should be addressed with the selected provider.
            </Typography>
          </Box>
        </Box>
      </Box>
    </CustomModal>
  );
}
Example #13
Source File: CodeSnippet.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
/**
 * Thin wrapper on top of {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}
 * providing consistent theming and copy code button
 *
 * @public
 */
export function CodeSnippet(props: CodeSnippetProps) {
  const {
    text,
    language,
    showLineNumbers = false,
    highlightedNumbers,
    customStyle,
    showCopyCodeButton = false,
  } = props;
  const theme = useTheme<BackstageTheme>();
  const mode = theme.palette.type === 'dark' ? dark : docco;
  const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';

  return (
    <div style={{ position: 'relative' }}>
      <LightAsync
        customStyle={customStyle}
        language={language}
        style={mode}
        showLineNumbers={showLineNumbers}
        wrapLines
        lineNumberStyle={{ color: theme.palette.textVerySubtle }}
        lineProps={(lineNumber: number) =>
          highlightedNumbers?.includes(lineNumber)
            ? {
                style: {
                  backgroundColor: highlightColor,
                },
              }
            : {}
        }
      >
        {text}
      </LightAsync>
      {showCopyCodeButton && (
        <div style={{ position: 'absolute', top: 0, right: 0 }}>
          <CopyTextButton text={text} />
        </div>
      )}
    </div>
  );
}
Example #14
Source File: CommentEdit.tsx    From clearflask with Apache License 2.0 5 votes vote down vote up
CommentDelete = (props: {
  server: Server;
  comment: Client.CommentWithVote;
  asAdmin: boolean
  open?: boolean;
  onClose: () => void;
  onDelete: () => void;
}) => {
  const [isSubmitting, setSubmitting] = useState(false);
  const theme = useTheme();
  return (
    <Dialog
      open={!!props.open}
      onClose={props.onClose}
    >
      <DialogTitle>Delete comment</DialogTitle>
      <DialogContent>
        <DialogContentText>Are you sure you want to permanently delete this comment?</DialogContentText>
      </DialogContent>
      <DialogActions>
        <Button onClick={props.onClose}>Cancel</Button>
        <SubmitButton
          isSubmitting={isSubmitting}
          style={{ color: !isSubmitting ? theme.palette.error.main : undefined }}
          onClick={() => {
            setSubmitting(true);
            (props.asAdmin
              ? props.server.dispatchAdmin().then(d => d.commentDeleteAdmin({
                projectId: props.server.getProjectId(),
                ideaId: props.comment.ideaId,
                commentId: props.comment.commentId,
              }))
              : props.server.dispatch().then(d => d.commentDelete({
                projectId: props.server.getProjectId(),
                ideaId: props.comment.ideaId,
                commentId: props.comment.commentId,
              })))
              .then(() => {
                setSubmitting(false);
                props.onDelete();
              })
              .catch(e => setSubmitting(false))
          }}>
          Delete
        </SubmitButton>
      </DialogActions>
    </Dialog>
  )
}
Example #15
Source File: TablePaginationActions.tsx    From frontegg-react with MIT License 5 votes vote down vote up
TablePaginationActions: FC<FeTablePaginationProps<any>> = <T extends object>(
  props: FeTablePaginationProps<T>
) => {
  const classes = useStyles();
  const theme = useTheme();
  const { count, page, rowsPerPage, onChangePage, gotoPage } = props;

  const handleFirstPageButtonClick = useCallback(() => {
    gotoPage(0);
  }, []);

  const handleBackButtonClick = useCallback(
    (event: any) => {
      onChangePage(event, page - 1);
    },
    [page]
  );

  const handleNextButtonClick = useCallback(
    (event: any) => {
      onChangePage(event, page + 1);
    },
    [page]
  );

  const handleLastPageButtonClick = useCallback(() => {
    gotoPage(Math.max(0, Math.ceil(count / rowsPerPage) - 1));
  }, []);

  return (
    <div className={classes.root}>
      <IconButton onClick={handleFirstPageButtonClick} disabled={page === 0} aria-label='first page'>
        {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
      </IconButton>
      <IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label='previous page'>
        {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
      </IconButton>
      <IconButton
        onClick={handleNextButtonClick}
        disabled={page >= Math.ceil(count / rowsPerPage) - 1}
        aria-label='next page'
      >
        {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
      </IconButton>
      <IconButton
        onClick={handleLastPageButtonClick}
        disabled={page >= Math.ceil(count / rowsPerPage) - 1}
        aria-label='last page'
      >
        {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
      </IconButton>
    </div>
  );
}
Example #16
Source File: GroupSelect.tsx    From asynqmon with MIT License 5 votes vote down vote up
ListboxComponent = React.forwardRef<HTMLDivElement>(
  function ListboxComponent(props, ref) {
    const { children, ...other } = props;
    const itemData = React.Children.toArray(children);
    const theme = useTheme();
    const smUp = useMediaQuery(theme.breakpoints.up("sm"), { noSsr: true });
    const itemCount = itemData.length;
    const itemSize = smUp ? 36 : 48;

    const getChildSize = (child: React.ReactNode) => {
      if (React.isValidElement(child) && child.type === ListSubheader) {
        return 48;
      }
      return itemSize;
    };

    const getHeight = () => {
      if (itemCount > 8) {
        return 8 * itemSize;
      }
      return itemData.map(getChildSize).reduce((a, b) => a + b, 0);
    };

    const gridRef = useResetCache(itemCount);

    return (
      <div ref={ref}>
        <OuterElementContext.Provider value={other}>
          <VariableSizeList
            itemData={itemData}
            height={getHeight() + 2 * LISTBOX_PADDING}
            width="100%"
            ref={gridRef}
            outerElementType={OuterElementType}
            innerElementType="ul"
            itemSize={(index) => getChildSize(itemData[index])}
            overscanCount={5}
            itemCount={itemCount}
          >
            {renderRow}
          </VariableSizeList>
        </OuterElementContext.Provider>
      </div>
    );
  }
)
Example #17
Source File: ReviewListDesktop.tsx    From ra-enterprise-demo with MIT License 5 votes vote down vote up
ReviewListDesktop: FC<{ selectedRow: number | false }> = ({
    selectedRow,
    ...props
}) => {
    const classes = useListStyles();
    const theme = useTheme();
    const [, setLocation] = useAppLocationState();
    const resourceLocation = useResourceAppLocation();
    const { filterValues } = useListContext();

    const effectDependency = JSON.stringify({
        resourceLocation,
        filter: filterValues,
    });
    useEffect(() => {
        const { status } = filterValues;
        if (typeof status !== 'undefined') {
            setLocation('reviews.status_filter', { status });
        } else {
            setLocation('reviews');
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [setLocation, effectDependency]);
    return (
        <Datagrid
            rowClick="edit"
            rowStyle={rowStyle(selectedRow, theme)}
            classes={{
                headerRow: classes.headerRow,
                headerCell: classes.headerCell,
                rowCell: classes.rowCell,
            }}
            optimized
            {...props}
        >
            <DateField source="date" />
            <CustomerReferenceField link={false} />
            <ProductReferenceField link={false} />
            <StarRatingField size="small" />
            <TextField source="comment" cellClassName={classes.comment} />
            <TextField source="status" />
        </Datagrid>
    );
}
Example #18
Source File: index.tsx    From Demae with MIT License 4 votes vote down vote up
OrderDetail = () => {
	const theme = useTheme()
	const { orderID } = useParams<{ orderID?: string }>()
	const [user] = useUser()
	const ref = user?.orders.collectionReference.doc(orderID)
	const [order, isLoading] = useDocumentListen<Order>(Order, ref)
	const [menuPros, menuOpen] = useMenu()
	const [showDrawer, closeDrawer] = useDrawer()
	const [showSnackbar] = useSnackbar()
	const [setProcessing] = useProcessing()

	if (isLoading || !order) {
		return (
			<Paper>
				<DataLoading />
			</Paper>
		)
	}

	return (
		<>
			<Typography variant="h2" gutterBottom>Order</Typography>
			<Paper style={{
				marginBottom: theme.spacing(2)
			}}>
				<Box padding={2}>
					<Box paddingBottom={2} display="flex" justifyContent="space-between">
						<Box>
							<Typography variant="subtitle1">{order.title}</Typography>
							<Typography variant="body2" color="textSecondary">ORDER ID: {order.id}</Typography>
						</Box>
						<Box>
							<IconButton aria-label="settings" onClick={menuOpen}>
								<MoreVertIcon />
							</IconButton>
							<Menu {...menuPros}>
								{
									order.paymentStatus === "succeeded" ?
										<MenuItem onClick={() => {
											showDrawer(
												<ActionSheet title="Would you like to refund this order?" actions={
													[
														{
															title: "Refund request",
															handler: async () => {
																setProcessing(true)
																const response = await order.refundRequest()
																const { error, result } = response.data
																if (error) {
																	console.error(error)
																	showSnackbar('error', error.message)
																	setProcessing(false)
																	closeDrawer()
																	return
																}
																console.log(result)
																showSnackbar("success", "The order was canceled.")
																setProcessing(false)
																closeDrawer()
															}
														}
													]
												} />
											)
										}}>Refund</MenuItem> :
										<MenuItem onClick={() => {
											showDrawer(
												<ActionSheet title="Would you like to cancel this order?" actions={
													[
														{
															title: "Cancel request",
															handler: async () => {
																setProcessing(true)
																const response = await order.cancel()
																const { error, result } = response.data
																if (error) {
																	console.error(error)
																	showSnackbar('error', error.message)
																	setProcessing(false)
																	closeDrawer()
																	return
																}
																console.log(result)
																showSnackbar("success", "The order was canceled.")
																setProcessing(false)
																closeDrawer()
															}
														}
													]
												} />
											)
										}}>Cancel</MenuItem>
								}

							</Menu>
						</Box>
					</Box>

					<Divider />

					<Box paddingTop={2}>
						<Typography variant="subtitle1" gutterBottom>Items</Typography>
						<Paper>
							<List>
								{order.items.map(data => {
									const image = (data.imageURLs().length > 0) ? data.imageURLs()[0] : undefined
									return (
										<ListItem key={data.skuReference?.path} button component={Link} to={`/providers/${order.providedBy}/products/${data.productReference?.id}/skus/${data.skuReference?.id}`}>
											<ListItemAvatar >
												<Avatar variant="rounded" src={image} style={{
													height: theme.spacing(5),
													width: theme.spacing(5)
												}}>
													<ImageIcon />
												</Avatar>
											</ListItemAvatar>
											<ListItemText primary={
												<>
													<Typography variant="subtitle2">{data.name}</Typography>
													<Typography variant="body2" color="textSecondary">{data.caption}</Typography>
													<Typography variant="body2" color="textSecondary">{data.currency} {data.price.toLocaleString()}</Typography>
												</>
											} secondary={
												<Typography>Qty: {data.quantity.toString()}</Typography>
											} />
										</ListItem>
									)
								})}
							</List>
						</Paper>
						{order.salesMethod === "online" &&
							<Box paddingY={2}>
								<Typography variant="subtitle1" gutterBottom>Shipping Information</Typography>
								<Typography variant="body2" >{order.shipping?.format(["postal_code", "line1", "line2", "city", "state"])}</Typography>
							</Box>
						}
					</Box>

					<Divider />

					<Box paddingTop={2}>
						<Typography variant="subtitle1" gutterBottom>Summary</Typography>
						<Box display="flex" justifyContent="space-between">
							<Typography variant="body1" gutterBottom>Total</Typography>
							<Typography variant="body1" gutterBottom>{order.currency} {order.amount.toLocaleString()}</Typography>
						</Box>
					</Box>
				</Box>
			</Paper>
			<Typography variant="h2" gutterBottom>Shop</Typography>
			<Paper>
				<ProviderInfo order={order} />
			</Paper>
		</>
	)
}
Example #19
Source File: CodeEditor.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function CodeEditor(props: any) {
  const {
    handleChange,
    extraLibs,
    height = 400,
    script,
    onValideStatusUpdate,
    diagnosticsOptions,
  } = props;
  const theme = useTheme();
  const monacoInstance = useMonaco();

  const [initialEditorValue] = useState(script ?? "");
  const { tableState } = useFiretableContext();
  const classes = useStyles();

  const editorRef = useRef<any>();

  function handleEditorDidMount(_, editor) {
    editorRef.current = editor;
  }

  const themeTransformer = (theme: string) => {
    switch (theme) {
      case "dark":
        return "vs-dark";
      default:
        return theme;
    }
  };

  useMemo(async () => {
    if (!monacoInstance) {
      // useMonaco returns a monaco instance but initialisation is done asynchronously
      // dont execute the logic until the instance is initialised
      return;
    }

    const firestoreDefsFile = await fetch(
      `${process.env.PUBLIC_URL}/firestore.d.ts`
    );
    const firebaseAuthDefsFile = await fetch(
      `${process.env.PUBLIC_URL}/auth.d.ts`
    );
    const firebaseStorageDefsFile = await fetch(
      `${process.env.PUBLIC_URL}/storage.d.ts`
    );
    const firestoreDefs = await firestoreDefsFile.text();
    const firebaseStorageDefs = await firebaseStorageDefsFile.text();
    const firebaseAuthDefs = (await firebaseAuthDefsFile.text())
      ?.replace("export", "declare")
      ?.replace("admin.auth", "adminauth");

    try {
      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        firestoreDefs
      );
      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        firebaseAuthDefs
      );
      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        firebaseStorageDefs
      );
      monacoInstance.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
        diagnosticsOptions ?? {
          noSemanticValidation: true,
          noSyntaxValidation: false,
        }
      );
      // compiler options
      monacoInstance.languages.typescript.javascriptDefaults.setCompilerOptions(
        {
          target: monacoInstance.languages.typescript.ScriptTarget.ES2020,
          allowNonTsExtensions: true,
        }
      );
      if (extraLibs) {
        monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
          extraLibs.join("\n"),
          "ts:filename/extraLibs.d.ts"
        );
      }
      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        [
          "    /**",
          "     * utility functions",
          "     */",
          `
          declare namespace utilFns {
            /**
             * Sends out an email through sendGrid
             */
            function sendEmail(msg: {
              from: string;
              templateId: string;
              personalizations: { to: string; dynamic_template_data: any }[];
            }): void {}
          
            /**
             * Gets the secret defined in Google Cloud Secret
             */
            async function getSecret(name: string, v?: string): any {}
          
            /**
             * Async version of forEach
             */
            async function asyncForEach(array: any[], callback: Function): void {}
          
            /**
             * Generate random ID from numbers and English charactors inlcuding lowercase and uppercase
             */
            function generateId(): string {}
          
            /**
             * Add an item to an array field
             */
            function arrayUnion(val: string): void {}

            /**
             * Remove an item to an array field
             */
            function arrayRemove(val: string): void {}

            /**
             * Increment a number field
             */
            function increment(val: number): void {}

            function hasRequiredFields(requiredFields: string[], data: any): boolean {}
          
            function hasAnyRole(
              authorizedRoles: string[],
              context: functions.https.CallableContext
            ): boolean {}
          }
          
          `,
        ].join("\n"),
        "ts:filename/utils.d.ts"
      );

      const rowDefinition = [
        ...Object.keys(tableState?.columns!).map((columnKey: string) => {
          const column = tableState?.columns[columnKey];
          switch (column.type) {
            case FieldType.shortText:
            case FieldType.longText:
            case FieldType.email:
            case FieldType.phone:
            case FieldType.code:
              return `${columnKey}:string`;
            case FieldType.singleSelect:
              const typeString = [
                ...(column.config?.options?.map((opt) => `"${opt}"`) ?? []),
              ].join(" | ");
              return `${columnKey}:${typeString}`;
            case FieldType.multiSelect:
              return `${columnKey}:string[]`;
            case FieldType.checkbox:
              return `${columnKey}:boolean`;
            default:
              return `${columnKey}:any`;
          }
        }),
      ].join(";\n");

      const availableFields = Object.keys(tableState?.columns!)
        .map((columnKey: string) => `"${columnKey}"`)
        .join("|\n");

      const sparksDefinition = `declare namespace sparks {

        // basic types that are used in all places
        type Row = {${rowDefinition}};
        type Field = ${availableFields} | string | object;
        type Fields = Field[];
        type Trigger = "create" | "update" | "delete";
        type Triggers = Trigger[];
      
        // the argument that the spark body takes in
        type SparkContext = {
          row: Row;
          ref:FirebaseFirestore.DocumentReference;
          storage:firebasestorage.Storage;
          db:FirebaseFirestore.Firestore;
          auth:adminauth.BaseAuth;
          change: any;
          triggerType: Triggers;
          sparkConfig: any;
          utilFns: any;
        }
      
        // function types that defines spark body and shuold run
        type ShouldRun = boolean | ((data: SparkContext) => boolean | Promise<any>);
        type ContextToString = ((data: SparkContext) => string | Promise<any>);
        type ContextToStringList = ((data: SparkContext) => string[] | Promise<any>);
        type ContextToObject = ((data: SparkContext) => object | Promise<any>);
        type ContextToObjectList = ((data: SparkContext) => object[] | Promise<any>);
        type ContextToRow = ((data: SparkContext) => Row | Promise<any>);
        type ContextToAny = ((data: SparkContext) => any | Promise<any>);

        // different types of bodies that slack message can use
        type slackEmailBody = {
          channels?: ContextToStringList;
          text?: ContextToString;
          emails: ContextToStringList;
          blocks?: ContextToObjectList;
          attachments?: ContextToAny;
        }

        type slackChannelBody = {
          channels: ContextToStringList;
          text?: ContextToString;
          emails?: ContextToStringList;
          blocks?: ContextToObjectList;
          attachments?: ContextToAny;
        }
      
        // different types of sparks
        type docSync = {
          label?:string;
          type: "docSync";
          triggers: Triggers;
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            fieldsToSync: Fields;
            row: ContextToRow;
            targetPath: ContextToString;
          }
        };
      
        type historySnapshot = {
          label?:string;
          type: "historySnapshot";
          triggers: Triggers;
          shouldRun: ShouldRun;
          sparkBody: {
            trackedFields: Fields;
          }
        }
      
        type algoliaIndex = {
          label?:string; 
          type: "algoliaIndex"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            fieldsToSync: Fields;
            index: string;
            row: ContextToRow;
            objectID: ContextToString;
          }
        }
        
        type meiliIndex = { 
          type: "meiliIndex"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            fieldsToSync: Fields;
            index: string;
            row: ContextToRow;
            objectID: ContextToString;
          }
        }
        
        type bigqueryIndex = { 
          type: "bigqueryIndex"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            fieldsToSync: Fields;
            index: string;
            row: ContextToRow;
            objectID: ContextToString;
          }
        }

        type slackMessage = {
          label?:string; 
          type: "slackMessage"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: slackEmailBody | slackChannelBody;
        }
      
        type sendgridEmail = {
          label?:string;
          type: "sendgridEmail";
          triggers: Triggers;
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            msg: ContextToAny;
          }
        }
      
        type apiCall = {
          label?:string; 
          type: "apiCall"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            body: ContextToString;
            url: ContextToString;
            method: ContextToString;
            callback: ContextToAny;
          }
        }
      
        type twilioMessage = {
          label?:string;
          type: "twilioMessage";
          triggers: Triggers;
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            body: ContextToAny;
            from: ContextToAny;
            to: ContextToAny;
          }
        }

        type task = {
          label?:string; 
          type: "task"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            promises: ContextToAny;
          }
        }

        type mailchimp = {
          label?:string; 
          type: "mailchimp"; 
          triggers: Triggers; 
          shouldRun: ShouldRun;
          requiredFields?: Fields;
          sparkBody: {
            method: any;
            path: any;
            body: any;
          }
        }
      
        // an individual spark 
        type Spark =
          | docSync
          | historySnapshot
          | algoliaIndex
          | meiliIndex
          | bigqueryIndex
          | slackMessage
          | sendgridEmail
          | apiCall
          | twilioMessage
          | mailchimp
          | task;
      
        type Sparks = Spark[]
      
        // use spark.config(sparks) in the code editor for static type check
        function config(sparks: Sparks): void;
      }`;

      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        [
          "    /**",
          "     * sparks type configuration",
          "     */",
          sparksDefinition,
        ].join("\n"),
        "ts:filename/sparks.d.ts"
      );

      monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
        [
          "  declare var require: any;",
          "  declare var Buffer: any;",
          "  const ref:FirebaseFirestore.DocumentReference",
          "  const storage:firebasestorage.Storage",
          "  const db:FirebaseFirestore.Firestore;",
          "  const auth:adminauth.BaseAuth;",
          "declare class row {",
          "    /**",
          "     * Returns the row fields",
          "     */",
          ...Object.keys(tableState?.columns!).map((columnKey: string) => {
            const column = tableState?.columns[columnKey];
            switch (column.type) {
              case FieldType.shortText:
              case FieldType.longText:
              case FieldType.email:
              case FieldType.phone:
              case FieldType.code:
                return `static ${columnKey}:string`;
              case FieldType.singleSelect:
                const typeString = [
                  ...(column.config?.options?.map((opt) => `"${opt}"`) ?? []),
                  //     "string",
                ].join(" | ");
                return `static ${columnKey}:${typeString}`;
              case FieldType.multiSelect:
                return `static ${columnKey}:string[]`;
              case FieldType.checkbox:
                return `static ${columnKey}:boolean`;
              default:
                return `static ${columnKey}:any`;
            }
          }),
          "}",
        ].join("\n"),
        "ts:filename/rowFields.d.ts"
      );
    } catch (error) {
      console.error(
        "An error occurred during initialization of Monaco: ",
        error
      );
    }
  }, [tableState?.columns, monacoInstance]);

  function handleEditorValidation(markers) {
    if (onValideStatusUpdate) {
      onValideStatusUpdate({
        isValid: markers.length <= 0,
      });
    }
  }

  return (
    <>
      <div className={classes.editorWrapper}>
        <Editor
          theme={themeTransformer(theme.palette.type)}
          onMount={handleEditorDidMount}
          language="javascript"
          height={height}
          value={initialEditorValue}
          onChange={handleChange}
          onValidate={handleEditorValidation}
          className={classes.editor}
        />
      </div>
    </>
  );
}
Example #20
Source File: App.tsx    From GitNotes with MIT License 4 votes vote down vote up
export default function App() {
    const classes = useStyles()
    const theme = useTheme()
    const [mobileOpen, setMobileOpen] = React.useState(false)

    function handleDrawerToggle() {
        setMobileOpen(!mobileOpen)
    }

    function handleFileClick(file: File) {
        setMobileOpen(false)
        
        const query = getQuery()
        let preUrl = ''
        let aftUrl = ''
        if (query.git === 'gitlab') {
            preUrl = `https://${query.gitlab}/api/v4/projects/${query.id}/repository/files/`
            aftUrl = '/raw?ref=master'
        } else {
            preUrl = `https://raw.githubusercontent.com/${query.github}/master/`
            aftUrl = ''
        }
        const url = `${preUrl}${query.git === 'gitlab' ?
            encodeURI(getPath(file.parent) + file.name).replace(/\//g, '%2F') :
            encodeURI(getPath(file.parent) + file.name)
        }${aftUrl}`
        if (!isMarkdown(file.name)) {
            console.log(window.location.search)
            window.open(url, '_blank')
            return
        }
        setTitle(file.name)
        setContent('# 加载中...\n\n如果您访问的是 GitHub 上的笔记, 也许是因为国内访问 GitHub 速度不佳, 可以自行寻找方式解决.')
        const request = new XMLHttpRequest()
        request.open('GET', url)
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    setCurrentFile(file)
                    setContent(request.responseText)
                } else {
                    setContent('# 加载失败...\n\n如果您访问的是 GitHub 上的笔记, 也许是因为国内访问 GitHub 速度不佳, 可以自行寻找方式解决.')
                }
            }
        }
        request.send(null)
    }

    // Load README.md
    function handleLoad(files: File[]) {
        files.forEach((file) => {
            if (file.name === 'README.md') {
                handleFileClick(file)
            }
        })
    }

    const [currentFile, setCurrentFile] = useState(null as File | null)
    const [title, setTitle] = useState('GitNotes | OrangeX4\'s Notes')
    const [content, setContent] = useState('')

    const [freshCount, setFreshCount] = useState(0)
    const fresh = () => setFreshCount(freshCount + 1)


    const [githubRepo, setGithubRepo] = useState('OrangeX4/NJUAI-Notes')
    const [githubToken, setGithubToken] = useState('')
    const [gitlabHost, setGitlabHost] = useState('git.nju.edu.cn')
    const [gitlabId, setGitlabId] = useState('2047')


    const drawer = (
        <div>
            <div className={classes.toolbar} style={{ color: '#303030', display: 'flex', alignItems: 'center', paddingLeft: 16 }}>
                <MenuIcon style={{ marginRight: 30 }} />
                <Typography variant="h6" noWrap>
                    目录
                </Typography>
            </div>
            <Divider />
            {getQuery().git ? (
                <SubList folder={folder} fresh={fresh} onClick={handleFileClick} onLoad={handleLoad} />
            ) : (
                null
            )}
        </div>
    )

    return (
        <div className={classes.root}>
            <CssBaseline />
            <AppBar position="fixed" className={classes.appBar} color='default'>
                <Toolbar>
                    <IconButton
                        color="inherit"
                        aria-label="open drawer"
                        edge="start"
                        onClick={handleDrawerToggle}
                        className={classes.menuButton}
                    >
                        <MenuIcon />
                    </IconButton>
                    <Typography variant="h6" noWrap>
                        {title}
                    </Typography>
                </Toolbar>
            </AppBar>
            <nav className={classes.drawer} aria-label="mailbox folders">
                {/* The implementation can be swapped with js to avoid SEO duplication of links. */}
                <Hidden smUp implementation="css">
                    <Drawer
                        variant="temporary"
                        anchor={theme.direction === 'rtl' ? 'right' : 'left'}
                        open={mobileOpen}
                        onClose={handleDrawerToggle}
                        classes={{
                            paper: classes.drawerPaper,
                        }}
                        ModalProps={{
                            keepMounted: true, // Better open performance on mobile.
                        }}
                    >
                        {drawer}
                    </Drawer>
                </Hidden>
                <Hidden xsDown implementation="css">
                    <Drawer
                        classes={{
                            paper: classes.drawerPaper,
                        }}
                        variant="permanent"
                        open
                    >
                        {drawer}
                    </Drawer>
                </Hidden>
            </nav>
            {/* <main className={classes.content} style={{width: '100%'}}> */}
            <main className={classes.content}>
                <div className={classes.toolbar} />
                {getQuery().git ? (
                    <div dangerouslySetInnerHTML={{ __html: md.render(contentProcess(content, currentFile)) }} />
                ) : (
                    <div>
                        <h1>这是什么?</h1>
                        <p>这是一个由 <b>OrangeX4</b> 开发的<b>笔记浏览应用</b>, 用于浏览以 <b>Markdown</b> 书写的, 存放在 <b>GitLab 或 GitHub</b> 上的笔记.</p>
                        <p>优点: <b>数学公式支持和移动端适配.</b></p>
                        <a href="https://github.com/OrangeX4/GitNotes">GitHub 地址</a>

                        <h1>OrangeX4 的笔记</h1>
                        <h2><a href="./?git=gitlab">OrangeX4's Notes</a></h2>
                        <h1>推荐的其他笔记</h1>
                        <h2><a href="./?git=github&github=typoverflow/note">Typoverflow's Notes</a></h2>
                        <h2><a href="./?git=github&github=fengdu78/Coursera-ML-AndrewNg-Notes">Coursera-ML-AndrewNg-Notes</a></h2>
                        <h2><a href="./?git=github&github=fengdu78/Data-Science-Notes">Data-Science-Notes</a></h2>

                        <h1>GitHub Repo</h1>
                        <form className={classes.github} noValidate autoComplete="off">
                            <TextField id="standard-basic" value={githubRepo} onChange={(e) => setGithubRepo(e.target.value)} label="Repo" />
                            <TextField id="standard-basic" value={githubToken} onChange={(e) => setGithubToken(e.target.value)} label="Token" />
                            <Button variant="outlined"
                                color="primary"
                                onClick={() => { window.location.href = `${GetHostUrl()}?git=github&github=${githubRepo}${githubToken === '' ? '' : '&token=' + githubToken}` }}
                                style={{ height: 50, width: 100, fontSize: 16 }}>浏览</Button>
                        </form>
                        <p>GitHub 对于 API 访问有一定的限制, 超过次数便需要 Token 才能继续浏览.</p>
                        <p>详见 <a href="https://docs.github.com/cn/github/authenticating-to-github/creating-a-personal-access-token">创建 Token</a>.</p>

                        <h1>GitLab Repo</h1>
                        <form className={classes.github} noValidate autoComplete="off">
                            <TextField id="standard-basic" value={gitlabHost} onChange={(e) => setGitlabHost(e.target.value)} label="Host" />
                            <TextField id="standard-basic" value={gitlabId} onChange={(e) => setGitlabId(e.target.value)} label="Id" />
                            <Button variant="outlined"
                                color="primary"
                                onClick={() => { window.location.href = `${GetHostUrl()}?git=gitlab&gitlab=${gitlabHost}&id=${gitlabId}` }}
                                style={{ height: 50, width: 100, fontSize: 16 }}>浏览</Button>
                        </form>
                        <p>Host 是 GitLab 所在的域名, 如 "gitlab.com" 和 "git.nju.edu.cn".</p>
                        <p>Id 是你要浏览的 GitLab 项目的 Id, 可以在项目页面上找到.</p>
                    </div>
                )}
            </main>
        </div>
    )
}
Example #21
Source File: AccountDetails.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
AccountDetails: React.FC<AccountDetailsProps> = ({
  toggleWalletModal,
  pendingTransactions,
  confirmedTransactions,
  ENSName,
  openOptions,
}) => {
  const { chainId, account, connector } = useActiveWeb3React();
  const classes = useStyles();
  const { palette } = useTheme();
  const dispatch = useDispatch<AppDispatch>();

  function formatConnectorName() {
    const { ethereum } = window as any;
    const isMetaMask = !!(
      ethereum &&
      !ethereum.isBitKeep &&
      ethereum.isMetaMask
    );
    const isBitkeep = !!(ethereum && ethereum.isBitKeep);
    const isBlockWallet = !!(ethereum && ethereum.isBlockWallet);
    const name = Object.keys(SUPPORTED_WALLETS)
      .filter(
        (k) =>
          SUPPORTED_WALLETS[k].connector === connector &&
          (connector !== injected ||
            (isBlockWallet && k === 'BLOCKWALLET') ||
            (isBitkeep && k === 'BITKEEP') ||
            (isMetaMask && k === 'METAMASK')),
      )
      .map((k) => SUPPORTED_WALLETS[k].name)[0];
    return <Typography variant='body2'>Connected with {name}</Typography>;
  }

  const clearAllTransactionsCallback = useCallback(() => {
    if (chainId) dispatch(clearAllTransactions({ chainId }));
  }, [dispatch, chainId]);

  return (
    <Box paddingX={3} paddingY={4}>
      <Box display='flex' justifyContent='space-between'>
        <Typography variant='h5'>Account</Typography>
        <Close style={{ cursor: 'pointer' }} onClick={toggleWalletModal} />
      </Box>
      <Box
        mt={2}
        padding={2}
        borderRadius={10}
        bgcolor={palette.secondary.dark}
      >
        <Box display='flex' justifyContent='space-between' alignItems='center'>
          {formatConnectorName()}
          <Box display='flex' alignItems='center'>
            {connector !== injected &&
              connector !== walletlink &&
              connector !== safeApp && (
                <Typography
                  style={{ cursor: 'pointer', marginRight: 8 }}
                  onClick={() => {
                    (connector as any).close();
                  }}
                  variant='body2'
                >
                  Disconnect
                </Typography>
              )}
            {connector !== safeApp && (
              <Typography
                style={{ cursor: 'pointer' }}
                onClick={() => {
                  openOptions();
                }}
                variant='body2'
              >
                Change
              </Typography>
            )}
          </Box>
        </Box>
        <Box display='flex' alignItems='center' my={1.5}>
          <StatusIcon />
          <Typography
            variant='h5'
            style={{ marginLeft: 8 }}
            id='web3-account-identifier-row'
          >
            {ENSName ? ENSName : account && shortenAddress(account)}
          </Typography>
        </Box>
        <Box display='flex' justifyContent='space-between' alignItems='center'>
          {account && (
            <Copy toCopy={account}>
              <span style={{ marginLeft: '4px' }}>Copy Address</span>
            </Copy>
          )}
          {chainId && account && (
            <a
              className={classes.addressLink}
              href={
                chainId &&
                getEtherscanLink(
                  chainId,
                  ENSName ? ENSName : account,
                  'address',
                )
              }
              target='_blank'
              rel='noopener noreferrer'
            >
              <LinkIcon size={16} />
              <Typography variant='body2'>View on Block Explorer</Typography>
            </a>
          )}
        </Box>
      </Box>
      {!!pendingTransactions.length || !!confirmedTransactions.length ? (
        <>
          <Box
            display='flex'
            justifyContent='space-between'
            alignItems='center'
            paddingX={2}
            pt={2}
            mb={1}
          >
            <Typography variant='body2'>Recent Transactions</Typography>
            <Typography
              variant='body2'
              style={{ cursor: 'pointer' }}
              onClick={clearAllTransactionsCallback}
            >
              Clear all
            </Typography>
          </Box>
          <Box paddingX={2} flex={1} overflow='auto'>
            {renderTransactions(pendingTransactions)}
            {renderTransactions(confirmedTransactions)}
          </Box>
        </>
      ) : (
        <Box paddingX={2} pt={2}>
          <Typography variant='body2'>
            Your transactions will appear here...
          </Typography>
        </Box>
      )}
    </Box>
  );
}