Filter image component in react JS - reactjs

I have an image gallery and I want to search by language name through a search bar and It throws this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
at Languages (Languages.jsx:28:25)
at renderWithHooks (react-dom.development.js:16305:18)
at mountIndeterminateComponent (react-dom.development.js:20074:13)
at beginWork (react-dom.development.js:21587:16)
at beginWork$1 (react-dom.development.js:27426:14)
at performUnitOfWork (react-dom.development.js:26557:12
Languages.jsx ( where I map my array through a filter)
import { languages } from "../../../database/languages";
import { Searchbar } from "../components/Searchbar";
const filterData = (query, data) => {
if (!query) data;
else return data.filter((d) => d.alt.toLowerCase().includes(query));
};
export const Languages = () => {
const [searchQuery, setSearchQuery] = useState("");
const filteredData = filterData(searchQuery, languages);
return(
<Searchbar searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
{filteredData.map((language) => (
<Grid key={language.id} item xs={12} sm={6} md={6} lg={3} xl={3}>
<Card elevation={0} xs={12}>
<Typography color="text.secondary" variant="p">
{language.alt}
</Typography>
<CardMedia
sx={{ height: 250, width: "100%" }}
component="img"
image={language.image}
alt={language.alt}
/>
</Card>
</Grid>
))}
);
};
languages.jsx (this is my array)
export const languages = [
{
id: "1",
image: "boostraplogo.svg",
alt: "BOOSTRAP",
language: "boostrap",
},
{
id: "2",
image: "csslogo.svg",
alt: "CSS",
language: "css",
},
{
id: "3",
image: "htmlogo.svg",
alt: "HTML",
language: "html",
},
];
Searcbar.jsx ( this is my search bar inputt)
export const Searchbar = ({ searchQuery, setSearchQuery }) => {
return (
<form>
<TextField
onInput={(e) => {
setSearchQuery(e.target.value);
}}
label="Type a language"
placeholder="type here.."
size="small"
/>
<IconButton type="submit" aria-label="search">
<Search />
</IconButton>
</form>
);
};
I have tried adding filteredtData.filter.map(...) but it does not work either.
I also need to validate if the image they are looking for does not appear I need a message showing that is not found.

import { languages } from "../../../database/languages";
import { Searchbar } from "../components/Searchbar";
const filterData = (query, data) => {
if (!query) data;
else return data.filter((d) => d.alt.toLowerCase().includes(query));
};
export const Languages = () => {
const [searchQuery, setSearchQuery] = useState("");
const filteredData = filterData(searchQuery, languages);
return(
<Searchbar searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
{filteredData.map((language) => (
<Grid key={language.id} item xs={12} sm={6} md={6} lg={3} xl={3}>
<Card elevation={0} xs={12}>
<Typography color="text.secondary" variant="p">
{language.alt}
</Typography>
<CardMedia
sx={{ height: 250, width: "100%" }}
component="img"
image={language.image}
alt={language.alt}
/>
</Card>
</Grid>
))}
);
};
If query is not matching data you get an empty array so you cant use map on that.To resolve this check if there is filteredData and to the mapping then, in other case write a message in your UI. Like this:
import { languages } from "../../../database/languages";
import { Searchbar } from "../components/Searchbar";
const filterData = (query, data) => {
if (!query) data;
else return data.filter((d) => d.alt.toLowerCase().includes(query));
};
export const Languages = () => {
const [searchQuery, setSearchQuery] = useState("");
const filteredData = filterData(searchQuery, languages);
return(
<Searchbar searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
{(filteredData && filteredData.length > 0 ) ? filteredData.map((language) => (
<Grid key={language.id} item xs={12} sm={6} md={6} lg={3} xl={3}>
<Card elevation={0} xs={12}>
<Typography color="text.secondary" variant="p">
{language.alt}
</Typography>
<CardMedia
sx={{ height: 250, width: "100%" }}
component="img"
image={language.image}
alt={language.alt}
/>
</Card>
</Grid>
)) : <div>Enter your message for no matching query here</div>}
);
};

Related

How can I fetch data from a specific subcollection with React, typescript and firebase v9

In the react app I have a page where users can post information. I want other users to be able to comment to those posts. Currently the comments are updated to a specific subcollection by the id of the collection in firebase, but I am not able to fetch those comments.
I get an error in the useEffect that I use to fetch the data. I've tried to define info by placing a "let info : any" at the top of the useEffect, but that didn't work.
My code looks like this:
export const Info = () => {
const [info, setInfo] = useState([]);
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const { user } = useAuthContext();
useEffect(() => {
const ref = query(collection(db, "Info"), orderBy("createdAt", "desc"));
const unsub = onSnapshot(ref, (snapshot) => {
let results: any = [];
snapshot.docs.forEach((doc) => {
results.push({ ...doc.data(), id: doc.id });
});
setInfo(results);
});
return () => unsub();
}, []);
// I get an error with info.id in the useEffect
useEffect(() => {
const ref = query(
collection(db, "Info", info.id, "comments"),
orderBy("createdAt", "desc")
);
const unsub = onSnapshot(ref, (snapshot) => {
let results: any = [];
snapshot.docs.forEach((doc) => {
results.push({ ...doc.data(), id: doc.id });
});
setComments(results);
});
return () => unsub();
}, []);
return (
<Container>
{info.map((info: any) => (
<Paper>
<Grid
container
key={info.id}
id={info.id}
marginTop={2}
marginBottom={2}
alignItems="center"
>
<Grid item xs={4} justifyContent="start">
<Typography variant="h6">{info.writer}</Typography>
</Grid>
<Paper style={{ width: "100%", backgroundColor: "#652d90" }}>
<Grid item md={12} xs={12}>
<Typography
variant="h6"
className="goal"
style={{ color: "white" }}
>
{info.title}
</Typography>
</Grid>
<Grid item md={12} xs={12}>
<Typography
variant="subtitle1"
className="goal"
style={{ color: "white" }}
>
{info.content}
</Typography>
</Grid>
</Paper>
<Grid container>
<Grid item xs={1}>
<FavoriteBorderOutlinedIcon />
</Grid>
</Grid>
{/*Comments*/}
{comments.map((comment: any) => (
<Grid container key={comment.id}>
<Grid item xs={8}>
<Typography variant="h6">{comment.comment}</Typography>
</Grid>
</Grid>
))}
<Grid container marginTop={1}>
<Grid item xs={12}>
<form
onSubmit={(e: React.SyntheticEvent) => {
e.preventDefault();
const ref = collection(db, "Info", info.id, "comments");
addDoc(ref, {
comment: comment,
username: user.displayName,
createdAt: serverTimestamp(),
});
setComment("");
}}
>
<Grid container alignItems="center">
<Grid item xs={2}>
<ChatOutlinedIcon />
</Grid>
<Grid item xs={7}>
<TextField
label="Add a comment..."
color="primary"
variant="standard"
fullWidth
value={comment}
onChange={(e) => setComment(e.target.value)}
></TextField>
</Grid>
<Grid item xs={1}>
<Button type="submit">Post</Button>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
</Grid>
</Paper>
))}
</Container>
);
};
The error that I get is: Uncaught TypeError: Cannot read properties of undefined (reading 'id')
This is the structure from firestore:

Adding skeleton effect to form fields until props data is loaded

I'm passing JSON data pulled off a REST API via props to the component below. Since I don't pre-set a value to the "Pick a team" select field, it outputs the following warning:
MUI: You have provided an out-of-range value undefined for the select component.
Consider providing a value that matches one of the available options or ''.
which is normal, because there isn't a selected value.
How can I add skeleton effect to the form below until the props data is loaded?
<Skeleton variant="text" />
<Skeleton variant="circular" width={40} height={40} />
<Skeleton variant="rectangular" width={210} height={118} />
FormOne.tsx
import {
Box,
Button,
FormControl,
Grid,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
Typography,
} from '#mui/material';
import { useState } from 'react';
import { TeamSeason as Team } from './lib/interfaces/TeamSeason';
const FormOne = (props: any) => {
const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);
const [selectedQuery, setSelectedQuery] = useState<number>(1);
const handleQueryChange = (event: SelectChangeEvent) => {
setSelectedQuery(Number(event.target.value));
};
const handleTeamChange = (event: SelectChangeEvent) => {
const team = props.data.find(
(team: Team) => team.statId === Number(event.target.value)
);
setSelectedTeam(team);
};
return (
<>
<Box mb={2}>
<Typography component="h1" variant="h4" align="center">
GUI #1
</Typography>
</Box>
<Box component="form" noValidate autoComplete="off">
<Grid container spacing={2}>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="team-label">Pick a team</InputLabel>
<Select
labelId="team-label"
id="team"
value={selectedTeam?.id?.toString()}
onChange={handleTeamChange}
>
{props.data.map((team: Team) => {
return (
<MenuItem key={team.statId} value={team.statId.toString()}>
{team.name} ({team.team})
</MenuItem>
);
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="query-label">Query</InputLabel>
<Select
labelId="query-label"
id="query"
value={selectedQuery.toString()}
onChange={handleQueryChange}
>
<MenuItem value={1}>What name does he use?</MenuItem>
<MenuItem value={2}>What abbreviature does he have?</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<Button variant="contained">Submit</Button>
</Grid>
<Grid item xs={12}>
{selectedTeam && selectedQuery === 1 && (
<p>team name: {`${selectedTeam?.name}`}</p>
)}
{selectedTeam && selectedQuery === 2 && (
<p>team abbreviature: {`${selectedTeam?.team}`}</p>
)}
</Grid>
</Grid>
</Box>
</>
);
};
export default FormOne;
index.tsx
import { useState, useEffect } from 'react';
import type { NextPage } from 'next';
import Container from '#mui/material/Container';
import Box from '#mui/material/Box';
import { DataGrid, GridColDef } from '#mui/x-data-grid';
import { Grid, Paper } from '#mui/material';
import Skeleton from '#mui/material/Skeleton';
import { blue } from '#mui/material/colors';
import FormOne from './../src/FormOne';
const LoadingSkeleton = () => (
<Box
sx={{
height: 'max-content',
}}
>
{[...Array(10)].map((_, index) => (
<Skeleton variant="rectangular" sx={{ my: 4, mx: 1 }} key={index} />
))}
</Box>
);
const columns: GridColDef[] = [
{ field: 'statId', headerName: 'Stat ID' },
{ field: 'name', headerName: 'Name', width: 200 },
{ field: 'season', headerName: 'Season' },
];
const Home: NextPage = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setInterval(
() =>
fetch('https://localhost:7000/TeamSeason/2021')
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
}),
3000
);
}, []);
return (
<Container
maxWidth={false}
sx={{
height: '100vh',
overflow: 'auto',
background: `linear-gradient(to right, ${blue[200]}, ${blue[500]})`,
}}
>
<Container maxWidth="lg" sx={{ mt: 3, mb: 3 }}>
<Grid container spacing={{ xs: 2, md: 3 }}>
<Grid item xs={12} md={6}>
<Paper sx={{ padding: 3 }}>
<FormOne data={data} />
</Paper>
</Grid>
<Grid item xs={12} md={6}>
<Paper sx={{ padding: 3 }}></Paper>
</Grid>
<Grid item xs={12}>
<Paper sx={{ padding: 3 }}>
<DataGrid
getRowId={(row) => row.statId}
sx={{ height: '650px' }} // either autoHeight or this
rows={data}
columns={columns}
pageSize={10}
// autoHeight
rowsPerPageOptions={[10]}
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
components={{
LoadingOverlay: LoadingSkeleton,
}}
loading={loading}
/>
</Paper>
</Grid>
</Grid>
</Container>
</Container>
);
};
export default Home;
CodeSandbox

Undesired scrolling in React on rendering component

I have a component where the search results of a query are displayed. When clicking on a item to view its details, instead of loading normally (scrolled all the way up), the details page is, somehow, being affected by the scroll position of the results page. I know I could probably solve this by including window.scrollTo({ top: 0, left: 0 }), but I just want it to behave normally like it should and eliminate what's causing this issue.
Results.js
function Results() {
const matches = useMediaQuery("(max-width:767px)");
const navigate = useNavigate();
const [details, setDetails] = useState({ results: [] });
// Create a custom hook that binds to the `search` property from `location` url object
function useQuery() {
const { search } = useLocation();
return React.useMemo(() => new URLSearchParams(search), [search]);
}
let query = useQuery().toString();
useEffect(() => {
window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
// On successful response, assign the results to `results` array in `details` object
axios
.get(`/api/results/${query}`)
.then((response) => {
setDetails(response.data);
})
.catch((error) => {
console.log(error);
});
}, [query]);
const results = details.total_results;
const pages = details.total_pages;
const baseURL = "https://image.tmdb.org/t/p/w154";
const placeholderImg =
"https://www.genius100visions.com/wp-content/uploads/2017/09/placeholder-vertical.jpg";
return (
<CustomCard
title="Results"
content={
<div>
<Grid container>
<Typography>{results ? results : 0} results found</Typography>
<Grid item xs={12}>
<List sx={{ mt: 3 }}>
{details.results.map((result) => {
return (
<ResultItem
key={result.id}
id={result.id}
imgURL={
result.poster_path
? baseURL + result.poster_path
: placeholderImg
}
title={result.title}
year={result.release_date}
synopsis={result.overview}
/>
);
})}
</List>
</Grid>
</Grid>
<Pagination
sx={{ mt: 2 }}
count={pages}
siblingCount={matches ? 0 : 1}
onChange={(event, page) => {
const url = new URLSearchParams(window.location.search);
url.set("page", page);
const query = url.toString();
navigate(`/results?${query}`);
}}
/>
</div>
}
/>
);
}
export default Results;
ResultItems.jsx
function ResultItem(props) {
const navigate = useNavigate();
const matches = useMediaQuery("(max-width:767px)");
return (
<div>
<ListItem disablePadding>
<ListItemButton alignItems="flex-start" sx={{ pl: 0, pt: 2 }}>
<div>
<img
src={props.imgURL}
alt={`${props.title} poster`}
style={
matches
? { width: "80px", height: "120px" }
: { width: "154px", height: "231px" }
}
/>
</div>
<ListItemText
sx={{ ml: 3 }}
primary={props.title}
secondary={
<React.Fragment>
<Typography component="span" variant="body2">
{props.year.slice(0, 4)}
</Typography>
<br />
<br />
{matches ? null : (
<span style={{ textAlign: "justify" }}>{props.synopsis}</span>
)}
</React.Fragment>
}
onClick={() => navigate(`/details/${props.id}`)}
/>
</ListItemButton>
</ListItem>
<Divider />
</div>
);
}
export default ResultItem;
Details.js
function Details() {
const matches = useMediaQuery("(max-width:718px)");
const navigate = useNavigate();
const [details, setDetails] = useState({
tmdbDetails: { genres: [] },
tmdbCredits: { cast: [], crew: [] },
userData: { rating: null, review: "", view_count: null },
});
const [show, setShow] = useState(false);
const [isUpdated, setIsUpdated] = useState(false);
// GET MOVIE DETAILS AND USER LOGGED DATA
useEffect(() => {
const url = new URL(window.location.href);
axios
.get(`/api${url.pathname}`)
.then((response) => {
setDetails(response.data);
})
.catch((err) => {
console.log(err);
});
}, [isUpdated]);
const baseURL = "https://image.tmdb.org/t/p/w342";
const placeholderImg =
"https://www.genius100visions.com/wp-content/uploads/2017/09/placeholder-vertical.jpg";
// Expand section to log new diary entry or view/edit previous logged data
function handleExpand() {
setShow(!show);
}
// ENTRY DATA
const [userData, setUserData] = useState({
rating: null,
review: "",
date: new Date(),
});
// New object passing user data and movie data to be saved on database
const entryData = {
...userData,
title: details.tmdbDetails.title,
year: getYear(details),
director: getDirector(details),
genres: getGenres(details),
runtime: details.tmdbDetails.runtime,
};
// Control value on Date Picker and set it to `userData.date`
function handleDate(date) {
setUserData((prevValue) => {
return {
...prevValue,
date: date.toISOString(),
};
});
}
// Control value on Rating selector and set it to `userData.rating`
function handleRating(event, value) {
setUserData((prevValue) => {
return {
...prevValue,
rating: value,
};
});
}
// Control value on Text Area and set it to `userData.review`
function handleReview(event) {
const { value } = event.target;
setUserData((prevValue) => {
return {
...prevValue,
review: value,
};
});
}
// Submit entry to database and navigate to Diary
function onSubmit(event) {
event.preventDefault();
const url = new URL(window.location.href);
axios.post(`/api${url.pathname}`, entryData).then((res) => {
navigate("/diary");
});
}
// Function passed to the "WatchedPanel" component to be executed on saving changes after edit entry. It changes `isUpdated` state to force a re-render of `useEffect()` and update entry data on-screen
function handleUpdateDetails() {
setIsUpdated(!isUpdated);
}
return (
<Container component="main" maxWidth="md">
<Card sx={{ padding: matches ? 0 : 3, paddingBottom: 0, margin: 2 }}>
<div style={{ textAlign: "right" }}>
<IconButton
aria-label="close"
style={{ color: "#e0e0e0" }}
onClick={() => {
navigate(-1);
}}
>
<CloseIcon />
</IconButton>
</div>
<CardContent>
<Grid container alignItems="center">
{/* MOVIE TITLE & YEAR */}
<Grid item xs={12}>
<Typography variant="h5">{details.tmdbDetails.title}</Typography>
<Typography sx={{ mb: 2 }} variant="h6">
({getYear(details)})
</Typography>
</Grid>
{/* MOVIE POSTER */}
<Grid item xs={12} sm={matches ? 12 : 5} md={4}>
<div style={{ textAlign: matches ? "center" : "left" }}>
<Poster
source={
details.tmdbDetails.poster_path
? baseURL + details.tmdbDetails.poster_path
: placeholderImg
}
altText={`${details.tmdbDetails.title} poster`}
/>
</div>
</Grid>
{/* MOVIE DETAILS */}
<Grid item xs={12} sm={7} md={8}>
<Collapse in={matches ? show : true}>
<Credits
director={getDirector(details).join(", ")}
cast={getCast(details)}
genres={getGenres(details).join(", ")}
runtime={details.tmdbDetails.runtime}
/>
</Collapse>
</Grid>
<Grid item xs={12} sx={{ mt: 2 }}>
<Collapse in={matches ? show : true}>
<Typography style={{ fontWeight: "bold" }}>Synopsis</Typography>
<Typography>{details.tmdbDetails.overview}</Typography>
</Collapse>
</Grid>
{/* EXPAND SECTION BUTTON */}
{matches ? (
<Fab
color="primary"
size="small"
aria-label="expand"
sx={{ m: "auto", mt: 2 }}
onClick={handleExpand}
>
{show ? <RemoveIcon /> : <AddIcon />}
</Fab>
) : null}
</Grid>
</CardContent>
</Card>
{/* LOG MOVIE PANEL */}
{details.userData === undefined ? (
<UnwatchedPanel
date={userData.date}
onDateChange={handleDate}
rating={userData.rating}
onRatingChange={handleRating}
review={userData.review}
onReviewChange={handleReview}
view_count={
details.userData === undefined ? null : details.userData.view_count
}
onClick={onSubmit}
/>
) : (
<WatchedPanel
date={userData.date}
onDateChange={handleDate}
rating={details.userData.rating}
review={details.userData.review}
view_count={details.userData.view_count}
onSubmit={onSubmit}
onSaveChanges={handleUpdateDetails}
/>
)}
</Container>
);
}
export default Details;
My mistake, actually: this is, indeed, the normal React behavior. If you're navigating from one (scrollable) component to another the scrollbar isn't aware of it, since you're just changing views without reloading the whole page, and will keep it's y (and x) position. To avoid this behavior you need to manually set the scroll position on re-render, like so:
useEffect(() => {
window.scrollTo({ top: 0, left: 0 });
// Do some stuff
}, []);

React RefObject as Array in TypeScript

I have problem with get values from reference object in array. Get data from reducer -> each on collection -> get values from input
When entering to component reference return empty array, but when I save something in code the reference working.
Can anyone help me? I am a beginner with React and Typescript and someone can explain me what I doing wrong.
Some code
interface StorableCreateProps extends RouteComponentProps<MatchParams> {
containers: Container[],
getContainers: () => void
addStorables: (locations: Array<string>, storables: Object[]) => void
}
type StorableCreateState = {
storablesCount: Array<any>,
open: boolean
}
class StorableCreate extends React.Component<StorableCreateProps, StorableCreateState> {
containerCount: React.RefObject<HTMLInputElement>[] = this.props.containers.map(() => React.createRef());
componentDidMount() {
this.props.getContainers()
}
render() {
console.log(this.containerCount.map(el => el.current));
return (
<div>
<Card variant="outlined">
<CardContent>
<Box>
{
this.props.containers.map((row, index) => {
return (
<div key={index}>
<ContainerStorable ref={this.containerCount[index]} container={row} />
</div>
)
})
}
</Box>
</CardContent>
</Card>
</div>
)
}
}
type ContainerStorableProps = {
container: Container,
}
export const ContainerStorable = React.forwardRef<HTMLInputElement, ContainerStorableProps>((props, ref) => {
const [count, setCount] = React.useState<string>("0");
return (
<div>
<Grid container spacing={4} justify="center">
<Grid item md={4}>
<Typography variant="body1">{props.container.container_name}</Typography>
</Grid>
<Grid item md={2}>
<Typography variant="body1">{props.container.short_name}</Typography>
</Grid>
<Grid item md={1}>
<TextField
fullWidth
placeholder="0"
size="small"
label="Count"
value={count}
inputRef={ref}
variant="outlined"
onChange={(e) => setCount(e.target.value)}
name={props.container.id.toString()}
/>
</Grid>
<Grid item md={2}>
<Button
variant="contained"
className="btn-success"
style={{ borderRadius: '50%', width: 40, height: 40, minWidth: 0 }}
>
<Add />
</Button>
</Grid>
</Grid>
</div>
)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Transfer data to dialog box when clicked

I would like when clicking on my accordion, the data in this line will go into the form of my dialog box. But I am not receiving any data in the form.
Why is the form not receiving the data?
import React, { useEffect, useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import moment from 'moment';
import PerfectScrollbar from 'react-perfect-scrollbar';
import {
Avatar,
Box,
Card,
Accordion,
AccordionSummary,
AccordionDetails,
Grid,
SvgIcon,
InputAdornment,
CardContent,
TextField,
ListItemText,
ListItem,
List,
Checkbox,
Table,
TableBody,
TableCell,
TableHead,
TablePagination,
IconButton,
Typography,
makeStyles,
Button
} from '#material-ui/core';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import getInitials from 'src/utils/getInitials';
import EditProjAdminE from './editProjAdminE';
import AjoutEven from './ajoutEven';
import dataEven from './data';
import SpeedDialTooltipOpen from './speedDialE';
import EditIcon from '#material-ui/icons/Edit';
import AddIcon from '#material-ui/icons/Add';
import { Search as SearchIcon } from 'react-feather';
import { Slide } from 'react-slideshow-image';
import axios from "axios";
import DeleteIcon from '#material-ui/icons/Delete';
const useStyles = makeStyles((theme) => ({
root: {},
absolute: {
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(3),
},
avatar: {
marginRight: theme.spacing(2)
}
}));
const ProjetAdminE = ({ className, dataEleve, ...rest }) => {
const classes = useStyles();
// const [data, setData] = useState(dataEven);
const [filteredEven, setFilteredEven] = useState([]);
const [dataSearch, setDataSearch] = useState([]);
const [loading, setLoading] = useState(false);
const [limit, setLimit] = useState(10);
const [page, setPage] = useState(0);
const [selectedeleveIds, setSelectedeleveIds] = useState([]);
// const dateR = new Date()
// const dateReel = dateR.setDate(dateR.getDate()+1);
const handleLimitChange = (event) => {
setLimit(event.target.value);
};
const handlePageChange = (event, newPage) => {
setPage(newPage);
};
const [search, setSearch] = useState('');
useEffect(() => {
setLoading(true);
axios
.get("http://localhost:8080/employees")
.then((res) => {
setDataSearch(res.data);
setLoading(false);
})
.catch((err) => {
console.log(err);
});
}, []);
const suppression = (id) => {
fetch('http://localhost:8080/evenement/' + id, {
method: 'DELETE',
})
.then(res => res.text())
.then(res => {
// setDataSearch(res.data);
console.log(res)
})
alert(JSON.stringify("événement Numéro " + id + " supprimé"))
}
// const modification =(id) =>{
// fetch('http://localhost:8080/update/' + id, {
// method: 'PUT',
// })
// .then(res => res.text())
// .then(res => console.log(res))
// alert(JSON.stringify("événement Numéro " +id+ " modifié"))
// }
// alert(JSON.stringify(index))
useEffect(() => {
setFilteredEven(
dataSearch.filter((Evenen) =>
Evenen.descrip_evene.toLowerCase().includes(search.toLowerCase())
)
);
}, [search, dataSearch]);
return (
<Card
className={clsx(classes.root, className)}
{...rest}
>
<>
<Box
display="flex"
justifyContent="left"
style={{ height: 30 }}
>
<Typography variant="h3" style={{ margin: 10, color: '#1565C0' }}>
LISTE DES EVENEMENTS
</Typography>
</Box>
<Box mt={3}>
<Card>
<CardContent>
<Box maxWidth={500}>
<TextField
value={search}
onChange={e => {
setSearch(e.target.value);
}}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SvgIcon
fontSize="small"
color="action"
>
<SearchIcon />
</SvgIcon>
</InputAdornment>
)
}}
placeholder="Recherchez un évenement"
variant="outlined"
/>
</Box>
{/* <Button
color="primary"
variant="contained"
onClick = {alert(JSON.stringify(dateReel))}
>
Rechercher
</Button> */}
</CardContent>
</Card>
</Box>
<Grid>
<Grid spacing={1} md={8} xs={12} style={{ margin: 2 }}>
{filteredEven.map((recherche, index) => (
<Accordion style={{ marginTop: 30 }} >
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
style={{ backgroundColor: '#DADFD9' }}
>
<Grid container spacing={1} md={12} xs={12} style={{ margin: 0 }}>
<Grid item md={2} xs={4}>
{recherche.date_even.slice(0, 10)}
</Grid>
<Grid item md={2} xs={2}>
{recherche.prix_even}
</Grid>
<Grid item md={2} xs={3}>
{recherche.statut}
</Grid>
<Grid item md={3} xs={3}>
{recherche.descrip_evene}
</Grid>
<Grid item md={3} xs={8} style={{ marginTop: -10 }}>
<IconButton>
<EditProjAdminE
dataSearch={dataSearch}
setDataSearch={setDataSearch}
id={recherche.id}
/>
</IconButton>
<IconButton
onClick={async () => {
suppression(recherche.id)
window.location.reload(false)
}}
>
<DeleteIcon fontSize="small" style={{ color: 'black' }} />
</IconButton>
{/* <SpeedDialTooltipOpen/> */}
</Grid>
</Grid>
</AccordionSummary>
<AccordionDetails>
<List>
<ListItem>
<ListItemText primary={
<Typography variant="caption" style={{ fontWeight: 'bold', fontSize: 16 }}>
{recherche.id}
</Typography>
}
secondary="Membre concerné"
/>
</ListItem>
<ListItem>
<ListItemText primary={
<Typography variant="caption" style={{ fontWeight: 'bold', fontSize: 16 }}>
{recherche.lieu}
</Typography>
}
secondary="Lieu"
/>
</ListItem>
<ListItem>
<ListItemText primary={
<Typography variant="caption" style={{ fontWeight: 'bold', fontSize: 16 }}>
{recherche.heure}
</Typography>
}
secondary="Heure"
/>
</ListItem>
</List>
</AccordionDetails>
</Accordion>
))}
</Grid>
</Grid>
<AjoutEven />
</>
</Card>
);
};
// Results.propTypes = {
// className: PropTypes.string,
// dataEleve: PropTypes.array.isRequired
// };
export default ProjetAdminE;
editProjetEven.js
import React, { useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import moment from 'moment';
import PerfectScrollbar from 'react-perfect-scrollbar';
import { makeStyles, useTheme, withStyles } from '#material-ui/core/styles';
import {
Button,
Grid,
MenuItem,
DialogContent,
DialogActions,
Dialog,
IconButton,
Avatar,
TextField,
DialogTitle,
} from '#material-ui/core';
import getInitials from 'src/utils/getInitials';
import CreateIcon from '#material-ui/icons/Create';
import EditIcon from '#material-ui/icons/Edit';
import DeleteIcon from '#material-ui/icons/Delete';
const useStyles = makeStyles((theme) => ({
root: {
width: 645,
},
item: {
height: 50
},
buttonDial: {
color: "#fff",
},
buttonAnnuler: {
color: "red"
},
buttonSave: {
background: "#558b2f",
color: "#558b2f",
}
}));
export default function EditProjAdminE(setDataSearch,dataSearch,data,setData,id,index) {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [opens, setOpens] = React.useState(false);
const handleChange = event => {
const { name, value } = event.target
setDataSearch({ ...dataSearch, [name]: value })
}
// const fullScreen = useMediaQuery(theme.breakpoints.down(645));
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
// const handleInputChange = event => {
// const { name, value } = event.target
// setData({ ...data, [name]: value })
// }
// const item = dataSearch.find(id);
return (
<div>
<div display="flex">
<IconButton onClick={handleClickOpen}>
<EditIcon fontSize="small" alt="modifier" style={{ color: '#205723' }} />
</IconButton>
</div>
<Dialog
fullWidth
// fullScreen
open={open }
onClose={handleClose}
aria-labelledby="responsive-dialog-title"
maxWidth = 'md'
>
{/* { index ==="" ? "aucune information":
<> */}
<DialogTitle id="responsive-dialog-title">Virement</DialogTitle>
<DialogContent >
<Grid container spacing={1}>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="text"
name="prix_even"
value={dataSearch.prix_even}
// defaultValue={dataSearch.prix_even}
label="Prix"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="text"
name="heure"
value={dataSearch.heure}
label="Heure"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="text"
name="lieu"
value={dataSearch.lieu}
label="Lieu"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="date"
name="date_even"
value={dataSearch.date_even}
helperText="Date de l'événement"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="text"
name="descrip_even"
value={dataSearch.descrip_even}
label="Descr de l'événement"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
<Grid item md={4} xs={12}>
<TextField
fullWidth
margin="dense"
type="text"
name="statut"
value={dataSearch.statut}
label="Statut"
variant="outlined"
onChange={(event) => handleChange(event)}
/>
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button
// onClick={alert(JSON.stringify(dataSearch))}
>
Modifier
</Button>
<Button onClick={handleClose} className={classes.buttonAnnuler}>
Fermer
</Button>
</DialogActions>
{/* </>
} */}
</Dialog>
</div>
);
}
on click I pass the index of the object to the array and send it to a new array that I created
<IconButton onClick={async () => {
setData({ ...dataSearch[index] })
handleClickOpen()
}}
>
<EditIcon fontSize="small" alt="modifier" style={{ color: '#205723' }} />
</IconButton>
The handleClickOpen seems to be only opening the dialog box and not invoking setDataSearch({ ...dataSearch, [name]: value }) which seems to be responsible to add values to the dataSearch object that is used in your form fields.
I would personally double check if the EditProjAdminE component is receiving the proper dataSearch and then later call a similar function to handleChange when the open event is triggered.

Resources