TypeError: Cannot read properties of null (reading 'username') at LeadAdmin.js:121:1 - node.js

I am Populating 'owner' field from My 'lead' document in moongose MERN,
it was working perfectly fine but after somer days its going on type erros of reading null
this is the errror
i am excepting to access the poppulated fields of user from lead (in lead -> owner field)
here my lead.js route
router.get('/', auth, (req, res) => {
User.findById(req.user.id).then((user) => {
if (user.isadmin) {
Lead.find({})
.populate({ path: 'owner', options: { sort: { recieveddate: -1 } } })
.exec((err, lead) => {
if (err) throw err;
// console.log(lead)
res.json(lead);
});
} else {
Lead.find({ owner: user._id })
.sort({ recieveddate: -1 })
.then((leads) => res.json(leads));
}
});
});
here my react rendering page
in map funtion
import * as React from 'react';
import { styled } from '#mui/material/styles';
import Table from '#mui/material/Table';
import TableBody from '#mui/material/TableBody';
import TableCell, { tableCellClasses } from '#mui/material/TableCell';
import TableContainer from '#mui/material/TableContainer';
import TableHead from '#mui/material/TableHead';
import TableRow from '#mui/material/TableRow';
import Paper from '#mui/material/Paper';
import { Container } from '#mui/material';
import Stack from '#mui/material/Stack';
import Button from '#mui/material/Button';
import { connect } from 'react-redux';
import { getLeads, deleteLead } from '../../actions/leadActions'
// import ItemModal from './ItemModal';
import PropTypes from 'prop-types';
import { Component } from 'react';
import SendMail from '../client/SendMail';
import moment from 'moment';
import DeleteLead from './DeleteLead';
import AssignLead from './AssignLead';
import UpdateLead from './UpdateLead';
import UpdateStatus from '../client/UpdateStatus';
import SendMsg from '../client/SendMsg';
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
'&:nth-of-type(odd)': {
// backgroundColor: 'green',
},
// hide last border
'&:last-child td, &:last-child th': {
border: 0,
},
}));
function createData(fullName, email, phoneNo, leadId, make, model, year, vehicleType, recievedDate, actions) {
return { fullName, email, phoneNo, leadId, make, model, year, vehicleType, recievedDate, actions };
}
class LeadAdmin extends Component {
static propTypes = {
auth: PropTypes.object.isRequired,
lead: PropTypes.object.isRequired
}
componentDidMount() {
this.props.getLeads();
this.interval = setInterval(() => { this.props.getLeads() }, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
// componentDidUpdate() {
// this.props.getLeads();
// }
render() {
const { leads, loading } = this.props.lead;
const { user } = this.props.auth;
return (
<Container sx={{ width: 1400 }} >
<TableContainer component={Paper} sx={{ maxHeight: 500, maxWidth: 1600, overflowY: 'scroll' }} >
<Table sx={{ minWidth: 1600 }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell>FullName </StyledTableCell>
<StyledTableCell align="center">Email</StyledTableCell>
<StyledTableCell align="center">Phone NO </StyledTableCell>
<StyledTableCell align="center">Assigned To </StyledTableCell>
<StyledTableCell align="center">Lead Id </StyledTableCell>
<StyledTableCell align="center">Make </StyledTableCell>
<StyledTableCell align="center">Model </StyledTableCell>
<StyledTableCell align="center">Year </StyledTableCell>
<StyledTableCell align="center">Vehicle Type </StyledTableCell>
<StyledTableCell align="center">Recieved Date </StyledTableCell>
<StyledTableCell align="center">Time </StyledTableCell>
<StyledTableCell sx={{ width: 300 }} align="center">Actions</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{leads.map((row) => (
<StyledTableRow key={row.fullname} sx={row.isassigned ? user.isadmin ? { backgroundColor: '#8EE2B8' } : { backgroundColor: '' } : ''} >
{row.status == 'lead' ?
<>
<StyledTableCell component="th" scope="row">
{row.fullname}
</StyledTableCell>
<StyledTableCell align="center">{row.email}</StyledTableCell>
<StyledTableCell align="center">{row.phoneno}</StyledTableCell>
<StyledTableCell align="center">{row.owner.username? row.owner.username : 'N/A'}</StyledTableCell>
<StyledTableCell align="center">{row._id}</StyledTableCell>
<StyledTableCell align="center">{row.make}</StyledTableCell>
<StyledTableCell align="center">{row.model}</StyledTableCell>
<StyledTableCell align="center">{row.modelyear}</StyledTableCell>
<StyledTableCell align="center">{row.vehicletype}</StyledTableCell>
<StyledTableCell align="center">{moment(row.recieveddate).format("ddd, MMM D YYYY")}</StyledTableCell>
<StyledTableCell align="center">{moment(row.recieveddate).format("h:mm a")}</StyledTableCell>
<StyledTableCell align="center" >
<Stack spacing={2} direction="row">
{user.isadmin ?
<>
<Button variant="contained" sx={{ width: 80, backgroundColor: 'black', borderRadius: 50 }}>Cherry</Button>
<UpdateLead {...row} />
<DeleteLead id={row._id} name={row.fullname} />
<AssignLead leadid={row._id} isassigned={row.isassigned} />
</>
:
<>
<SendMail email={row.email} />
<SendMsg {...row} />
<Button variant="contained" sx={{ width: 80, backgroundColor: 'black', borderRadius: 50 }} >Orange</Button>
<UpdateStatus leadid={row._id} />
<UpdateLead {...row} />
</>
}
</Stack>
</StyledTableCell>
</>
: ''}
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Container>
);
}
}
LeadAdmin.propTypes = {
getLeads: PropTypes.func.isRequired,
lead: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
lead: state.lead,
auth: state.auth,
})
export default connect(mapStateToProps, { getLeads })(LeadAdmin);

you are accessing json to 3 level row.owner.username, in some row.owner does not have any value i.e is undefined , update your code as below
<StyledTableCell align="center">{row?.owner?.username? row?.owner?.username : 'N/A'}</StyledTableCell>

Related

Invalid hook call

I am tring to create a video streaming app, and I got an error logging: "Invalid hook call" when i set "{ ready, tracks } = useMicrophoneAndCameraTracks();" and client = useClient();
I tried not calling the hook useMicrophoneAndCameraTracks and useClient, the error wasn't there but the video won't stream. Here is my code
Settings.js
import { createClient, createMicrophoneAndCameraTracks } from "agora-rtc-react";
const appId = "d13f5075f00d417092285bc8a52f17f2";
const token = "007eJxTYOjZ/X7lClbPsGXOv7vW/egUYDx+N+WSl9Bzddlf2fyLD5orMKQYGqeZGpibphkYpJgYmhtYGhlZmCYlWySaGqUZmqcZKT+bk9wQyMiwSdaKkZEBAkF8FobcxMw8BgYAbJIfFw=="
export const config = { mode: "rtc", codec: "vp8", appId: appId, token: token };
export const useClient = createClient(config);
export const useMicrophoneAndCameraTracks = createMicrophoneAndCameraTracks();
export const channelName = "main";
VideoCall.js
import { useState, useEffect } from "react";
import {
config,
useClient,
useMicrophoneAndCameraTracks,
channelName,
} from "./settings.js";
import { Grid } from "#material-ui/core";
import Video from "./Video";
import Controls from "./Controls";
export default function VideoCall(props) {
const { setInCall } = props;
const [users, setUsers] = useState([]);
const [start, setStart] = useState(false);
const client = useClient();
const { ready, tracks } = useMicrophoneAndCameraTracks();
useEffect(() => {
let init = async (name) => {
client.on("user-published", async (user, mediaType) => {
await client.subscribe(user, mediaType);
if (mediaType === "video") {
setUsers((prevUsers) => {
return [...prevUsers, user];
});
}
if (mediaType === "audio") {
user.audioTrack.play();
}
});
client.on("user-unpublished", (user, mediaType) => {
if (mediaType === "audio") {
if (user.audioTrack) user.audioTrack.stop();
}
if (mediaType === "video") {
setUsers((prevUsers) => {
return prevUsers.filter((User) => User.uid !== user.uid);
});
}
});
client.on("user-left", (user) => {
setUsers((prevUsers) => {
return prevUsers.filter((User) => User.uid !== user.uid);
});
});
try {
await client.join(config.appId, name, config.token, null);
} catch (error) {
console.log("error");
}
if (tracks) await client.publish([tracks[0], tracks[1]]);
setStart(true);
};
if (ready && tracks) {
try {
init(channelName);
} catch (error) {
console.log(error);
}
}
}, [channelName, client, ready, tracks]);
return (
<Grid container direction="column" style={{ height: "100%" }}>
<Grid item style={{ height: "5%" }}>
{ready && tracks && (
<Controls tracks={tracks} setStart={setStart} setInCall={setInCall} />
)}
</Grid>
<Grid item style={{ height: "95%" }}>
{start && tracks && <Video tracks={tracks} users={users} />}
</Grid>
</Grid>
);
}
App.js
import { useState } from "react";
import { Button } from "#material-ui/core";
import VideoCall from "./VideoCall";
function App() {
const [inCall, setInCall] = useState(false);
return (
<div className="App" style={{ height: "100%" }}>
{inCall ? (
<VideoCall setInCall={setInCall} />
) : (
<Button
variant="contained"
color="primary"
onClick={() => setInCall(true)}
>
Join Call
</Button>
)}
</div>
);
}
export default App;
Controls.js
import { useState } from 'react';
import { useClient } from './settings';
import { Grid, Button } from '#material-ui/core';
import MicIcon from '#material-ui/icons/Mic';
import MicOffIcon from '#material-ui/icons/MicOff';
import VideocamIcon from '#material-ui/icons/Videocam';
import VideocamOffIcon from '#material-ui/icons/VideocamOff';
import ExitToAppIcon from '#material-ui/icons/ExitToApp';
export default function Controls(props) {
const client = useClient();
const {tracks, setStart, setInCall} = props;
const [trackState, setTrackState] = useState({video: true, audio: true});
const mute = async(type)=> {
if(type === "audio") {
await tracks[0].setEnabled(!trackState.audio);
setTrackState((ps) => {
return {...ps, audio: !ps.audio}
})
}
else if(type === "video") {
await tracks[1].setEnabled(!trackState.video);
setTrackState((ps) => {
return {...ps, video: !ps.video}
})
}
}
const leaveChannel = async() => {
await client.leave();
client.removeAllListeners();
tracks[0].close();
tracks[1].close();
setStart(false);
setInCall(false);
}
return (
<Grid container spacing={2} alignItems='center'>
<Grid item>
<Button variant="contained" color={trackState.audio ? "primary" : "secondary"} onclick={() => mute("audio")}>
{trackState.audio ? <MicIcon/> : <MicOffIcon/>}
</Button>
</Grid>
<Grid item>
<Button variant="contained" color={trackState.video ? "primary" : "secondary"} onclick={() => mute("video")}>
{trackState.video ? <VideocamIcon/> : <VideocamOffIcon/>}
</Button>
</Grid>
<Grid item>
<Button variant="contained" color="default" onclick={() => leaveChannel()}>
Leave <ExitToAppIcon/>
</Button>
</Grid>
</Grid>
)
}
Video.js
import { AgoraVideoPlayer } from "agora-rtc-react";
import { Grid } from "#material-ui/core";
import { useState, useEffect } from "react";
export default function Video(props) {
const { users, tracks } = props;
const [gridSpacing, setGridSpacing] = useState(12);
useEffect(() => {
setGridSpacing(Math.max(Math.floor(12 / (users.length + 1)), 4));
}, [users, tracks]);
return (
<Grid container style={{ height: "100%" }}>
<Grid item xs={gridSpacing}>
<AgoraVideoPlayer
videoTrack={tracks[1]}
style={{ height: "100%", width: "100%" }}
/>
</Grid>
{users.length > 0 &&
users.map((user) => {
if (user.videoTrack) {
return (
<Grid item xs={gridSpacing}>
<AgoraVideoPlayer
videoTrack={user.videoTrack}
key={user.uid}
style={{ height: "100%", width: "100%" }}
/>
</Grid>
);
} else return null;
})}
</Grid>
);
}
Without more detailed code, we can't help you. You probably broke a rule regarding react hooks.
The official docs state the following:
There are three common reasons you might be seeing it:
You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app.
Read more about it here:
https://reactjs.org/warnings/invalid-hook-call-warning.html

React Socketio set online status for multiple users

How can i update online status of multiple users in React.i want that when user A is online,user B and C can also see if user A is online.Here is what i have tried using react usestate but it isnt working
function MyOffers() {
const [loading, setLoading] = useState(true);
const [cookies] = useCookies();
const { enqueueSnackbar } = useSnackbar();
const navigate = useNavigate();
const [data, setData] = useState(false);
let { id } = useParams();
const [user, setUser] = useState({
username: null,
online: false,
});
////set online status
const socket = useContext(SocketContext);
useEffect(() => {
ifvisible.on('focus', function () {
socket.emit('online', user);
console.log(user);
});
ifvisible.on('blur', function () {
socket.emit('offline', user);
console.log('offline');
});
return () => {
ifvisible.off('focus');
ifvisible.off('blur');
};
}, [user]);
useEffect(() => {
socket.on('online', (data) => {
setUser((prevState) => ({
...prevState,
...data,
}));
console.log(user);
});
socket.on('offline', (data) => {
setUser((prevState) => ({
...prevState,
...data,
}));
});
}, [socket]);
useEffect(() => {
$.ajax({
type: 'POST',
url: '/get_offer',
headers: {
'X-XSRF-TOKEN': cookies['XSRF-TOKEN'],
'Authorization': `Bearer ${localStorage.getItem('auth')}`,
},
data: {
id: id,
},
success: function (data) {
switch (data.success) {
case true:
setData(data);
setLoading(false);
break;
case false:
break;
}
},
error: function () {},
statusCode: {
403: function () {
navigate('/');
},
},
});
}, []);
return (
<React.Fragment>
<Box flexGrow={1}>
{/*seller info*/}
<Grid item xs={12} sm={4}>
{loading ? (
<Skeleton
variant="rectangular"
animation="wave"
width={'100%'}
height={200}
sx={{ borderRadius: 2, marginTop: 1 }}
/>
) : (
<Item>
<Badge
color={
data.offer &&
data.offer[0].user.username === user.username &&
user.online === true
? 'success'
: 'warning'
}
variant="dot"
overlap="circular"
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
>
<Avatar
alt="Remy Sharp"
src="/static/images/avatar/1.jpg"
sx={{ width: 56, height: 56 }}
/>
</Badge>
<Typography variant={'h5'}>
{data.offer ? data.offer[0].user.username : ''}
</Typography>
<Typography paragraph>
<Rating name="read-only" value={5} readOnly />
<Typography variant={'subtitle1'}>[5]</Typography>
</Typography>
<CardActions sx={{ display: 'flex', justifyContent: 'space-evenly' }}>
<IconButton aria-label="add to favorites">
<LockClockOutlinedIcon />
</IconButton>
<IconButton aria-label="share">
<LockClockOutlinedIcon />
</IconButton>
</CardActions>
</Item>
)}
</Grid>
</Grid>
</Box>
</React.Fragment>
);
}
export default MyOffers;
i want such when the owner of the offer is online,to update the online status badge of the user viewing the offer.Here is my server code
/**
* Listen for incoming socket connections
*/
Ws.io.on('connection', (socket) => {
socket.on('online', (data) => {
data.online = true;
socket.broadcast.emit('online', data);
});
socket.on('offline', (data) => {
data.online = false;
socket.broadcast.emit('offline', data);
});
});

Remove object from array with specific index (MongoDB, NodeJS, React)

I have app with devices-array which have objects
with device_name and device_id. I'd like to remove specific device depending which device user want's to remove from devices array.
I've already tryied to findIndex and indexOf -methods, but it return's undefined for request. How to access device depending which device user want's to remove?
deviceController.js
'use strict'
import Users from '../models/userModel.js'
deleteDevice: async (req, res) => {
try {
const { device } = req.body.device.device_id
const dev = await Users.findOne({ _id: req.user.id }).populate('device')
const devs = dev.device //devices
const index = devs.findIndex(req.body.device)
const devic = devs.slice(index, 1)
await Users.findOneAndUpdate({ _id: req.user.id }, { device: devic })
res.json({ msg: 'Deleted success' })
} catch (err) {
return res.status(500).json({ msg: err.message })
}
}
export { deviceControl }
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import axios from 'axios'
import { useSelector, useDispatch } from 'react-redux'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faEdit, faTrash } from '#fortawesome/free-solid-svg-icons'
import { Container, Table } from 'react-bootstrap'
import { showErr, showSuccess } from '../utils/notifications/Notification'
import {
fetchAllUsers,
dispatchGetAllUsers
} from '../../redux/actions/usersAction'
import '../../index.css'
//initialize device
const initialState = {
device: { device_name: '', _id: '', device_id: '' },
err: '',
success: ''
}
function AllDevices() {
//authentication
const auth = useSelector((state) => state.auth)
//token
const token = useSelector((state) => state.token)
//set data
const [data, setData] = useState(initialState)
//users
const users = useSelector((state) => state.users)
const { device_name, device_id, err, success } = data
//loading
const [loading, setLoading] = useState(false)
//authentication
const { user, isAdmin } = auth
const dispatch = useDispatch()
const handleChange = (e) => {
const { name, value } = e.target
setData({ ...data, [name]: value, err: '', success: '' })
}
useEffect(() => {
if (isAdmin) {
fetchAllUsers(token).then((res) => {
dispatch(dispatchGetAllUsers(res))
})
}
if (isAdmin || user) {
setData(initialState)
}
}, [token, user, isAdmin, dispatch, loading])
const updateDeviceName = async () => {
try {
if (window.confirm('Are you sure you want to rename this device?')) {
await axios.patch(
`/device/edit/${data.device._id}/${data.device.device_name}`,
{
device: { device_name, device_id }
},
{
headers: { Authorization: token }
}
)
}
setData({ ...data, err: '', success: 'Updated Success!' })
} catch (err) {
setData({ ...data, err: err.response.data.msg, success: '' })
}
}
const handleUpdate = () => {
if (device_name) updateDeviceName(device_name)
}
const handleDelete = async () => {
try {
if (window.confirm('Are you sure you want to delete this device?')) {
setLoading(true)
await axios.patch(
`/device/delete/${data.device}`,
{ device: data.device },
{
headers: { Authorization: token }
}
)
}
setData({ ...data, err: '', success: 'Updated Success!' })
} catch (err) {
setData({ ...data, err: err.response.data.msg, success: '' })
}
}
return (
<>
<h5 className='m-5'>
{' '}
<Link to='/'>
<i className='fas fa-undo-alt'></i>Takaisin
</Link>
</h5>
<Container fluid='sm'>
<div>
{err && showErr(err)}
{success && showSuccess(success)}
{loading && <h3>Loading.....</h3>}
</div>
<Table bordered hover variant='light' responsive>
<tbody>
<tr>
<th>Nimi</th>
<th>Laite</th>
</tr>
{/* Loop through user details */}
{users.map((p) => (
<tr>
<td>
{p.name}
<br />
{p.email}
</td>
<td>
{p.device.map((d) => (
<div>
<div
className='d-flex-inline'
style={{
position: 'relative',
width: '170px'
}}
>
{' '}
<input
type='text'
style={{
fontSize: '16px',
width: '100px'
}}
defaultValue={d.device_name}
name='device_name'
onChange={handleChange}
/>{' '}
<FontAwesomeIcon
style={{
position: 'absolute',
top: '3px',
right: '70px',
zIndex: '2'
}}
icon={faEdit}
title='Edit'
onClick={() => handleUpdate(d.device_name)}
/>{' '}
</div>
<div
className='d-flex'
style={{
position: 'relative',
width: '100px'
}}
>
<input
type='text'
style={{
fontSize: '14px',
width: '200px',
color: '#333'
}}
defaultValue={d.device_id}
disabled
name='device_id'
/>{' '}
<FontAwesomeIcon
style={{
position: 'absolute',
top: '3px',
right: '3px',
zIndex: '2'
}}
icon={faTrash}
title='Trash'
onClick={() => handleDelete(d.device)}
/>{' '}
</div>
</div>
))}
</td>
</tr>
))}
</tbody>
</Table>
</Container>
</>
)
}
export default AllDevices
const deviceSchema = mongoose.Schema({
device_id: { type: Number, required: true },
device_name: { type: String, required: true }
})
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Please enter your name!']
},
email: {
type: String,
required: [true, 'Please enter your email!']
},
device: [deviceSchema, { type: mongoose.Schema.Types.ObjectId }],
password: {
type: String,
required: [true, 'Please enter your password!']
},
days: { type: Date },
role: {
type: Number,
default: 0 // 0 = user 1= admin 3=visitor
}
},
{
timestamps: true
}
)
const Users = mongoose.model('User', userSchema)
export default Users
import { deviceControl } from '../controllers/deviceController.js'
import express from 'express'
import auth from '../middleware/auth.js'
import authAdmin from '../middleware/authAdmin.js'
const router = express.Router()
router.get('/device', auth, authAdmin, deviceControl.getUsersAllDevices)
router.post('/device', auth, authAdmin, deviceControl.getUsersAllDevices)
router.patch('/device/delete/:id', auth, authAdmin, deviceControl.deleteDevice)
router.put('/add_device', auth, deviceControl.addDevice)
router.patch('/device/edit', auth, deviceControl.updateDeviceName)
export default router
try using JS filter function.
const removeDevice(devices, id) => {
return devices.filter(device => device.id !== id)
}

ReactJS: Is there a way to avoid child component re-rendering when drawer opens?

I'm looking for a way to be able to open the drawer, with the least possible re-rendering of the DOM.
Every time the drawer opens, a re-rendering of the route component occurs, however I think it is unnecessary since the child components have not changed and are only re-rendered due to the fact that I am updating the state to open the drawer.
Aprecio su ayuda y orientacion con este tema
This is my code for Appbar.js
import React, { useState, Fragment, lazy, Suspense, useCallback} from "react";
import { Switch,Router, Route, Link, useLocation } from "react-router-dom";
import { createBrowserHistory } from "history";
import { withStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import logo_LH_webp from '../../imagenes/logo.webp';
import logo_LH_png from '../../imagenes/logo.png';
import AccountCircle from '#material-ui/icons/AccountCircle';
import { useSelector } from 'react-redux'
import { isEmpty } from 'react-redux-firebase'
import { useFirebase } from "react-redux-firebase";
import { store } from '../../index'
import { setMesa } from "../../slices/cart";
import axios from 'axios';
import {MemoMyDrawer} from './MyDrawer'
import Button from '#material-ui/core/Button';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import PopupState, { bindTrigger, bindMenu } from 'material-ui-popup-state';
const drawerWidth = 240;
const history = createBrowserHistory();
const styles = theme => ({
root: {
flexGrow: 1
},
flex: {
flex: 1
},
drawerPaper: {
position: "relative",
width: drawerWidth
},
menuButton: {
marginLeft: "auto",
},
toolbarMargin: theme.mixins.toolbar,
aboveDrawer: {
zIndex: theme.zIndex.drawer + 1
},
appBar: {
backgroundColor: "white"
}
});
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
const menuId = 'primary-search-account-menu';
const getQuery = () => {
if (typeof window !== "undefined") {
return new URLSearchParams(window.location.search);
}
return new URLSearchParams();
};
function AppBarInteraction({ classes, variant }) {
const query = getQuery();
console.log("MESA")
console.log()
const cart = useSelector(state => state.cart);
let valor = getQuery().get('q');
if (cart.mesa === "")
{
store.dispatch(setMesa(valor));
}
else
{
valor = cart.mesa;
}
const auth = useSelector(state => state.firebase.auth);
console.log('Auth vacio')
console.log(isEmpty(auth))
console.log(auth.isEmpty);
const [drawer, setDrawer] = useState(false);
const firebase = useFirebase();
firebase.auth().onAuthStateChanged(async (user) => {
if (user) {
console.log("usuario");
console.log(user);
//setAutorizado(true);
const token = await user.getIdToken();
axios.defaults.headers.common['Authorization'] = "Bearer " + token;
} else {
console.log("No logueado");
//setAutorizado(false);
}
});
// const [autorizado, setAutorizado] = React.useState(null);
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
console.log('Autorizado?');
//console.log(autorizado);
const toggleDrawer = useCallback(() => {
console.log(drawer)
setDrawer(!drawer);
}, [drawer]);
const logout = () => {
//setAutorizado(false);
firebase.logout();
}
const perfil = () => {
history.push("/perfil");
}
const MemoMyDraw = (drawer) => (
<MemoMyDrawer
open={drawer}
variant="temporary"
onClose={toggleDrawer}
toggleDrawer={toggleDrawer}
/>
)
const MenuPropio = () => (
// <Menu
// id="menu-appbar"
// anchorEl={anchorEl}
// open={open}
// onClose={handleClose}
// >
// <MenuItem onClick={perfil}>Perfil de Usuario</MenuItem>
// <MenuItem onClick={logout}>Cerrar Sesión</MenuItem>
// </Menu>
<PopupState variant="popover" popupId="demo-popup-menu">
{(popupState) => (
<React.Fragment>
<IconButton
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
color="primary"
{...bindTrigger(popupState)}
>
<AccountCircle />
</IconButton>
<Menu {...bindMenu(popupState)}>
<MenuItem onClick={perfil}>Perfil de Usuario</MenuItem>
<MenuItem onClick={logout}>Cerrar Sesión</MenuItem>
</Menu>
</React.Fragment>
)}
</PopupState>
)
return (
<div className={classes.root}>
<Fragment>
<Router history={history}>
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<Link to={"/" + "?q=" + valor} ><picture><source srcSet={logo_LH_webp} type="image/webp" /><img alt="logo" srcSet={logo_LH_png} height="56" width="77" /></picture></Link>
<IconButton
color="default"
aria-label="open drawer"
edge="end"
onClick={toggleDrawer} //{handleDrawerToggle}
className={classes.menuButton}
>
<MenuIcon />
</IconButton>
{true && (
<Fragment>
<div>
<MenuPropio />
</div>
</Fragment>
)}
</Toolbar>
</AppBar>
</Router>
<div className={classes.toolbarMargin} />
</Fragment>
{MemoMyDraw(drawer)}
</div>
);
}
export default React.memo(withStyles(styles)(AppBarInteraction));
And this is the code for MyDrawer.js
import React, { Suspense, lazy} from "react";
import { withStyles } from "#material-ui/core/styles";
import Drawer from "#material-ui/core/Drawer";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import PrivateRoute from "../PrivateRoute/PrivateRoute"
import clsx from "clsx";
import Divider from "#material-ui/core/Divider";
import { Switch,Router, Route, Link, useLocation } from "react-router-dom";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import InboxIcon from "#material-ui/icons/MoveToInbox";
import MailIcon from "#material-ui/icons/Mail";
import { createBrowserHistory } from "history";
import { useSelector } from 'react-redux'
import { isLoaded, isEmpty } from 'react-redux-firebase'
import Prueba from '../Prueba/Prueba';
const Cart = lazy(() => import ('../Cart/Cart'));
const Feedback = lazy(() => import ('../Feedback/Feedback'));
const Perfil = lazy(() => import ('../Perfil/Perfil'));
const OneClick = lazy(() => import ('../OneClick/OneClick'));
const Login = lazy(() => import ('../Login/Login'));
const Menu_LH = lazy(() => import ('../Menu/Menu'));
const Principal = lazy(() => import('../Principal/Principal'));
const ProductList = lazy(() => import( '../ProductList/ProductList'));
const Carta= lazy(() => import( '../Carta/Carta'));
const ProductosCategoria = lazy(() => import('../ProductosCategoria/ProductosCategoria'));
const InfoProducto = lazy(() => import('../InfoProducto/InfoProducto'));
const Confirmacion = lazy(() => import('../Confirmacion/Confirmacion'));
const drawerWidth = 240;
const history = createBrowserHistory();
function AuthIsLoaded({ children }) {
const auth = useSelector(state => state.firebase.auth)
if (!isLoaded(auth)) return <div></div>;
return children
}
console.log("DRAWER----------------------------")
const getQuery = () => {
if (typeof window !== "undefined") {
return new URLSearchParams(window.location.search);
}
return new URLSearchParams();
};
function switchResult(a){
switch(a){
case 'Tu Pedido Actual':
return 'pedido';
break;
case 'Carta':
return 'carta';
break;
case 'Inicio':
return '';
break;
case 'Carta':
return 'Carta';
break;
case 'Prueba':
return 'Prueba';
break;
case 'Comentarios':
return 'feedback';
break;
default:
return "OK";
}
}
const styles = theme => ({
root: {
flexGrow: 1
},
flex: {
flex: 1
},
drawerPaper: {
position: "relative",
width: drawerWidth
},
menuButton: {
marginLeft: "auto",
},
toolbarMargin: theme.mixins.toolbar,
aboveDrawer: {
zIndex: theme.zIndex.drawer + 1
},
appBar: {
backgroundColor: "white"
}
});
const MyDrawer = withStyles(styles)(
({ classes, variant, open, onClose, toggleDrawer }) => (
<Router history={history}>
<Drawer
variant="temporary"
open={open}
onClose={onClose}
classes={{
paper: classes.drawerPaper
}}
>
<div
className={clsx({
[classes.toolbarMargin]: variant === "persistent"
})}
/>
<Divider />
<List>
{["Inicio", "Carta" , "Tu Pedido Actual", "Comentarios" ].map((text, index) => (
<ListItem key={text} onClick={toggleDrawer} component={Link} to={"/" + switchResult(text) + "?q=" + getQuery().get('q')}>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
<main className={classes.content}>
<Suspense fallback={<div>Cargando...</div>}>
<Switch>
<AuthIsLoaded>
<PrivateRoute exact path = "/" component={Principal}></PrivateRoute>
<PrivateRoute exact path="/perfil" component={Perfil}></PrivateRoute>
<PrivateRoute exact path="/OneClick"component={OneClick}></PrivateRoute>
{/* <Route exact path="/Menu" render={() => <div id="G"><ProductList /></div>} /> */}
<PrivateRoute path="/carta"component={Carta}></PrivateRoute>
<PrivateRoute path="/pedido"component={Cart}></PrivateRoute>
{/* <Route path="/carta" render={() => <div id="G"><ProductList /></div>} /> */}
{/* <PrivateRoute exact path="/"><div id="G"><Principal /></div></PrivateRoute> */}
<Route exact path="/Categoria/:categoriaId"><div id="ProductosCategoria"><ProductosCategoria /></div></Route>
<Route exact path="/login"><div id="Login"><Login /></div></Route>
<Route exact path="/feedback" > <div id="Feedback"><Feedback /></div></Route>
</AuthIsLoaded>
</Switch>
</Suspense>
</main>
</Router>
)
);
export const MemoMyDrawer = React.memo(withStyles(styles)(MyDrawer));
You have to separate the reference to drawer's state open from MyDrawer because when open chage re-render MyDrawer. My solution was to extends Drawer and manage its state with redux using this code:
import { useSelector, useDispatch } from "react-redux";
function VDrawer(props){
const dispatch = useDispatch();
const onClose=() => {dispatch({ type: "drawer"})};
const drawer = useSelector((state) => state.drawer);
return <Drawer variant="temporary"
open={drawer}
onClose={onClose}
ModalProps={{
keepMounted: true,
}}>
{props.children}
</Drawer>
}
In this way the state drawer wich open/close drawer don't affect to MyDrawer

React Native and node js - fetching input values and using them in controllers

I have a react native component that has username and password text input fields. I want the values which are entered to be available in the node js controller to query my db. I am not able to use AsyncStorage as I cannot import AsyncStorage inside controller. How do I make this work? Please help.
My login screen:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image,
TextInput,
Alert,
Navigator,
TouchableHighlight,
BackAndroid,
ScrollView,
AsyncStorage,
} from 'react-native';
var _navigator;
import Container from './Container';
import Button from './Button';
import Label from './Label';
import ImageContainer from './ImageContainer';
import RegisterView from './RegisterView';
export default class LoginView extends Component {
constructor(props) {
super(props);
this.state = {
userName: '',
userPass: '',
error:null,
};
}
_navigate(){
this.props.navigator.push({
name: 'RegisterView', // Matches route.name
})
}
_handleAdd = () => {
if((this.state.userName)!=="" && (this.state.userPass)!=="" ){
const data = {
username: this.state.userName,
password: this.state.userPass
}
// Serialize and post the data
const json = JSON.stringify(data)
fetch('http://10.0.2.2:3000/users/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: json
})
.then((response) => response.json())
.then((res) => {
if (res.error) {
alert(res.error)
} else {
this.props.navigator.push({
name: 'CheckList', // Matches route.name
})
}
})
.catch(() => {
alert('There was an error logging in.');
})
.done()
}
else{
alert('Cannot be empty!');
}
}
render() {
return (
<ScrollView style={styles.scroll}>
<ImageContainer>
<Image
style={{width:110,height: 110, justifyContent: 'center',
alignItems: 'center'}}
source={require('./Logo.png')}>
</Image>
</ImageContainer>
<Container>
<TextInput
placeholder="Username"
style={styles.textInput}
onChangeText={(text) => this.setState({userName:text})}
autoCapitalize="none"
autoCorrect={false}
onSubmitEditing={(event) => {
const{userName}=this.state.userName;
const{onSubmitEditing}=this.props;
if(!userName) return
onSubmitEditing(userName)
this.refs.SecondInput.focus();
}}
/>
<TextInput
placeholder="Password"
ref='SecondInput'
secureTextEntry={true}
onChangeText={(text) => this.setState({userPass:text})}
style={styles.textInputPass}
/>
</Container>
<Container>
<Button
label="Sign In"
styles={{button: styles.primaryButton, label:
styles.buttonWhiteText}}
onPress={() => this._handleAdd()}
/>
</Container>
<Container>
<TouchableHighlight onPress={ () => this._navigate()}
underlayColor= 'transparent'>
<Text style ={styles.buttonBlackText}>New? Register
</Text>
</TouchableHighlight>
</Container>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
scroll: {
backgroundColor: '#FFFFFF',
padding: 30,
flexDirection: 'column'
},
buttonWhiteText: {
fontSize: 20,
color: '#FFF'
},
buttonBlackText: {
fontSize: 20,
marginTop: 20,
textAlign:'center',
color: '#000000'
},
textInput: {
fontSize: 20,
backgroundColor: '#FFF',
marginBottom: 20,
marginTop: 20
},
textInputPass: {
fontSize: 20,
backgroundColor: '#FFF',
marginBottom: 20,
},
primaryButton: {
backgroundColor: '#34A853'
},
});
Controller to query the username from db. For now, it's hardcoded.
import Profile from '../models/profile';
import moment from 'moment';
export const index = (req, res, next) => {
Profile.find({'username': 'John'}).lean().exec((err, profiles) =>
res.json(
// Iterate through each movie
{ profiles: profiles.map(profile => ({
...profile,
}))}
));
};

Resources