@material-ui/core#ListItemAvatar TypeScript Examples
The following examples show how to use
@material-ui/core#ListItemAvatar.
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: ReviewListItem.tsx From ra-enterprise-demo with MIT License | 6 votes |
ReviewListItem: FC<any> = props => {
const { data, onClick } = props;
const classes = useStyles();
const { content } = data;
if (!content) {
return null;
}
return (
<ListItem
button
component={SearchListItemLink}
data={data}
onClick={onClick}
alignItems="flex-start"
>
<ListItemAvatar className={classes.avatar}>
<Avatar alt={content.reference}>
<CommentIcon fontSize="large" />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={<Rating value={content.rating} readOnly />}
secondary={<ReviewComment comment={content.comment} />}
// @ts-ignore Could not make TS happy
secondaryTypographyProps={secondaryTypographyProps}
/>
</ListItem>
);
}
Example #2
Source File: PlayersContainer.tsx From cards-against-formality-pwa with BSD 2-Clause "Simplified" License | 6 votes |
Player = ({ player, isHost, isCzar, onPlayerKick, isCurrentUserHost }: any) => {
function renderIcon() {
return <div style={!isCzar ? { opacity: 0 } : {}}>
<ListItemAvatar>
<Avatar>
<StyleIcon />
</Avatar>
</ListItemAvatar>
</div>
}
function renderKick() {
if (isHost || !isCurrentUserHost) {
return null;
}
return <ListItemSecondaryAction style={{ right: '-10px' }}>
<Button color="secondary" onClick={() => { onPlayerKick(player?._id) }}>Kick</Button>
</ListItemSecondaryAction>
}
return <ListItem>
{renderIcon()}
<ListItemText primary={player.username} secondary={`Score: ${!player?.score ? 0 : player.score}`} />
{renderKick()}
</ListItem>;
}
Example #3
Source File: ConnectWallet.tsx From homebase-app with MIT License | 6 votes |
ConnectWallet: React.FC = () => {
const { connect } = useTezos();
return (
<PageContainer container justify="flex-start" alignItems="center">
<Grid item>
<SpacingTitle align="left" variant="h3" color="textSecondary">
Connect your wallet
</SpacingTitle>
<SpacingTitle align="left" variant="subtitle1" color="textSecondary">
Create an organization by picking a template below
</SpacingTitle>
<Box>
<List>
<ListItem button={true} onClick={() => connect()}>
<ListItemAvatar>
<Avatar>
<ImageIcon />
</Avatar>
</ListItemAvatar>
<ListItemText>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Connect
</Typography>{" "}
</ListItemText>
</ListItem>
</List>
</Box>
</Grid>
</PageContainer>
);
}
Example #4
Source File: LiveStreamListItem.tsx From twitch-live-extension with BSD 3-Clause "New" or "Revised" License | 5 votes |
LiveStreamListItem = (elem: FollowedLivestream) => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
const handlePopoverOpen = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
setAnchorEl(event.currentTarget);
};
const [elapsedTime, setElapsedTime] = useState(getElapsedTime(elem.started_at));
useEffect(() => {
const timer = setInterval(() => {
setElapsedTime(getElapsedTime(elem.started_at));
}, 1000);
return () => clearInterval(timer);
}, [elem.started_at]);
const handlePopoverClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
return (
<>
<ListItem
className={classes.root}
button
component="a"
target="_blank"
rel="noopener noreferrer"
href={elem.url}
divider
dense
onMouseEnter={handlePopoverOpen}
onMouseLeave={handlePopoverClose}
>
<ListItemAvatar>
<Avatar src={elem.profile_image_url} />
</ListItemAvatar>
<ListItemText
className={classes.streamerDiv}
primary={elem.display_name}
secondary={
<Typography
className={classes.gameText}
noWrap
variant={'subtitle2'}
color={'textSecondary'}
>
{elem.game}
</Typography>
}
/>
<ListItemSecondaryAction>
<IconButton edge="end" disabled size={'small'}>
<Typography
noWrap
variant={'subtitle1'}
color={'textSecondary'}
className={classes.viewersText}
>
{formatViewers(elem.viewer_count)}
</Typography>
<ViewerIcon />
</IconButton>
<Typography
noWrap
variant={'subtitle2'}
color={'textSecondary'}
className={classes.elapsedTimeText}
>
{elapsedTime}
</Typography>
</ListItemSecondaryAction>
</ListItem>
<PopperTitle title={elem.title} anchorEl={anchorEl} open={open} />
</>
);
}
Example #5
Source File: AddServerDialog.tsx From shadowsocks-electron with GNU General Public License v3.0 | 5 votes |
AddServerDialog: React.FC<AddServerDialog> = props => {
const { onClose, open } = props;
const { t } = useTranslation();
return (
<AdaptiveDialog onClose={() => onClose('')} open={open}>
<DialogTitle attr='' onClose={onClose}>{t('add_server')}</DialogTitle>
<List>
<ListItemButton button onClick={() => onClose("manual")}>
<ListItemAvatar>
<CreateIcon />
</ListItemAvatar>
<ListItemText primary={t('add_server_manually')} />
</ListItemButton>
<ListItemButton button onClick={() => onClose("qrcode")}>
<ListItemAvatar>
<CameraIcon />
</ListItemAvatar>
<ListItemText primary={t('scan_qt_code_from_screen')} />
</ListItemButton>
<ListItemButton button onClick={() => onClose("url")}>
<ListItemAvatar>
<CopyIcon />
</ListItemAvatar>
<ListItemText primary={
<TextWithTooltip
text={t('import_server_url_from_clipboard')}
tooltip={t('import_server_url_from_clipboard_tips')}
/>
} />
</ListItemButton>
<ListItemButton button onClick={() => onClose("subscription")}>
<ListItemAvatar>
<CopyIcon />
</ListItemAvatar>
<ListItemText primary={
<TextWithTooltip
text={t('import_server_subscription_from_clipboard')}
tooltip={t('import_server_subscription_from_clipboard_tips')}
/>
}
/>
</ListItemButton>
</List>
</AdaptiveDialog>
);
}
Example #6
Source File: ProductListItem.tsx From ra-enterprise-demo with MIT License | 5 votes |
ProductListItem: FC<any> = props => {
const { data, onClick } = props;
const { content } = data;
const classes = useProductListItemStyles();
const translate = useTranslate();
if (!content) {
return null;
}
return (
<ListItem
button
component={SearchListItemLink}
data={data}
onClick={onClick}
alignItems="flex-start"
className={classes.root}
>
<ListItemAvatar className={classes.avatar}>
<div className={classes.art}>
<img src={content.thumbnail} alt={content.reference} />
</div>
</ListItemAvatar>
<ListItemText
primary={
<Typography color="textPrimary">
{content.reference}
</Typography>
}
secondary={
content.reviews > 0 ? (
<Box
component="ul"
display="flex"
justifyContent="space-between"
padding={0}
marginTop={1}
marginBottom={1}
>
<LinkedData
icon={<CommentIcon />}
label={translate('resources.reviews.name', {
smart_count: 2,
})}
to={`/reviews?filter=%7B"product_id"%3A${content.id}%7D`}
>
{content.reviews}
</LinkedData>
</Box>
) : undefined
}
// @ts-ignore Could not make TS happy
secondaryTypographyProps={secondaryTypographyProps}
/>
</ListItem>
);
}
Example #7
Source File: CommandListItem.tsx From ra-enterprise-demo with MIT License | 5 votes |
CommandListItem: FC<any> = props => {
const { data, onClick } = props;
const { content } = data;
const classes = useCommandListItemStyles();
const translate = useTranslate();
if (!content) {
return null;
}
return (
<ListItem
button
component={SearchListItemLink}
data={data}
onClick={onClick}
alignItems="flex-start"
>
<ListItemAvatar className={classes.avatar}>
<Avatar alt={content.reference}>
<ShoppingCartIcon fontSize="large" />
</Avatar>
</ListItemAvatar>
<Grid className={classes.root} container spacing={2}>
<Grid container item xs>
<Grid item xs={8}>
<Typography
variant="body1"
color="textPrimary"
gutterBottom
>
Ref. {content.reference}
</Typography>
</Grid>
<Grid item xs={4}>
<CommandStatus status={content.status} />
</Grid>
<Grid item xs={12}>
<Typography
variant="body2"
color="textPrimary"
gutterBottom
>
{new Date(content.date).toLocaleDateString()}
-
{`${content.customer.first_name} ${content.customer.last_name}`}
-
{`${translate(
'resources.commands.fields.basket.total'
)} ${content.total}`}
€
</Typography>
</Grid>
</Grid>
</Grid>
</ListItem>
);
}
Example #8
Source File: PendingReviews.tsx From ra-enterprise-demo with MIT License | 5 votes |
PendingReviews = ({
reviews = [],
customers = {},
}: {
reviews?: Review[];
customers?: { [key: string]: Customer };
}): React.ReactElement => {
const classes = useStyles();
const translate = useTranslate();
return (
<Card className={classes.root}>
<CardHeader title={translate('pos.dashboard.pending_reviews')} />
<List>
{reviews.map((record: Review) => (
<ListItem
key={record.id}
button
component={Link}
to={`/reviews/${record.id}`}
alignItems="flex-start"
>
<ListItemAvatar>
{customers[record.customer_id] ? (
<Avatar
src={`${
customers[record.customer_id].avatar
}?size=32x32`}
className={classes.avatar}
/>
) : (
<Avatar />
)}
</ListItemAvatar>
<ListItemText
primary={<StarRatingField record={record} />}
secondary={record.comment}
className={classes.listItemText}
style={{ paddingRight: 0 }}
/>
</ListItem>
))}
</List>
</Card>
);
}
Example #9
Source File: NewCustomers.tsx From ra-enterprise-demo with MIT License | 5 votes |
NewCustomers = (): ReactElement => {
const translate = useTranslate();
const classes = useStyles();
const aMonthAgo = useMemo(() => {
const date = new Date();
date.setDate(date.getDate() - 30);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
}, []);
const { loaded, data: visitors } = useQueryWithStore({
type: 'getList',
resource: 'customers',
payload: {
filter: {
has_ordered: true,
first_seen_gte: aMonthAgo.toISOString(),
},
sort: { field: 'first_seen', order: 'DESC' },
pagination: { page: 1, perPage: 100 },
},
});
if (!loaded) {
return <Loading />;
}
return (
<Card className={classes.root}>
<CardHeader title={translate('pos.dashboard.new_customers')} />
<List>
{visitors
? visitors.map((record: Customer) => (
<ListItem
button
to={`/customers/${record.id}`}
component={Link}
key={record.id}
>
<ListItemAvatar>
<Avatar src={`${record.avatar}?size=32x32`} />
</ListItemAvatar>
<ListItemText
primary={`${record.first_name} ${record.last_name}`}
/>
</ListItem>
))
: null}
</List>
</Card>
);
}
Example #10
Source File: UploadWarnings.tsx From aqualink-app with MIT License | 5 votes |
DetailsDialog = ({ open, details, onClose }: DetailsDialogProps) => {
const classes = useStyles();
return (
<Dialog maxWidth="md" fullWidth open={open} onClose={onClose}>
<DialogTitle disableTypography className={classes.dialogTitle}>
<Typography variant="h4">Upload Details</Typography>
<IconButton className={classes.closeButton} onClick={onClose}>
<CloseIcon />
</IconButton>
</DialogTitle>
<DialogContent>
<List>
{details.map(({ file, ignoredHeaders }, index) =>
ignoredHeaders?.length ? (
// eslint-disable-next-line react/no-array-index-key
<ListItem key={`${file}-${index}`}>
<ListItemAvatar>
<Avatar className={classes.avatar}>
<WarningIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={file}
primaryTypographyProps={{
color: "textSecondary",
variant: "h5",
}}
secondary={`
These columns are not configured for import yet and were
not uploaded: ${ignoredHeaders
.map((header) => `"${header}"`)
.join(", ")}.
`}
secondaryTypographyProps={{ variant: "subtitle1" }}
/>
</ListItem>
) : null
)}
</List>
</DialogContent>
</Dialog>
);
}
Example #11
Source File: index.tsx From Demae with MIT License | 5 votes |
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 #12
Source File: UserListItem.tsx From End-to-End-Web-Testing-with-Cypress with MIT License | 5 votes |
UserListItem: React.FC<UserListItemProps> = ({ user, setReceiver, index }) => {
return (
<ListItem data-test={`user-list-item-${user.id}`} onClick={() => setReceiver(user)}>
<ListItemAvatar>
<Avatar src={user.avatar} />
</ListItemAvatar>
<ListItemText
primary={`${user.firstName} ${user.lastName}`}
secondary={
<span>
<Grid
component={"span"}
container
direction="row"
justify="flex-start"
alignItems="flex-start"
spacing={1}
>
<Grid item component={"span"}>
<b>U: </b>
{user.username}
</Grid>
<Grid item component={"span"}>
•
</Grid>
<Grid item component={"span"}>
<b>E: </b>
{user.email}
</Grid>
<Grid item component={"span"}>
•
</Grid>
<Grid item component={"span"}>
<b>P: </b>
{user.phoneNumber}
</Grid>
</Grid>
</span>
}
/>
</ListItem>
);
}
Example #13
Source File: TransactionItem.tsx From End-to-End-Web-Testing-with-Cypress with MIT License | 5 votes |
TransactionItem: React.FC<TransactionProps> = ({ transaction }) => {
const classes = useStyles();
const history = useHistory();
const showTransactionDetail = (transactionId: string) => {
history.push(`/transaction/${transactionId}`);
};
return (
<ListItem
data-test={`transaction-item-${transaction.id}`}
alignItems="flex-start"
onClick={() => showTransactionDetail(transaction.id)}
>
<Paper className={classes.paper} elevation={0}>
<Grid container spacing={2}>
<Grid item>
<ListItemAvatar>
<Badge
overlap="circle"
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
badgeContent={<SmallAvatar src={transaction.receiverAvatar} />}
>
<Avatar src={transaction.senderAvatar} />
</Badge>
</ListItemAvatar>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<TransactionTitle transaction={transaction} />
<Typography variant="body2" color="textSecondary" gutterBottom>
{transaction.description}
</Typography>
<Grid
container
direction="row"
justify="flex-start"
alignItems="flex-start"
spacing={1}
className={classes.socialStats}
>
<Grid item>
<LikeIcon className={classes.countIcons} />
</Grid>
<Grid item>
<Typography data-test="transaction-like-count" className={classes.countText}>
{transaction.likes.length}
</Typography>
</Grid>
<Grid item>
<CommentIcon className={classes.countIcons} />
</Grid>
<Grid item>
<Typography data-test="transaction-comment-count" className={classes.countText}>
{transaction.comments.length}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item>
<TransactionAmount transaction={transaction} />
</Grid>
</Grid>
</Grid>
</Paper>
</ListItem>
);
}
Example #14
Source File: index.tsx From firetable with Apache License 2.0 | 5 votes |
Notification = () => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(
null
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
const notifications: Notification[] = [
{
title: "a",
subtitle: "a",
variant: "error",
link:
"https://console.cloud.google.com/cloud-build/builds;region=global/f7b8fd9b-eb6e-401f-a889-73c4bf75f232?project=antler-vc",
},
];
const notificationsCount = notifications.length;
return (
<>
<IconButton onClick={handleClick}>
<Badge
color={"primary"}
variant="standard"
badgeContent={notificationsCount}
>
<BellIcon />
</Badge>
</IconButton>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
}}
>
<List>
{notifications.map((notification) => (
<ListItem>
<ListItemAvatar>
<Avatar>
<ErrorIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={notification.title}
secondary={notification.subtitle}
/>
<ListItemSecondaryAction>
<IconButton edge="end" aria-label="delete">
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
))}
</List>
</Popover>
</>
);
}
Example #15
Source File: comment.tsx From jupyter-extensions with Apache License 2.0 | 4 votes |
render() {
const data = this.props.detachedComment
? this.props.detachedComment
: this.props.reviewComment;
return (
<>
<ListItem key="context">
<CommentContext
range={data.range}
filePath={data.filePath}
file={this.props.file}
/>
</ListItem>
<ListItem key="comment" alignItems="flex-start">
<ListItemAvatar>
<Avatar alt="avatar" />
</ListItemAvatar>
<ListItemText
primary={
<div>
<p style={style.username}> {data.author} </p>
<p style={style.date}> {data.timestamp} </p>
</div>
}
secondary={
<Typography
variant="body2"
style={style.inline}
color="textPrimary"
>
{data.text}
</Typography>
}
/>
</ListItem>
<div style={style.commentBottom}>
<Button
color="primary"
size="small"
onClick={() => {
this.setState({
showCommentEditor: !this.state.showCommentEditor,
});
}}
className="replyButton"
>
{' '}
Reply{' '}
</Button>
{this.state.showCommentEditor &&
(this.state.commentType === 'detached' ? (
<NewReplyComment
currFilePath={data.filePath}
hash={data.hash}
commentType={this.state.commentType}
/>
) : (
<NewReplyComment
currFilePath={data.filePath}
hash={data.hash}
commentType={this.state.commentType}
reviewHash={this.props.reviewComment.request.reviewHash}
/>
))}
{data.children && (
<Button
size="small"
endIcon={
this.state.expandThread ? (
<ArrowDropUpIcon />
) : (
<ArrowDropDownIcon />
)
}
onClick={() => {
this.setState({ expandThread: !this.state.expandThread });
}}
className="threadButton"
>
{' '}
{this.state.expandThread ? 'Hide thread' : 'Show thread'}{' '}
</Button>
)}
</div>
<div style={style.threadIndent} className="threadList">
{this.state.expandThread && data.children && (
<List>
{data.children.map((reply, index) => {
if (this.props.detachedComment) {
const detached = createDetachedCommentFromJSON(
reply,
reply.filePath
);
return (
<Comment
detachedComment={detached}
file={this.props.file}
key={index}
/>
);
} else {
const review = createReviewCommentFromJSON(
reply,
this.props.reviewComment.revision,
this.props.reviewComment.request,
data.filePath
);
return (
<Comment
reviewComment={review}
file={this.props.file}
key={index}
/>
);
}
})}
</List>
)}
</div>
</>
);
}
Example #16
Source File: KeyDisclosure.tsx From DamnVulnerableCryptoApp with MIT License | 4 votes |
KeyDisclosure = (props: IChallengeProps) => {
const classes = useStyles();
const [inboxUnlocked, setInboxUnlocked] = useState(false);
const [mailboxKey, setMailboxKey] = useState("");
const [emails, setEmails] = useState<IEmail[]>([]);
const [selectedEmail, setSelectedEmail] = useState<IEmail>({} as IEmail);
const layoutContext = useContext(LayoutContext);
useEffect(() => {
props.setWarning("This challenge is intended for you to go to the source code of the application and search for something. "
+ "So don't waste your time, go to the project's github page and start digging");
}, []);
useEffect(() => {
setEmailDetails();
}, [selectedEmail]);
const onChangeOpenEmail = (mail: IEmail) => {
return (e: React.MouseEvent) => {
setSelectedEmail(mail);
};
};
const emailEntry = (index: number, mail: IEmail) => {
const from = mail.from.split("<")[0];
const img = mail.from.startsWith("Fake Reporter") ? FakeReporterImg : DetectiveImg;
return (
<List key={index}>
<ListItem button onClick={onChangeOpenEmail(mail)}>
<ListItemAvatar>
<Avatar>
<img src={img} width="50" />
</Avatar>
</ListItemAvatar>
<ListItemText primary={from} secondary={mail.subject} />
</ListItem>
</List>
);
};
const setEmailDetails = () => {
if (!selectedEmail?.from) return;
const img = selectedEmail.from.startsWith("Fake Reporter") ? FakeReporterImg : DetectiveImg;
return (
<Box p={2}>
<Box display="flex">
<Avatar><img src={img} width="50" /></Avatar>
<Box ml={1}>
<Typography><strong>Subject:</strong> {selectedEmail.subject}</Typography>
<Typography><small><strong>Date: </strong>{selectedEmail.date}</small></Typography>
</Box>
</Box>
<Box className={classes.emailBody}>
<Typography>{selectedEmail.body} </Typography>
</Box>
</Box>
);
};
return (
<Box id="key-disclosure-container" style={{ position: 'relative' }}>
<KeyModal inboxUnlocked={inboxUnlocked} mailboxKey={mailboxKey} setSelectedEmail={setSelectedEmail}
setEmails={setEmails} setInboxUnlocked={setInboxUnlocked} setMailboxKey={setMailboxKey} setFlag={props.setFlag} />
<Box mt={2}>
<AppBar position="static" className={classes.tabs}>
<Tabs value={0}>
<Tab label="Inbox" icon={<DraftsIcon />} />
<Tab label="Stared" icon={<StarIcon />} />
<Tab label="Drafts" icon={<InsertDriveFileIcon />} />
</Tabs>
</AppBar>
<div role="tabpanel">
<Box>
<Grid container className={classes.mailbox} >
<Grid item sm={4} className={classes.emailList}>
{
emails.map((mail, i) => emailEntry(i, mail))
}
</Grid>
<Grid item sm={8} className={classes.emailDetails}>{setEmailDetails()}</Grid>
</Grid>
</Box>
</div>
</Box>
</Box >
);
}
Example #17
Source File: UserMenu.tsx From firetable with Apache License 2.0 | 4 votes |
export default function UserMenu(props: IconButtonProps) {
const classes = useStyles();
const anchorEl = useRef<HTMLButtonElement>(null);
const [open, setOpen] = useState(false);
const [themeSubMenu, setThemeSubMenu] = useState<EventTarget | null>(null);
const [latestUpdate] = useLatestUpdateState<null | Record<string, any>>();
const {
currentUser,
userDoc,
theme,
themeOverridden,
setTheme,
setThemeOverridden,
} = useAppContext();
if (!currentUser || !userDoc || !userDoc?.state?.doc)
return <div className={classes.spacer} />;
const displayName = userDoc?.state?.doc?.user?.displayName;
const avatarUrl = userDoc?.state?.doc?.user?.photoURL;
const email = userDoc?.state?.doc?.user?.email;
const avatar = avatarUrl ? (
<Avatar src={avatarUrl} className={classes.avatar} />
) : (
<AccountCircleIcon color="secondary" />
);
const changeTheme = (option: "system" | "light" | "dark") => {
switch (option) {
case "system":
setThemeOverridden(false);
return;
case "light":
setTheme("light");
break;
case "dark":
setTheme("dark");
break;
default:
break;
}
setThemeOverridden(true);
};
return (
<>
<IconButton
aria-label="Open user menu"
aria-controls="user-menu"
aria-haspopup="true"
edge="end"
{...props}
ref={anchorEl}
onClick={() => setOpen(true)}
className={classes.iconButton}
>
{latestUpdate?.tag_name > "v" + meta.version ? (
<Badge color="primary" overlap="circular" variant="dot">
{avatar}
</Badge>
) : (
avatar
)}
</IconButton>
<Menu
anchorEl={anchorEl.current}
id="user-menu"
keepMounted
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
getContentAnchorEl={null}
transformOrigin={{ vertical: "top", horizontal: "right" }}
open={open}
onClose={() => setOpen(false)}
classes={{ paper: classes.paper }}
>
<MenuItem
component="a"
href={`https://console.firebase.google.com/project/${projectId}/firestore/data/~2F_FT_USERS~2F${currentUser.uid}`}
target="_blank"
rel="noopener"
>
<ListItemAvatar>{avatar}</ListItemAvatar>
<ListItemText primary={displayName} secondary={email} />
</MenuItem>
<Divider className={classes.divider} />
<MenuItem onClick={(e) => setThemeSubMenu(e.target)}>
Theme
<ListItemSecondaryAction className={classes.secondaryAction}>
<ArrowRightIcon className={classes.secondaryIcon} />
</ListItemSecondaryAction>
</MenuItem>
{themeSubMenu && (
<Menu
anchorEl={themeSubMenu as any}
id="theme-sub-menu"
anchorOrigin={{ vertical: "top", horizontal: "left" }}
getContentAnchorEl={null}
transformOrigin={{ vertical: "top", horizontal: "right" }}
open
onClose={() => setThemeSubMenu(null)}
classes={{ paper: classes.subMenu }}
>
<MenuItem onClick={() => changeTheme("system")}>
<ListItemIcon>{!themeOverridden && <CheckIcon />}</ListItemIcon>
System
</MenuItem>
<MenuItem onClick={() => changeTheme("light")}>
<ListItemIcon>
{themeOverridden && theme === "light" && <CheckIcon />}
</ListItemIcon>
Light
</MenuItem>
<MenuItem onClick={() => changeTheme("dark")}>
<ListItemIcon>
{themeOverridden && theme === "dark" && <CheckIcon />}
</ListItemIcon>
Dark
</MenuItem>
</Menu>
)}
<MenuItem component={Link} to={routes.signOut}>
Sign out
</MenuItem>
<Divider className={classes.divider} />
<UpdateChecker />
</Menu>
</>
);
}
Example #18
Source File: CustomerListItem.tsx From ra-enterprise-demo with MIT License | 4 votes |
CustomerListItem: FC<any> = props => {
const { data, onClick } = props;
const { content } = data;
const classes = useStyles();
const translate = useTranslate();
if (!content) {
return null;
}
const fullname = `${content.first_name} ${content.last_name}`;
return (
<ListItem
button
component={SearchListItemLink}
data={data}
onClick={onClick}
alignItems="flex-start"
className={classes.root}
data-testid="customer"
>
<ListItemAvatar className={classes.avatar}>
<Avatar alt={fullname} src={content.avatar} />
</ListItemAvatar>
<ListItemText
primary={
<Typography color="textPrimary">{fullname}</Typography>
}
secondary={
<Box
component="ul"
display="flex"
justifyContent="flex-start"
padding={0}
marginTop={1}
marginBottom={1}
>
{content.pending_orders > 0 ? (
<LinkedData
icon={<ShoppingCartIcon />}
label={translate('resources.commands.name', {
smart_count: 2,
})}
to={`/commands?filter=%7B"status"%3A"ordered"%2C"customer_id"%3A${content.id}%7D`}
>
{content.pending_orders}
</LinkedData>
) : null}
{content.total_spent > 0 ? (
<LinkedData
icon={<DollarIcon />}
label={translate(
'resources.customers.fields.total_spent'
)}
to={`/commands?filter=%7B"status"%3A"delivered"%2C"customer_id"%3A${content.id}%7D`}
>
{content.total_spent.toLocaleString()}
</LinkedData>
) : null}
{content.reviews > 0 ? (
<LinkedData
icon={<CommentIcon />}
label={translate('resources.reviews.name', {
smart_count: 2,
})}
to={`/reviews?filter=%7B"customer_id"%3A${content.id}%7D`}
>
{content.reviews}
</LinkedData>
) : null}
</Box>
}
// @ts-ignore Could not make TS happy
secondaryTypographyProps={secondaryTypographyProps}
/>
</ListItem>
);
}
Example #19
Source File: SKUList.tsx From Demae with MIT License | 4 votes |
SKUListItem = ({ providerID, product, sku }: { providerID: string, product: Product, sku: SKU }) => {
const classes = useStyles()
const theme = useTheme()
const [user] = useUser()
const [cart] = useCart()
const [showDialog] = useDialog()
const [showModal, closeModal] = useModal()
const mediatorID = useMediator()
const imageURL = (sku.imagePaths().length > 0) ? sku.imagePaths()[0] : undefined
const imgProps = useImage({ path: imageURL, alt: `${sku.name ?? ""} ${sku.caption ?? ""}`, sizes: "96px" })
const amount = sku.price || 0
const price = new Intl.NumberFormat("ja-JP", { style: "currency", currency: sku.currency }).format(amount)
const withLogin = async (sku: SKU, onNext: (sku: SKU) => void) => {
if (user) {
onNext(sku)
} else {
showDialog("Please Login", undefined, [
{
title: "Cancel",
},
{
title: "OK",
variant: "contained",
color: "primary",
handler: () => {
showModal(<Login onNext={async (user) => {
onNext(sku)
closeModal()
}} />)
}
}
])
}
}
const addSKU = async (sku: SKU) => {
withLogin(sku, async (sku) => {
if (!product) return
if (user) {
const groupID = CartGroup.ID(product)
if (cart) {
const group = cart?.cartGroup(groupID) || CartGroup.fromSKU(product, sku)
group.groupID = groupID
group.addSKU(product, sku, mediatorID)
cart?.setCartGroup(group)
await cart.save()
} else {
const cart = new Cart(user.id)
const group = cart?.cartGroup(groupID) || CartGroup.fromSKU(product, sku)
group.groupID = groupID
group.addSKU(product, sku, mediatorID)
cart?.setCartGroup(group)
await cart.save()
}
}
})
}
const deleteSKU = async (sku: SKU) => {
if (!cart) return
const group = cart.cartGroup(providerID)
group?.deleteSKU(sku)
if ((group?.items.length || 0) <= 0) {
cart.groups = cart.groups.filter(group => group.groupID !== providerID)
}
await cart.save()
}
return (
<ListItem button component={Link} to={`/providers/${providerID}/products/${product.id}/skus/${sku.id}`}>
<ListItemAvatar>
<Avatar className={classes.avater} variant="rounded" {...imgProps}>
<ImageIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
<>
<Box mx={2} my={0} >
<Box fontSize={16} fontWeight={800}>
{sku.name}
</Box>
<Box>
{price}
</Box>
<Box color="text.secondary">
{sku.caption}
</Box>
</Box>
</>
}
secondary={
<>
{/* <Box fontWeight="fontWeightMedium" fontSize="subtitle1" mx={2} my={0} >
{`${ISO4217[product.currency]["symbol"]}${item.subtotal().toLocaleString()}`}
</Box> */}
</>
} />
<ListItemSecondaryAction>
<Tooltip title="Delete" onClick={(e) => {
e.stopPropagation()
deleteSKU(sku)
}}>
<IconButton>
<RemoveCircleIcon color="inherit" />
</IconButton>
</Tooltip>
<Tooltip title="Add" onClick={(e) => {
e.stopPropagation()
addSKU(sku)
}}>
<IconButton>
<AddCircleIcon color="inherit" />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
)
}
Example #20
Source File: global-search-field.tsx From mtcute with GNU Lesser General Public License v3.0 | 4 votes |
export function GlobalSearchField({ isMobile }: { isMobile: boolean }): React.ReactElement {
const classes = useStyles()
const allObjects: {
allTlObject: GraphqlAllResponse<ExtendedTlObject>
} = useStaticQuery(graphql`
query {
allTlObject {
edges {
node {
id
prefix
type
name
}
}
}
}
`)
const [includeMtproto, setIncludeMtproto] = useLocalState('mtproto', false)
const { hits, query, onSearch } = useFuse(
allObjects.allTlObject.edges,
{
keys: ['node.name'],
includeMatches: true,
threshold: 0.3,
},
{ limit: 25 },
includeMtproto ? undefined : (it) => it.node.prefix !== 'mtproto/'
)
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null)
const [open, setOpen] = useState(false)
const notFound = () => (
<>
<ErrorOutlineIcon className={classes.popupEmptyIcon} />
Nothing found
{!includeMtproto && (
<Button
variant="text"
size="small"
style={{
margin: '4px auto',
}}
onClick={() => {
setIncludeMtproto(true)
}}
>
Retry including MTProto objects
</Button>
)}
</>
)
const emptyField = () => (
<>
<SearchIcon className={classes.popupEmptyIcon} />
Start typing...
</>
)
const renderSearchItem = (
node: ExtendedTlObject,
matches: ReadonlyArray<Fuse.FuseResultMatch>
) => (
<ListItem
button
divider
component={Link}
to={`/${node.prefix}${node.type}/${node.name}`}
className={classes.popupListItem}
onClick={() => setOpen(false)}
key={node.id}
>
<ListItemAvatar>
<Avatar
style={{
backgroundColor:
node.type === 'class'
? blue[600]
: node.type === 'method'
? red[600]
: yellow[700],
}}
>
{node.type === 'class' ? (
<ClassIcon />
) : node.type === 'method' ? (
<FunctionsIcon />
) : (
<UnionIcon />
)}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
<>
{node.prefix}
<FuseHighlight
matches={matches}
value={node.name}
className={classes.searchItemMatch}
/>
</>
}
secondary={node.type}
/>
</ListItem>
)
const popupContent = (
<Paper className={classes.popup}>
{query.length <= 1 || !hits.length ? (
<div className={classes.popupEmpty}>
{query.length <= 1 ? emptyField() : notFound()}
</div>
) : (
<List disablePadding dense className={classes.popupList}>
{hits.map(({ item: { node }, matches }) =>
renderSearchItem(node, matches!)
)}
<div style={{ textAlign: 'center' }}>
<Button
variant="text"
size="small"
style={{
margin: '4px auto',
}}
onClick={() => {
setIncludeMtproto(!includeMtproto)
}}
>
{includeMtproto ? 'Hide' : 'Include'} MTProto
objects
</Button>
</div>
</List>
)}
</Paper>
)
return (
<ClickAwayListener onClickAway={() => setOpen(false)}>
<>
<ActionBarSearchField
inputRef={setAnchorEl}
autoComplete="off"
onFocus={() => setOpen(true)}
onBlur={() => setOpen(false)}
onChange={onSearch}
/>
<Popper
open={open}
anchorEl={anchorEl}
placement="bottom"
transition
style={{
width: isMobile ? '100%' : anchorEl?.clientWidth,
zIndex: 9999,
}}
>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
{popupContent}
</Fade>
)}
</Popper>
</>
</ClickAwayListener>
)
}
Example #21
Source File: index.tsx From Demae with MIT License | 4 votes |
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>
</>
)
}