Re-render component with useEffect when something changes in a child component - javascript

I have an application that lets a user to add tasks in a list. The tasks are fetched from the API and are displayed with the "List" component. When a user adds a new task from the "AddButton" component the task is stored in the database.
I want the to re-render the "List" component when the handleSubmit function happens on the "AddButton" component and adds the task to the database. The "addTask" and "getTasks" are fetching data from the API.
Thanks for your help in advance.
List component
import React, { useState, useEffect } from 'react';
import { makeStyles } from '#material-ui/styles';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import Moment from 'react-moment';
import { getTasks } from './services/getTasks';
import AddButton from './AddButton';
import './App.css';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
flexDirection: 'column',
width: '100%',
justifyContent: 'space-between',
height: '100%',
fontSize: '16px',
},
listItemLinkRoot: {
paddingLeft: theme.spacing(3),
width: '100%',
'&:hover': {
backgroundColor: '#212121',
color: 'white',
},
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
},
buttonContainer: {
display: 'flex',
width: '100%',
flexDirection: 'column',
justifyContent: 'flex-end',
},
list: {
flexGrow: 1,
overflow: 'auto',
},
listItemText: {
marginBottom: 8,
// fontSize: 20,
},
}));
function ListItemLink(props) {
return <ListItem button component="a" {...props} />;
}
export default function TaskList() {
const classes = useStyles();
const [tasks, setTasks] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await getTasks();
setTasks(result);
};
fetchData();
}, []);
return (
<div className={classes.root}>
<List classes={{ root: classes.list }}>
{tasks.map(task => (
<ListItemLink
divider
key={task.id}
classes={{ root: classes.listItemLinkRoot }}
href="simple-list"
>
<ListItemText
classes={{ root: classes.listItemText }}
primary={task.description}
/>
<Moment
classes={{ root: classes.listItemDate }}
format="DD/MM/YYYY"
>
{task.createdAt}
</Moment>
</ListItemLink>
))}
</List>
<div className={classes.buttonContainer}>
<AddButton classes={{ root: classes.add }} />
</div>
</div>
);
}
AddButton component
import React, { useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Fab from '#material-ui/core/Fab';
import AddIcon from '#material-ui/icons/Add';
import TextField from '#material-ui/core/TextField';
import { addTask } from './services/postTask';
const useStyles = makeStyles(theme => ({
cont: {
display: 'flex',
flexDirection: 'row',
paddingBottom: '24px',
justifyContent: 'space-between',
backgroundColor: '#e0e0e0',
width: '100%',
alignItems: 'center',
felxGrow: 1,
},
fab: {
marginTop: theme.spacing(2),
marginRight: theme.spacing(2),
width: '100%',
},
textField: {
marginLeft: theme.spacing(3),
marginTop: 0,
marginBottom: 0,
flexGrow: 1,
},
}));
export default function AddButton() {
const classes = useStyles();
const [task, setTask] = useState({
description: '',
completed: false,
});
const handleChange = ev => {
setTask({ ...task, [ev.target.id]: ev.target.value });
};
const handleSubmit = () => {
addTask(task);
};
return (
<div className={classes.cont}>
<TextField
onChange={handleChange}
id="description"
label="Add a task"
rowsMax="4"
className={classes.textField}
margin="normal"
/>
<Fab
onClick={handleSubmit}
variant="extended"
size="small"
color="primary"
aria-label="add"
className={classes.fab}
>
<AddIcon />
Add
</Fab>
</div>
);
}

In your list component you can have your handleSubmit function and pass it down to your child AddButton component:
<AddButton classes={{ root: classes.add }} handleSubmit={handleSubmit} />

One solution I can think of is to move the fetchData function outside of your useEffect hook and pass it to the Button as a prop:
const fetchData = async () => {
const result = await getTasks();
setTasks(result);
};
useEffect(() => {
fetchData();
}, []);
...
<AddButton classes={{ root: classes.add }} refetch={fetchData}/>
Then in AddButton (assuming addTask() is async).
const handleSubmit = () => {
addTask(task)
.then(res => props.refetch())
};
Though it may make more sense to handle all of the state functionality in the parent component.

Related

Retrieval of the Inspected elements and manipulating them

I have the following component:
import * as React from "react";
import { createTheme, ThemeProvider } from '#mui/material/styles'
import { Box } from '#mui/system';
import { InputBase, TextField, Typography } from "#mui/material";
import ReactQuill from 'react-quill';
import { NoEncryption } from "#mui/icons-material";
type Props = {
issueId: string
}
export default function DialogBox({ issueId }: Props) {
const myTheme = createTheme({
// Set up your custom MUI theme here
})
const [newMsg, setNewMsg] = React.useState("");
const [startNewMsg, setStartNewMsg] = React.useState(false)
const handleNewMsgInput = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
}
const handleKeyPress = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "Escape") {
// setStartNewMsg(false);
setNewMsg((prev) => "");
}
}
return (
<Box flexDirection="column" sx={{ display: "flex", alignItems: "center", backgroundColor: "lightblue", height: "100%", gap: "2rem" }} onKeyPress={(e) => {
handleKeyPress(e)
}}>
<Typography
sx={{
width: "fit-content",
height: "fit-content",
fontFamily: "Amatic SC",
background: "lightblue",
fontSize: "3rem"
}}>
Message board
</Typography>
{startNewMsg ?
<Box sx={{ width: "fit-content", height: "fit-content" }}>
<ReactQuill style={{ backgroundColor: "white", height: "10rem", maxWidth: "30rem", maxHeight: "10rem" }} theme="snow" />
</Box>
:
<TextField id="filled-basic" label="write new message" sx={{ "& fieldset": { border: 'none' }, backgroundColor: "white", borderRadius: "5px" }} variant="filled" fullWidth={true} onClick={(e) => setStartNewMsg((prev) => true)} onChange={(e) => handleNewMsgInput(e)} />}
</Box >
)
}
Which's causing me the following issue of text appearing out of my white textbox:
I notice on inspection the following property which's responsible for the problem:
My question is, what would be the best way to manipulating the values of that element? How should I retrieve them?
Regards!
Use ch units (the size of the text characters) and adjust the size based on the input.
Example:
const Test = () => {
const [text, setText] = useState('');
return (
<div>
<input
value={text}
onChange= {(e) => setText(e.target.value)}
style= {{height: `${text.length}ch`, width: `${text.length}ch`}}
/>
</div>
);
};
^ that is an input box that will grow based on the size of the text.
You don't want:
height: 100%;
as this will only allow the height to be as big as its parent container.

Google OAuth2 Styling issue

I'm new to coding, and trying to build a social media application. I'm using react js in which I'm not able to provide styling to the Google Login Button. I have tried to provide style in various ways like from tweking the parent component to doing changes in style js, but none of it seems to work.
This is Auth.js
import React, { useState, useEffect } from 'react';
import { Avatar, Button, Paper, Grid, Typography, Container, TextField } from '#material-ui/core';
import { GoogleOAuthProvider, GoogleLogin, googleLogout } from '#react-oauth/google';
// import {GoogleLogin, googleLogout} from 'react-google-login'
import Icon from './icon';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import useStyles from './styles';
import Input from './Input';
const Auth = () => {
const classes = useStyles();
const [showPassword, setShowPassword] = useState(false);
const [isSignup, setIsSignup] = useState(false);
const handleShowPassword = () => setShowPassword((prevShowPassword) => !prevShowPassword);
const handleSubmit = () => {
};
const handleChange = () => {
}
const switchMode = () => {
setIsSignup((prevIsSignup) => !prevIsSignup);
handleShowPassword(false);
}
function handleCallbackResponse(response) {
console.log("JWT ID Token" + response.credential);
}
useEffect(() => {
/*global google*/
google.accounts.id.initialize({
client_id: '29955464017-7ng0cb3718pnb4lmmhd9tqqf1qqgqn4d.apps.googleusercontent.com',
callback: handleCallbackResponse
});
google.accounts.id.renderButton(
document.getElementById('signInDiv'),
{ theme: 'outline', size: 'large' }
)
}, [])
// const googleSuccess = (res) => {
// console.log(res);
// }
// const googleFailure = () => {
// console.log('Google Sign In was unsuccessful. Try again later');
// }
return (
<Container component='main' maxWidth='xs'>
<Paper className={classes.paper} elevation={3}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography variant='h5'>{isSignup ? "Sign Up" : "Sign In"}</Typography>
<form className={classes.form} onSubmit={handleSubmit}>
<Grid container spacing={2}>
{isSignup && (
<>
<Input name='firstName' label='First Name' handleChange={handleChange} autoFocus half />
<Input name='firstName' label='First Name' handleChange={handleChange} half />
</>
)}
<Input name='email' label='Email address' handleChange={handleChange} type='email' />
<Input name='password' label='Password' handleChange={handleChange} type={showPassword ? 'text' : 'password'} handleShowPassword={handleShowPassword} />
{isSignup && <Input name='confirmPassword' label='Repeat Password' handleChange={handleChange} type='password' />}
</Grid>
<Button type='submit' fullWidth variant='contained' color='primary' className={classes.submit}>
{isSignup ? "Sign Up" : "Sign In"}
</Button>
<div id='signInDiv'></div>
<Grid container justifyContent='flex-end'>
<Grid item>
<Button onClick={switchMode}>
{isSignup ? 'Already Have an account? Sign In' : "Don't have an account? Sign Up"}
</Button>
</Grid>
</Grid>
</form>
</Paper>
</Container>
)
}
export default Auth
This is Style.js
import { makeStyles } from '#material-ui/core/styles';
import Icon from './icon';
export default makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: theme.spacing(2),
},
root: {
'& .MuiTextField-root': {
margin: theme.spacing(1),
},
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
googleButton: {
marginBottom: theme.spacing(2),
},
}));
import { makeStyles } from '#material-ui/core/styles';
import Icon from './icon';
export default makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: theme.spacing(2),
},
root: {
'& .MuiTextField-root': {
margin: theme.spacing(1),
},
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
googleButton: {
marginBottom: theme.spacing(2),
},
}));
Please help me understand how can I style the div of Google login button

Firestore "get" function getting executed multiple times

I'm a newbie at React-Native and Firebase and i'm using Firebase Cloud Firestore for a project. I'm trying to get filtered data from the database statically (as i'm learning to use it for now), but somehow my function is getting executed multiple times, the numbers of readings is increasing rapidly and i'm having some random errors too. I would like to know what's wrong.
Here is my code for the file that only deals with the database (Firestore.js):
import React, { useState, useEffect } from "react";
import { ActivityIndicator } from "react-native";
import * as firebase from "firebase";
import "firebase/firestore";
function onResult(QuerySnapshot) {
console.log("Pegamos a coleção de Animais.");
}
function onError(error) {
console.error(error);
}
export function GetAnimalsByEspecie(especie) {
const [loading, setLoading] = useState(true);
const [animais, setAnimais] = useState([]);
console.log("entrou Especie");
const subscriber = firebase
.firestore()
.collection("Animal")
.where("especie", "==", especie)
.get()
.then((querySnapshot) => {
const animaisList = [];
querySnapshot.forEach((documentSnapshot) => {
animaisList.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setAnimais(animaisList);
setLoading(false);
});
if (loading) {
console.log("loading");
return <ActivityIndicator />;
}
return animais;
}
export function GetAnimalsByNome(nomeAnimal) {
const [loading, setLoading] = useState(true);
const [animais, setAnimais] = useState([]);
console.log("entrou nome nooome");
const subscriber = firebase
.firestore()
.collection("Animal")
.where("nome", "==", nomeAnimal)
.get()
.then((querySnapshot) => {
const animaisList = [];
querySnapshot.forEach((documentSnapshot) => {
animaisList.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setAnimais(animaisList);
setLoading(false);
});
if (loading) {
console.log("loading");
return <ActivityIndicator />;
}
return animais;
}
export default function GetAnimals() {
const [loading, setLoading] = useState(true);
const [animais, setAnimais] = useState([]);
useEffect(() => {
console.log("entrou listener");
const subscriber = firebase
.firestore()
.collection("Animal")
// .where('')
.onSnapshot((querySnapshot) => {
const animaisList = [];
querySnapshot.forEach((documentSnapshot) => {
animaisList.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setAnimais(animaisList);
setLoading(false);
});
return () => subscriber();
}, []);
if (loading) {
console.log("loading");
return <ActivityIndicator />;
}
return animais;
}
Here is my code for the file that displays data on the screen (index.js):
import React, { useState } from "react";
import {
View,
Text,
KeyboardAvoidingView,
StyleSheet,
Image,
TextInput,
TouchableHighlight,
ScrollView,
Button,
ActivityIndicator,
FlatList,
} from "react-native";
import { SearchBar } from "react-native-elements";
import { createStackNavigator } from "#react-navigation/stack";
import { SafeAreaView } from "react-native-safe-area-context";
import SubmitButton from "../../shared/SubmitButton";
import FocusAwareStatusBar from "../../shared/StatusBar";
import GetAnimals, {GetAnimalsByEspecie, GetAnimalsByNome} from "../../db/Firestore";
const styles = StyleSheet.create({
background: {
flex: 1,
backgroundColor: "#fafafa",
alignItems: "center",
justifyContent: "center",
},
regform: {
alignSelf: "stretch",
},
textInput: {
fontFamily: "Roboto_400Regular",
fontSize: 14,
alignSelf: "stretch",
paddingLeft: 12,
marginHorizontal: 16,
color: "#000000",
borderBottomColor: "#dcdcdc",
borderBottomWidth: 0.8,
paddingBottom: 8,
},
label: {
alignSelf: "stretch",
marginTop: 28,
marginBottom: 32,
paddingLeft: 28,
color: "#589b9b",
},
container: {
flex: 1,
justifyContent: "center",
alignSelf: "center",
height: 128,
width: 128,
backgroundColor: "#fff",
elevation: 4,
},
button: {
alignItems: "center",
backgroundColor: "#f1f2f2",
paddingTop: 44,
paddingBottom: 48,
},
infobox: {
backgroundColor: "#cfe9e5",
borderRadius: 4,
height: 80,
width: 328,
marginTop: 16,
marginHorizontal: 16,
justifyContent: "space-evenly",
alignContent: "center",
},
infotext: {
fontFamily: "Roboto_400Regular",
fontSize: 14,
color: "#434343",
paddingHorizontal: 15,
marginVertical: 11,
textAlign: "center",
},
});
export default function Animais() {
var animais = GetAnimalsByEspecie('shitzu');
const search = () => {
const [searchQuery, setSearchQuery] = useState("");
return (
<SearchBar
placeholder="Escreva aqui..."
onChangeText={""}
value={searchQuery}
/>)
};
return (
<SafeAreaView style={{ flex: 1 }}>
<FocusAwareStatusBar barStyle="light-content" backgroundColor="#88c9bf" />
<KeyboardAvoidingView style={styles.background}>
<View>
<Text>Animais</Text>
<FlatList
ListHeaderComponent={''}
data={animais}
renderItem={({ item }) => (
<View
style={{
height: 50,
width: 350,
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<Text>Animal ID: {item.id}</Text>
<Text>Animal Name: {item.nome}</Text>
</View>
)}
/>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
I'm not using SearchBar yet, for now i'm just trying to fetch and display the data which have 'especies' field equal to 'shitzu' from the database. Sometimes I get the correct information, sometimes I get errors.
Thanks for the help.
You should put your fetches inside of a useEffect so you can make it run only once. Otherwise, when your fetch callbacks set state, you'll get a re-render, and your fetch code will run again. Also, it looks like GetAnimalsByEspecie, since it invokes hooks, should itself be a hook. For example:
export function useAnimalsByEspecie(especie) {
const [loading, setLoading] = useState(true);
const [animais, setAnimais] = useState([]);
useEffect(() => {
const subscriber = firebase
.firestore()
.collection("Animal")
.where("especie", "==", especie)
.get()
.then((querySnapshot) => {
const animaisList = [];
querySnapshot.forEach((documentSnapshot) => {
animaisList.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setAnimais(animaisList);
setLoading(false);
});
}, [especie]);
return [animais, loading];
}
...which would be used like:
function Animais() {
var [animais, isLoading] = useAnimalsByEspecie('shitzu');
const search = () => {
const [searchQuery, setSearchQuery] = useState("");
return (
<SearchBar
placeholder="Escreva aqui..."
onChangeText={""}
value={searchQuery}
/>)
};
if (isLoading) {
return <ActivityIndicator />;
}
return (
<SafeAreaView style={{ flex: 1 }}>
<FocusAwareStatusBar barStyle="light-content" backgroundColor="#88c9bf" />
<KeyboardAvoidingView style={styles.background}>
<View>
<Text>Animais</Text>
<FlatList
ListHeaderComponent={''}
data={animais}
renderItem={({ item }) => (
<View
style={{
height: 50,
width: 350,
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<Text>Animal ID: {item.id}</Text>
<Text>Animal Name: {item.nome}</Text>
</View>
)}
/>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
}

How to use dispatch in nextjs getStaticprops or getServerSideProps

I am new to Next js, I want to call the news api in useEffect and dispatch the news array to my store. then filter it based on the user's input in the search bar in the header. problem is once the use effect data fetching is done and user starts typing rather than filtering the news array the screen gets re-render and the data fetching starts again. how to prevent this re-rendering and save the news array?
I tried to use getStaticprops but useDispatch is not allowed in there.
index.js
import { fetchNews } from "../store/actions/newsActions";
import NewsInfo from "../components/NewsInfo";
import { useDispatch, useSelector } from "react-redux";
import CircularProgress from "#material-ui/core/CircularProgress";
export default function Home() {
const dispatch = useDispatch();
const { news } = useSelector((state) => state.news);
React.useEffect(() => {
dispatch(fetchNews());
}, []);
return (
<>
{/* this wrapper cmp will make each headline uniquely accessible */}
{news?.articles ? (
news.articles.map((article) => (
<React.Fragment key={article.publishedAt}>
<NewsInfo headlines={article} />
</React.Fragment>
))
) : (
<CircularProgress />
)}
</>
);
}
Header.js
import React from "react";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import IconButton from "#material-ui/core/IconButton";
import Typography from "#material-ui/core/Typography";
import InputBase from "#material-ui/core/InputBase";
import { fade, makeStyles } from "#material-ui/core/styles";
import MenuIcon from "#material-ui/icons/Menu";
import SearchIcon from "#material-ui/icons/Search";
import { useDispatch } from "react-redux";
import { filterHeadlines } from "../store/actions/newsActions";
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
display: "none",
[theme.breakpoints.up("sm")]: {
display: "block",
},
},
search: {
position: "relative",
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
"&:hover": {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: "100%",
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(1),
width: "auto",
},
},
searchIcon: {
padding: theme.spacing(0, 2),
height: "100%",
position: "absolute",
pointerEvents: "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
inputRoot: {
color: "inherit",
},
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
transition: theme.transitions.create("width"),
width: "100%",
[theme.breakpoints.up("sm")]: {
width: "12ch",
"&:focus": {
width: "20ch",
},
},
},
}));
function SearchAppBar() {
const classes = useStyles();
const dispatch = useDispatch();
const [input, setInput] = React.useState("");
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
>
<MenuIcon />
</IconButton>
<Typography className={classes.title} variant="h6" noWrap>
Material-UI
</Typography>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ "aria-label": "search" }}
value={input}
onChange={(e) => setInput(e.target.value)}
onBlur={() => dispatch(filterHeadlines(input))}
/>
</div>
</Toolbar>
</AppBar>
</div>
);
}
export default SearchAppBar;
you can use store dispatch to getServersideProps, getstaticprops
from your store file
export const rootDispatch = store.dispatch;

How to update data and render new components with API call after change of route?

I'm still new to React so I have this project which has a drawer component with several routes (Dashboard, Chart, and User Settings). Under the Dashboard component (which also consists of the Navbar and Drawer component), I have a TablePage, ChartPage and SettingsPage components which will be rendered based from the route.
When I log in, it will render the table component in the /dashboard which gets the data from an API. If I click Chart from the drawer, it will reroute to /chart.
Currently it will call an API which will get the information when the dashboard component is loaded (/dashboard) and it will pass all necessary data (props) to the child component in ChartPage and SettingsPage. The problem is, if the database is updated, I will need to refresh the page in order to get the updated data. What I want to do, is whenever the user clicks on the button from the drawer, it will call the API to get the updated value.
In order to that, I'm using the useContext hooks which will pass the readData function to the TablePage component. How do I render it once if there is no information is updated and will render the component if there is an updated information from the database? Apparently it says that the readData is not a function even though I retrieve it from the useContext method in TablePage.js.
Dashboard.js
import clsx from "clsx";
import Drawer from "#material-ui/core/Drawer";
import MenuIcon from "#material-ui/icons/Menu";
import ChevronLeftIcon from "#material-ui/icons/ChevronLeft";
import DrawerHeader from "./DrawerHeader";
import DrawerContent from "./DrawerContent";
import React, { useState, useContext, useEffect, Fragment } from "react";
import { makeStyles } from "#material-ui/core/styles";
import CssBaseline from "#material-ui/core/CssBaseline";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import IconButton from "#material-ui/core/IconButton";
// import RefreshIcon from "#material-ui/icons/Refresh";
// import Badge from "#material-ui/core/Badge";
// import NotificationsIcon from "#material-ui/icons/Notifications";
import ToggleMenu from "./ToggleMenu";
import Loader from "./Loader";
import axios from "axios";
import AuthApi from "../utils/createContext";
import moment from "moment";
import PageRoute from "./PageRoute";
import DataApi from "../utils/createContext";
const m = moment();
const today = m.format("LL");
// function refresh() {
// setTimeout(function () {
// window.location.reload();
// }, 100);
// }
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
},
listContainer: {
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: {
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: {
marginRight: 36,
},
menuButtonHidden: {
display: "none",
},
title: {
flexGrow: 1,
},
drawerPaper: {
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,
}),
width: theme.spacing(7),
[theme.breakpoints.up("sm")]: {
width: theme.spacing(9),
},
},
appBarSpacer: theme.mixins.toolbar,
// content: {
// flexGrow: 1,
// height: "100vh",
// overflow: "auto",
// },
paper: {
padding: theme.spacing(2),
display: "flex",
overflow: "auto",
flexDirection: "column",
},
fixedHeight: {
height: 240,
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
// marginLeft: "-70px",
},
contentShift: {
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginLeft: 0,
},
}));
export default function Dashboard2() {
const classes = useStyles();
const [open, setOpen] = useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
const { value } = useContext(AuthApi);
//get user and customer api
const [userData, setUserData] = useState({});
const [customerData, setCustomerData] = useState([]);
const [customerCount, setCustomerCount] = useState();
const [isFetching, setIsFetching] = useState(false);
const readData = async () => {
const fetchUserInfo = await axios.post(`/auth/getemail/${value}`);
console.log(fetchUserInfo);
// console.log(result.data.user[0]._id);
const { data } = fetchUserInfo;
const { user } = data;
let newUserData = {};
user.forEach((cData) => {
newUserData = {
joindate: cData.joindate,
email: cData.email,
adminId: cData.adminId,
_id: cData._id,
};
});
// console.log(newUserData);
setUserData(newUserData);
const fetchCustomerInfo = await axios.post(
`/customerinfo/getcustomer/${fetchUserInfo.data.user[0].adminId}`
);
// console.log(fetchCustomerInfo);
const cust = fetchCustomerInfo.data;
// console.log(cust.customer_info);
// console.log(cust.count);
setCustomerData(cust.customer_info);
setCustomerCount(cust.count);
setIsFetching(true);
};
useEffect(() => {
readData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// const username = value.slice(0, value.search("#"));
return (
<Fragment>
{isFetching ? (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="absolute"
className={clsx(classes.appBar, open && classes.appBarShift)}
>
<Toolbar className={classes.toolbar}>
<IconButton
edge="start"
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
className={clsx(
classes.menuButton,
open && classes.menuButtonHidden
)}
>
<MenuIcon />
</IconButton>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
className={classes.title}
>
Dashboard
</Typography>
{/* <IconButton color="inherit" onClick={refresh}>
<RefreshIcon />
</IconButton> */}
{/* <IconButton color="inherit">
<Badge badgeContent={4} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton> */}
<ToggleMenu />
</Toolbar>
</AppBar>
<Drawer
variant="persistent" //persistent,permanent,temporary
anchor="left"
classes={{
paper: clsx(
classes.drawerPaper,
!open && classes.drawerPaperClose
),
}}
open={open}
>
<div className={classes.toolbarIcon}>
<IconButton onClick={handleDrawerClose}>
<ChevronLeftIcon />
</IconButton>
</div>
<DrawerHeader
email={userData.email}
joindate={moment(userData.joindate).format("LL")}
id={userData._id}
/>
<DrawerContent />
</Drawer>
<DataApi.Provider
value={{
customerData,
customerCount,
userData,
isFetching,
readData,
}}
>
<main
className={clsx(classes.content, {
[classes.contentShift]: open,
})}
>
<div className={classes.appBarSpacer} />
<PageRoute
customerdata={customerData}
userdata={userData}
customercount={customerCount}
momentdate={today}
/>
</main>
</DataApi.Provider>
</div>
) : (
<Loader type={"Bars"} color={"#9370DB"} />
)}
</Fragment>
);
}
TablePage.js
import React, { useContext, useEffect, Fragment } from "react";
import MaterialTable from "material-table";
import { Container, Grid } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
import DataApi from "../utils/createContext";
import Loader from "./Loader";
const useStyles = makeStyles((theme) => ({
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
},
}));
export default function TablePage({ customerdata }) {
const classes = useStyles();
const { readData, isFetching } = useContext(DataApi);
useEffect(() => {
readData();
}, []);
return (
<Fragment>
{isFetching ? (
<div>
<Container maxWidth="lg" className={classes.container}>
<Grid>
<MaterialTable
columns={[
{ title: "Customer Name", field: "fullname" },
{ title: "Phone No.", field: "phone", type: "string" },
{ title: "Address", field: "address" },
{ title: "Date", field: "updated", type: "date" }, //Data type: 'boolean', 'numeric', 'date', 'datetime', 'time', 'currency'
{ title: "Time", field: "updated", type: "time" },
]}
data={customerdata}
title="Check-In Information"
options={{
exportButton: true,
filtering: true,
}}
/>
</Grid>
</Container>
</div>
) : (
<Loader type={"Bars"} color={"#9370DB"} />
)}
</Fragment>
);
}
UPDATED: DataApi.Provider location is changed to wrap only the Routes component and the readData dependencies on the useEffect for Table.js has been removed

Categories