I have written the following website:https://konekto-hgol6b5mz.now.sh
If you quickly click through the onboarding and settings you can see that I have one screen with on "Direct SOS" button. However, its function is not executed and thus I do not get redirected. Here you can see the class concerning that:
import React from 'react';
import { Button, Grid } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
import AppContext from '../utils/AppContext';
const styles = theme => ({
container: {
alignItems: 'center',
// background: 'white',
border: 'black',
'border-width': 'medium',
'margin-top': '80px',
background: 'rgba(255, 255, 255, 0.8)',
'border-radius': '20px'
},
item: {
// background: 'red',
width: '100%',
//background: 'white',
'text-align': 'center',
'border-radius': '5px',
'margin-top': '10px'
},
sosbutton: {
background: 'red',
'text-align': 'center',
'margin-top': '30px',
height: '80%',
width: '100%'
}
});
class Landingpage extends React.Component {
static contextType = AppContext;
constructor(props) {
super(props);
this.classes = props.classes;
this.state = {};
this.handleDirectSOS = this.handleDirectSOS.bind(this);
}
componentDidMount() {
console.log(this.context);
if (this.context.onBoardingStatus === false) {
console.log('IN IF');
this.props.history.push('/onboarding');
}
}
handleDirectSOS() {
console.log('direct SOS');
this.props.history.push('/emergency_sent');
}
render() {
console.log('direct SOS');
return (
<Header title="Send out SOS" />
<Grid
container
className={this.classes.container}
direction="column"
spacing={2}
>
<Grid
item
sm={12}
className={(this.classes.item, this.classes.forwardbutton)}
>
<Button
className={this.classes.sosbutton}
name="type_person"
value="1"
onClick={this.props.handleDirectSOS}
>
Direct SOS
</Button>
</Grid>
</Grid>
);
}
}
export default withStyles(styles)(Landingpage);
index.js:1375 Warning: Can't perform a React state update on an
unmounted component. This is a no-op, but it indicates a memory leak
in your application. To fix, cancel all subscriptions and asynchronous
tasks in the componentWillUnmount method.
in Settings (created by WithStyles(Settings))
in WithStyles(Settings) (created by Context.Consumer)
This might be associated with the Settings file but I have no idea what might be the reason. Here you can see the settings file:
import React from 'react';
import axios from 'axios';
import {
Grid,
Box,
Container,
Typography,
Button,
TextField
} from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
import Header from '../Layout/Header';
import CONST from '../utils/Constants';
const CssTextField = withStyles({
root: {
'& label.Mui-focused': {
color: 'green'
},
'& .MuiInput-underline:after': {
borderBottomColor: 'green'
},
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'red'
},
'&:hover fieldset': {
borderColor: 'yellow'
},
'&.Mui-focused fieldset': {
borderColor: 'green'
}
}
},
layout: {
width: '100%'
}
})(TextField);
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
width: '100%'
},
title: {
'text-align': 'center'
},
textfield: {
'margin-top': theme.spacing(1),
'margin-bottom': theme.spacing(2)
}
});
//const classes = useStyles();
class Settings extends React.Component {
constructor(props) {
super(props);
//const { classes } = props;
this.classes = props.classes;
this.state = {};
this.onChangeText = this.onChangeText.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChangeText(e) {
console.log('text has changed.');
const key = e.target.id;
const value = e.target.value;
let state_obj = {};
state_obj[key] = value;
this.setState(state_obj);
}
onSubmit(e) {
console.log('Submit button pressed.');
axios
.post(CONST.URL + 'user/update', {
id: 1,
data: this.state
})
.then(res => {
console.log(res);
console.log(res.data);
})
.catch(err => {
console.log(err);
});
this.props.history.push('/');
}
componentDidMount() {
console.log('Component did mount.');
axios
.get(CONST.URL + 'user', {
params: { id: 1 }
})
.then(resp => {
// console.log(resp);
const data = resp.data.data;
this.setState(data);
console.log(this.state.fullname);
})
.catch(function(error) {
console.log(error);
})
.then(function() {
// always executed
});
}
render() {
return (
<React.Fragment>
<Header title="Settings" BackButton="true" />
<Container component="main" maxWidth="sm">
{/* <Typography variant="h4" align="center" gutterBottom="true">
Settings
</Typography> */}
<Box className={this.classes.textfield}>
<Grid
container
direction="column"
justify="flex-end"
alignItems="left"
item
xs
>
<Typography variant="h6">Personal Information</Typography>
<CssTextField
id="fullname"
label="Fullname"
onChange={this.onChangeText}
value={this.state.fullname}
/>
<CssTextField
id="birthday"
label="Birthday"
onChange={this.onChangeText}
value={this.state.birthday}
/>
<CssTextField
id="address"
label="Home address"
onChange={this.onChangeText}
value={this.state.address}
/>
</Grid>
</Box>
<Box className={this.classes.textfield}>
<Grid
container
direction="column"
justify="flex-end"
alignItems="left"
item
xs
>
<Typography variant="h6">Health information</Typography>
<CssTextField
id="allergies"
label="Allergies"
onChange={this.onChangeText}
value={this.state.allergies}
/>
<CssTextField
id="past_injuries"
label="Past injuries"
onChange={this.onChangeText}
value={this.state.past_injuries}
/>
</Grid>
</Box>
<Box className={this.classes.textfield}>
<Grid
container
direction="column"
justify="flex-end"
alignItems="left"
item
xs
>
<Typography variant="h6">Contact information</Typography>
<CssTextField
id="fullname_relative_1"
label="Fullname relative 1"
onChange={this.onChangeText}
value={this.state.fullname_relative_1}
/>
<CssTextField
id="phone_number_relative_1"
label="Phone number relative 1"
onChange={this.onChangeText}
value={this.state.phone_number_relative_1}
/>
<CssTextField
id="fullname_relative_2"
label="Fullname relative 2"
onChange={this.onChangeText}
value={this.state.fullname_relative_2}
/>
<CssTextField
id="phone_number_relative_2"
label="Phone number relative 2"
onChange={this.onChangeText}
value={this.state.phone_number_relative_2}
/>
</Grid>
</Box>
<Box>
<Grid
container
direction="column"
justify="flex-end"
alignItems="left"
item
xs
>
<Button
variant="contained"
className={this.classes.button}
onClick={this.onSubmit}
>
Save
</Button>
<br />
{/* <Button
variant="contained"
className={this.classes.button}
onClick={() => {
this.props.history.push('/');
}}
>
Cancel emergency
</Button> */}
{/* <br /> */}
<Button
variant="contained"
className={this.classes.button}
onClick={() => {
this.props.history.push('/onboarding_reset');
}}
>
Reset App
</Button>
{/* <br />
<Button
variant="contained"
className={this.classes.button}
onClick={() => {
this.props.history.push('/Signin');
}}
>
Signin
</Button> */}
</Grid>
</Box>
</Container>
</React.Fragment>
);
}
}
export default withStyles(styles)(Settings);
I would really appreciate your help!
I think you have two separate issues.
The button press issue is because you're calling onClick={this.props.handleDirectSOS} instead of onClick={this.handleDirectSOS}
The error you're seeing is because of the line this.setState(data);, you need to wrap that or cancel the call if the component is unmounted. There's quite a few articles on it like Is there a way to check if the react component is unmounted?
Related
I am working on a next.js theme. I want to navigate to the "dashboards/analytics" page upon successfull authentication. we are using JWT based authentication. Authentication is done. but i could not navigate to the dashboards page.I really could not understand what is wrong in this code. Also i am getting a "Password is required error" even after passing a value. but it is not effecting the login function(i was able to login though, with the same password value). i tried commenting out the "yup resolver" code. but it didnt show any error when i clicked login button without a password(but login was not successfull). Kindly someone help me to fix these issues.
AuthContext.js file is as shown below
// ** React Imports
import { createContext, useEffect, useState } from 'react'
// ** Next Import
import {useRouter} from 'next/router'
// ** Axios
import axios from 'axios'
// ** Config
import authConfig from 'src/configs/auth'
// ** Defaults
const defaultProvider={
user: null,
loading: true,
setUser: () => null,
setLoading: () => Boolean,
isInitialized: false,
login: (token) => {},
logout: () => Promise.resolve(),
setIsInitialized: () => Boolean,
register: () => Promise.resolve(),
token:'',
};
const AuthContext = createContext(defaultProvider)
const AuthProvider = ({ children }) => {
// ** States
const [user, setUser] = useState(defaultProvider.user)
const [loading, setLoading] = useState(defaultProvider.loading)
const [isInitialized, setIsInitialized] = useState(defaultProvider.isInitialized)
const [token,setToken]=useState(defaultProvider.token)
// ** Hooks
const router = useRouter()
useEffect(() => {
const initAuth = async () => {
setIsInitialized(true)
const storedToken = window.localStorage.getItem(authConfig.storageTokenKeyName)
if (storedToken) {
setLoading(true)
await axios
.get(authConfig.meEndpoint, {
headers: {
Authorization: storedToken
}
})
.then(async response => {
setLoading(false)
setUser({ ...response.data.userData })
})
} else {
setLoading(false)
}
}
initAuth()
}, [])
const handleLogin=(token)=>{
setToken(token);
router.push('/dashboards/analytics');
}
const handleLogout = () => {
setUser(null)
setIsInitialized(false)
window.localStorage.removeItem('userData')
window.localStorage.removeItem(authConfig.storageTokenKeyName)
router.push('/login')
}
const handleRegister = (params, errorCallback) => {
axios
.post(authConfig.registerEndpoint, params)
.then(res => {
if (res.data.error) {
if (errorCallback) errorCallback(res.data.error)
} else {
handleLogin({ email: params.email, password: params.password })
}
})
.catch(err => (errorCallback ? errorCallback(err) : null))
}
const values = {
user,
loading,
setUser,
setLoading,
isInitialized,
setIsInitialized,
login: handleLogin,
logout: handleLogout,
register: handleRegister,
token
}
return <AuthContext.Provider value={values}>{children}</AuthContext.Provider>
}
export { AuthContext, AuthProvider }
Login/index.js file is as shown below,
// ** React Imports
import { useState, useContext } from 'react'
import {useRouter} from 'next/router'
// ** Next Imports
import Link from 'next/link'
import axios from 'axios'
// ** MUI Components
import Button from '#mui/material/Button'
import Divider from '#mui/material/Divider'
import Checkbox from '#mui/material/Checkbox'
import TextField from '#mui/material/TextField'
import InputLabel from '#mui/material/InputLabel'
import IconButton from '#mui/material/IconButton'
import Box from '#mui/material/Box'
import FormControl from '#mui/material/FormControl'
import useMediaQuery from '#mui/material/useMediaQuery'
import OutlinedInput from '#mui/material/OutlinedInput'
import { styled, useTheme } from '#mui/material/styles'
import FormHelperText from '#mui/material/FormHelperText'
import InputAdornment from '#mui/material/InputAdornment'
import Typography from '#mui/material/Typography'
import MuiFormControlLabel from '#mui/material/FormControlLabel'
// ** Icons Imports
import Google from 'mdi-material-ui/Google'
import Github from 'mdi-material-ui/Github'
import Twitter from 'mdi-material-ui/Twitter'
import Facebook from 'mdi-material-ui/Facebook'
import EyeOutline from 'mdi-material-ui/EyeOutline'
import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'
// ** Third Party Imports
import * as yup from 'yup'
import { useForm, Controller } from 'react-hook-form'
import { yupResolver } from '#hookform/resolvers/yup'
// ** Hooks
import { useAuth } from 'src/hooks/useAuth'
import useBgColor from 'src/#core/hooks/useBgColor'
import { useSettings } from 'src/#core/hooks/useSettings'
// ** Configs
import themeConfig from 'src/configs/themeConfig'
// ** Layout Import
import BlankLayout from 'src/#core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrationsV2 from 'src/views/pages/auth/FooterIllustrationsV2'
import { AuthContext } from 'src/context/AuthContext'
// ** Styled Components
const LoginIllustrationWrapper = styled(Box)(({ theme }) => ({
padding: theme.spacing(20),
paddingRight: '0 !important',
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(10)
}
}))
const LoginIllustration = styled('img')(({ theme }) => ({
maxWidth: '48rem',
[theme.breakpoints.down('lg')]: {
maxWidth: '35rem'
}
}))
const RightWrapper = styled(Box)(({ theme }) => ({
width: '100%',
[theme.breakpoints.up('md')]: {
maxWidth: 450
}
}))
const BoxWrapper = styled(Box)(({ theme }) => ({
[theme.breakpoints.down('xl')]: {
width: '100%'
},
[theme.breakpoints.down('md')]: {
maxWidth: 400
}
}))
const TypographyStyled = styled(Typography)(({ theme }) => ({
fontWeight: 600,
marginBottom: theme.spacing(1.5),
[theme.breakpoints.down('md')]: { marginTop: theme.spacing(8) }
}))
const LinkStyled = styled('a')(({ theme }) => ({
fontSize: '0.875rem',
textDecoration: 'none',
color: theme.palette.primary.main
}))
const FormControlLabel = styled(MuiFormControlLabel)(({ theme }) => ({
'& .MuiFormControlLabel-label': {
fontSize: '0.875rem',
color: theme.palette.text.secondary
}
}))
const schema = yup.object().shape({
username: yup.string().required(),
password: yup.string().min(5 ).required()
})
const LoginPage = () => {
const [showPassword, setShowPassword] = useState(false)
const [username,setUsername]=useState('');
const [password,setPassword]=useState('');
//const [errMsg,setErrMsg]=useState('');
// ** Hooks
const auth = useContext(AuthContext);
const theme = useTheme()
const router=useRouter();
const bgClasses = useBgColor()
const {
settings: { skin }
} = useSettings()
const {
control,
setError,
//handleSubmit,
formState: { errors }
} = useForm({
//defaultValues,
mode: 'onBlur',
resolver: yupResolver(schema)
})
// ** Vars
const hidden = useMediaQuery(theme.breakpoints.down('md'))
const handleSubmit=(e)=>{
e.preventDefault();
fetch(
'url',
{
method:'POST',
body:JSON.stringify({
username:username,
password:password,
}),
headers: {
'Content-Type':'application/json',
'X-Correlation-ID':'123456',
'Source-ID':'abc123',
}
}).then(res =>{
if(res.ok){
return res.json();
}
else{
return res.json().then(data=> {
let errorMessage="Authentication Failed";
throw new Error(errorMessage);
});
}
}).then(data=>{
auth.login(data.response.accessToken);
}).catch(err=>{
alert(err.message);
});
}
return (
<Box className='content-right'>
{!hidden ? (
<Box sx={{ flex: 1, display: 'flex', position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
<LoginIllustrationWrapper>
<LoginIllustration
alt='login-illustration'
src={`/images/pages/auth-v2-login-illustration-${theme.palette.mode}.png`}
/>
</LoginIllustrationWrapper>
<FooterIllustrationsV2 />
</Box>
) : null}
<RightWrapper sx={skin === 'bordered' && !hidden ? { borderLeft: `1px solid ${theme.palette.divider}` } : {}}>
<Box
sx={{
p: 12,
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'background.paper'
}}
>
<BoxWrapper>
<Box
sx={{
top: 30,
left: 40,
display: 'flex',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Typography
variant='h6'
sx={{
ml: 3,
lineHeight: 1,
fontWeight: 600,
textTransform: 'uppercase',
fontSize: '1.5rem !important'
}}
>
{themeConfig.templateName}
</Typography>
</Box>
<Box sx={{ mb: 6 }}>
<TypographyStyled variant='h5'>Welcome to {themeConfig.templateName}! 👋🏻</TypographyStyled>
<Typography variant='body2'>Please sign-in to your account and start the adventure</Typography>
</Box>
<form noValidate autoComplete='off' onSubmit={handleSubmit}>
<FormControl fullWidth sx={{ mb: 4 }}>
<Controller
name='Username'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<TextField
autoFocus
label='Username'
value={value}
onBlur={onBlur}
//onChange={onChange}
onChange={(e)=> setUsername(e.target.value)}
error={Boolean(errors.user)}
// placeholder='admin#materio.com'
/>
)}
/>
{errors.user && <FormHelperText sx={{ color: 'error.main' }}>{errors.user.message}</FormHelperText>}
</FormControl>
<FormControl fullWidth>
<InputLabel htmlFor='auth-login-v2-password' error={Boolean(errors.password)}>
Password
</InputLabel>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field: { value,onChange, onBlur } }) => (
<OutlinedInput
value={value}
onBlur={onBlur}
label='Password'
//onChange={onChange}
onChange={(e)=> setPassword(e.target.value)}
id='auth-login-v2-password'
error={Boolean(errors.password)}
type={showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onMouseDown={e => e.preventDefault()}
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOutline /> : <EyeOffOutline />}
</IconButton>
</InputAdornment>
}
/>
)}
/>
{errors.password && (
<FormHelperText sx={{ color: 'error.main' }} id=''>
{errors.password.message}
</FormHelperText>
)}
</FormControl>
<Box
sx={{ mb: 4, display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}
>
<FormControlLabel control={<Checkbox />} label='Remember Me' />
<Link passHref href='/forgot-password'>
<LinkStyled>Forgot Password?</LinkStyled>
</Link>
</Box>
<Button fullWidth size='large' type='submit' variant='contained' sx={{ marginBottom: 7 }}>
Login
</Button>
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}>
<Typography variant='body2' sx={{ marginRight: 2 }}>
New on our platform?
</Typography>
<Typography variant='body2'>
<Link passHref href='/register'>
<LinkStyled>Create an account</LinkStyled>
</Link>
</Typography>
</Box>
<Divider sx={{ my: 5 }}>or</Divider>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Facebook sx={{ color: '#497ce2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Twitter sx={{ color: '#1da1f2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Github
sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }}
/>
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Google sx={{ color: '#db4437' }} />
</IconButton>
</Link>
</Box>
</form>
</BoxWrapper>
</Box>
</RightWrapper>
</Box>
)
}
LoginPage.getLayout = page => <BlankLayout>{page}</BlankLayout>
LoginPage.guestGuard = true
export default LoginPage
Anybody has experience or idea how to implement an edit photo feature like in LinkedIn edit photo or background in React.js?
Here's the functionalities I wanted.
Can upload image
Show image
Edit uploaded image
zoom-in/zoom-out
rotate
delete
Use react-cropper package which is a react version of cropper.js. You can perform all the functionalities you need using that. There are some changes required in this code also add rotate functionality from cropper.js.
import React, { useState, useRef } from "react";
import Cropper from "react-cropper";
import Button from "#material-ui/core/Button";
import "cropperjs/dist/cropper.css";
import Grid from '#material-ui/core/Grid';
import IconButton from '#material-ui/core/IconButton';
import Tooltip from '#material-ui/core/Tooltip';
import CheckCircleIcon from '#material-ui/icons/CheckCircle';
import ArrowForwardIcon from '#material-ui/icons/ArrowForward';
import ArrowBackIcon from '#material-ui/icons/ArrowBack';
import ArrowDownwardIcon from '#material-ui/icons/ArrowDownward';
import ArrowUpwardIcon from '#material-ui/icons/ArrowUpward';
import CancelIcon from '#material-ui/icons/Cancel';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
button: {
backgroundColor: "#2774b8",
'&:hover': {
backgroundColor: "#2774b8",
}
},
toolsCtr: {
display: 'flex',
padding: '0.5rem'
},
tooltip: {
marginRight: '0.5rem'
},
icnBtn: {
padding: '8px',
borderRadius: '3px',
backgroundColor: '#f0f8ff'
},
icn: {
fontSize: '1.5rem',
color: '#2774b8'
},
cropperCtr: {
border: '2px solid #d9e5f0'
}
}))
export default function Crop(props) {
const cropperRef = useRef();
const classes = useStyles();
const [uploadedImg, setUploadedImg] = useState(props && props.image)
const [croppedLiveUrl, setCoppedLiveUrl] = useState("");
const [croppedData, setCoppedData] = useState({ url: "", data: {} });
const selForProcessing = () => {
props.useImage(croppedLiveUrl);
}
const _onMoveCropBox = () => {
if (null !== cropperRef.current) {
setCoppedLiveUrl(cropperRef.current.cropper.getCroppedCanvas().toDataURL());
setCoppedData({ url: "", data: {} });
}
};
const _onMoveImageLeft = () => {
if (null !== cropperRef.current) {
cropperRef.current.cropper.move(-10, 0);
}
}
const _onMoveImageRight = () => {
if (null !== cropperRef.current) {
cropperRef.current.cropper.move(10, 0);
}
}
const _onMoveImageTop = () => {
if (null !== cropperRef.current) {
cropperRef.current.cropper.move(0, -10);
}
}
const _onMoveImageBottom = () => {
if (null !== cropperRef.current) {
cropperRef.current.cropper.move(0, 10);
}
}
return (
<React.Fragment>
<div className={classes.cropperCtr}>
<Grid container spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={12}>
<Cropper
ref={cropperRef}
src={uploadedImg}
style={{ height: 400, width: "100%", overflow:
'scroll' }}
guides={false}
crop={() => { _onMoveCropBox() }}
crossOrigin={"true"}
autoCrop={false}
movable={true}
move={() => { _onMoveImageTop() }}
/>
</Grid>
</Grid>
<div className={classes.toolsCtr}>
<Tooltip title="Use Selection" aria-label="use" className=.
{classes.tooltip}>
<IconButton className={classes.icnBtn} onClick={() => {
selForProcessing()
}}>
<CheckCircleIcon className={classes.icn} />
</IconButton>
</Tooltip>
<Tooltip title="Move Left" aria-label="left" className=
{classes.tooltip}>
<IconButton className={classes.icnBtn} onClick={() => {
_onMoveImageLeft()
}}>
<ArrowBackIcon className={classes.icn} />
</IconButton>
</Tooltip>
<Tooltip title="Move Right" aria-label="right" className=
{classes.tooltip}>
<IconButton className={classes.icnBtn} onClick={() => {
_onMoveImageRight()
}}>
<ArrowForwardIcon className={classes.icn} />
</IconButton>
</Tooltip>
<Tooltip title="Move Top" aria-label="top" className=.
{classes.tooltip}>
<IconButton className={classes.icnBtn} onClick={() => {
_onMoveImageTop()
}}>
<ArrowUpwardIcon className={classes.icn} />
</IconButton>
</Tooltip>
<Tooltip title="Move Down" aria-label="down" className={classes.tooltip}>
<IconButton className={classes.icnBtn} onClick={() => {
_onMoveImageBottom()
}}>
<ArrowDownwardIcon className={classes.icn} />
</IconButton>
</Tooltip>
</div>
</div>
</React.Fragment >
);
}
I'm using Material UI's "Dialog" component to open a separate mini-form upon a button click event. However, the Dialog box is actually opening up on page render. And I'm also unable to close it by clicking the box's "Cancel" button. Not to mention, whenever I attempt to type in anything into either of the Dialog box's textfields: my client crashes with an error of "TypeError: this.setState is not a function" for the line of: onChange={(e) => this.setState({ playlistName: e.target.value })}
import React, { Component } from 'react';
import { ThemeProvider } from '#material-ui/core';
import Grid from '#material-ui/core/Grid';
import Button from '#material-ui/core/Button';
import FormLabel from '#material-ui/core/FormLabel';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import TextField from '#material-ui/core/TextField';
import { makeStyles, withStyles } from '#material-ui/core/styles';
import { DataGrid } from '#material-ui/data-grid';
import Footer from './Footer';
import theme from '../../styles/MuiTheme';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemAvatar from '#material-ui/core/ListItemAvatar';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import FormGroup from '#material-ui/core/FormGroup';
import Checkbox from '#material-ui/core/Checkbox'
import Typography from '#material-ui/core/Typography';
import DeleteIcon from '#material-ui/icons/Delete';
import EditIcon from '#material-ui/icons/Edit';
import ListItemSecondaryAction from '#material-ui/core/ListItemSecondaryAction';
import QueueMusicIcon from '#material-ui/icons/QueueMusic';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
const styles = theme => ({
root: {
flexGrow: 1,
'& > *': {
margin: theme.spacing(1),
width: '25ch',
maxWidth: 752
},
control: {
padding: theme.spacing(2)
},
button: {
primary: "#1DB954"
},
listAllPlaylists: {
backgroundColor: theme.palette.background.paper,
overflow: "auto",
maxHeight: "10"
},
title: {
margin: theme.spacing(4, 0, 2)
}
}
});
function generate(element) {
return [0].map((value) =>
React.cloneElement(element, {
key: value
}),
);
}
class EditPlaylistDetails extends Component {
constructor(props) {
super(props);
this.state = {
artist: '',
album: '',
song: '',
playlistName: '',
description: '',
playlistData: [],
allPlaylists: [],
open: false,
secondary: false
}
// this.displayExistingPlaylists = this.displayExistingPlaylists.bind(this);
// this.displayLivePlaylistData = this.displayLivePlaylistData.bind(this);
this.editModal = this.editModal.bind(this)
this.handlePlaylistDelete = this.handlePlaylistDelete.bind(this)
this.handlePlaylistEdit = this.handlePlaylistEdit.bind(this)
this.handleClickOpen = this.handleClickOpen.bind(this)
this.handleClose = this.handleClose.bind(this)
};
handleSecondary = () => {
this.setState({ secondary: true });
};
// handleDense = () => {
// this.setState({ dense: true });
// };
componentDidMount() {
fetch('http://localhost:5040/playlist/', {
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
}).then((response) => response.json())
.then((res) => {
console.log(res);
return res;
}).then((res) => {
this.setState({
allPlaylists: res,
playlistData: res
})
})
.catch((err) => { console.log(err) })
};
handlePlaylistDelete(playlistDeleteId, userId) {
console.log(playlistDeleteId)
fetch(`http://localhost:5040/playlist/delete/${playlistDeleteId}`, {
method: 'DELETE',
body: JSON.stringify({
playlist: {
playlistId: this.props.playlistIdProp,
playlistName: this.state.playlistName,
description: this.state.description
}
}),
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
})
.then(res => res.json())
.catch(err => console.log(err))
};
handlePlaylistEdit(playlistUpdateId) {
playlistUpdateId.preventDefault();
fetch(`http://localhost:5040/playlist/update/${playlistUpdateId}`, {
method: 'PUT',
body: JSON.stringify({
playlist: {
playlistId: this.props.playlistIdProp,
playlistName: this.state.playlistName,
description: this.state.description
}
}),
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
}).then(
(response) => response.json()
).then((allPlaylistsResponse) => {
console.log(this.state.open)
});
};
editModal(playlistId) {
return (
<div>
<form onSubmit={() => this.handlePlaylistEdit(playlistId)} noValidate autoComplete="off" style={{ marginTop: '2rem' }}>
<TextField size="small" id="outlined-basic standard-size-small" label="Artist / Band" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ artist: e.target.value })} value={this.state.artist} />
<TextField size="small" id="outlined-basic standard-size-small" label="Album" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ album: e.target.value })} value={this.state.album} />
<TextField size="small" id="outlined-basic standard-size-small" label="Song" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ song: e.target.value })} value={this.state.song} />
<br />
<Button variant="contained" color="primary" type="submit">Add Info to Playlist</Button>
</form>
</div>
)
};
handleClickOpen() {
this.setState = ({
open: true
})
};
handleClose() {
this.setState = ({
open: false
})
};
render() {
const { classes } = this.props;
return (
<ThemeProvider theme={theme}>
<div style={{ width: '100%', marginTop: '80px' }}>
<h1>View / Edit Your Created Playlists:</h1>
{/* <div >
{this.displayExistingPlaylists()}
</div> */}
<Grid container direction="column" alignContent="center" spacing={2} className={this.props.classes.root}>
<Grid item xs={12} md={6}>
<div style={{ textAlign: "-webkit-center", maxHeight: 400, overflow: 'auto' }}>
{this.state.allPlaylists.map((allPlaylistsCreated, index) => {
console.log(this.state.allPlaylists)
console.log(allPlaylistsCreated)
const { classes } = this.props;
return (
<Grid key={index} item xs={12} md={6} style={{ maxHeight: '100px', overflow: 'auto', textAlign: "center" }}>
<div className={classes.listAllPlaylists}>
<List>
{generate(
<ListItem>
<ListItemAvatar>
<Avatar>
<QueueMusicIcon key={index} style={{ color: "#191414" }} />
</Avatar>
</ListItemAvatar>
<ListItemText
key={index}
primary={allPlaylistsCreated.playlistName}
secondary={allPlaylistsCreated.description}
style={{ color: "white" }}
/>
<ListItemSecondaryAction>
<IconButton edge="start" aria-label="edit">
<EditIcon key={index} style={{ color: "#1DB954" }} onClick={this.handleClickOpen(allPlaylistsCreated.id)} />
</IconButton>
<IconButton edge="end" aria-label="delete">
<DeleteIcon key={index} style={{ color: "red" }} onClick={() => this.handlePlaylistDelete(allPlaylistsCreated.id, allPlaylistsCreated.userId)} />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
)}
</List>
</div>
</Grid>
)
})}
</div>
</Grid>
</Grid>
<form onSubmit={this.handlePlaylistEdit}>
<Dialog open={this.handleClickOpen} onClose={this.handleClose}>
<DialogTitle>Update Playlist Details:</DialogTitle>
<DialogContent>
<DialogContentText>
You may update your playlist information below:
</DialogContentText>
<TextField
margin='dense'
id='playlistName'
label='Playlist Name:'
fullWidth
onChange={(e) => this.setState({ playlistName: e.target.value })}
value={this.state.playlistName}
required
/>
<br />
<TextField
margin='dense'
id='description'
label='Description:'
fullWidth
onChange={(e) => this.setState({ description: e.target.value })}
value={this.state.description}
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color='primary'>
Cancel
</Button>
<Button onClick={this.handlePlaylistEdit} color='primary'>
Update Playlist
</Button>
</DialogActions>
</Dialog>
</form>
</div>
</ThemeProvider >
)
}
}
export default withStyles(styles, { withTheme: true })(EditPlaylistDetails);
syntax is wrong for setState
handleClickOpen() {
this.setState ({
open: true
})
}
handleClose() {
this.setState({
open: false
})
}
also correct below open value binding to {this.state.open}
<Dialog open={this.state.open} .... />
You are passing something for handleClickOpen() method, but not accepting any parameter in function definition.
<EditIcon key={index} style={{ color: "#1DB954" }} onClick={this.handleClickOpen(**allPlaylistsCreated.id**)} />
I want to change the background colour of the options inside an Autocomplete component, and the closest I can get is by using the renderOption prop.
The problem is that I can't figure out how to iterate (using map()) the options that I have in my state.
What I would like to do is something like
{state.myOptions.map( option => {
// here I would like to call renderOption = .....
}
Inside the <Autocomplete/> component
Is it possible to implement something like this or is there a well defined manner to do it?
EDIT
This is the component
import React, { useEffect } from 'react'
import { useForm, Form } from './hooks/useForm'
import EventIcon from '#material-ui/icons/Event';
import { makeStyles, TextField, Typography } from '#material-ui/core'
import CustomTextField from './inputs/CustomTextField';
import { Autocomplete } from '#material-ui/lab';
import { connect } from 'react-redux'
const EventForm = (props) => {
// Redux
const { family } = props
// React
const initialState = {
email: "",
password: "",
errors: {
email: "",
password: ""
},
familyMembers: ["rgeg"]
}
const { state, handleOnChange, setState } = useForm(initialState)
useEffect(() => {
family && state.familyMembers !== family.members && setState({
...state,
familyMembers: family.members
})
})
// Material UI
const useStyles = makeStyles(theme => (
{
message: {
marginTop: theme.spacing(3)
},
icon: {
backgroundColor: "lightgrey",
padding: "10px",
borderRadius: "50px",
border: "2px solid #3F51B5",
marginBottom: theme.spacing(1)
},
typography: {
marginBottom: theme.spacing(1),
marginTop: theme.spacing(4)
},
customTextField: {
marginTop: theme.spacing(0)
},
dateTimeWrapper: {
marginTop: theme.spacing(4)
}
}
))
const classes = useStyles()
return (
<>
<div>WORK IN PROGRESS...</div>
<br />
<br />
<EventIcon className={classes.icon} />
<Form
title="Add new event"
>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a title for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Title"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a location for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Location"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Which member/s of the family is/are attending
</Typography>
<Autocomplete
multiple
id="tags-outlined"
options={state.familyMembers}
getOptionLabel={(option) => option.name}
// defaultValue={[familyMembers[0]]}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Members Attending"
placeholder="Family Member"
/>
)}
/>
</Form>
</>
);
}
// Redux
const mapStateToProps = (state) => {
return {
family: state.auth.family
}
}
export default connect(mapStateToProps)(EventForm);
If you only want to override the color of the option you can do it by overriding it's styles. No need to make custom option rendering function.
Above is the example of how can you achieve that.
import React, { useEffect } from 'react'
import { useForm, Form } from './hooks/useForm'
import EventIcon from '#material-ui/icons/Event';
import { makeStyles, TextField, Typography } from '#material-ui/core'
import CustomTextField from './inputs/CustomTextField';
import { Autocomplete } from '#material-ui/lab';
import { connect } from 'react-redux'
const EventForm = (props) => {
// Redux
const { family } = props
// React
const initialState = {
email: "",
password: "",
errors: {
email: "",
password: ""
},
familyMembers: ["rgeg"]
}
const { state, handleOnChange, setState } = useForm(initialState)
useEffect(() => {
family && state.familyMembers !== family.members && setState({
...state,
familyMembers: family.members
})
})
// Material UI
const useStyles = makeStyles(theme => (
{
message: {
marginTop: theme.spacing(3)
},
icon: {
backgroundColor: "lightgrey",
padding: "10px",
borderRadius: "50px",
border: "2px solid #3F51B5",
marginBottom: theme.spacing(1)
},
typography: {
marginBottom: theme.spacing(1),
marginTop: theme.spacing(4)
},
customTextField: {
marginTop: theme.spacing(0)
},
dateTimeWrapper: {
marginTop: theme.spacing(4)
},
option: {
backgroundColor: 'red'
}
}
))
const classes = useStyles()
return (
<>
<div>WORK IN PROGRESS...</div>
<br />
<br />
<EventIcon className={classes.icon} />
<Form
title="Add new event"
>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a title for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Title"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a location for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Location"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Which member/s of the family is/are attending
</Typography>
<Autocomplete
multiple
id="tags-outlined"
classes={{
option: classes.option
}}
options={state.familyMembers}
getOptionLabel={(option) => option.name}
// defaultValue={[familyMembers[0]]}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Members Attending"
placeholder="Family Member"
/>
)}
/>
</Form>
</>
);
}
// Redux
const mapStateToProps = (state) => {
return {
family: state.auth.family
}
}
export default connect(mapStateToProps)(EventForm);
Wow, this took a while but the solution seems to use 'renderTags' algong with
here is the exact solution
import React, { useEffect } from 'react'
import { useForm, Form } from './hooks/useForm'
import EventIcon from '#material-ui/icons/Event';
import { makeStyles, TextField, Typography } from '#material-ui/core'
import CustomTextField from './inputs/CustomTextField';
import { Autocomplete } from '#material-ui/lab';
import { connect } from 'react-redux'
import Chip from '#material-ui/core/Chip';
import getColorvalue from './outputs/ColorValues'
const EventForm = (props) => {
// Redux
const { family } = props
// React
const initialState = {
email: "",
password: "",
errors: {
email: "",
password: ""
},
familyMembers: ["rgeg"]
}
const { state, handleOnChange, setState } = useForm(initialState)
useEffect(() => {
family && state.familyMembers !== family.members && setState({
...state,
familyMembers: family.members
})
})
// Material UI
const useStyles = makeStyles(theme => (
{
message: {
marginTop: theme.spacing(3)
},
icon: {
backgroundColor: "lightgrey",
padding: "10px",
borderRadius: "50px",
border: "2px solid #3F51B5",
marginBottom: theme.spacing(1)
},
typography: {
marginBottom: theme.spacing(1),
marginTop: theme.spacing(4)
},
customTextField: {
marginTop: theme.spacing(0)
},
dateTimeWrapper: {
marginTop: theme.spacing(4)
}
}
))
const classes = useStyles()
return (
<>
<div>WORK IN PROGRESS...</div>
<br />
<br />
<EventIcon className={classes.icon} />
<Form
title="Add new event"
>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a title for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Title"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Enter a location for this event
</Typography>
<CustomTextField
className={classes.customTextField}
label="Location"
/>
<Typography
variant="subtitle1"
className={classes.typography}
align="left">
Which member/s of the family is/are attending
</Typography>
<Autocomplete
multiple
id="tags-outlined"
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="outlined"
key={option}
style={{
backgroundColor: `${getColorvalue(state.familyMembers[state.familyMembers.indexOf(option)].color)}`,
color: "white"
}}
label={option.name}
onDelete={() => console.log("test")}
{...getTagProps({ index })}
/>
))
}
options={state.familyMembers}
getOptionLabel={(option) => option.name}
// defaultValue={[familyMembers[0]]}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Members Attending"
placeholder="Family Member"
/>
)}
/>
</Form>
</>
);
}
// Redux
const mapStateToProps = (state) => {
return {
family: state.auth.family
}
}
export default connect(mapStateToProps)(EventForm);
my build is not working correctly in build when i deploy to heroku. i have read about reordering the css but how do i verify this or make it work with material ui.
i have tried to look at the inspector and verify css is reordered.
this is the container and the whole screen and is being set off a good bit. the whole build in total has extra padding and the header is not working correctly. it can hopefully be seen at this address.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { logoutUser } from '../../actions/authActions';
import { getSongs, getSong } from '../../actions/songActions';
import { clearCurrentProfile, getCurrentProfile } from '../../actions/profileActions';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ChevronLeftIcon from '#material-ui/icons/ChevronLeft';
import FadeIn from 'react-fade-in';
import ListItem from '#material-ui/core/ListItem';
import Modal from '#material-ui/core/Modal';
import Editor from "./Editor";
import Viewer from "./Viewer";
import ANContainer from '../audio-and-notes/ANContainer';
import AddSongModal from './AddSongModal';
import Resources from '../resources/Resources';
import Songs from '../songs/Songs';
import Song from '../song/Song';
import Spinner from '../../common/Spinner';
import { MenuItem } from '#material-ui/core';
import InboxIcon from "#material-ui/icons/MoveToInbox";
import ListItemText from "#material-ui/core/ListItemText";
import Menu from "#material-ui/core/Menu";
import MailIcon from "#material-ui/icons/Mail";
import { ExpansionPanelDetails } from "#material-ui/core";
const logo = require('../../img/songbird-logo.png');
const drawerWidth = 276;
const styles = theme => ({
root: {
display: 'flex',
},
toolbar: {
paddingRight: 24, // keep right padding when drawer closed
},
toolbarIcon: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar,
},
appBar: {
backgroundColor: "#203e55",
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
menuButton: {
marginLeft: 12,
marginRight: 36,
},
menuButtonHidden: {
display: 'none',
},
//right side menu
menu2Button: {
marginLeft: 0,
marginRight: 0,
},
menu2ButtonHidden: {
display: 'none',
},
//songbook
drawerTitle: {
color: "white",
flexGrow: 1,
textAlign: "center"
},
//songbird
title: {
marginLeft: "300px",
flexGrow: 1,
fontFamily: 'Open Sans, sans-serif'
},
drawerPaper: {
backgroundColor: "#203e55",
color: "white",
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
//how much it pops out from the drawer pre-view
width: theme.spacing.unit * 0,
[theme.breakpoints.up('sm')]: {
width: theme.spacing.unit * 0,
},
},
appBarSpacer: theme.mixins.toolbar,
content: {
flexGrow: 1,
padding: theme.spacing.unit * 3,
height: '96.6vh',
overflow: 'auto',
},
h5: {
marginBottom: theme.spacing.unit * 2,
},
});
const options = ["Viewer", "Resources", "Notes"];
class AppContainer extends Component {
state = {
open: false,
left: false,
right: false,
anchorEl: null,
selectedIndex: 0
};
toggleDrawer = (side, open) => () => {
this.setState({ [side]: open
});
};
componentDidMount(){
this.props.getSongs();
this.props.getCurrentProfile();
}
//trying to maintain the component state for switcher
pageControl() {
if (this.state.selectedIndex === 0) {
return <Viewer />;
} else if (this.state.selectedIndex === 1) {
return <Resources />;
} else if (this.state.selectedIndex === 2) {
return <ANContainer />;
}
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
handleDrawerOpen = () => {
this.setState({ open: true });
};
handleDrawerClose = () => {
this.setState({ open: false });
};
handleDrawerOpen = () => {
this.setState({ open: true });
};
handleDrawerClose = () => {
this.setState({ open: false });
};
handleClickListItem = event => {
this.setState({ anchorEl: event.currentTarget });
this.pageControl();
};
handleMenuItemClick = (event, index) => {
this.setState({ selectedIndex: index, anchorEl: null });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
openSongModal = () => {
//open popup here
}
onLogoutClick(e){
e.preventDefault();
this.props.clearCurrentProfile();
this.props.logoutUser();
}
render(){
//for routing
const { isAuthenticated, user } = this.props.auth;
const { profile, loading } = this.props.profile;
const { classes } = this.props;
const { anchorEl } = this.state;
//will display iframe for wix site if the user does not have an account
const unauthContent = (
<div>
<nav class="navbar">
<div class="nav-wrapper">
<Link to="/" class="brand-logo"><img className="navlogo" src={logo} /></Link>
<ul class="right hide-on-med-and-down">
<li><Link to="/register">Sign Up</Link></li>
<li><Link to="/login">Log In</Link></li>
</ul>
</div>
</nav>
<iframe
style={{height: "92vh", width: "100%"}}
src="https://www.songbirdapp.com/"
frameBorder="none">
</iframe>
</div>
);
//rendered content
return(
<div className={classes.root}>
<CssBaseline />
{/* NAVBAR SECTION!!! */}
<AppBar
position="absolute"
className={classNames(classes.appBar, this.state.open && classes.appBarShift)}
>
<Toolbar disableGutters={!this.state.open} className={classes.toolbar}>
<IconButton
color="inherit"
aria-label="Open drawer"
onClick={this.handleDrawerOpen}
className={classNames(
classes.menuButton,
this.state.open && classes.menuButtonHidden,
)}
>
<MenuIcon />
</IconButton>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
className={classes.title}
>
Editor
</Typography>
<div className="hide-on-med-and-down">
</div>
{/* TO CHANGE THE VIEWER RESOURCE PANEL */}
<List
component="nav-wrapper"
style={{
display: "flex",
flexDirection: "row",
alignContent: "center",
justifyContent: "flex-end",
width: "14%",
backgroundColor: "transparent"
}}
>
<ListItem
button
aria-haspopup="true"
aria-controls="lock-menu"
aria-label="Select Resource"
onClick={this.handleClickListItem}
>
<ListItemText
style={{
color: "white"
}}
primary={options[this.state.selectedIndex]}
/>
<ExpandMoreIcon />
</ListItem>
</List>
<Menu
id="lock-menu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={this.handleClose}
>
{options.map((option, index) => (
<MenuItem
key={option}
disabled={index === 4}
selected={index === this.state.selectedIndex}
onClick={event =>
this.handleMenuItemClick(event, index) & this.pageControl()
}
>
{option}
</MenuItem>
))}
</Menu>
{/* End Resources */}
</Toolbar>
</AppBar>
{/* NAVBAR SECTION END */}
{/* LEFT DRAWER */}
<Drawer
variant="permanent"
classes={{
paper: classNames(classes.drawerPaper, !this.state.open && classes.drawerPaperClose),
}}
open={this.state.open}
>
<div className={classes.toolbarIcon}>
<Typography variant="h6" className={classes.drawerTitle}>
Songs
</Typography>
<IconButton onClick={this.handleDrawerClose}>
<ChevronLeftIcon style={{color: "white"}}/>
</IconButton>
</div>
<Divider />
<List>
<AddSongModal />
<Songs />
</List>
<Divider />
<List>
<ListItem>
<Link className="menu-listitem" to="/myprofile">
{user.firstName} {user.lastName}
</Link>
</ListItem>
<ListItem>
<Link className="menu-listitem" to="/subscription">
Your Subscription
</Link>
</ListItem>
<ListItem>
<a className="logout-listitem"
href=""
onClick={this.onLogoutClick.bind(this)}
>
Logout</a>
</ListItem>
</List>
</Drawer>
{/* LEFT DRAWER END */}
<main className={classes.content}>
<div
className="row no-padding"
style={{
display: "flex",
margin: 0
}}
>
<div
className="col s12 no-padding"
style={{
margin: 0
}}
>
<Song />
</div>
<div className="col s12 m9 no-padding" style={{}}>
{this.pageControl()}
</div>
</div>
</main>
{/* RIGHT DRAWER TO BE USED FOR DRAFTS */}
{/* <Drawer
anchor="right"
variant="permanent"
classes={{
paper: classNames(classes.drawerPaper, !this.state.open && classes.drawerPaperClose),
}}
open={this.state.open}
>
<div className={classes.toolbarIcon}>
<Typography variant="h6" className={classes.drawerTitle}>
Songs
</Typography>
<IconButton onClick={this.handleDrawerTwoClose}>
<ChevronLeftIcon />
</IconButton>
</div>
<List>
<ListItem>Draft 04/12/2019 1PM</ListItem>
<ListItem>Draft 04/12/2019 12:30PM</ListItem>
<ListItem>Draft 04/10/2019 3PM</ListItem>
<ListItem>Draft 04/09/2019 11AM</ListItem>
<ListItem>Draft 04/09/2019 9PM</ListItem>
<ListItem>Draft 04/08/2019 8:34PM</ListItem>
</List>
</Drawer> */}
{/* RIGHT DRAWER END */}
</div>
);
}
}
AppContainer.propTypes = {
getCurrentProfile: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
profile: PropTypes.object.isRequired,
song: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
logoutUser: PropTypes.func.isRequired,
getSongs: PropTypes.func.isRequired,
};
const mapStateToProps = (state) => ({
profile: state.profile,
auth: state.auth,
song: state.song,
});
export default connect(mapStateToProps, { logoutUser, getCurrentProfile, clearCurrentProfile, getSongs, getSong })(withStyles(styles)(AppContainer));
https://ovrchr-songbirdapp.herokuapp.com/