@material-ui/core#ListItemAvatar JavaScript 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: SideBar.js From surveillance-forms with MIT License | 6 votes |
SideBarCard = ({ user, onLanguageSelect, lang, langCode }) => {
const classes = useStyles();
//TODO: this could be done better
const fields = {
label: lang.t("note.lable"),
notes: [
lang.t("note.note1"),
lang.t("note.note2"),
lang.t("note.note3"),
lang.t("note.note4"),
],
};
return (
<Card className={classes.card}>
<CardContent>
<Typography variant="h6" component="h2">
{fields.label}
</Typography>
<List>
{fields.notes.map((el, index) => {
return (
<ListItem key={index} disableGutters>
<ListItemAvatar style={{ flexShrink: 1 }}>
<Avatar style={{ background: '#fff', margin: 0 }}>
<CheckIcon style={{ fill: 'green', width: 20 }}/>
</Avatar>
</ListItemAvatar>
<ListItemText className="sidebarText">{el}</ListItemText>
</ListItem>
);
})}
</List>
</CardContent>
</Card>
);
}
Example #2
Source File: ChatList.jsx From react-03.03 with MIT License | 6 votes |
ChatList = ({ chats, createChat }) => {
const classes = useStyles();
const [name, setName, setNameState] = useInput('');
const handleAddChat = (event) => {
event.preventDefault();
createChat(name);
setNameState('');
}
return (
<List className={classes.root}>
{ chats.map(({id, name}) => {
return (
<Link key={id} to={`/chats/${id}`}>
<ListItem className={classes.listItem}>
<ListItemAvatar>
<Avatar />
</ListItemAvatar>
<ListItemText
primary={name}
/>
</ListItem>
</Link>
)
})
}
<ListItem className={classes.listItem}>
<form onSubmit={handleAddChat}>
<input type="text" placeholder="Chat name" value={name} onChange={setName} />
<button>Create chat</button>
</form>
</ListItem>
</List>
)
}
Example #3
Source File: ToolbarExtension.js From eSim-Cloud with GNU General Public License v3.0 | 6 votes |
export function ImageExportDialog (props) {
const classes = useStyles()
const { onClose, open } = props
const handleClose = () => {
onClose('')
}
const handleListItemClick = (value) => {
onClose(value)
}
return (
<Dialog onClose={handleClose} aria-labelledby="image-export-dialog-title" open={open}>
<DialogTitle id="image-export-dialog-title">Select Image type</DialogTitle>
<List>
{ImgTypes.map((img) => (
<ListItem button onClick={() => handleListItemClick(img)} key={img}>
<ListItemAvatar>
<Avatar className={classes.avatar}>
{img.charAt(0).toUpperCase()}
</Avatar>
</ListItemAvatar>
<ListItemText primary={img} />
</ListItem>
))}
</List>
<DialogActions>
<Button onClick={handleClose} color="primary" autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
)
}
Example #4
Source File: firstTimersOnlyIssue.js From GSOD.Contributors_website with Mozilla Public License 2.0 | 5 votes |
function GetIssues(props){
const classes = useStyles();
const {
repo: [repo, setRepo]} = {repo: useState('GCBM.Visualisation_Tool'),...(props.state || {})};
console.log({repo});
const { loading, error, data } = useQuery(GET_LABELLED_ISSUES, {
variables: { repo: repo},
});
//const { loading, error, data } = useQuery(GET_LABELLED_ISSUES, {variables: {state.name} ,});
console.log(data);
if (loading) return <p>Loading...</p>;
console.log(error);
if (error) return <p>Error :(</p>;
return data.repository.issues.edges.map(({ node }) => (
<div>
<ListItem alignItems="flex-start">
<ListItemAvatar>
<Avatar alt={node.author.login} src={node.author.avatarUrl} />
</ListItemAvatar>
<ListItemLink href={node.url}>
<ListItemText
primary={node.title}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
className={classes.inline}
color="textPrimary"
>
#{node.number}
</Typography>
" — " {node.createdAt}
</React.Fragment>
}
/>
</ListItemLink>
</ListItem>
<Divider variant="inset" component="li" />
</div>
));
}
Example #5
Source File: PublicComments.js From app with MIT License | 5 votes |
function CommentList({ requestId }) {
const classes = useStyles();
const firestore = useFirestore();
const querySnapshot = useFirestoreCollection(
firestore
.collection(`${REQUESTS_COMMENTS_PUBLIC_COLLECTION}`)
.where('requestId', '==', requestId)
.orderBy('createdAt', 'asc'),
);
if (querySnapshot.empty) {
return (
<Box color="text.disabled">
<Typography
variant="body2"
className={classes.noComments}
data-test="no-comments">
No public comments.
</Typography>
</Box>
);
}
return (
<List>
{querySnapshot.docs.map(
(docSnap) =>
// When new comment is added locally, the createdAt can be the serverTimestamp() value.
// So, we wait on rendering until any new snapshot has finished writing.
!docSnap.metadata.hasPendingWrites && (
<ListItem
key={docSnap.id}
divider
alignItems="flex-start"
data-test="public-comment">
<ListItemAvatar>
<Avatar>{docSnap.get('author.firstName').slice(0, 1)}</Avatar>
</ListItemAvatar>
<ListItemText
disableTypography
primary={
<Typography variant="subtitle2" data-test="comment-author">
{docSnap.get('author.firstName')} –{' '}
<Typography
variant="body2"
display="inline"
color="textSecondary">
{format(docSnap.get('createdAt').toDate(), 'p - PPPP')}
</Typography>
</Typography>
}
secondary={docSnap
.get('content')
.split('\n')
.map((content, key) => (
<Typography
variant="body1"
/* eslint-disable react/no-array-index-key */
key={key}
/* eslint-enable react/no-array-index-key */
gutterBottom
data-test="comment-content">
{content}
</Typography>
))}
/>
</ListItem>
),
)}
</List>
);
}
Example #6
Source File: Inbox.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 5 votes |
Inbox = ({ threads, selected, handleListItemClick }) => {
const { paper, searchInbox, list, listItem, listText, avatar } = useStyles();
const [search, setSearch] = useState('');
return (
<Paper className={paper}>
<List className={list}>
{threads
.filter((thread) => {
if (search === '') {
return thread;
} else if (
thread.userName.toLowerCase().includes(search.toLowerCase())
) {
return thread;
}
})
.map((thread, i) => (
<ListItem
key={`${thread.userName}-${i}`}
alignItems="flex-start"
className={listItem}
selected={thread.userName === selected}
onClick={() => handleListItemClick(thread.userName)}
>
<ListItemAvatar>
{thread.messages[0].type === 'message' ? (
<Avatar src={thread.avatar} className={avatar}></Avatar>
) : thread.messages[0].type === 'announce' ? (
<Announcement color="inherit" />
) : (
<Ballot color="inherit" />
)}
</ListItemAvatar>
{thread.messages[0].type === 'survey' ||
thread.messages[0].type === 'announce' ? (
<ListItemText
primary={thread.messages[0].subject}
secondary={
thread.messages[0].subject
? thread.messages[0].composed_at.slice(0, 10)
: thread.userName
}
className={listText}
/>
) : (
<ListItemText primary={thread.userName} className={listText} />
)}
<Typography>
{timeAgoFormatDate(
new Date(
thread.messages[thread.messages.length - 1].composed_at
)
)}
</Typography>
</ListItem>
))}
</List>
<SearchInbox className={searchInbox} setSearch={setSearch} />
</Paper>
);
}
Example #7
Source File: NotificationsPopover.js From course-manager with MIT License | 5 votes |
function NotificationItem({ notification }) {
const { avatar, title } = renderContent(notification);
return (
<ListItem
button
to="#"
disableGutters
component={RouterLink}
sx={{
py: 1.5,
px: 2.5,
mt: '1px',
...(notification.isUnRead && {
bgcolor: 'action.selected'
})
}}
>
<ListItemAvatar>
<Avatar sx={{ bgcolor: 'background.neutral' }}>{avatar}</Avatar>
</ListItemAvatar>
<ListItemText
primary={title}
secondary={
<Typography
variant="caption"
sx={{
mt: 0.5,
display: 'flex',
alignItems: 'center',
color: 'text.disabled'
}}
>
<Box component={Icon} icon={clockFill} sx={{ mr: 0.5, width: 16, height: 16 }} />
{formatDistanceToNow(new Date(notification.createdAt))}
</Typography>
}
/>
</ListItem>
);
}
Example #8
Source File: ParticipantsList.js From SyntaxMeets with MIT License | 5 votes |
function ParticipantsList(props) {
const classes = useStyles();
const { users } = props;
const [openList, setOpenList] = useState(false);
const renderParticipants = () => {
return Object.keys(users).map(elem => {
const name = users[elem];
return (
<>
<ListItem>
<ListItemAvatar>
<Avatar style={{ fontWeight: "bold" }}>
{nameGenerator(name.split(" "))}
</Avatar>
</ListItemAvatar>
<ListItemText
style={{
borderRadius: "10px",
padding: "10px",
color: "rgb(62 53 53)",
border: "solid rgb(62 53 53) 1px",
textAlign: "center",
fontWeight: "bolder",
wordWrap: "break-word",
overflowWrap: "break-word",
hyphens: "auto",
WebkitHyphens: "auto",
}}
primary={name}
/>
</ListItem>
</>
);
});
};
return (
<div>
<Button
onClick={() => setOpenList(true)}
variant="contained"
color="primary"
startIcon={<GroupIcon />}
style={{
fontFamily: "poppins",
marginLeft: "15px",
fontWeight: "600",
color: "white",
}}
>
Participants [ {Object.keys(users).length} ]
</Button>
<Drawer
anchor={"right"}
open={openList}
onClose={() => setOpenList(false)}
>
<CloseSharpIcon
style={{ padding: "5px", fontSize: "3em", cursor: "pointer" }}
onClick={() => setOpenList(false)}
/>
<div
className={classes.list}
style={{
display: "flex",
flexDirection: "column",
minHeight: "100%",
}}
role="presentation"
>
<List>{renderParticipants()}</List>
</div>
</Drawer>
</div>
);
}
Example #9
Source File: ChatMessage.js From SyntaxMeets with MIT License | 5 votes |
ChatMessage = (props) => {
return props.messages.map((data) => (
<ListItem
style={{
flexDirection: `${
localStorage.getItem("my_name") === data.name ? "row-reverse" : "row"
}`,
}}
>
<ListItemAvatar
style={{
padding: `${
localStorage.getItem("my_name") === data.name ? "0.6rem" : "unset"
}`,
}}
>
<Avatar>{nameGenerator(data.name.split(" "))}</Avatar>
</ListItemAvatar>
<ListItemText
style={{
paddingTop: "5px",
borderRadius: "15px",
paddingLeft: "20px",
paddingBottom: "10px",
backgroundColor: `${
localStorage.getItem("my_name") === data.name
? "#00b4d8"
: "#f0f0f0"
}`,
color: `${
localStorage.getItem("my_name") === data.name ? "#fff" : "#404040"
}`,
}}
primary={
<span
style={{
color: `${
localStorage.getItem("my_name") === data.name
? "#fff"
: "#404040"
}`,
}}
>
<em>{data.name}</em>
</span>
}
secondary={
<span
style={{
color: `${
localStorage.getItem("my_name") === data.name
? "#fff"
: "#404040"
}`,
wordWrap: "break-word",
overflowWrap: "break-word",
hyphens: "auto",
WebkitHyphens: "auto",
}}
>
{data.message}
</span>
}
/>
</ListItem>
));
}
Example #10
Source File: LatestProducts.js From EMP with MIT License | 5 votes |
LatestProducts = () => {
const classes = useStyles();
const [products] = useState(data);
return (
<Card>
<CardHeader
subtitle={`${products.length} in total`}
title="Latest Products"
/>
<Divider />
<List>
{products.map((product, i) => (
<ListItem
divider={i < products.length - 1}
key={product.id}
>
<ListItemAvatar>
<img
alt="Product"
className={classes.image}
src={product.imageUrl}
/>
</ListItemAvatar>
<ListItemText
primary={product.name}
secondary={`Updated ${product.updatedAt.fromNow()}`}
/>
<IconButton
edge="end"
size="small"
>
<MoreVertIcon />
</IconButton>
</ListItem>
))}
</List>
<Divider />
<Box
display="flex"
justifyContent="flex-end"
p={2}
>
<Button
color="primary"
endIcon={<ArrowRightIcon />}
size="small"
variant="text"
>
View all
</Button>
</Box>
</Card>
);
}
Example #11
Source File: DashboardSidebar.js From eSim-Cloud with GNU General Public License v3.0 | 5 votes |
// Vertical Navbar for user dashboard
export default function DashSidebar (props) {
const classes = useStyles()
const auth = useSelector(state => state.authReducer)
const dispatch = useDispatch()
// For Fetching Saved Schematics
useEffect(() => {
dispatch(fetchSchematics())
dispatch(fetchOtherProjects())
dispatch(fetchRole())
}, [dispatch])
return (
<>
<Hidden smDown>
<div className={classes.toolbar} />
</Hidden>
<List>
<ListItem
alignItems="flex-start"
component={RouterLink}
to="/dashboard"
style={{ marginTop: '15px' }}
className={classes.sideItem}
button
divider
>
<ListItemAvatar>
<Avatar className={classes.purple}>
{auth.user.username.charAt(0).toUpperCase()}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={auth.user.username}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
color="textSecondary"
>
{auth.roles !== null && auth.roles.group.map((value, key) => (<h3 key={value}>{value}</h3>))}
</Typography>
</React.Fragment>
}
/>
</ListItem>
<ListItem
component={RouterLink}
to="/dashboard/profile"
className={classes.sideItem}
button
divider
>
<ListItemText primary='My Profile' />
</ListItem>
<ListItem
component={RouterLink}
to="/dashboard/schematics"
className={classes.sideItem}
button
>
<ListItemText primary='My Schematics' />
</ListItem>
<Divider />
{auth.roles && auth.roles.e_sim_reviewer &&
<ListItem
component={RouterLink}
to="/dashboard/review_projects"
className={classes.sideItem}
button
>
<ListItemText primary='Review Projects' />
</ListItem>}
</List>
</>
)
}
Example #12
Source File: Notification.jsx From zubhub with GNU Affero General Public License v3.0 | 5 votes |
Notification = ({ notification, onNotificationClick }) => {
const classes = useStyles();
const token = useSelector(store => store.auth.token);
const { t } = useTranslation();
const st = dFormatter(JSON.parse('"' + notification.date + '"'));
return (
<Link to={notification.link} className={classes.notificationLink}>
<ListItem
alignItems="center"
disableGutters
button
className={classes.notificationStyle}
onClick={() => {
if (!notification.viewed) {
let obj = new API();
obj.viewNotification({
id: notification.id,
token: token,
body: notification,
});
}
onNotificationClick();
}}
>
<ListItemAvatar>
{notification.sources.length === 1 && (
<AvatarGroup className={classes.group}>
<Avatar
className={classes.image}
src={notification.sources[0].avatar}
/>
</AvatarGroup>
)}
{notification.sources.length > 1 && (
<AvatarGroup className={classes.group}>
<Avatar
className={classes.firstImage}
src={notification.sources[0].avatar}
/>
<Avatar
className={classes.secondImage}
src={notification.sources[1].avatar}
/>
</AvatarGroup>
)}
</ListItemAvatar>
<ListItemText
className={classes.text}
classes={{ primary: classes.message, secondary: classes.time }}
primary={
<span
dangerouslySetInnerHTML={{
__html: notification.message,
}}
></span>
}
secondary={st.value + ' ' + st.key + ' ' + 'ago'}
/>
{!notification.viewed && <div className={classes.viewDot}></div>}
{notification.viewed && <div className={classes.unviewed}></div>}
</ListItem>
</Link>
);
}
Example #13
Source File: Comment.js From yasn with MIT License | 5 votes |
export default function Comment(props) {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid item xs={12}>
<div className={classes.demo}>
<List>
{/* {generate( */}
<ListItem>
<ListItemAvatar>
{props.username ? (
<Link to={`/user/${props.username}`}>
<Avatar className={classes.avatar}>
{props.name
? props.name[0]
: // + props.name.split(" ")[1][0]
"X"}
</Avatar>
</Link>
) : (
<Avatar className={classes.avatar}>
{props.name
? props.name[0]
: // + props.name.split(" ")[1][0]
"X"}
</Avatar>
)}
</ListItemAvatar>
<ListItemText
primary={props.comment}
secondary={
<Moment format="MMM D" withTitle>
{props.date}
</Moment>
}
/>
<ListItemSecondaryAction>
{/* <IconButton edge="end" aria-label="delete">
<DeleteIcon fontSize="small" />
</IconButton> */}
</ListItemSecondaryAction>
</ListItem>
</List>
</div>
</Grid>
</div>
);
}
Example #14
Source File: user-details.js From js-miniapp with MIT License | 4 votes |
function UserDetails(props: UserDetailsProps) {
const [state, dispatch] = useReducer(dataFetchReducer, initialState);
const classes = useStyles();
const buttonClassname = clsx({
[classes.buttonFailure]: state.isError,
[classes.buttonSuccess]: !state.isError,
});
function requestUserDetails() {
const permissionsList = [
{
name: CustomPermissionName.USER_NAME,
description:
'We would like to display your Username on your profile page.',
},
{
name: CustomPermissionName.PROFILE_PHOTO,
description:
'We would like to display your Profile Photo on your profile page.',
},
{
name: CustomPermissionName.CONTACT_LIST,
description: 'We would like to send messages to your contacts.',
},
];
props
.requestPermissions(permissionsList)
.then((permissions) => filterAllowedPermissions(permissions))
.then((permissions) =>
Promise.all([
hasPermission(CustomPermissionName.USER_NAME, permissions)
? props.getUserName()
: null,
hasPermission(CustomPermissionName.PROFILE_PHOTO, permissions)
? props.getProfilePhoto()
: null,
hasPermission(CustomPermissionName.CONTACT_LIST, permissions)
? props.getContacts()
: null,
])
)
.then(() => dispatch({ type: 'FETCH_SUCCESS' }))
.catch((e) => {
console.error(e);
dispatch({ type: 'FETCH_FAILURE' });
});
}
function requestPoints() {
const permissionsList = [
{
name: CustomPermissionName.POINTS,
description:
'We would like to display your Points on your profile page.',
},
];
props
.requestPermissions(permissionsList)
.then((permissions) => filterAllowedPermissions(permissions))
.then((permissions) =>
Promise.all([
hasPermission(CustomPermissionName.POINTS, permissions)
? props.getPoints()
: null,
])
)
.then(() => dispatch({ type: 'POINTS_FETCH_SUCCESS' }))
.catch((e) => {
console.error(e);
dispatch({ type: 'POINTS_FETCH_FAILURE' });
});
}
function filterAllowedPermissions(permissions) {
return permissions
.filter(
(permission) => permission.status === CustomPermissionStatus.ALLOWED
)
.map((permission) => permission.name);
}
function handleClick(e) {
if (!state.isLoading) {
e.preventDefault();
dispatch({ type: 'FETCH_INIT' });
requestUserDetails();
}
}
function handlePointsClick(e) {
if (!state.isLoading) {
e.preventDefault();
dispatch({ type: 'POINTS_FETCH_INIT' });
requestPoints();
}
}
function ProfilePhoto() {
const hasDeniedPermission =
state.hasRequestedPermissions &&
!hasPermission(CustomPermissionName.PROFILE_PHOTO);
return [
hasDeniedPermission ? (
<ListItemText
primary='"Profile Photo" permission not granted.'
className={classes.red}
key="avatar-error"
/>
) : null,
<Avatar
src={props.profilePhoto}
className={classes.profilePhoto}
key="avatar"
/>,
];
}
function UserDetails() {
const hasDeniedPermission =
state.hasRequestedPermissions &&
!hasPermission(CustomPermissionName.USER_NAME);
return (
<Paper className={classes.paper}>
<CardHeader subheader="User Details" />
<TextField
variant="outlined"
disabled={true}
className={classes.formInput}
id="input-name"
error={state.isError || hasDeniedPermission}
label={'Name'}
value={
hasDeniedPermission
? '"User Name" permission not granted.'
: props.userName || ' '
}
/>
</Paper>
);
}
function ContactList() {
const hasDeniedPermision =
state.hasRequestedPermissions &&
!hasPermission(CustomPermissionName.CONTACT_LIST);
return (
<Paper className={classes.paper}>
<CardHeader subheader="Contact List" />
<List className={classes.contactsList}>
{hasDeniedPermision && (
<ListItem>
<ListItemText
primary='"Contacts" permission not granted.'
className={classes.red}
/>
</ListItem>
)}
{!hasDeniedPermision &&
props.contactList &&
props.contactList.map((contact) => (
<ListItem divider>
<ListItemAvatar>
<Avatar className={classes.contactIcon} />
</ListItemAvatar>
<ListItemText
primary={contact.id}
secondary={
<React.Fragment>
<Typography>
{contact.name && contact.name !== '' && (
<span>{'Name: ' + contact.name}</span>
)}
</Typography>
<Typography>
{contact.email && contact.email !== '' && (
<span>{'Email: ' + contact.email}</span>
)}
</Typography>
</React.Fragment>
}
/>
</ListItem>
))}
</List>
</Paper>
);
}
function PointBalance() {
const hasDeniedPermission =
state.hasRequestedPointPermissions &&
!hasPermission(CustomPermissionName.POINTS);
return (
<Paper className={classes.paper}>
<CardHeader subheader="Points" />
<TextField
variant="outlined"
disabled={true}
className={classes.formInput}
id="input-points-standard"
error={state.isPointsError || hasDeniedPermission}
label={'Points (Standard)'}
value={
hasDeniedPermission
? '"Points" permission not granted.'
: props.points !== undefined &&
props.points.standard !== undefined
? props.points.standard.toString()
: '-'
}
/>
<TextField
variant="outlined"
disabled={true}
className={classes.formInput}
id="input-points-term"
error={state.isPointsError || hasDeniedPermission}
label={'Points (Time-Limited)'}
value={
hasDeniedPermission
? '"Points" permission not granted.'
: props.points !== undefined && props.points.term !== undefined
? props.points.term.toString()
: '-'
}
/>
<TextField
variant="outlined"
disabled={true}
className={classes.formInput}
id="input-points-cash"
error={state.isPointsError || hasDeniedPermission}
label={'Points (Rakuten Cash)'}
value={
hasDeniedPermission
? '"Points" permission not granted.'
: props.points !== undefined && props.points.cash !== undefined
? props.points.cash.toString()
: '-'
}
/>
</Paper>
);
}
function CardActionsForm() {
return (
<FormGroup column="true" className={classes.rootUserGroup}>
<div className={classes.wrapper}>
<Button
onClick={handleClick}
variant="contained"
color="primary"
classes={{ root: classes.button }}
className={buttonClassname}
disabled={state.isLoading}
data-testid="fetchUserButton"
>
Fetch User Details
</Button>
{state.isLoading && (
<CircularProgress size={20} className={classes.buttonProgress} />
)}
</div>
{state.isError && (
<Typography variant="body1" className={classes.error}>
Error fetching the User Details
</Typography>
)}
</FormGroup>
);
}
function CardPointActionsForm() {
return (
<FormGroup column="true" className={classes.rootUserGroup}>
<div className={classes.wrapper}>
<Button
onClick={handlePointsClick}
variant="contained"
color="primary"
classes={{ root: classes.button }}
className={buttonClassname}
disabled={state.isPointsLoading}
data-testid="fetchPointsButton"
>
Fetch Points
</Button>
{state.isPointsLoading && (
<CircularProgress size={20} className={classes.buttonProgress} />
)}
</div>
{state.isPointsError && (
<Typography variant="body1" className={classes.error}>
Error fetching the points
</Typography>
)}
</FormGroup>
);
}
function hasPermission(permission, permissionList: ?(string[])) {
permissionList = permissionList || props.permissions || [];
return permissionList.indexOf(permission) > -1;
}
return (
<div className={classes.scrollable}>
<GreyCard className={classes.card}>
<CardContent>
<div
className={classes.dataFormsWrapper}
data-testid="dataFormsWrapper"
>
{ProfilePhoto()}
{UserDetails()}
{ContactList()}
</div>
</CardContent>
<CardActions classes={{ root: classes.rootCardActions }}>
{CardActionsForm()}
</CardActions>
<CardContent>
<div
className={classes.dataFormsWrapper}
data-testid="pointDataFormsWrapper"
>
{PointBalance()}
</div>
</CardContent>
<CardActions classes={{ root: classes.rootCardActions }}>
{CardPointActionsForm()}
</CardActions>
</GreyCard>
</div>
);
}
Example #15
Source File: WebChatListItem.js From WhatsApp-Clone with MIT License | 4 votes |
WebChatListItem = ({ item, position, onItemClick }) => {
const [userType, setUserType] = useState("");
const classes = useStyles();
let data = item.chat[0];
useEffect(() => {
setUserName();
}, []);
function setUserName() {
let userType = getUserType(item);
setUserType(userType);
}
return (
<div style={{cursor:'pointer'}} onClick={() => onItemClick(item)}>
{position > 0 && (
<div
light={true}
className={classes.parentDiv}
/>
)}
<ListItem
alignItems="flex-start"
style={{
display: "flex",
flexDirection: "row",
flex: 1,
marginTop: "-1%"
}}
>
<ListItemAvatar style={{ flex: 0.15, marginLeft: "-1%" }}>
{/* <chatImage /> */}
<Avatar alt="User" src={chatImage} className={classes.profileImage} />
</ListItemAvatar>
<div
style={{
display: "flex",
flexDirection: "column",
flex: 0.7
}}
>
<ListItemText
primary={
<Typography className={classes.userName}>
{userType == webConstants.FRIEND
? data.userName
: data.chatName}
</Typography>
}
/>
<ListItemText
secondary={
<Typography className={classes.userMessage}>
{data.chatMessage}
</Typography>
}
/>
</div>
<ListItemText
style={{
display: "flex",
flex: 0.15,
justifyContent: "flex-end",
alignItems: "flex-end",
flexDirection: "column"
}}
primary={
<Typography className={classes.userTime}>
{getTimeInFormat(data.chatTime)}
</Typography>
}
secondary={
<Avatar className={item.chatUnreadCount != 0 ? classes.avatarStyle : classes.emptyAvatarStyle}>
<Typography className={classes.textMsgCount}>
{item.chatUnreadCount}
</Typography>
</Avatar>
}
/>
</ListItem>
{/* <Card transparent style={{ elevation: 0, marginRight: -5 }}>
<CardItem>
<View style={{ marginLeft: -5 }}>
<Thumbnail
source={
data.chatImage === ""
? PROFILE
: { isStatic: true, uri: data.chatImage }
}
/>
</View>
<Body
style={{
flexDirection: "column",
marginLeft: 15
}}
>
<Text
numberOfLines={1}
style={[DEFAULT_STYLES.poppinsSemiBold, styles.userName]}
>
{userType == webConstants.FRIEND ? data.userName : data.chatName}
</Text>
<Text
numberOfLines={2}
style={[DEFAULT_STYLES.poppinsLight, styles.userMessage]}
>
{data.chatMessage}
</Text>
</Body>
<View>
<Text style={[DEFAULT_STYLES.poppinsSemiBold, styles.userTime]}>
{getTimeInFormat(item.chatTime)}
</Text>
{data.chatUnreadCount === "" && (
<View style={styles.textMsgCountView}>
<Text
style={[DEFAULT_STYLES.poppinsSemiBold, styles.textMsgCount]}
>
{data.chatUnreadCount}
</Text>
</View>
)}
{data.chatUnreadCount != "" && (
<Icon
style={styles.msgIcon}
name={data.chatUnreadCount}
type={data.chatUnreadCount}
/>
)}
</View>
</CardItem>
</Card> */}
</div>
);
}
Example #16
Source File: OftadehAvatarMenu.jsx From oftadeh-react-admin with MIT License | 4 votes |
OftadehAvatarMenu = props => {
const classes = useStyles(props);
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen(prevOpen => !prevOpen);
};
const handleClose = event => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
return (
<>
<ListItem
button
ref={anchorRef}
aria-controls={open ? "menu-list-grow" : undefined}
aria-haspopup="true"
onClick={handleToggle}
alignItems="flex-start"
className={classes.paddingRightZero}
>
<ListItemAvatar>
<OftadehAvatarBadge
overlap="circle"
anchorOrigin={{
vertical: "bottom",
horizontal: "right"
}}
variant="dot"
>
<Avatar
alt="Mohammad Oftadeh"
src="https://lh5.googleusercontent.com/-WqhFe4eMggE/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdFUa5CK9Wi6g5qd8ZUt6apKFYSwA/photo.jpg?sz=328"
/>
</OftadehAvatarBadge>
</ListItemAvatar>
<Hidden implementation="css" smDown>
<ListItemText
primary={
<React.Fragment>
<Typography component="span" variant="subtitle2">
Mohammad Oftadeh
</Typography>
</React.Fragment>
}
secondary={
<React.Fragment>
<Typography
component="span"
variant="caption"
className={classes.inline}
color="textPrimary"
>
Admin
</Typography>
</React.Fragment>
}
/>
</Hidden>
</ListItem>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow">
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<AccountCircle fontSize="small" />
</ListItemIcon>
Profile
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<Settings fontSize="small" />
</ListItemIcon>
settings
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<ExitToApp fontSize="small" />
</ListItemIcon>
Logout
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</>
);
}
Example #17
Source File: TransactionMessage.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
getMessage = (message, classes) => {
switch (message.typeUrl) {
case TransactionMessageData.Types.MSG_CLOSE_DEPLOYMENT:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<PowerOffIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Close Deployment"
secondary={`Close deployment with dseq: ${message.value.id.dseq}`}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_CREATE_CERTIFICATE:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<VerifiedUserIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Create Certificate" classes={{ primary: classes.listItemPrimaryText }} />
</>
);
case TransactionMessageData.Types.MSG_CREATE_DEPLOYMENT:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<PublishIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Create Deployment"
secondary={
<>
New deployment with dseq <strong>{message.value.id.dseq}</strong> and a deposit of <strong>{uaktToAKT(message.value.deposit.amount)}AKT</strong>
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_UPDATE_DEPLOYMENT:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<PublishIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Update Deployment"
secondary={
<>
Update deployment with dseq <strong>{message.value.id.dseq}</strong>
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_DEPOSIT_DEPLOYMENT:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<AddBoxIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Deposit Deployment"
secondary={
<>
Add funds of <strong>{uaktToAKT(message.value.amount.amount)}AKT</strong> to deployment with dseq <strong>{message.value.id.dseq}</strong>
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_CREATE_LEASE:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<ReceiptIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Create Lease"
secondary={
<>
New Lease with provider <strong>{message.value.bid_id.provider}</strong>, dseq: <strong>{message.value.bid_id.dseq}</strong>, gseq:{" "}
<strong>{message.value.bid_id.gseq}</strong>, oseq: <strong>{message.value.bid_id.oseq}</strong>.
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_REVOKE_CERTIFICATE:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<CancelIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Revoke Certificate" secondary={`Serial: ${message.value.id.serial}`} classes={{ primary: classes.listItemPrimaryText }} />
</>
);
case TransactionMessageData.Types.MSG_SEND_TOKENS:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<SendIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Send"
secondary={
<>
<strong>{message.value.toAddress}</strong> will receive <strong>{uaktToAKT(message.value.amount[0].amount, 6)}AKT</strong>
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
case TransactionMessageData.Types.MSG_GRANT:
return (
<>
<ListItemAvatar>
<Avatar classes={{ root: classes.avatarRoot }}>
<AccountBalanceIcon classes={{ root: classes.avatarIcon }} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Authorize Spend"
secondary={
<>
<strong>{message.value.grantee}</strong> will be able to spend up to{" "}
<strong>{uaktToAKT(message.value.grant.authorization.value.spend_limit.amount, 6)}AKT</strong> on your behalf. Expires:{" "}
<FormattedDate value={new Date(message.value.grant.expiration.seconds * 1_000)} />
<FormattedTime value={new Date(message.value.grant.expiration.seconds * 1_000)} />.
</>
}
classes={{ primary: classes.listItemPrimaryText }}
/>
</>
);
default:
return null;
}
}
Example #18
Source File: Settings.js From hk-independent-bus-eta with GNU General Public License v3.0 | 4 votes |
Settings = () => {
const {
schemaVersion, versionMd5, updateTime, geoPermission,
setGeoPermission, renewDb, resetUsageRecord
} = useContext ( AppContext )
const [ updating, setUpdating ] = useState(false)
const [ showGeoPermissionDenied, setShowGeoPermissionDenied ] = useState(false)
const [ isCopied, setIsCopied ] = useState(false)
const { t, i18n } = useTranslation()
const classes = useStyles()
useEffect(() => {
setUpdating(false)
}, [updateTime])
return (
<Paper className={classes.root}>
<List>
<ListItem
button
onClick={() => {vibrate(1);setUpdating(true);renewDb()}}
>
<ListItemAvatar>
<Avatar><BuildIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("架構版本")+": "+schemaVersion+" - "+versionMd5.substr(0,6)}
secondary={t('更新時間') + ": " + (new Date(updateTime)).toLocaleString().slice(0,20).replace(',',' ')}
/>
</ListItem>
<ListItem
button
onClick={() => {
vibrate(1)
if ( geoPermission === 'granted' ) {
setGeoPermission('closed')
} else {
setGeoPermission('opening')
navigator.geolocation.getCurrentPosition(position => {
setGeoPermission('granted')
}, () => {
setGeoPermission('denied')
setShowGeoPermissionDenied(true)
})
}
}}
>
<ListItemAvatar>
<Avatar>{geoPermission === 'granted' ? <LocationOnIcon /> : <LocationOffIcon />}</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("地理位置定位功能")}
secondary={t(geoPermission === 'granted' ? '開啟' : ( geoPermission === 'opening' ? '開啟中...' : '關閉' )) }
/>
</ListItem>
<ListItem
button
onClick={() => {vibrate(1);resetUsageRecord()}}
>
<ListItemAvatar>
<Avatar><DeleteIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("一鍵清空用戶記錄")}
secondary={t("包括鎖定和常用報時")}
/>
</ListItem>
<Divider />
<ListItem
button
component='a'
href={`https://github.com/chunlaw/hk-independent-bus-eta/`}
target="_blank"
onClick={() => {vibrate(1)}}
>
<ListItemAvatar>
<Avatar><GitHubIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={"Source Code"}
secondary={"GPL-3.0 License"}
/>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar><DataUsageIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("交通資料來源")}
secondary={t('資料一線通') + " https://data.gov.hk" }
/>
</ListItem>
<Divider />
<ListItem
button
component='a'
href={`https://donate.612fund.hk/${i18n.language}/`}
target="_blank"
onClick={() => {vibrate(1)}}
>
<ListItemAvatar>
<Avatar><MonetizationOnIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("捐款支持")}
secondary={t('請捐款到 612 人道支援基金') }
/>
</ListItem>
<ListItem
button
onClick={() => {
vibrate(1)
if ( navigator.clipboard ) {
navigator.clipboard.writeText('https://hkbus.app/')
.then(() => {
setIsCopied(true)
})
}
}}
>
<ListItemAvatar>
<Avatar><ShareIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("複製應用程式鏈結")}
secondary={t('經不同媒介分享給親友') }
/>
</ListItem>
<ListItem
button
component='a'
href={`https://t.me/hkbusapp`}
target="_blank"
onClick={() => {vibrate(1)}}
>
<ListItemAvatar>
<Avatar><TelegramIcon /></Avatar>
</ListItemAvatar>
<ListItemText
primary={t("Telegram 交流區")}
secondary={t('歡迎意見及技術交流') }
/>
</ListItem>
</List>
<Snackbar
anchorOrigin={{vertical: 'bottom', horizontal: 'center'}}
open={updating}
message={t('資料更新中')+'...'}
/>
<Snackbar
anchorOrigin={{vertical: 'bottom', horizontal: 'center'}}
open={showGeoPermissionDenied}
autoHideDuration={1500}
onClose={(e, reason) => {
setShowGeoPermissionDenied(false)
}}
message={t('無法獲得地理位置定位功能權限')}
/>
<Snackbar
anchorOrigin={{vertical: 'bottom', horizontal: 'center'}}
open={isCopied}
autoHideDuration={1500}
onClose={(event, reason) => {
setIsCopied(false);
}}
message={t('鏈結已複製到剪貼簿')}
/>
</Paper>
)
}
Example #19
Source File: index.js From Recess with MIT License | 4 votes |
function LikePanel({ postId, user }) {
const classes = useStyles();
const [like, setLike] = useState(false);
const [usersLiked, setUsersLiked] = useState([]);
const [likeCounter, setLikeCounter] = useState(0);
const [likeModal, setLikeModal] = useState(false);
const onLike = (e) => {
e.preventDefault();
if (user) {
db.collection("posts")
.doc(postId)
.collection("likes")
.doc(user.uid)
.set({
username: user.displayName,
photoURL: user.photoURL,
})
.then(() => {
setLike(true);
setLikeCounter(likeCounter + 1);
})
.catch((err) => console.log(err));
}
};
const onDislike = (e) => {
e.preventDefault();
if (user) {
db.collection("posts")
.doc(postId)
.collection("likes")
.doc(user.uid)
.delete()
.then(() => {
setLike(false);
setLikeCounter(likeCounter - 1);
})
.catch((err) => console.log(err));
}
};
// Getting Post's like data and updating like state
useEffect(() => {
db.collection("posts")
.doc(postId)
.collection("likes")
.onSnapshot((snap) => {
let documents = [];
snap.forEach((doc) => {
documents.push({
userName: doc.data().username,
photoURL: doc.data().photoURL,
userId: doc.id,
});
});
setUsersLiked(documents);
setLikeCounter(documents.length);
if (user) {
documents.map((u) => {
if (u.userId === user.uid) {
setLike(true);
}
});
}
});
}, []);
return (
<>
<div className={classes.likeContainer}>
<Button>
{like ? (
<FavoriteIcon onClick={onDislike} />
) : (
<FavoriteBorderIcon onClick={onLike} />
)}
</Button>
{likeCounter ? (
<Typography>
Liked by{" "}
<b
className={classes.likeCounter}
onClick={() => setLikeModal(true)}
>
{likeCounter} {likeCounter > 1 ? " users." : " user."}
</b>
</Typography>
) : null}
</div>
<Modal
className={classes.modal}
open={likeModal}
onClose={() => setLikeModal(false)}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={likeModal}>
<div className={classes.paper}>
<h2>Users Liked:</h2>
<Divider />
<List className={classes.likelist}>
{usersLiked.map((user) => (
<ListItem button key={user.userId}>
<ListItemAvatar>
<Avatar
className={classes.avatar}
alt={user.userName}
src={user?.photoURL}
/>
</ListItemAvatar>
<ListItemText primary={user.userName} />
</ListItem>
))}
</List>
</div>
</Fade>
</Modal>
</>
);
}
Example #20
Source File: List.js From Dog-Book with MIT License | 4 votes |
MyList = (props) => {
const classes = useStyles();
const { breedName, setBreedName, setValue } = props;
const [breeds, setBreeds] = useState(undefined);
const [searchValue, setSearchValue] = useState();
const [expandedPanel, setExpandedPanel] = useState(false);
const handleAccordionChange = (key) => (event, isExpanded) => {
setExpandedPanel(isExpanded ? key : false);
};
const handleChange = (event) => {
let value = event.target.value.toLowerCase();
setSearchValue(value);
};
useEffect(() => {
axios.get("https://dog.ceo/api/breeds/list/all").then((response) => {
console.log(response.data.message);
setBreeds(response.data.message);
});
}, [searchValue]);
return (
<>
<Scroll showBelow={250} />
<Grid container justify="flex-end">
<Grid item xs="12" md="4">
<AutoSearchComplete
searchValue={searchValue}
setSearchValue={setSearchValue}
breeds={breeds}
handleChange={(e) => handleChange(e)}
/>
</Grid>
</Grid>
{breeds ? (
Object.keys(breeds)
.filter((key) =>
searchValue !== "" && searchValue !== undefined
? key === searchValue
: "null"
)
.map((key, i) => {
return (
<Accordion
key={i}
style={{ margin: "1rem" }}
onClick={() => {
setBreedName(key);
}}
expanded={expandedPanel === key}
onChange={handleAccordionChange(key)}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="key"
>
<Typography
style={{ textTransform: "capitalize" }}
className={
breedName === key
? classes.Accordion_a
: classes.Accordion
}
>
{key}
</Typography>
</AccordionSummary>
<AccordionDetails>
<List>
{breeds[key].length === 0 ? (
<Typography>No Sub-Breads</Typography>
) : (
breeds[key].map((breed) => (
<ListItem>
<ListItemAvatar>
<Avatar>
<Pets />
</Avatar>
</ListItemAvatar>
<ListItemText primary={breed} />
</ListItem>
))
)}
</List>
</AccordionDetails>
<Divider />
<Box p={2}>
<Button
variant="contained"
color="secondary"
onClick={() => setValue(1)}
>
Select
</Button>
</Box>
</Accordion>
);
})
) : (
<Grid
container
direction="row"
justify="center"
alignItems="center"
style={{ height: "60vh" }}
>
<Grid item>
<CircularProgress color="secondary" size="4rem" />
</Grid>
</Grid>
)}
</>
);
}
Example #21
Source File: GrowerDetail.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 4 votes |
GrowerDetail = ({ open, growerId, onClose }) => {
// console.log('render: grower detail');
const classes = useStyle();
const appContext = useContext(AppContext);
const { growers } = useContext(GrowerContext);
const { sendMessageFromGrower } = useContext(MessagingContext);
const [growerRegistrations, setGrowerRegistrations] = useState(null);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [grower, setGrower] = useState({});
const [deviceIdentifiers, setDeviceIdentifiers] = useState([]);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarLabel, setSnackbarLabel] = useState('');
const [verificationStatus, setVerificationStatus] = useState({});
const [loading, setLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
useEffect(() => {
setErrorMessage(null);
async function loadGrowerDetail() {
if (grower && grower.growerAccountUuid !== growerId) {
setGrower({});
setDeviceIdentifiers([]);
}
if (growerId) {
let match;
if (isNaN(Number(growerId))) {
match = await getGrower({
id: undefined,
growerAccountUuid: growerId,
});
} else {
match = await getGrower({
id: growerId,
growerAccountUuid: undefined,
});
}
if (match.error) {
setErrorMessage(match.message);
}
setGrower(match);
if (
match.id &&
(!growerRegistrations ||
(growerRegistrations.length > 0 &&
growerRegistrations[0].planter_id !== match.id))
) {
setGrowerRegistrations(null);
api.getGrowerRegistrations(match.id).then((registrations) => {
if (registrations && registrations.length) {
const sortedReg = registrations.sort((a, b) =>
a.created_at > b.created_at ? 1 : -1
);
const uniqueDevices = {};
const devices = sortedReg.reduce((result, reg) => {
if (!reg.device_identifier) {
return result;
}
if (!uniqueDevices[reg.device_identifier]) {
uniqueDevices[reg.device_identifier] = true;
// if manufacturer isn't 'apple' it's an android phone
result.push({
id: reg.device_identifier,
os:
reg.manufacturer?.toLowerCase() === 'apple'
? 'iOS'
: 'Android',
});
}
return result;
}, []);
setDeviceIdentifiers(devices);
setGrowerRegistrations(sortedReg);
}
});
}
}
}
loadGrowerDetail();
// eslint-disable-next-line
}, [growerId, growers]);
useEffect(() => {
async function loadCaptures() {
if (grower.id) {
setLoading(true);
const [
approvedCount,
awaitingCount,
rejectedCount,
] = await Promise.all([
getCaptureCountGrower(true, true, grower.id),
getCaptureCountGrower(true, false, grower.id),
getCaptureCountGrower(false, false, grower.id),
]);
setVerificationStatus({
approved: approvedCount,
awaiting: awaitingCount,
rejected: rejectedCount,
});
setLoading(false);
}
}
loadCaptures();
}, [grower]);
async function getCaptureCountGrower(active, approved, growerId) {
let filter = new FilterModel();
filter.planterId = growerId?.toString();
filter.active = active;
filter.approved = approved;
const countResponse = await treeTrackerApi.getCaptureCount(filter);
return countResponse && countResponse.count ? countResponse.count : 0;
}
async function getGrower(payload) {
const { id, growerAccountUuid } = payload;
let grower = growers?.find(
(p) =>
(growerAccountUuid && p.growerAccountUuid === growerAccountUuid) ||
p.id === id
); // Look for a match in the context first
if (!grower && !id) {
const filter = new FilterGrower();
filter.growerAccountUuid = growerAccountUuid;
[grower] = await api.getGrowers({ filter }); // Otherwise query the API
}
if (!grower && !growerAccountUuid) {
grower = await api.getGrower(id);
}
// throw error if no match at all
return grower || { error: true, message: 'Sorry! No grower info found' };
}
function handleEditClick() {
setEditDialogOpen(true);
}
function handleEditClose() {
setEditDialogOpen(false);
setSnackbarOpen(false);
setSnackbarLabel('');
}
function confirmCopy(label) {
setSnackbarOpen(false);
setSnackbarLabel(label);
setSnackbarOpen(true);
}
return (
<>
<Drawer anchor="right" open={open} onClose={onClose}>
<Grid
style={{
width: GROWER_IMAGE_SIZE,
}}
>
{errorMessage ? (
<Grid container direction="column">
<Grid item>
<Grid container justify="space-between" alignItems="center">
<Grid item>
<Box m={4}>
<Typography color="primary" variant="h6">
Grower Detail
</Typography>
<Typography variant="h4">{errorMessage}</Typography>
</Box>
</Grid>
<Grid item>
<IconButton onClick={() => onClose()}>
<Close />
</IconButton>
</Grid>
</Grid>
</Grid>
<Grid item className={classes.imageContainer}>
<CardMedia className={classes.cardMedia}>
<Grid container className={classes.personBox}>
<Person className={classes.person} />
</Grid>
</CardMedia>
</Grid>
</Grid>
) : (
<Grid container direction="column">
<Grid item>
<Grid container justify="space-between" alignItems="center">
<Grid item>
<Box m={4}>
<Typography color="primary" variant="h6">
Grower Detail
</Typography>
</Box>
</Grid>
<Grid item>
<IconButton onClick={() => onClose()}>
<Close />
</IconButton>
</Grid>
</Grid>
</Grid>
<Grid item className={classes.imageContainer}>
{grower?.imageUrl && (
<OptimizedImage
src={grower.imageUrl}
width={GROWER_IMAGE_SIZE}
height={GROWER_IMAGE_SIZE}
className={classes.cardMedia}
fixed
rotation={grower.imageRotation}
alertTitleSize="1.6rem"
alertTextSize="1rem"
alertHeight="50%"
/>
)}
{!grower.imageUrl && (
<CardMedia className={classes.cardMedia}>
<Grid container className={classes.personBox}>
<Person className={classes.person} />
</Grid>
</CardMedia>
)}
{hasPermission(appContext.user, [
POLICIES.SUPER_PERMISSION,
POLICIES.MANAGE_GROWER,
]) && (
<Fab
data-testid="edit-grower"
className={classes.editButton}
onClick={() => handleEditClick()}
>
<EditIcon />
</Fab>
)}
</Grid>
<Grid item className={classes.box}>
<Typography
variant="h5"
color="primary"
className={classes.name}
>
{grower.firstName} {grower.lastName}
</Typography>
<Typography variant="body2">
ID: <LinkToWebmap value={grower.id} type="user" />
</Typography>
</Grid>
{process.env.REACT_APP_ENABLE_MESSAGING === 'true' &&
hasPermission(appContext.user, [POLICIES.SUPER_PERMISSION]) && (
<Grid item>
<Button
className={classes.messageButton}
onClick={() => sendMessageFromGrower(grower)}
component={Link}
to={'/messaging'}
>
Send Message
</Button>
</Grid>
)}
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Captures</Typography>
{loading ? (
<LinearProgress color="primary" />
) : (
<List className={classes.listCaptures}>
<Box
borderColor="grey.300"
borderRadius={10}
border={0.5}
m={0.5}
>
<ListItem>
<ListItemAvatar>
<Avatar className={classes.approvedChip}>
<Done />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
<Typography variant="h5">
{verificationStatus.approved || 0}
</Typography>
}
secondary="Approved"
/>
</ListItem>
</Box>
<Box
borderColor="grey.300"
borderRadius={10}
border={0.5}
m={0.5}
>
<ListItem>
<ListItemAvatar>
<Avatar className={classes.awaitingChip}>
<HourglassEmptyOutlined />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
<Typography variant="h5">
{verificationStatus.awaiting || 0}
</Typography>
}
secondary="Awaiting"
/>
</ListItem>
</Box>
<Box
borderColor="grey.300"
borderRadius={10}
border={0.5}
m={0.5}
>
<ListItem>
<ListItemAvatar>
<Avatar className={classes.rejectedChip}>
<Clear />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
<Typography variant="h5">
{verificationStatus.rejected || 0}
</Typography>
}
secondary="Rejected"
/>
</ListItem>
</Box>
</List>
)}
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Email address</Typography>
<Typography variant="body1">{grower.email || '---'}</Typography>
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Phone number</Typography>
<Typography variant="body1">{grower.phone || '---'}</Typography>
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Person ID</Typography>
<Typography variant="body1">
{grower.personId || '---'}
</Typography>
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Organization</Typography>
{grower.organization || grower.organizationId ? (
<GrowerOrganization
organizationName={grower.organization}
assignedOrganizationId={grower.organizationId}
/>
) : (
<Typography variant="body1">---</Typography>
)}
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Country</Typography>
<Typography variant="body1">
{(growerRegistrations &&
growerRegistrations
.map((item) => item.country)
.filter(
(country, i, arr) =>
country && arr.indexOf(country) === i
)
.join(', ')) ||
'---'}
</Typography>
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">Registered</Typography>
<Typography variant="body1">
{(growerRegistrations &&
growerRegistrations.length > 0 &&
getDateTimeStringLocale(
growerRegistrations[0].created_at
)) ||
'---'}
</Typography>
</Grid>
<Divider />
<Grid container direction="column" className={classes.box}>
<Typography variant="subtitle1">
Device Identifier{deviceIdentifiers.length >= 2 ? 's' : ''}
</Typography>
{(deviceIdentifiers.length && (
<table>
<tbody>
{deviceIdentifiers.map((device, i) => (
<tr key={i}>
<td>
<Typography variant="body1">
{device.id}
<CopyButton
label={'Device Identifier'}
value={device.id}
confirmCopy={confirmCopy}
/>
</Typography>
</td>
<td>
<Typography variant="body1">
({device.os})
</Typography>
</td>
</tr>
))}
</tbody>
</table>
)) || <Typography variant="body1">---</Typography>}
</Grid>
</Grid>
)}
</Grid>
</Drawer>
<CopyNotification
snackbarLabel={snackbarLabel}
snackbarOpen={snackbarOpen}
setSnackbarOpen={setSnackbarOpen}
/>
<EditGrower
isOpen={editDialogOpen}
grower={grower}
onClose={handleEditClose}
></EditGrower>
</>
);
}
Example #22
Source File: Discussion.js From app with MIT License | 4 votes |
function CommentList({ requestId }) {
const classes = useStyles();
const firestore = useFirestore();
const [retries, setRetries] = useState(0);
const { showError } = useNotifications();
// This is used to trigger the snapshot subscription after confirming that the user
// has permission to access the contact info.
const [query, setQuery] = useState(null);
const [commentDocs, setCommentDocs] = useState([]);
// Because of timing issues, this component will likely get run before the server has applied
// the requested document access resulting in almost a guranteed permission-denied error. So,
// we use this effect to monitor for permission-denied until the change has propagated, at which
// point, we do the actual doc subscription (next useEffect);
useEffect(() => {
async function getData() {
try {
const dataQuery = firestore
.collection(`${REQUESTS_DISCUSSIONS_COLLECTION}`)
.where('requestId', '==', requestId)
.orderBy('createdAt', 'asc');
// Call it once because this will throw the permission exception.
await dataQuery.get();
setQuery(dataQuery); // Setting this will trigger the subscription useEffect.
} catch (err) {
// We only try reloading if insufficient permissions.
if (err.code !== 'permission-denied') {
throw err;
}
if (retries >= 25) {
// setAccessFailed(true);
showError(
'Failed to get contact info access, please try again later.',
);
} else {
window.setTimeout(() => {
setRetries(retries + 1);
}, 1000);
}
}
}
getData();
}, [retries, firestore, requestId, showError]);
// Once the previous useEffect verifies that the user has access then this one does the actual
// document subscription.
useEffect(() => {
if (!query) return undefined;
const unsub = query.onSnapshot((querySnap) => {
setCommentDocs(querySnap.docs);
});
return unsub;
}, [query]);
// const querySnapshot = useFirestoreCollection(
// firestore
// .collection(`${REQUESTS_DISCUSSIONS_COLLECTION}`)
// .where('requestId', '==', requestId)
// .orderBy('createdAt', 'asc'),
// );
if (!commentDocs.length) {
return (
<Box color="text.disabled">
<Typography
variant="body2"
className={classes.noComments}
data-test="no-comments">
No comments yet.
</Typography>
<Divider className={classes.divider} />
</Box>
);
}
return (
<List>
{commentDocs.map(
(docSnap) =>
// When new comment is added locally, the createdAt can be the serverTimestamp() value.
// So, we wait on rendering until any new snapshot has finished writing.
!docSnap.metadata.hasPendingWrites && (
<ListItem
key={docSnap.id}
divider
alignItems="flex-start"
data-test="private-comment">
<ListItemAvatar>
<Avatar>{docSnap.get('author.firstName').slice(0, 1)}</Avatar>
</ListItemAvatar>
<ListItemText
disableTypography
primary={
<Typography variant="subtitle2">
{docSnap.get('author.firstName')} –{' '}
<Typography
variant="body2"
display="inline"
color="textSecondary">
{format(docSnap.get('createdAt').toDate(), 'p - PPPP')}
</Typography>{' '}
{docSnap.get('kind') !== 1 && (
<Chip
variant="outlined"
size="small"
icon={kindMap[docSnap.get('kind')].icon}
label={kindMap[docSnap.get('kind')].shortDescription}
/>
)}
</Typography>
}
secondary={docSnap
.get('content')
.split('\n')
.map((content, key) => (
// eslint-disable-next-line react/no-array-index-key
<Typography variant="body1" key={key} gutterBottom>
{content}
</Typography>
))}
/>
</ListItem>
),
)}
</List>
);
}
Example #23
Source File: TemplateGallery.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function TemplateGallery(props) {
const [selectedCategoryTitle, setSelectedCategoryTitle] = useState(null);
const [searchTerms, setSearchTerms] = useState("");
const [searchTermsUsed, setSearchTermsUsed] = useState(null);
const { isLoading, categories, templates } = useTemplates();
const query = useQueryParams();
const history = useHistory();
const selectedCategory = selectedCategoryTitle && categories.find((x) => x.title === selectedCategoryTitle);
const classes = useStyles();
const searchTermsSplit = searchTermsUsed?.split().map((x) => x.toLowerCase());
const searchResults =
searchTermsSplit && templates.filter((x) => searchTermsSplit.some((s) => x.name.toLowerCase().includes(s) || x.readme.toLowerCase().includes(s)));
useEffect(() => {
const queryCategory = query.get("category");
const querySearch = query.get("search");
if (queryCategory) {
setSelectedCategoryTitle(queryCategory);
}
if (querySearch) {
setSearchTerms(querySearch);
setSearchTermsUsed(querySearch);
}
return () => {
clearTimeout(timeoutId);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
const queryCategory = query.get("category");
if (categories?.length > 0 && !queryCategory) {
setSelectedCategoryTitle(categories[0].title);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [categories]);
const onSearchChange = (event) => {
const searchValue = event.target.value;
setSearchTerms(searchValue);
if (searchValue) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
setSearchTermsUsed(searchValue);
history.replace(UrlService.templates(selectedCategoryTitle, searchValue));
}, 300);
} else {
setSearchTermsUsed(searchValue);
history.replace(UrlService.templates(selectedCategoryTitle, searchValue));
}
};
const onCategoryClick = (categoryTitle) => {
setSelectedCategoryTitle(categoryTitle);
history.replace(UrlService.templates(categoryTitle, searchTerms));
};
const onClearSearch = () => {
setSearchTerms("");
setSearchTermsUsed("");
};
return (
<>
<Helmet title="Template Gallery" />
<LinearLoadingSkeleton isLoading={isLoading} />
<Box padding="1rem">
<Typography variant="h3" className={classes.title}>
Template Gallery
</Typography>
<Box paddingTop={2}>
These templates come from the{" "}
<a href="https://github.com/ovrclk/awesome-akash" target="_blank" rel="noreferrer">
Awesome Akash
</a>{" "}
repository.
</Box>
<TextField
fullWidth
label="Search"
disabled={isLoading}
value={searchTerms}
onChange={onSearchChange}
InputProps={{
endAdornment: searchTerms && (
<IconButton onClick={onClearSearch} size="small">
<CloseIcon fontSize="small" />
</IconButton>
)
}}
/>
</Box>
{searchTermsUsed || searchTerms ? (
<ViewPanel bottomElementId="footer" overflow="auto" className={classes.templateList}>
<List className={classes.templateList}>
{searchResults?.map((template) => (
<ListItem button key={template.id} component={Link} to={UrlService.templateDetails(template.id)}>
<ListItemAvatar>
{template.logoUrl ? (
<Avatar src={template.logoUrl} variant="square" />
) : (
<div className={classes.logoPlaceholder}>
<ImageIcon />
</div>
)}
</ListItemAvatar>
<ListItemText
primary={
<>
{template.name} - <strong>{template.category}</strong>
</>
}
secondary={template.summary}
/>
</ListItem>
))}
</List>
</ViewPanel>
) : (
<>
<Box className={classes.gallery}>
<ViewPanel bottomElementId="footer" overflow="auto" className={classes.categoryList}>
<List>
{categories
.sort((a, b) => (a.title < b.title ? -1 : 1))
.map((category) => (
<ListItem button key={category.title} onClick={() => onCategoryClick(category.title)} selected={category.title === selectedCategoryTitle}>
<ListItemText primary={`${category.title} (${category.templates.length})`} />
</ListItem>
))}
</List>
</ViewPanel>
{selectedCategory && selectedCategory.templates && (
<ViewPanel bottomElementId="footer" overflow="auto" className={classes.templateList}>
<List>
{selectedCategory.templates.map((template) => (
<ListItem button key={template.id} component={Link} to={UrlService.templateDetails(template.id)}>
<ListItemAvatar>
{template.logoUrl ? (
<Avatar src={template.logoUrl} variant="square" />
) : (
<div className={classes.logoPlaceholder}>
<ImageIcon />
</div>
)}
</ListItemAvatar>
<ListItemText primary={template.name} secondary={template.summary} />
</ListItem>
))}
</List>
</ViewPanel>
)}
</Box>
</>
)}
</>
);
}
Example #24
Source File: TemplateList.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function TemplateList(props) {
const classes = useStyles();
const history = useHistory();
const { setSelectedTemplate } = props;
function handleGithubOpen(value) {
window.electron.openUrl(value.githubUrl);
}
function selectTemplate(template) {
setSelectedTemplate(template);
history.push("/createDeployment/editManifest");
}
async function fromFile() {
const fileDef = await window.electron.openTemplateFromFile();
if (fileDef) {
setSelectedTemplate({
title: "From file",
code: "from-file",
category: "General",
description: fileDef.path,
content: fileDef.content
});
history.push("/createDeployment/editManifest");
}
}
function fromGallery() {
history.push(UrlService.templates());
}
return (
<>
<Helmet title="Create Deployment - Template List" />
<Box padding="1rem">
<Typography variant="h5"><strong>What do you want to deploy?</strong></Typography>
</Box>
<List className={classes.root}>
<ListItem dense button onClick={() => selectTemplate(emptyTemplate)}>
<ListItemAvatar>
<div className={classes.logoItem}>
<InsertDriveFileIcon />
</div>
</ListItemAvatar>
<ListItemText primary={emptyTemplate.title} secondary={emptyTemplate.description} />
{emptyTemplate.githubUrl && (
<ListItemSecondaryAction>
<IconButton edge="end" aria-label="github" onClick={() => handleGithubOpen(emptyTemplate)}>
<GitHubIcon />
</IconButton>
</ListItemSecondaryAction>
)}
</ListItem>
<ListItem dense button onClick={() => selectTemplate(helloWorldTemplate)}>
<ListItemAvatar>
<div className={classes.logoItem}>
<CloudIcon />
</div>
</ListItemAvatar>
<ListItemText primary={helloWorldTemplate.title} secondary={helloWorldTemplate.description} />
{helloWorldTemplate.githubUrl && (
<ListItemSecondaryAction>
<IconButton edge="end" aria-label="github" onClick={() => handleGithubOpen(helloWorldTemplate)}>
<GitHubIcon />
</IconButton>
</ListItemSecondaryAction>
)}
</ListItem>
<ListItem dense button onClick={() => fromFile()}>
<ListItemAvatar>
<div className={classes.logoItem}>
<DescriptionIcon />
</div>
</ListItemAvatar>
<ListItemText primary="From a file" secondary="Load a deploy.yml file from the computer." />
</ListItem>
<ListItem dense button onClick={() => fromGallery()}>
<ListItemAvatar>
<div className={classes.logoItem}>
<CollectionsIcon />
</div>
</ListItemAvatar>
<ListItemText primary="Browse template gallery" secondary="Explore the template gallery for a great variety of pre-made template by the community." />
</ListItem>
</List>
</>
);
}