@material-ui/core#CardActionArea JavaScript Examples
The following examples show how to use
@material-ui/core#CardActionArea.
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: Gravatars.jsx From Gameplayer with MIT License | 6 votes |
Gravatar = ({ classes, id, displayName, imageUrl, owner }) => (
<Grid item>
<Card>
<CardActionArea className={classes.actionArea}>
{imageUrl && (
<CardMedia className={classes.image} image={imageUrl} title={displayName} />
)}
<CardContent>
<Typography variant="h6" component="h3" className={classes.displayName}>
{displayName || '—'}
</Typography>
<Typography color="textSecondary">ID</Typography>
<Typography component="p" className={classes.id}>
{id}
</Typography>
<Typography color="textSecondary">Owner</Typography>
<Typography component="p" className={classes.owner}>
{owner}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
)
Example #2
Source File: ChallengeCard.js From dscbppimt-official-website with MIT License | 6 votes |
ChallengeCard = (props) => {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
image="/static/images/cards/contemplative-reptile.jpg"
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Lizard
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging
across all continents except Antarctica
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
)
}
Example #3
Source File: JoinUsOnDiscord.js From qasong with ISC License | 6 votes |
function Playlist() {
const classes = useStyles();
return (
<Grid key={"discord"} item>
<CardActionArea href="https://discord.gg/VnpcrtYnrS" className={classes.playlist}>
<Grid
container
alignContent="center"
justify="center"
alignItems="center"
align="center"
>
<Grid item xs={12} sm={3}>
<img className={classes.svg} src="./static/img/discord.svg"></img>
</Grid>
<Grid item xs={12} sm={6}>
<Typography align="center" color="secondary">
Join Us On Discord
</Typography>
<Typography align="center" variant="body2" color="textSecondary">
contact the Qasong Team
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<img width="80px" src="./static/img/qasong.svg"></img>
</Grid>
</Grid>
</CardActionArea>
</Grid>
);
}
Example #4
Source File: RouteRow.js From hk-independent-bus-eta with GNU General Public License v3.0 | 6 votes |
RouteRow = React.memo(( {data, index, style} ) => {
const { t, i18n } = useTranslation()
const { routeList } = data
const route = routeList[index]
const [routeNo, service_type] = route[0].split('+').slice(0,2)
const classes = useStyles()
const history = useHistory()
const handleClick = () => {
vibrate(1)
setTimeout(() => {
history.push('/'+i18n.language+'/route/'+route[0])
}, 0)
}
return (
<div onClick={handleClick} >
<Card variant="outlined" key={route[0]} style={style} square>
<CardActionArea>
<CardContent className={classes.cardContent}>
<Typography variant="h5" display="inline">{routeNo}</Typography>
<Typography variant="caption"> - {route[1].co.map(co => t(co)).join('+')}</Typography>
<br/>
<RouteInfo route={route[1]} />
<Typography variant="caption">{service_type >= 2 ? t('特別班次') : ' '}</Typography>
</CardContent>
</CardActionArea>
</Card>
</div>
)
}, areEqual)
Example #5
Source File: About.jsx From Design-Initiative-Dashboard-frontend with GNU General Public License v3.0 | 6 votes |
export default function AboutCard() {
const classes = useStyles();
return (
<Card className={classes.root}>
<React.Fragment>
{about.map((data)=> (
<CardActionArea>
<CardContent>
<Typography
variant="body2"
color="textPrimary"
component="p"
align="left"
className={classes.pos2}
>
{data.desc}
</Typography>
{data.features.map((f) => (
<Button variant="contained" color="primary" size="small" className={classes.cap} >
{f.name}
</Button>
))}
</CardContent>
</CardActionArea>
))}
</React.Fragment>
</Card>
);
}
Example #6
Source File: team-member.js From turinghut-website with BSD Zero Clause License | 6 votes |
export default function TeamMember() {
const classes = teamMemberStyles();
return (
<div>
<Typography variant="h3" className={classes.heading}>our team</Typography>
<div className={classes.root}>
<Grid container spacing={4} className={classes.gridContainer}>
{team.map((member, i) => (
<Grid item xs={12} md={4} key={i}>
<Card className={classes.card}>
<CardActionArea >
<CardMedia className={classes.media} image={member.imageUrl} title={member.name} />
<DialogDisplay person={member} />
</CardActionArea>
</Card>
</Grid>
))}
</Grid>
</div>
</div>
);
}
Example #7
Source File: Categories.jsx From scholar-front-end with MIT License | 6 votes |
categoriesCard = data.map(item => (
<Grid item sm={3}>
<Card className="cardActions">
<CardActionArea >
<CardMedia className="card"
image={require(`../../data/Images/${item.name}`).default}
style={{ height: 300 }} />
<CardContent>
<Typography variant="h5"><span className="categoryName">{item.category}</span></Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
))
Example #8
Source File: Sliders.jsx From scholar-front-end with MIT License | 6 votes |
function CourseCard({data}){
var image = require("./CourseLogo.jpg").default;
const classes = useStyles();
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia alt="course" component="img" height="140" title={data} image={image}/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Course Title
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Course Number {data}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">Open</Button>
</CardActions>
</Card>
)
}
Example #9
Source File: AccountDialogThanks.js From crypto-red.github.io with MIT License | 6 votes |
render() {
const { classes, open } = this.state;
return (
<Dialog className={classes.thanksCard} open={open} onClick={this.props.accept} onClose={(event) => {this.props.onClose(event)}}>
<CardActionArea className={classes.thanksCardArea}>
<CardHeader className={classes.thanksCardHeader}>
Thanks !
</CardHeader>
<CardContent className={classes.thanksCardContent}>
<div className={classes.thanksCardImage} />
Thanks for your engagement, we appreciate it a lot,
We have a new friend or user, do you want to join with a new person?
</CardContent>
<KindlyHappyEmojiIcon className={classes.thanksEmoji} />
<div className={classes.thanksButtonContainer}>
<Button color="primary" variant={"contained"} className={classes.thanksButton}>Invite a friend</Button>
</div>
</CardActionArea>
</Dialog>
);
}
Example #10
Source File: ProjectCard.js From eSim-Cloud with GNU General Public License v3.0 | 6 votes |
export default function ProjectCard ({ pub, is_review }) {
const classes = useStyles()
return (
<>
<Card>
<ButtonBase
target="_blank"
component={RouterLink}
to={'/project?save_id=' + pub.save_id + '&version=' + pub.active_version + '&branch=' + pub.active_branch + '&project_id=' + pub.project_id}
style={{ width: '100%' }}>
<CardActionArea>
<CardHeader title={pub.title} />
<CardMedia
className={classes.media}
image={pub.active_save.base64_image} />
<CardContent>
<Typography variant="body2" component="p" noWrap={true}>
{pub.description}
</Typography>
<br/>
<Typography variant='body2' color='textSecondary' component='p'>
Status: {pub.status_name}
</Typography>
{/* <Typography variant='body2' component='p' color='textSecondary' style={{ margin: '5px 0px 0px 0px' }}>
Updated at {timeSince(pub.save_time)} ago...
</Typography> */}
</CardContent>
</CardActionArea>
</ButtonBase>
</Card>
</>
)
}
Example #11
Source File: LinkContent.js From covid19ph.net with MIT License | 5 votes |
LinkContent = ({
image,
title,
url,
}) => {
const classes = useStyles()
return (
<CardActionArea
component="a"
href={url}
rel="noreferrer noopener"
target="_blank"
>
<CardMedia
component="img"
height="256"
image={image}
alt={title}
title={title}
className={classes.linkImage}
/>
<CardContent>
<Typography
gutterBottom
variant="h5"
component="h2"
className={classes.linkTitle}
>
{title}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
className={classes.linkUrl}
>
{url}
</Typography>
</CardContent>
</CardActionArea>
)
}
Example #12
Source File: ResultCard.js From qasong with ISC License | 5 votes |
export default function ResultCard({
video,
setNowPlaying,
nowPlaying,
queue,
setQueue,
}) {
const classes = useStyles();
const [playing, setPlaying] = useState(false);
useEffect(() => {
if (nowPlaying && nowPlaying.videoId === video.videoId) {
setPlaying(true);
} else {
setPlaying(false);
}
}, [nowPlaying]);
function handlePlayButton(event) {
event.stopPropagation();
if (!playing) {
setNowPlaying(video);
setPlaying(true);
} else {
setNowPlaying({});
setPlaying(false);
}
}
function handleAddQueue(event) {
event.stopPropagation();
setQueue(
queue.concat({
...video,
qid: uuid(),
})
);
}
return (
<Card
className={classes.card}
style={{ backgroundColor: playing && qasongOrange }}
onClick={handlePlayButton}
>
<CardActionArea>
<CardMedia className={classes.media} image={video.image} />
<Box p={1}>
<Grid container direction="column">
<Grid item>
<Typography className={classes.truncate} variant="caption">
{video.title}
</Typography>
</Grid>
<Grid item container justify="space-between">
<Grid item>
<Typography className={classes.truncate} variant="caption">
{video.author.name}
</Typography>
</Grid>
<Grid item>
<Typography className={classes.truncate} variant="caption">
{video.timestamp}
</Typography>
</Grid>
</Grid>
</Grid>
</Box>
</CardActionArea>
<Box className={classes.overlay}>
<AddToQueueButton {...{ handleAddQueue }} />
</Box>
</Card>
);
}
Example #13
Source File: EventCard.js From AdaptivApps-fe with MIT License | 5 votes |
export default function EventCard({ event }) {
const classes = useStyles();
const [updateEvent] = useMutation(REGISTER_EVENT);
const { user } = useAuth0();
const navigate = useNavigate();
const registerEvent = async () => {
await updateEvent({
variables: { id: event.id, email: user.email },
});
await navigate(`/calendar/${event.id}`);
};
return (
<Card className={classes.root}>
<CardActionArea className={classes.card}>
<Box>
<div className={classes.banner}>{event.type}</div>
<CardMedia
className={classes.cardImg}
component="img"
alt="Event"
width="15rem"
image={event?.imgUrl}
title="Angel City Event"
/>
</Box>
<CardContent className={classes.content}>
<Typography
className={classes.cardDate}
variant="body2"
color="textSecondary"
component="p"
>
{event.startDate} - {event.endDate}
</Typography>
<Typography
className={classes.cardTitle}
gutterBottom
variant="h5"
component="h2"
>
{event.title}
</Typography>
<Typography
className={classes.cardLoc}
variant="body2"
color="textSecondary"
component="p"
>
{event.location}
</Typography>
</CardContent>
</CardActionArea>
<CardActions className={classes.btnContainer}>
<SimpleModal event={event} registerEvent={registerEvent} />
</CardActions>
</Card>
);
}
Example #14
Source File: Rules.js From gitlab-lint-react with BSD 3-Clause "New" or "Revised" License | 5 votes |
Rules = () => {
const classes = useStyles();
const [rows, setData] = useState({});
const fetchData = () => {
GitlabLintHttpClient("GET_ALL", { entity: "rules" })
.then((data) => {
setData(data.data);
})
.catch((err) => console.error(err));
};
useEffect(() => {
fetchData();
}, []);
if (Object.keys(rows).length === 0 && rows.constructor === Object) {
return <Loading />;
}
return (
<React.Fragment>
<Typography variant="h4" paragraph>
Rules
</Typography>
<Grid container spacing={4}>
{rows.map((row) => {
return (
<Grid item key={row.ruleId} xs={12} sm={6} md={4}>
<Card className={classes.root}>
<CardActionArea component={Link} to={`rules/${row.ruleId}`}>
<CardHeader
className={classes[row.level]}
classes={{ title: classes["title"] }}
title={row.level}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{row.name}
</Typography>
{row.description && (
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{row.description}
</Typography>
)}
</CardContent>
</CardActionArea>
<CardActions>
<Button
component={Link}
size="small"
color="secondary"
to={`/rules/${row.ruleId}`}
>
Show projects
</Button>
</CardActions>
</Card>
</Grid>
);
})}
</Grid>
</React.Fragment>
);
}
Example #15
Source File: ProjectCard.jsx From Design-Initiative-Dashboard-frontend with GNU General Public License v3.0 | 5 votes |
export default function ProjectCard() {
const classes = useStyles();
const history = useHistory();
function handleChange(){
history.push('./ProjectDetails');
}
return (
<React.Fragment>
{cardData.map((data) => (
<Card className={classes.root}>
<CardActionArea>
<div className={classes.details}>
<CardMedia
className={classes.im}
component="img"
alt="org-logo"
height="140"
src={data.image}
title="Organisation card"
/>
<CardContent className={classes.content}>
<Typography
variant="h5"
component="h2"
align="left"
className={classes.pos1}
>
{data.title}
{data.features.map((f) => (
<Button
variant="contained"
color="primary"
size="small"
className={classes.cap}
>
{f.name}
</Button>
))}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
align="left"
className={classes.pos2}
>
{data.desc}
</Typography>
</CardContent>
</div>
</CardActionArea>
<div>
<CardActions>
<Button size="small" color="primary" className={classes.btn} onClick={handleChange}>
View more
</Button>
</CardActions>
</div>
</Card>
))}
</React.Fragment>
);
}
Example #16
Source File: Gallery.js From eSim-Cloud with GNU General Public License v3.0 | 5 votes |
// Card displaying overview of gallery sample schematics.
function SchematicCard ({ sch }) {
const classes = useStyles()
const auth = useSelector(state => state.authReducer)
const dispatch = useDispatch()
const [snacOpen, setSnacOpen] = React.useState(false)
const handleSnacClick = () => {
setSnacOpen(true)
}
const handleSnacClose = (event, reason) => {
if (reason === 'clickaway') {
return
}
setSnacOpen(false)
}
useEffect(() => {
dispatch(fetchRole())
}, [dispatch])
return (
<>
<Card>
<ButtonBase
target="_blank"
component={RouterLink}
to={'/editor?id=' + sch.save_id}
style={{ width: '100%' }}
>
<CardActionArea>
<CardMedia
className={classes.media}
image={sch.media}
title={sch.name}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{sch.name}
</Typography>
<Typography variant="body2" component="p">
{sch.description}
</Typography>
</CardContent>
</CardActionArea>
</ButtonBase>
<CardActions>
<Button
target="_blank"
component={RouterLink}
to={'/editor?id=' + sch.save_id}
size="small"
color="primary"
>
Launch in Editor
</Button>
{console.log(auth.roles)}
{auth.roles && auth.roles.is_type_staff &&
<Button onClick={() => { handleSnacClick() }}>
<Tooltip title="Delete" placement="bottom" arrow>
<DeleteIcon
color="secondary"
fontSize="small"
/>
</Tooltip>
</Button>}
<SimpleSnackbar open={snacOpen} close={handleSnacClose} sch={sch} confirmation={deleteGallerySch} />
</CardActions>
</Card>
</>
)
}
Example #17
Source File: Project.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function Project Component
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function Project(props) {
const classes = useStyles();
const common_classes = useCommonStyles();
const { project, t } = props;
return (
<Link to={`/projects/${project.id}`} className={classes.textDecorationNone}>
<Card className={classes.root}>
<CardMedia className={classes.mediaBoxStyle} title={project.title}>
<Tooltip
title={getPublishTypeLabel(project.publish.type)}
placement="right-start"
arrow
>
<Box className={classes.publishStyle}>
{project.publish.type === publish_type.Draft
? t('project.publish.draft')
: ''}
{project.publish.type === publish_type.Preview
? t('project.publish.preview')
: ''}
{project.publish.type ===
publish_type['Authenticated Creators'] ? (
<LockIcon />
) : (
''
)}
{project.publish.type === publish_type.Public ? (
<PublicIcon />
) : (
''
)}
</Box>
</Tooltip>
{project.video ? (
<>
<img
className={classes.mediaImageStyle}
src={buildVideoThumbnailURL(project.video)}
alt={project.title}
/>
<img className={classes.playIconStyle} src={playIcon} alt="" />
</>
) : project.images.length > 0 ? (
<img
className={classes.mediaImageStyle}
src={project.images[0].image_url}
alt={project.title}
/>
) : null}
</CardMedia>
<CardActionArea className={classes.actionAreaStyle}>
<CardContent
className={clsx(classes.contentStyle, classes.positionRelative)}
>
<Fab
className={classes.fabButtonStyle}
size="small"
aria-label="save button"
onClick={(e, id = project.id) => toggleSave(e, id, props)}
>
{project.saved_by.includes(props.auth.id) ? (
<BookmarkIcon aria-label="unsave" />
) : (
<BookmarkBorderIcon aria-label="save" />
)}
</Fab>
<Fab
className={clsx(classes.fabButtonStyle, classes.likeButtonStyle)}
size="small"
aria-label="like button"
variant="extended"
onClick={(e, id = project.id) => toggleLike(e, id, props)}
>
{project.likes.includes(props.auth.id) ? (
<ClapIcon arial-label="unlike" />
) : (
<ClapBorderIcon arial-label="like" />
)}
{nFormatter(project.likes.length)}
</Fab>
<Typography
className={classes.titleStyle}
variant="h5"
component="h2"
>
{project.title}
</Typography>
<Box className={classes.descriptionStyle}>
<Typography
variant="subtitle2"
color="textSecondary"
component="p"
>
{formatProjectDescription(project.description)}
</Typography>
</Box>
<Link
to={`/creators/${project.creator.username}`}
className={classes.textDecorationNone}
>
<Box className={classes.creatorBoxStyle}>
<Avatar
className={classes.creatorAvatarStyle}
src={project.creator.avatar}
alt={project.creator.username}
/>
<Typography
color="textSecondary"
variant="caption"
component="p"
>
{project.creator.username}
</Typography>
<Link
className={common_classes.textDecorationNone}
to={`/search/?q=${project.creator.tags[0]}&tab=creators`}
>
<Typography
className={clsx(common_classes.baseTagStyle, {
[common_classes.extendedTagStyle]: !isBaseTag(
project.creator.tags[0],
),
})}
component="h2"
>
{project.creator.tags[0]}
</Typography>
</Link>
</Box>
</Link>
<Box className={classes.captionStyle}>
<Box className={classes.captionStyle}>
<Typography
className={clsx(
classes.captionIconStyle,
classes.VisibilityIconStyle,
)}
color="textSecondary"
variant="caption"
component="span"
>
<VisibilityIcon /> {project.views_count}
</Typography>
<Typography
className={classes.captionIconStyle}
color="textSecondary"
variant="caption"
component="span"
>
<CommentIcon /> {project.comments_count}
</Typography>
</Box>
<Typography
color="textSecondary"
variant="caption"
component="span"
>
{`${dFormatter(project.created_on).value} ${t(
`date.${dFormatter(project.created_on).key}`,
)} ${t('date.ago')}`}
</Typography>
</Box>
</CardContent>
</CardActionArea>
</Card>
</Link>
);
}
Example #18
Source File: MyEventCard.js From AdaptivApps-fe with MIT License | 4 votes |
export default function MyEventCard({ event, refetch }) {
const classes = useStyles();
const navigate = useNavigate();
// Retrieves current user info from Auth0
const { user } = useAuth0();
const { data } = useQuery(GET_PARTICIPANT_IDS, {
variables: { email: user.email, id: event.id },
fetchPolicy: "no-cache",
});
const [unregisterFromAll] = useMutation(UNREGISTER_FROM_ALL);
const [unregisterFromEventActivity] = useMutation(
UNREGISTER_FROM_EVENT_ACTIVITY
);
// Unregisters user from specified event and all it's activities
const unregisterFromEvent = async () => {
const participantIds = data?.participants?.map(participant => {
return participant.id;
});
const participantIdValue = data?.participants?.map(participant => {
return participant.id;
});
const participantId = JSON.stringify(participantIdValue).replace(
/[\[\]"]+/g,
""
);
data && data?.participants?.length === 1
? await unregisterFromEventActivity({
variables: {
id: event.id,
email: user.email,
participantId: participantId,
},
})
: data && data?.participants === null
? await unregisterFromEvent({
variables: {
id: event.id,
email: user.email,
},
})
: await unregisterFromAll({
variables: {
id: event.id,
email: user.email,
participantIds: participantIds,
},
});
await refetch();
};
const viewEventDetails = async () => {
await navigate(`/myevents/${event?.id}`);
};
return (
<Card className={classes.root}>
<CardActionArea className={classes.card}>
<Box>
<div className={classes.banner}>{event.type}</div>
<CardMedia
className={classes.cardImg}
component="img"
alt="Event"
width="15rem"
image={event?.imgUrl}
title="Angel City Event"
/>
</Box>
<CardContent className={classes.content}>
<Typography
className={classes.cardDate}
variant="body2"
color="textSecondary"
component="p"
>
{event.startDate} - {event.endDate}
</Typography>
<Typography
className={classes.cardTitle}
gutterBottom
variant="h5"
component="h2"
>
{event.title}
</Typography>
<Typography
className={classes.cardLoc}
variant="body2"
color="textSecondary"
component="p"
>
{event.location}
</Typography>
</CardContent>
</CardActionArea>
<CardActions className={classes.btnContainer}>
<Button onClick={viewEventDetails} className={classes.btn}>
View Details
</Button>
<Button className={classes.btn} onClick={unregisterFromEvent}>
Unregister
</Button>
</CardActions>
</Card>
);
}
Example #19
Source File: Signup.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function Signup View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function Signup(props) {
const classes = useStyles();
const refs = {
phone_el: React.useRef(null),
location_el: React.useRef(null),
date_of_birth_el: React.useRef(null),
};
const [state, setState] = React.useState({
locations: [],
show_password1: false,
show_password2: false,
tool_tip_open: false,
subscribe_box_checked: false,
});
React.useEffect(() => {
handleSetState(getLocations(props));
}, []);
React.useEffect(() => {
initIntlTelInput(props, refs);
}, [refs.phone_el]);
React.useEffect(() => {
setLabelWidthOfStaticFields(refs, document, props);
}, [props.i18n.language]);
React.useEffect(() => {
if (props.touched['email']) {
vars.email_field_touched = true;
} else {
vars.email_field_touched = false;
}
if (props.touched['phone']) {
vars.phone_field_touched = true;
} else {
vars.phone_field_touched = false;
}
}, [props.touched['email'], props.touched['phone']]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const {
locations,
tool_tip_open,
show_password1,
show_password2,
subscribe_box_checked,
} = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="signup"
noValidate="noValidate"
onSubmit={e => signup(e, props)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('signup.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('signup.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['username']) ||
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
{t('signup.inputs.username.label')}
</InputLabel>
<ClickAwayListener
onClickAway={() => handleSetState(handleTooltipClose())}
>
<Tooltip
title={t('signup.tooltips.noRealName')}
placement="top-start"
arrow
onClose={() => handleSetState(handleTooltipClose())}
PopperProps={{
disablePortal: true,
}}
open={tool_tip_open}
disableFocusListener
disableHoverListener
disableTouchListener
>
<OutlinedInput
className={classes.customInputStyle}
id="username"
name="username"
type="text"
onClick={() => handleSetState(handleTooltipOpen())}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.username.label'),
document,
)}
/>
</Tooltip>
</ClickAwayListener>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`signup.inputs.username.errors.${props.errors['username']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'])
}
>
<InputLabel
className={classes.customLabelStyle}
id="user_location"
>
{t('signup.inputs.location.label')}
</InputLabel>
<Select
ref={refs.location_el}
labelId="user_location"
id="user_location"
name="user_location"
className={classes.customInputStyle}
value={
props.values.user_location
? props.values.user_location
: ''
}
onChange={e => handleLocationChange(e, props)}
onBlur={props.handleBlur}
// label="Location"
labelWidth={calculateLabelWidth(
t('signup.inputs.location.label'),
document,
)}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(locations) &&
locations.map(location => (
<MenuItem key={location.name} value={location.name}>
{location.name}
</MenuItem>
))}
</Select>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'] &&
t(
`signup.inputs.location.errors.${props.errors['user_location']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['dateOfBirth']) ||
(props.touched['dateOfBirth'] &&
props.errors['dateOfBirth'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="dateOfBirth"
shrink
>
{t('signup.inputs.dateOfBirth.label')}
</InputLabel>
<OutlinedInput
ref={refs.date_of_birth_el}
className={clsx(classes.customInputStyle)}
id="dateOfBirth"
name="dateOfBirth"
type="date"
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['dateOfBirth']) ||
(props.touched['dateOfBirth'] &&
props.errors['dateOfBirth'] &&
t(
`signup.inputs.dateOfBirth.errors.${props.errors['dateOfBirth']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['phone']) ||
(props.touched['phone'] && props.errors['phone'])
}
>
<InputLabel
className={classes.customLabelStyle}
shrink
htmlFor="phone"
>
{t('signup.inputs.phone.label')}
</InputLabel>
<OutlinedInput
ref={refs.phone_el}
className={clsx(
classes.customInputStyle,
classes.locationInputStyle,
)}
id="phone"
name="phone"
type="phone"
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['phone']) ||
(props.touched['phone'] &&
props.errors['phone'] &&
t(
`signup.inputs.phone.errors.${props.errors['phone']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['email']) ||
(props.touched['email'] && props.errors['email'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="email"
>
{t('signup.inputs.email.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="email"
name="email"
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.email.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['email']) ||
(props.touched['email'] &&
props.errors['email'] &&
t(
`signup.inputs.email.errors.${props.errors['email']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['password1']) ||
(props.touched['password1'] &&
props.errors['password1'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password1"
>
{t('signup.inputs.password1.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="password1"
name="password1"
type={show_password1 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label={t(
'signup.ariaLabel.togglePasswordVisibility',
)}
onClick={() =>
setState({
...state,
show_password1: !show_password1,
})
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password1 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('signup.inputs.password1.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['password1']) ||
(props.touched['password1'] &&
props.errors['password1'] &&
t(
`signup.inputs.password1.errors.${props.errors['password1']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['password2']) ||
(props.touched['password2'] &&
props.errors['password2'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password2"
>
{t('signup.inputs.password2.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="password2"
name="password2"
type={show_password2 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label={t(
'signup.ariaLabel.togglePasswordVisibility',
)}
onClick={() =>
setState({
...state,
show_password2: !show_password2,
})
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password2 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('signup.inputs.password2.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['password2']) ||
(props.touched['password2'] &&
props.errors['password2'] &&
t(
`signup.inputs.password2.errors.${props.errors['password2']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['bio']) ||
(props.touched['bio'] && props.errors['bio'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="bio"
>
{t('signup.inputs.bio.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="bio"
name="bio"
type="text"
multiline
rows={6}
rowsMax={6}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.bio.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('signup.inputs.bio.helpText')}
</Typography>
<br />
{(props.status && props.status['bio']) ||
(props.touched['bio'] &&
props.errors['bio'] &&
t(
`signup.inputs.bio.errors.${props.errors['bio']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControlLabel
value={subscribe_box_checked}
onChange={e =>
handleSetState(
handleToggleSubscribeBox(e, props, state),
)
}
control={
<Checkbox
name="subscribe"
id="subscribe"
color="primary"
/>
}
label={
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('signup.unsubscribe')}
</Typography>
}
labelPlacement="end"
/>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
type="submit"
fullWidth
customButtonStyle
>
{t('signup.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{t('signup.alreadyAMember')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/login" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
{t('signup.login')}
</CustomButton>
</Link>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #20
Source File: PhoneConfirm.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function PhoneConfirm View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function PhoneConfirm(props) {
const classes = useStyles();
let { username, key } = getUsernameAndKey(props.location.search);
const [state, setState] = React.useState({
username: username ?? null,
key: key ?? null,
errors: null,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
username = state.username;
let errors = state.errors;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="phone_confirm"
noValidate="noValidate"
onSubmit={e => handleSetState(confirmPhone(e, props, state))}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('phoneConfirm.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('phoneConfirm.welcomeMsg.secondary').replace(
'<>',
username,
)}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box component="p" className={errors && classes.errorBox}>
{errors && (
<Box component="span" className={classes.error}>
{errors}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
fullWidth
primaryButtonStyle
customButtonStyle
>
{t('phoneConfirm.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #21
Source File: PasswordResetConfirm.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function PasswordResetConfirm View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function PasswordResetConfirm(props) {
const classes = useStyles();
const [state, setState] = React.useState({
show_password1: false,
show_password2: false,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const { show_password1, show_password2 } = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="password_reset_confirm"
noValidate="noValidate"
onSubmit={e => resetPassword(e, props)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('passwordResetConfirm.welcomeMsg.primary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['new_password1']) ||
(props.touched['new_password1'] &&
props.errors['new_password1'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="new_password1"
>
{t('passwordResetConfirm.inputs.newPassword1.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="new_password1"
name="new_password1"
type={show_password1 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={(_, field = 1) =>
handleSetState(
handleClickShowPassword(field, state),
)
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password1 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('passwordResetConfirm.inputs.newPassword1.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['new_password1']) ||
(props.touched['new_password1'] &&
props.errors['new_password1'] &&
t(
`passwordResetConfirm.inputs.newPassword1.errors.${props.errors['new_password1']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['new_password2']) ||
(props.touched['new_password2'] &&
props.errors['new_password2'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="new_password2"
>
{t('passwordResetConfirm.inputs.newPassword2.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="new_password2"
name="new_password2"
type={show_password2 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={(_, field = 2) =>
handleSetState(
handleClickShowPassword(field, state),
)
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password2 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('passwordResetConfirm.inputs.newPassword2.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['new_password2']) ||
(props.touched['new_password2'] &&
props.errors['new_password2'] &&
t(
`passwordResetConfirm.inputs.newPassword2.errors.${props.errors['new_password2']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
primaryButtonStyle
customButtonStyle
fullWidth
>
{t('passwordResetConfirm.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #22
Source File: PasswordReset.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function PasswordReset View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function PasswordReset(props) {
const classes = useStyles();
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="password_reset"
noValidate="noValidate"
onSubmit={e => sendPasswordResetLink(e, props)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('passwordReset.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('passwordReset.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['email']) ||
(props.touched['email'] && props.errors['email'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="email"
>
{t('passwordReset.inputs.email.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="email"
name="email"
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('passwordReset.inputs.email.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['email']) ||
(props.touched['email'] &&
props.errors['email'] &&
t(
`passwordReset.inputs.email.errors.${props.errors['email']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
customButtonStyle
type="submit"
fullWidth
>
{t('passwordReset.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #23
Source File: Login.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function Login View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function Login(props) {
const classes = useStyles();
const [state, setState] = React.useState({
show_password: false,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const { show_password } = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="login"
noValidate="noValidate"
onSubmit={e => handleSetState(login(e, props))}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('login.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('login.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['username']) ||
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
{t('login.inputs.username.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="username"
name="username"
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('login.inputs.username.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`login.inputs.username.errors.${props.errors['username']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['password']) ||
(props.touched['password'] && props.errors['password'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password"
>
{t('login.inputs.password.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="password"
name="password"
type={show_password ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() =>
handleSetState(handleClickShowPassword(state))
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('login.inputs.password.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['password']) ||
(props.touched['password'] &&
props.errors['password'] &&
t(
`login.inputs.password.errors.${props.errors['password']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
primaryButtonStyle
customButtonStyle
fullWidth
>
{t('login.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
className={classes.dividerText}
variant="body2"
color="textSecondary"
component="p"
>
{t('login.notAMember')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/signup" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
{t('login.signup')}
</CustomButton>
</Link>
</Grid>
<Grid item xs={12}>
<Box className={classes.center}>
<Link
to="/password-reset"
className={classes.secondaryLink}
>
{t('login.forgotPassword')}
</Link>
</Box>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #24
Source File: GroupInviteConfirm.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function GroupInviteConfirm
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function GroupInviteConfirm(props) {
const classes = useStyles();
let { username, key } = getUsernameAndKey(props.location.search);
const [state, setState] = React.useState({
username: username ?? null,
key: key ?? null,
errors: null,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState({ ...state, ...obj });
});
}
};
username = state.username;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="email_confirm"
noValidate="noValidate"
onSubmit={e =>
handleSetState(confirmGroupInvite(e, props, state))
}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('groupInviteConfirm.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('groupInviteConfirm.welcomeMsg.secondary').replace(
'<>',
username,
)}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
fullWidth
primaryButtonStyle
customButtonStyle
>
{t('groupInviteConfirm.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #25
Source File: EmailConfirm.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function EmailConfirm View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function EmailConfirm(props) {
const classes = useStyles();
let { username, key } = getUsernameAndKey(props.location.search);
const [state, setState] = React.useState({
username: username ?? null,
key: key ?? null,
errors: null,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
username = state.username;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="email_confirm"
noValidate="noValidate"
onSubmit={e => handleSetState(confirmEmail(e, props, state))}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('emailConfirm.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('emailConfirm.welcomeMsg.secondary').replace(
'<>',
username,
)}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
fullWidth
primaryButtonStyle
customButtonStyle
>
{t('emailConfirm.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #26
Source File: EditProfile.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function EditProfile View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function EditProfile(props) {
const refs = {
username_el: React.useRef(null),
location_el: React.useRef(null),
email_el: React.useRef(null),
phone_el: React.useRef(null),
bio_el: React.useRef(null),
};
const [state, setState] = React.useState({
locations: [],
tool_tip_open: false,
});
React.useEffect(() => {
getProfile(refs, props);
handleSetState(getLocations(props));
}, []);
const classes = useStyles();
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const { locations, tool_tip_open } = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="signup"
noValidate="noValidate"
onSubmit={e => editProfile(e, props, toast)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('editProfile.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('editProfile.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['username']) ||
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
{t('editProfile.inputs.username.label')}
</InputLabel>
<ClickAwayListener
onClickAway={() => handleSetState(handleTooltipClose())}
>
<Tooltip
title={t('editProfile.tooltips.noRealName')}
placement="top-start"
arrow
onClose={() => handleSetState(handleTooltipClose())}
PopperProps={{
disablePortal: true,
}}
open={tool_tip_open}
disableFocusListener
disableHoverListener
disableTouchListener
>
<OutlinedInput
ref={refs.username_el}
className={clsx(classes.customInputStyle)}
id="username"
name="username"
type="text"
value={
props.values.username ? props.values.username : ''
}
onClick={() => handleSetState(handleTooltipOpen())}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.username.label'),
document,
)}
/>
</Tooltip>
</ClickAwayListener>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`editProfile.inputs.username.errors.${props.errors['username']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
ref={refs.location_el}
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'])
}
>
<InputLabel
className={classes.customLabelStyle}
id="user_location"
>
{t('editProfile.inputs.location.label')}
</InputLabel>
<Select
labelId="user_location"
id="user_location"
name="user_location"
className={clsx(classes.customInputStyle)}
value={
props.values.user_location
? props.values.user_location
: ''
}
onChange={props.handleChange}
onBlur={props.handleBlur}
label="Location"
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(locations) &&
locations.map(location => (
<MenuItem key={location.name} value={location.name}>
{location.name}
</MenuItem>
))}
</Select>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'] &&
t(
`editProfile.inputs.location.errors.${props.errors['user_location']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['email']) ||
(props.touched['email'] && props.errors['email'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="email"
>
{t('editProfile.inputs.email.label')}
</InputLabel>
<OutlinedInput
ref={refs.email_el}
disabled={
props.status && props.status['init_email']
? true
: false
}
className={clsx(classes.customInputStyle)}
id="email"
name="email"
type="text"
value={props.values.email ? props.values.email : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.email.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{props.status && props.status['init_email'] && (
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.email.disabledHelperText')}
</Typography>
)}
<br />
{(props.status && props.status['email']) ||
(props.touched['email'] &&
props.errors['email'] &&
t(
`editProfile.inputs.email.errors.${props.errors['email']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['phone']) ||
(props.touched['phone'] && props.errors['phone'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="phone"
>
{t('editProfile.inputs.phone.label')}
</InputLabel>
<OutlinedInput
ref={refs.phone_el}
disabled={
props.status && props.status['init_phone']
? true
: false
}
className={clsx(classes.customInputStyle)}
id="phone"
name="phone"
type="phone"
value={props.values.phone ? props.values.phone : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.phone.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{props.status && props.status['init_phone'] && (
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.phone.disabledHelperText')}
</Typography>
)}
<br />
{(props.status && props.status['phone']) ||
(props.touched['phone'] &&
props.errors['phone'] &&
t(
`editProfile.inputs.phone.errors.${props.errors['phone']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['bio']) ||
(props.touched['bio'] && props.errors['bio'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="bio"
>
{t('editProfile.inputs.bio.label')}
</InputLabel>
<OutlinedInput
ref={refs.bio_el}
className={clsx(classes.customInputStyle)}
id="bio"
name="bio"
type="text"
multiline
rows={6}
rowsMax={6}
value={props.values.bio ? props.values.bio : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.bio.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.bio.helpText')}
</Typography>
<br />
{(props.status && props.status['bio']) ||
(props.touched['bio'] &&
props.errors['bio'] &&
t(
`editProfile.inputs.bio.errors.${props.errors['bio']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
type="submit"
fullWidth
customButtonStyle
>
{t('editProfile.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{t('editProfile.or')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/profile" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
{t('editProfile.backToProfile')}
</CustomButton>
</Link>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #27
Source File: CreateProject.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function CreateProject View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function CreateProject(props) {
const [category, setCategory] = React.useState([]);
const classes = useStyles();
const common_classes = useCommonStyles();
const refs = {
title_el: React.useRef(null),
desc_el: React.useRef(null),
image_el: React.useRef(null),
image_upload_button_el: React.useRef(null),
video_upload_button_el: React.useRef(null),
image_count_el: React.useRef(null),
video_el: React.useRef(null),
video_file_el: React.useRef(null),
video_selection_feedback_el: React.useRef(null),
add_materials_used_el: React.useRef(null),
add_tags_el: React.useRef(null),
publish_type_el: React.useRef(null),
publish_visible_to_el: React.useRef(null),
};
const [state, setState] = React.useState({
...JSON.parse(JSON.stringify(vars.default_state)),
});
React.useEffect(() => {
if (props.match.params.id) {
Promise.all([getProject(refs, props, state), getCategories(props)]).then(
result => handleSetState({ ...result[0], ...result[1] }),
);
} else {
handleSetState(getCategories(props));
}
handleSetState(buildPublishTypes(props));
}, []);
React.useEffect(() => {
checkMediaFilesErrorState(refs, props);
}, [
props.errors['project_images'],
props.touched['project_images'],
props.errors['video'],
props.touched['video'],
]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const {
desc_input_is_focused,
video_upload_dialog_open,
media_upload,
categories,
tag_suggestion,
tag_suggestion_open,
select_video_file,
publish_types,
publish_visible_to_suggestion_open,
publish_visible_to_suggestion,
} = state;
const { t } = props;
const id = props.match.params.id;
if (!props.auth.token) {
return <ErrorPage error={t('createProject.errors.notLoggedIn')} />;
} else {
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="project-create-form"
name="create_project"
noValidate="noValidate"
onSubmit={e =>
!vars.upload_in_progress
? initUpload(e, state, props, handleSetState)
: e.preventDefault()
}
>
<Typography
className={classes.titleStyle}
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
>
{!id
? t('createProject.welcomeMsg.primary')
: t('createProject.inputs.edit')}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
className={classes.descStyle}
>
{t('createProject.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['title']) ||
(props.touched['title'] && props.errors['title'])
}
>
<label htmlFor="title">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>1</Box>
{t('createProject.inputs.title.label')}
</Typography>
</label>
<OutlinedInput
ref={refs.title_el}
className={classes.customInputStyle}
id="title"
name="title"
type="text"
onChange={e => handleTextFieldChange(e, props)}
onBlur={e => handleTextFieldBlur(e, props)}
/>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['title']) ||
(props.touched['title'] &&
props.errors['title'] &&
t(
`createProject.inputs.title.errors.${props.errors['title']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
>
<label htmlFor="description">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>2</Box>
{t('createProject.inputs.description.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.description.helperText')}
</Typography>
<ClickAwayListener
onClickAway={() =>
handleSetState({ desc_input_is_focused: false })
}
>
<ReactQuill
ref={refs.desc_el}
className={clsx(
classes.descInputStyle,
{
[classes.descInputFocusStyle]:
desc_input_is_focused,
},
{
[classes.descInputErrorStyle]:
(props.status &&
props.status['description']) ||
(props.touched['description'] &&
props.errors['description']),
},
)}
modules={vars.quill.modules}
formats={vars.quill.formats}
defaultValue={''}
placeholder={t(
'createProject.inputs.description.placeholder',
)}
onChange={value =>
handleDescFieldChange(
value,
props,
handleSetState,
)
}
onFocus={() =>
handleDescFieldFocusChange(
null,
props,
handleSetState,
)
}
/>
</ClickAwayListener>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['description']) ||
(props.touched['description'] &&
props.errors['description'] &&
t(
`createProject.inputs.description.errors.${props.errors['description']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
fullWidth
error={
(props.status && props.status['project_images']) ||
(props.touched['project_images'] &&
props.errors['project_images'])
}
>
<label htmlFor="project_images">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>3</Box>
{t('createProject.inputs.projectImages.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t(
'createProject.inputs.projectImages.topHelperText',
)}
</Typography>
<Grid container spacing={1}>
<Grid item xs={12} sm={6} md={6}>
<CustomButton
ref={refs.image_upload_button_el}
variant="outlined"
size="large"
margin="normal"
id="image_upload_button"
startIcon={<ImageIcon />}
onClick={e =>
handleImageButtonClick(e, props, refs)
}
secondaryButtonStyle
mediaUploadButtonStyle
customButtonStyle
fullWidth
>
{t('createProject.inputs.projectImages.label2')}
</CustomButton>
<Typography
color="textSecondary"
variant="caption"
component="span"
ref={refs.image_count_el}
></Typography>
</Grid>
</Grid>
<input
ref={refs.image_el}
className={classes.displayNone}
aria-hidden="true"
type="file"
accept="image/*"
id="project_images"
name="project_images"
multiple
onChange={_ =>
handleImageFieldChange(
refs,
props,
state,
handleSetState,
)
}
onBlur={props.handleBlur}
/>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['images']) ||
(props.errors['project_images'] &&
t(
`createProject.inputs.projectImages.errors.${props.errors['project_images']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
fullWidth
error={
(props.status && props.status['video']) ||
(props.touched['video'] && props.errors['video'])
}
>
<label htmlFor="video">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>4</Box>
{t('createProject.inputs.video.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.video.topHelperText')}
</Typography>
<Grid container spacing={1}>
<Grid item xs={12} sm={6} md={6}>
<CustomButton
ref={refs.video_upload_button_el}
variant="outlined"
size="large"
margin="normal"
id="video_upload_button"
startIcon={<VideoIcon />}
onClick={e =>
handleSetState(
handleVideoButtonClick(
e,
props,
video_upload_dialog_open,
),
)
}
secondaryButtonStyle
mediaUploadButtonStyle
customButtonStyle
fullWidth
>
{t('createProject.inputs.video.label2')}
</CustomButton>
<Typography
color="textSecondary"
variant="caption"
component="span"
ref={refs.video_selection_feedback_el}
></Typography>
</Grid>
</Grid>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['video']) ||
(props.errors['video'] &&
t(
`createProject.inputs.video.errors.${props.errors['video']}`,
))}
</FormHelperText>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('createProject.inputs.video.bottomHelperText')}
</Typography>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['materials_used']) ||
(props.touched['materials_used'] &&
props.errors['materials_used'])
}
>
<label htmlFor="add_materials_used">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>5</Box>
{t('createProject.inputs.materialsUsed.label')}
</Typography>
</label>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12} sm={8}>
<Box ref={refs.add_materials_used_el}>
{buildMaterialUsedNodes({
props,
refs,
classes,
common_classes,
})}
</Box>
</Grid>
<Grid item xs={12} sm={4} md={4}>
<CustomButton
variant="outlined"
size="large"
onClick={e => addMaterialsUsedNode(e, props)}
secondaryButtonStyle
customButtonStyle
fullWidth
>
<AddIcon />{' '}
{t('createProject.inputs.materialsUsed.addMore')}
</CustomButton>
</Grid>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['materials_used']) ||
(props.touched['materials_used'] &&
props.errors['materials_used'] &&
t(
`createProject.inputs.materialsUsed.errors.${props.errors['materials_used']}`,
))}
</FormHelperText>
</Grid>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['category']) ||
(props.touched['category'] &&
props.errors['category'])
}
>
<label htmlFor="category">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>6</Box>
{t('createProject.inputs.category.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.category.topHelperText')}
</Typography>
<Select
labelId="category"
id="category"
name="category"
className={classes.customInputStyle}
value={
props.values.category ? props.values.category : ''
}
onChange={props.handleChange}
onBlur={props.handleBlur}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(categories) &&
categories.map(category => (
<MenuItem key={category.id} value={category.name}>
{category.name}
</MenuItem>
))}
</Select>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['category']) ||
(props.touched['category'] &&
props.errors['category'] &&
t(
`createProject.inputs.category.errors.${props.errors['category']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['tags']) ||
(props.touched['tags'] && props.errors['tags'])
}
>
<label htmlFor="add_tags">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>7</Box>
{t('createProject.inputs.tags.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.tags.topHelperText')}
</Typography>
<Box className={classes.tagsViewStyle}>
{props.values['tags'] &&
JSON.parse(props.values['tags']).map((tag, num) =>
tag && tag.name ? (
<Chip
className={classes.customChipStyle}
key={num}
label={tag.name}
onDelete={e => removeTag(e, props, tag.name)}
color="secondary"
variant="outlined"
/>
) : null,
)}
<input
ref={refs.add_tags_el}
className={classes.tagsInputStyle}
name="tags"
type="text"
autocomplete="off"
placeholder={
props.values['tags'] &&
JSON.parse(props.values['tags']).length >= 5
? t(
'createProject.inputs.tags.errors.limitReached',
)
: `${t('createProject.inputs.tags.addTag')}...`
}
onChange={e => {
handleSuggestTags(
e,
props,
state,
handleSetState,
);
handleSetState(handleAddTags(e, props));
}}
onBlur={e => {
handleAddTags(e, props);
}}
/>
<ClickAwayListener
onClickAway={() =>
handleSetState({
tag_suggestion_open: false,
tag_suggestion: [],
})
}
>
<Box
className={clsx(
classes.tagSuggestionStyle,
!tag_suggestion_open
? common_classes.displayNone
: null,
)}
>
{tag_suggestion && tag_suggestion.length > 0 ? (
tag_suggestion.map((tag, index) => (
<Typography
key={index}
color="textPrimary"
className={classes.tagSuggestionTextStyle}
onClick={() => {
clearTimeout(vars.timer.id);
handleSetState(
handleAddTags(
{
currentTarget: {
value: `${tag.name},`,
},
},
props,
refs.add_tags_el,
),
);
}}
>
{tag.name}
</Typography>
))
) : (
<CircularProgress size={30} thickness={3} />
)}
</Box>
</ClickAwayListener>
</Box>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['tags']) ||
(props.touched['tags'] &&
props.errors['tags'] &&
t(
`createProject.inputs.tags.errors.${props.errors['tags']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['publish']) ||
(props.touched['publish'] && props.errors['publish'])
}
>
<label htmlFor="publish">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>8</Box>
{t('createProject.inputs.publish.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.publish.topHelperText')}
</Typography>
<Select
ref={refs.publish_type_el}
labelId="publish"
id="publish"
name="publish"
className={classes.customInputStyle}
value={
props.values.publish
? props.values.publish.type
: publish_types[0]
? publish_types[0].value
: ''
}
onChange={e => handlePublishFieldChange(e, props)}
onBlur={e => handlePublishFieldBlur(e, props)}
>
{publish_types.map(type => (
<MenuItem key={type.name} value={type.value}>
{t(`createProject.inputs.publish.publishTypes.${type.name}`)}
</MenuItem>
))}
</Select>
<Box
className={clsx(
classes.tagsViewStyle,
common_classes.marginTop1em,
{
[common_classes.displayNone]:
props.values.publish?.type !==
publish_type['Preview'],
},
)}
>
{props.values.publish?.visible_to &&
props.values['publish']['visible_to'].map(
(username, num) =>
username ? (
<Chip
className={classes.customChipStyle}
key={num}
label={username}
onDelete={e =>
handleRemovePublishVisibleTo(
e,
props,
username,
)
}
color="secondary"
variant="outlined"
/>
) : null,
)}
<input
ref={refs.publish_visible_to_el}
className={classes.tagsInputStyle}
name="publish_visible_to"
type="text"
autocomplete="off"
placeholder={`${t(
'createProject.inputs.publish.addUsernames',
)}...`}
onChange={e => {
handleSuggestPublishVisibleTo(
e,
props,
state,
handleSetState,
);
handleSetState(
handleAddPublishVisibleTo(e, props),
);
}}
onBlur={e => {
handleAddPublishVisibleTo(e, props);
}}
/>
<ClickAwayListener
onClickAway={() =>
handleSetState({
publish_visible_to_suggestion_open: false,
publish_visible_to_suggestion: [],
})
}
>
<Box
className={clsx(
classes.tagSuggestionStyle,
!publish_visible_to_suggestion_open
? common_classes.displayNone
: null,
)}
>
{publish_visible_to_suggestion &&
publish_visible_to_suggestion.length > 0 ? (
publish_visible_to_suggestion.map(
(username, index) => (
<Typography
key={index}
color="textPrimary"
className={classes.tagSuggestionTextStyle}
onClick={() => {
clearTimeout(vars.timer.id);
handleSetState(
handleAddPublishVisibleTo(
{
currentTarget: {
value: `${username},`,
},
},
props,
refs.publish_visible_to_el,
),
);
}}
>
{username}
</Typography>
),
)
) : (
<CircularProgress size={30} thickness={3} />
)}
</Box>
</ClickAwayListener>
</Box>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['publish']) ||
(props.touched['publish'] &&
props.errors['publish'] &&
t(
`createProject.inputs.publish.errors.${props.errors['publish']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
primaryButtonStyle
customButtonStyle
fullWidth
>
{!id
? t('createProject.inputs.submit')
: t('createProject.inputs.edit')}
</CustomButton>
</Grid>
</Grid>
<Dialog
PaperProps={{
style: {
backgroundColor: 'transparent',
boxShadow: 'none',
},
}}
open={video_upload_dialog_open}
onClose={async () =>
handleSetState({
...(await handleVideoFieldCancel(refs, props, state)),
video_upload_dialog_open: false,
})
}
aria-labelledby="video upload dialog"
>
<Container
className={clsx(
classes.containerStyle,
classes.videoInputDialogContainerStyle,
)}
>
<Card
className={clsx(
classes.cardStyle,
classes.videoInputDialogCardStyle,
)}
>
<CardActionArea>
<CardContent>
<div
className={
classes.videoInputDialogControlSectionStyle
}
>
<CustomButton
className={
classes.videoInputDialogControlButtonStyle
}
primaryButtonStyle={!select_video_file}
secondaryButtonStyle={select_video_file}
size="medium"
onClick={_ =>
handleSetState({ select_video_file: false })
}
>
<div
className={
classes.videoInputDialogControlButtonUseTextDescStyle
}
>
{t(
'createProject.inputs.video.dialogURLToggle',
)}
</div>
<InsertLinkIcon
className={
classes.videoInputDialogControlButtonUseIconDescStyle
}
/>
</CustomButton>
<CustomButton
className={
classes.videoInputDialogControlButtonStyle
}
primaryButtonStyle={select_video_file}
secondaryButtonStyle={!select_video_file}
size="medium"
onClick={_ =>
handleSetState(
handleSelectVideoFileChecked(
refs.video_file_el.current,
),
)
}
>
<div
className={
classes.videoInputDialogControlButtonUseTextDescStyle
}
>
{t(
'createProject.inputs.video.dialogFileToggle',
)}
</div>
<MovieIcon
className={
classes.videoInputDialogControlButtonUseIconDescStyle
}
/>
</CustomButton>
</div>
<Grid container spacing={1} alignItems="flex-end">
<Grid
item
xs={12}
sm={12}
className={clsx(
common_classes.marginTop1em,
classes.videoInputDialogBodyGridStyle,
)}
>
{!select_video_file ? (
<FormControl
className={clsx(
classes.margin,
classes.textField,
classes.videoInputDialogURLFormControlStyle,
)}
variant="outlined"
size="small"
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="url-input"
>
{t(
'createProject.inputs.video.dialogURLFieldLabel',
)}
</InputLabel>
<OutlinedInput
ref={refs.video_el}
className={classes.customInputStyle}
type="text"
name="url-input"
labelWidth={calculateLabelWidth(
t(
'createProject.inputs.video.dialogURLFieldLabel',
),
document,
)}
placeholder="https://youtube.com/..."
onChange={async e =>
handleSetState(
await handleVideoFieldChange(
e,
refs,
props,
state,
handleSetState,
),
)
}
/>
</FormControl>
) : null}
{select_video_file ? (
<p className={classes.videoFileName}>
{refs.video_file_el.current?.files?.[0]
? refs.video_file_el.current?.files?.[0]
?.name
: t(
'createProject.inputs.video.dialogFileToggle',
)}
</p>
) : null}
<CustomButton
className={
classes.videoInputDialogActionButtonStyle
}
secondaryButtonStyle
variant="outlined"
size="medium"
onClick={async () =>
handleSetState({
...(await handleVideoFieldCancel(
refs,
props,
state,
)),
video_upload_dialog_open: false,
})
}
>
<CloseIcon />
</CustomButton>
<CustomButton
className={
classes.videoInputDialogActionButtonStyle
}
primaryButtonStyle
size="medium"
onClick={async () =>
handleSetState({
...(await handleVideoSelectDone(
refs,
props,
state,
)),
video_upload_dialog_open: false,
})
}
>
<CheckIcon />
</CustomButton>
<input
className={common_classes.displayNone}
ref={refs.video_file_el}
type="file"
accept="video/*"
id="video"
name="video"
onChange={async e => {
handleSetState(
await handleVideoFieldChange(
e,
refs,
props,
state,
handleSetState,
),
);
}}
onBlur={props.handleBlur}
/>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Dialog>
</form>
<Dialog
PaperProps={{
style: {
backgroundColor: 'transparent',
boxShadow: 'none',
},
}}
className={classes.uploadProgressDialogStyle}
open={media_upload.upload_dialog}
aria-labelledby="upload progress dialog"
>
<Box
className={classes.uploadProgressIndicatorContainerStyle}
>
<CircularProgress
className={classes.uploadProgressStyle}
variant="determinate"
size={70}
thickness={6}
value={media_upload.upload_percent}
/>
<Box
top={0}
left={0}
bottom={0}
right={0}
position="absolute"
display="flex"
alignItems="center"
justifyContent="center"
>
<Typography
className={classes.uploadProgressLabelStyle}
variant="caption"
component="div"
>{`${Math.round(
media_upload.upload_percent,
)}%`}</Typography>
</Box>
</Box>
</Dialog>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
}
Example #28
Source File: AddGroupMembers.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function AddGroupMembers
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function AddGroupMembers(props) {
const refs = {
add_group_members_el: React.useRef(null),
drag_drop_el: React.useRef(null),
};
const classes = useStyles();
const common_classes = useCommonStyles();
const [state, setState] = React.useState({
loading: true,
error: null,
csv: null,
upload_dialog: false,
bulk_add_checked: false,
});
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState({ ...state, ...obj });
});
}
};
const { upload_dialog, bulk_add_checked, csv } = state;
const { t } = props;
vars.csv_not_added = !csv;
if (!props.auth.token) {
return <ErrorPage error={t('addGroupMembers.errors.notLoggedIn')} />;
} else if (props.auth.members_count === null) {
return <ErrorPage error={t('addGroupMembers.errors.unauthorized')} />;
} else {
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="project-create-form"
name="create_project"
noValidate="noValidate"
onSubmit={e => handleSubmit(e, state, handleSetState, props)}
>
<Typography
className={classes.titleStyle}
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
>
{t('addGroupMembers.welcomeMsg.primary')}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
className={classes.descStyle}
>
{t('addGroupMembers.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['group_members']) ||
(props.touched['group_members'] &&
props.errors['group_members'])
}
>
<label htmlFor="add_group_members">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
{t('addGroupMembers.inputs.groupMembers.label')}
</Typography>
</label>
<Grid container spacing={1} alignItems="flex-end">
{!bulk_add_checked ? (
<>
<Grid item xs={12} sm={8}>
<Box ref={refs.add_group_members_el}>
{buildGroupMembersNodes({
props,
refs,
classes,
common_classes,
})}
</Box>
</Grid>
<Grid item xs={12} sm={4}>
<CustomButton
variant="outlined"
size="large"
onClick={e => addGroupMembersNode(e, props)}
secondaryButtonStyle
customButtonStyle
fullWidth
>
<AddIcon />{' '}
{t(
'addGroupMembers.inputs.groupMembers.addMore',
)}
</CustomButton>
</Grid>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status &&
props.status['group_members']) ||
(props.touched['group_members'] &&
props.errors['group_members'] &&
t(
`addGroupMembers.inputs.groupMembers.errors.${props.errors['group_members']}`,
))}
</FormHelperText>
</>
) : (
<label
htmlFor="addcsv"
className={classes.addCSVStyles}
>
<Box
className={classes.CSVBoxStyles}
ref={refs.drag_drop_el}
onDragLeave={e => {
refs.drag_drop_el.current.style.border =
'1px dashed rgb(196, 194, 194)';
}}
onDragOver={e => {
e.preventDefault();
refs.drag_drop_el.current.style.border =
'1px solid #878dcd';
}}
onDrop={e =>
handleSetState(handleAddCSV(e, refs))
}
>
<img
src={csvLogo}
alt={
csv
? csv.name
: t(
'addGroupMembers.inputs.groupMembers.addCSV',
)
}
/>
<br />
{csv
? csv.name
: t(
'addGroupMembers.inputs.groupMembers.addCSV',
)}
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status &&
props.status['group_members']) ||
(props.touched['group_members'] &&
props.errors['group_members'] &&
t(
`addGroupMembers.inputs.groupMembers.errors.${props.errors['group_members']}`,
))}
</FormHelperText>
<input
type="file"
accept=".csv"
style={{ display: 'none' }}
id="addcsv"
onChange={e =>
handleSetState({
csv: e.target.files[0],
})
}
/>
</Box>
</label>
)}
</Grid>
</FormControl>
</Grid>
<Grid item xs={12} sm={8}>
<FormControlLabel
className={common_classes.floatLeft}
control={
<Switch
className={classes.bulkAddStyles}
checked={bulk_add_checked}
onChange={e =>
handleSetState(
handleBulkAddCheck(bulk_add_checked),
)
}
/>
}
label={
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
{t('addGroupMembers.inputs.groupMembers.bulkAdd')}
</Typography>
}
/>
</Grid>
<Grid item xs={12} sm={4}>
<CustomButton
variant="contained"
size="large"
type="submit"
primaryButtonStyle
customButtonStyle
fullWidth
className={common_classes.floatRight}
>
{t('addGroupMembers.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Dialog
PaperProps={{
style: {
backgroundColor: 'transparent',
boxShadow: 'none',
overflow: 'hidden',
},
}}
open={upload_dialog}
aria-label={t('addGroupMembers.ariaLabels.submitting')}
>
<Box position="relative" display="inline-flex">
<CircularProgress
className={classes.uploadProgressStyle}
size={70}
thickness={6}
/>
</Box>
</Dialog>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
}
Example #29
Source File: GrowerTooltip.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 4 votes |
GrowerTooltip = ({ grower, growerClick }) => {
const classes = useStyle();
const matches = grower.imageUrl?.match(/\/\/(.*?)\/(.*)/);
const useStyles = makeStyles(() => ({
box: {
display: 'flex',
marginTop: '2px',
},
label: {
marginLeft: '12px',
},
}));
const growerToolTipStyles = useStyles();
return (
<Box>
<Box style={{ width: '160px', display: 'block' }}>
<Card
style={{
display: 'flex',
justifyContent: 'space-around',
flexDirection: 'column',
alignItems: 'center',
}}
onClick={() => growerClick(grower)}
>
<CardActionArea>
<Box style={{ display: 'flex', margin: '4px' }}>
<Box
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
margin: '2px',
}}
>
{matches?.length > 1 ? (
<OptimizedImage
rotation={grower.imageRotation}
src={grower.imageUrl}
style={{
height: '24px',
width: '24px',
}}
/>
) : (
<Person
className={classes.person}
style={{
height: '24px',
width: '24px',
}}
/>
)}
</Box>
<Box>
<Typography className={growerToolTipStyles.label}>
{grower.firstName} {grower.lastName}
</Typography>
</Box>
</Box>
<Divider
variant="middle"
sx={{
marginBottom: '2px',
marginTop: '4px',
}}
/>
<Box
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
margin: '0 4px 0 4px',
}}
>
{grower.email && (
<Box className={growerToolTipStyles.box}>
<EmailIcon color="primary" />
<Typography className={growerToolTipStyles.label}>
{grower.email}
</Typography>
</Box>
)}
{(grower.organizaton || grower.organizationId) && (
<Box className={growerToolTipStyles.box}>
<OrgIcon color="primary" />
<Box className={growerToolTipStyles.label}>
<GrowerOrganization
organizationName={grower.organization}
assignedOrganizationId={grower.organizationId}
compact={true}
/>
</Box>
</Box>
)}
{grower.phone && (
<Box className={growerToolTipStyles.box}>
<PhoneIcon color="primary" />
<Typography className={growerToolTipStyles.label}>
{grower.phone}
</Typography>
</Box>
)}
</Box>
</CardActionArea>
</Card>
</Box>
</Box>
);
}