I'm still trying to get the hang of passing state between components in React. I have a NavigationBar and RunSimsModal component, with a Ratings page.
The user tweaks inputs on the Ratings page which then contains inputs that go into RunSimsModal. I'm not sure how to do this as RunSimsModal is only accessible from NavigationBar. The NavigationBar does not know the Ratings state at any time. How do I go about passing data/state from Ratings to RunSimsModal ?
NavigationBar.js
import React, {useState} from "react";
import { Nav, Navbar, Form, FormControl, Button } from "react-bootstrap";
import styled from "styled-components";
import RunSimsModal from "./RunSimsModal";
const Styles = styled.div`
.navbar {
background-color: #222;
}
a,
.navbar-nav,
.navbar-light .nav-link {
color: #9fffcb;
&:hover {
color: white;
}
}
.navbar-brand {
font-size: 1.4em;
color: #9fffcb;
&:hover {
color: white;
}
}
.form-center {
position: absolute !important;
left: 55%;
right: 25%;
}
`;
export const NavigationBar = function () {
const [modalShow, setModalShow] = useState(false);
return <Styles>
<Navbar expand="lg" fixed ="top">
<Navbar.Brand href="/">Decade3</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Form className="form-center">
<FormControl type="text" placeholder="Search" className="" />
</Form>
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
<Button variant="primary" onClick={() => setModalShow(true)} >Run Sims</Button>{' '}
<Nav.Item>
<Nav.Link href="/">Home</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link href="/about">About</Nav.Link>
</Nav.Item>
</Nav>
</Navbar.Collapse>
</Navbar>
<RunSimsModal show={modalShow} onHide={() => setModalShow(false)} />
</Styles>
}
RunSimsModal.js
import React, { useState} from "react";
import { Button, Modal, FormFile, Form } from "react-bootstrap";
import * as outrightSimulatorApi from "../api/outrightSimulatorApi";
import Body from "../api/model/body.json";
import { withRouter } from "react-router-dom";
function RunSimsModal({ staticContext, ...props }) {
const [numberofSims, setNumberOfSims] = useState("");
const [simName, setSimName] = useState("");
const runSims = event => {
console.log("triggered");
outrightSimulatorApi.runSim(
Body.clientId,
simName,
numberofSims,
Body.teamRatings, //This is the data I want to pass in from the Ratings page, it's an array
Body.fixtureOverrides,
Body.tournamentId
);
props.history.push("/reports");
};
return (
<Modal
{...props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Run Simulations
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Run Sims</h4>
<Form onSubmit={runSims}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Number Of Simulations</Form.Label>
<Form.Control
required
type="text"
placeholder="Enter number of sims"
value={numberofSims}
onChange={e => setNumberOfSims(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="formBasicEmail">
<Form.Label>Simulation Name</Form.Label>
<Form.Control
required
type="text"
placeholder="Enter simulation name"
value={simName}
onChange={e => setSimName(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="formBasicEmail">
<Form.Label>Tournament Type</Form.Label>
<Form.Control as="select">
<option>LEAGUE</option>
</Form.Control>
</Form.Group>
<Form.Group controlId="formBasicEmail">
<Form.Label>Teams in tournament</Form.Label>
<FormFile.Input />
</Form.Group>
<Button type="submit">Run</Button>
</Form>
</Modal.Body>
<Modal.Footer>
<Button onClick={props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
);
}
export default withRouter(RunSimsModal);
Ratings.js
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { Table } from "react-bootstrap";
import NumericInput from "react-numeric-input";
import Teams from "../assets/Teams.js";
import { loadRatings } from "../actions/outrightSimulatorActions";
import ratingsStore from "../stores/ratingsStore";
const GridWrapper = styled.div`
display: grid;
grid-gap: 10px;
margin-top: 4.5em;
margin-left: 6em;
margin-right: 6em;
grid-template-columns: repeat(1, 1fr);
grid-auto-rows: minmax(25px, auto);
`;
const TeamIcon = styled.span`
margin-right: 0.5em;
`;
const teams = Teams;
function Display() {
return (
<GridWrapper>
<div>
<RatingsGrid />
</div>
</GridWrapper>
);
}
function RatingsGrid() {
const [ratings, setRatings] = useState(ratingsStore.getRatings());
useEffect(() => {
ratingsStore.addChangeListener(onChange);
if (ratingsStore.getRatings().length === 0) loadRatings();
return () => {
ratingsStore.removeChangeListener(onChange);
};
}, []);
function onChange() {
console.log("ratings changed");
setRatings(ratingsStore.getRatings());
}
return (
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Teams</th>
<th>Ratings</th>
<th>Home Advantage</th>
</tr>
</thead>
<tbody>
{ratings.map(rating => (
<tr key={rating.teamId}>
<td>
<TeamIcon>
<span>
<img
src={teams.find(t => t.id === rating.teamId).icon}
className="icon"
height="42"
width="42"
alt={rating.teamName}
/>
</span>
{rating.teamName}
</TeamIcon>
</td>
<td>
<NumericInput
value={rating.rating}
step={0.01}
mobile={false}
size="14"
/>
</td>
<td>
<NumericInput value={0.4} step={0.01} mobile={false} size="14" />
</td>
</tr>
))}
</tbody>
</Table>
);
}
export default Display;
Related
Hi Everyone, Many Greetings from Turkey.
firstly this is my App.js Codes
/* React Imports*/
import { Routes, Route } from "react-router-dom";
import { useState } from "react";
/*Local Imports */
import { ColorModeContext, useMode } from "./theme";
import Dashboard from "./WorkPages/Dashboard/Dashboard";
import Topbar from "./WorkPages/GlobalPages/Topbar";
import Sidebar from "./WorkPages/GlobalPages/Sidebar";
import Team from "./WorkPages/Team/Team";
import CreateNewUser from "./WorkPages/CreateNewUser/CreateNewUser";
import Projects from "./WorkPages/Projects/Projects";
import CreateNewProjects from "./WorkPages/CreateNewProject/CreateNewProject";
import Bar from "./WorkPages/BarChart/BarChart";
import PieChart from "./WorkPages/PieChart/PieChart";
import LineChartGraph from "./WorkPages/LineChartGraph/LineChartGraph";
import TeamLocation from "./WorkPages/TeamLocation/TeamLocation";
import ProductBooks from "./WorkPages/ProductBooks/ProductBooks";
import WorkPlan from "./WorkPages/WorkPlan/WorkPlan";
import RoomInfoInput from "./WorkPages/RoomInfoInput/RoomInfoInput";
import StairsInfoInput from "./WorkPages/StairsInfoInput/StairsInfoInput";
import Specifications from "./WorkPages/Specifications/Specifications";
import InteractiveDB from "./WorkPages/InteractiveDB/InteractiveDB";
import Multiplication from "./WorkPages/Multiplication/Multiplication";
import ImportData from "./WorkPages/ImportData/ImportData";
import ExportData from "./WorkPages/ExportData/ExportData";
import HelpMenu from "./WorkPages/HelpMenu/HelpMenu";
/*MUI Imports */
import { CssBaseline, ThemeProvider } from "#mui/material";
import BarChart from "./components/_BarChart";
import Tabs from "#mui/material/Tabs";
function App() {
const [theme, colorMode] = useMode();
const [isSidebar, setIsSidebar] = useState(true);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<CssBaseline />
<Tabs>
<div className="app">
<Sidebar isSidebar={isSidebar} />
<main className="content">
<Topbar setIsSidebar={setIsSidebar} />
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/team" element={<Team />} />
<Route
path="/createnewuser"
element={<CreateNewUser />}
/>
<Route path="/projects" element={<Projects />} />
<Route
path="/createnewproject"
element={<CreateNewProjects />}
/>
<Route path="/barchart" element={<BarChart />} />
<Route path="/piechart" element={<PieChart />} />
<Route path="/linechart" element={<LineChartGraph />} />
<Route
path="/teamlocation"
element={<TeamLocation />}
/>
<Route
path="/productbooks"
element={<ProductBooks />}
/>
<Route path="/workplan" element={<WorkPlan />} />
<Route
path="/roominfoinput"
element={<RoomInfoInput />}
/>
<Route
path="/stairsinfoinput"
element={<StairsInfoInput />}
/>
<Route
path="/specifications"
element={<Specifications />}
/>
<Route
path="/interactivedb"
element={<InteractiveDB />}
/>
<Route
path="/multiplication"
element={<Multiplication />}
/>
<Route path="/importdata" element={<ImportData />} />
<Route path="/exportdata" element={<ExportData />} />
<Route path="/helpmenu" element={<HelpMenu />} />
</Routes>
</main>
</div>
</Tabs>
</ThemeProvider>
</ColorModeContext.Provider>
);
}
export default App;
My index.css codes
/* Google Fonts */
#import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght#400;600;700&display=swap');
/* CSS CODES*/
html,
body,
#root,
.app,
.content {
height: 100%;
width: 100%;
font-family: "Source Sans Pro", sans-serif;
overflow: hidden;
/* Default Font Will be "Source Sans Pro" */
}
.app {
display: flex;
position: relative;
}
/* Scroll Bar Setting */
::-webkit-scrollbar {
width: 10px;
}
/* Track Bar Setting */
::-webkit-scrollbar-track {
background: #e0e0e0;
}
/* Handle Setting */
::-webkit-scrollbar-thumb {
background: #888;
}
/* Handle On Hover Setting */
::-webkit-scrollbar-track:hover {
background: #555;
}
and current view of my project on the browser
How can I fix this problem with css codes or without css so with MUI classes? I tried many way to fix that but I didn't get a solution.
I tried
overflow:hidden
code lines but they're doesn't working for my problem.
here is my sidebar codes
/*REACT IMPORTS*/
import { useState } from "react";
import { Link } from "react-router-dom";
/*MUI IMPORTS*/
import { Box, IconButton, Typography, useTheme } from "#mui/material";
/*MUI ICONS IMPORTS*/
import MenuOutlinedIcon from "#mui/icons-material/MenuOutlined";
import HomeOutlinedIcon from "#mui/icons-material/HomeOutlined";
import EngineeringOutlinedIcon from "#mui/icons-material/EngineeringOutlined";
import FoundationOutlinedIcon from "#mui/icons-material/FoundationOutlined";
import BarChartOutlinedIcon from "#mui/icons-material/BarChartOutlined";
import DonutSmallOutlinedIcon from "#mui/icons-material/DonutSmallOutlined";
import StackedLineChartOutlinedIcon from "#mui/icons-material/StackedLineChartOutlined";
import LocationSearchingOutlinedIcon from "#mui/icons-material/LocationSearchingOutlined";
import MenuBookOutlinedIcon from "#mui/icons-material/MenuBookOutlined";
import CalendarMonthOutlinedIcon from "#mui/icons-material/CalendarMonthOutlined";
import InputOutlinedIcon from "#mui/icons-material/InputOutlined";
import StairsOutlinedIcon from "#mui/icons-material/StairsOutlined";
import LibraryBooksOutlinedIcon from "#mui/icons-material/LibraryBooksOutlined";
import StorageOutlinedIcon from "#mui/icons-material/StorageOutlined";
import DynamicFeedOutlinedIcon from "#mui/icons-material/DynamicFeedOutlined";
import FileUploadOutlinedIcon from "#mui/icons-material/FileUploadOutlined";
import FileDownloadOutlinedIcon from "#mui/icons-material/FileDownloadOutlined";
import HelpOutlinedIcon from "#mui/icons-material/HelpOutlined";
/*LOCAL IMPORTS*/
import { tokens } from "../../theme";
/*OTHER IMPORTS MAIN COMMENT*/
/*REACT PRO SIDEBAR IMPORTS*/
import { ProSidebar, Menu, MenuItem } from "react-pro-sidebar";
import "react-pro-sidebar/dist/css/styles.css";
/*-----------Components--------------*/
const Item = ({ title, to, icon, selected, setSelected }) => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
return (
<MenuItem
active={selected == title}
style={{ color: colors.grey[100] }}
onClick={() => setSelected(title)}
icon={icon}>
<Typography>{title}</Typography>
<Link to={to} />
</MenuItem>
);
};
const Sidebar = () => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
const [isCollapsed, setIsCollapsed] = useState(false);
const [selected, setSelected] = useState("Dashboard");
return (
<Box
sx={{
"& .pro-siderbar-inner": {
background: `${colors.primary[400]} !important`,
},
"& .pro-icon-wrapper": {
backgroundColor: "transparent ! important",
},
"& .pro-inner-item": {
padding: "5px 35px 5px 20px !important",
},
"& .pro-inner-item:hover": {
color: "#F08221 !important",
},
"& .pro-menu-item.active": {
colors: "#6870fa !important",
},
}}>
<ProSidebar collapsed={isCollapsed}>
{/* COMPANY LOGO AND MENU ICON */}
<Menu iconShape='square'>
<MenuItem
onClick={() => setIsCollapsed(!isCollapsed)}
icon={
isCollapsed ? (
<MenuOutlinedIcon fontSize='large' />
) : undefined
}
style={{ margin: "10px 0 20px 0", color: colors.grey[100] }}>
{!isCollapsed && (
<Box
display='flex'
justifyContent='space-between'
alignItems='center'
ml='15px'
overflow='hidden'>
<Typography variant='h3'>Metraj Merkezi</Typography>
<IconButton
onClick={() => setIsCollapsed(!isCollapsed)}>
<MenuOutlinedIcon fontSize='large' />
</IconButton>
</Box>
)}
</MenuItem>
{!isCollapsed && (
<Box mb='25px'>
<Box
display='flex'
justifyContent='center'
alignItems='center'>
<img
alt='profile-user'
width='100px'
height='100px'
src={`../../assets/fikret.jpg`}
style={{ cursor: "pointer", borderRadius: "50%" }}
/>
</Box>
<Box textAlign='center'>
<Typography variant='h3' color={colors.grey[100]}>
Fikret AKBAŞ
</Typography>
<Typography variant='h6' color={colors.grey[500]}>
Metraj Merkezi CEO
</Typography>
</Box>
</Box>
)}
<Box paddingLeft={isCollapsed ? undefined : "10%"}>
<Item
title='Anasayfa'
to='/'
icon={<HomeOutlinedIcon fontSize='large' />}
selected={selected}
setSelected={setSelected}
/>
<Typography
variant='h6'
color={colors.grey[300]}
sx={{ m: "15px 0 5px 20px" }}>
Yönetici Paneli
</Typography>
<Item
title='Takımı Yönet'
to='/team'
icon={<EngineeringOutlinedIcon fontSize='large' />}
selected={selected}
setSelected={setSelected}
/>
... there are many items but I didn't add here for too long waste codes here
</Box>
</Menu>
</ProSidebar>
</Box>
);
};
export default Sidebar;
here is my Topbar codes
/*REACT IMPORTS*/
import { useContext } from "react";
/*MUI IMPORTS*/
import { Box, IconButton, useTheme } from "#mui/material";
import InputBase from "#mui/material/InputBase";
/*MUI ICONS IMPORTS*/
import LightModeOutlinedIcon from "#mui/icons-material/LightModeOutlined";
import DarkModeOutlinedIcon from "#mui/icons-material/DarkModeOutlined";
import NotificationsOutlinedIcon from "#mui/icons-material/NotificationsOutlined";
import SettingsOutlinedIcon from "#mui/icons-material/SettingsOutlined";
import PersonOutlinedIcon from "#mui/icons-material/PersonOutlined";
import SearchIcon from "#mui/icons-material/Search";
import FolderSharedOutlinedIcon from "#mui/icons-material/FolderSharedOutlined";
import FactCheckOutlinedIcon from "#mui/icons-material/FactCheckOutlined";
/*LOCAL IMPORTS*/
import { ColorModeContext, tokens } from "../../theme";
/*OTHER IMPORTS MAIN COMMENT*/
/*OTHER IMPORTS*/
/*-----------Components--------------*/
const Topbar = () => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
const colorMode = useContext(ColorModeContext);
return (
<Box display="flex" justifyContent="space-between" p={2}>
{/* SEARCH BAR */}
<Box
display="flex"
backgroundColor={colors.primary[700]}
borderRadius="3px"
>
<InputBase sx={{ ml: 2, flex: 1 }} placeholder="Search" />
<IconButton type="button" sx={{ p: 1 }}>
<SearchIcon />
</IconButton>
</Box>
{/* ICONS */}
<Box display="flex" border="1px solid" borderRadius={3}>
<IconButton onClick={colorMode.toggleColorMode}>
{theme.palette.mode === "dark" ? (
<LightModeOutlinedIcon />
) : (
<DarkModeOutlinedIcon />
)}
</IconButton>
<IconButton>
<FactCheckOutlinedIcon />
</IconButton>
<IconButton>
<FolderSharedOutlinedIcon />
</IconButton>
<IconButton>
<NotificationsOutlinedIcon />
</IconButton>
<IconButton>
<SettingsOutlinedIcon />
</IconButton>
<IconButton>
<PersonOutlinedIcon />
</IconButton>
</Box>
</Box>
);
};
export default Topbar;
As of right now my searchbar wont minimize, I don't really know how to write a code so if it's empty it doesn't display anything. Also I would like to be able to click somewhere else on the screen to make it dissapear. Anyone got any ideas? :)
GIF of problem: https://gyazo.com/518e8a14216b527c003aab7fc32f343c
My input:
<input
className="form-control"
placeholder="Search CARLDb..."
value={props.value}
onChange={(event) => props.setSearchValue(event.target.value)}>
</input>
My search list: https://gyazo.com/a7c5b2f2ada0379f2d5b0cee717d7d07
import React from "react";
import { Link } from "react-router-dom";
import "./components.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faStar } from "#fortawesome/free-solid-svg-icons";
import placeholder from './Images/placeholder.jpg'
const image_url = "https://image.tmdb.org/t/p/w500";
const SearchList = (props) => {
return (
<>
{props.tvShow?.map((movie) => (
<div key={movie.id} className="search-box">
<img
className="search-image"
src={movie.poster_path === null ? placeholder : image_url + movie.poster_path}
alt={movie.poster_path}
/>
<span className="search-span">
<FontAwesomeIcon id="search-star" icon={faStar} />
{movie.vote_average}
</span>
<a className="search-link" href={`https://www.themoviedb.org/movie/${movie.id}`} target="_blank" rel="nooponer noreferrer">
<p className="searchp" onClick={()=> props.handleFavouritesClick(movie)}>{movie.title || movie.name}</p>
</a>
</div>
))}
</>
);
};
export default SearchList;
CSS:
.search-list { /*built with container fluid*/
position: absolute;
left: 38%;
width: 350px;
display: inline;
z-index: 99;
max-height: 40%;
max-width: 550px;
}
.search-box {
background-color: #1a1a1a;
height: 75px;
max-width: 505px;
display: flex;
border: 1px solid black;
overflow: hidden;
}
Please let me know if I should there is any other code you would like to see. I'm a beginner to React and JavaScript.
Thanks! :)
edit: refered to searchbar instead of my results. I would like to keep the searchbar at all times but I want my resultbox to dissapear.
edit2: added navbar.js and app.js
Navbar.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import logo from "../carldb2.png";
import "bootstrap/dist/css/bootstrap.min.css";
import "./components.css";
import SearchBox from "./SearchBox";
import SearchList from "./SearchList";
const Navbar = (props) => {
const getSearchRequest = async () => {
const search_url = `https://api.themoviedb.org/3/search/movie?api_key=1e08baad3bc3eca3efdd54a0c80111b9&language=en-US&query=${props.searchValue}&page=1&include_adult=false`;
const response = await fetch(search_url);
const responseJson = await response.json();
if (responseJson.results) {
props.setMovieSearch(responseJson.results.slice(0, 7));
}
};
useEffect(() => {
if (props.searchValue) {
getSearchRequest();
}
}, [props.searchValue]);
return (
<div>
<nav className="navbar">
<div className="nav-center d-flex">
<Link to="/">
<img className="logo" src={logo} alt="logo" />
</Link>
<SearchBox
searchValue={props.searchValue}
setSearchValue={props.setSearchValue}
/>
</div>
</nav>
<div className="container-fluid search-list">
<SearchList
tvShow={props.movieSearch}
handleFavouritesClick={props.addRecentlyViewed}
/>
<Link to="/search">
<button className="results" onClick={closeFunction()}>
<h7 className="results-text">See all results for "{props.searchValue}"</h7>
</button>
</Link>
</div>
</div>
);
};
export default Navbar;
app.js
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Homepage from "./components/Homepage";
import Footer from "./components/Footer";
import Navbar from "./components/Navbar";
import React, { useEffect } from "react";
import SearchPage from "./components/SearchPage";
function App() {
const [searchValue, setSearchValue] = React.useState("");
const [movieSearch, setMovieSearch] = React.useState([]);
const [tvShow, setTVShow] = React.useState([]);
const [recentlyViewed, setRecentlyViewed] = React.useState([]);
useEffect(() => {
const recentlyMovies = [
...new Set(
JSON.parse(localStorage.getItem("recently-watched"))
),
];
if (recentlyMovies) {
setRecentlyViewed([...new Set(recentlyMovies.slice(0, 5))]);
}
}, []);
const saveToLocalStorage = (items) => {
localStorage.setItem("recently-watched", JSON.stringify(items));
};
const addRecentlyViewed = (movie) => {
recentlyViewed.forEach((item) => {
let index = recentlyViewed.indexOf(item);
if (item.id === movie.id) {
recentlyViewed.splice(index, 1);
}
});
const newRecentlyViewed = [movie, ...recentlyViewed];
setRecentlyViewed([...new Set(newRecentlyViewed)].slice(0, 5));
saveToLocalStorage(newRecentlyViewed);
};
return (
<Router>
<Navbar
searchValue={searchValue}
setSearchValue={setSearchValue}
addRecentlyViewed={addRecentlyViewed}
movieSearch={movieSearch}
setMovieSearch={setMovieSearch}
/>
<Routes>
<Route
path="/"
element={
<Homepage
tvShow={tvShow}
setTVShow={setTVShow}
addRecentlyViewed={addRecentlyViewed}
recentlyViewed={recentlyViewed}
setRecentlyViewed={setRecentlyViewed}
/>
}
/>
<Route
path="/search"
element={
<SearchPage
handleFavouritesClick={addRecentlyViewed}
tvShow={movieSearch}
setTVShow={setTVShow}
searchValue={searchValue}
setSearchValue={setSearchValue}
addRecentlyViewed={addRecentlyViewed}
/>
}
/>
</Routes>
<Footer />
</Router>
);
}
export default App;
In the Navbar component you could add some flag to show / hide the SearchList
const showList = props.searchValue !== "";
{
showList ? (
<div className="container-fluid search-list">
<SearchList
tvShow={props.movieSearch}
handleFavouritesClick={props.addRecentlyViewed}
/>
<Link to="/search">
<button className="results" onClick={closeFunction()}>
<h7 className="results-text">
See all results for "{props.searchValue}"
</h7>
</button>
</Link>
</div>
) : null;
}
I'm following this Tutorial for build WhatsApp clone, but i'm using latest version of React and react-router-dom,
And whenever i'm start new conversation it should renders this component, instead of that, it renders nothing.
OpenConversation.js
import React, { useState, useCallback } from 'react'
import { Form, InputGroup, Button } from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider';
export default function OpenConversation() {
const [text, setText] = useState('')
const setRef = useCallback(node => {
if (node) {
node.scrollIntoView({ smooth: true })
}
}, [])
const { sendMessage, selectedConversation } = useConversations()
function handleSubmit(e) {
e.preventDefault()
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message, index) => {
const lastMessage = selectedConversation.messages.length - 1 === index
return (
<div
ref={lastMessage ? setRef : null}
key={index}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form onSubmit={handleSubmit}>
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={e => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<InputGroup.Append>
<Button type="submit">Send</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
And this component is rendered on Dashboard.js
import React, { useState, useCallback } from 'react'
import { Form, InputGroup, Button } from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider';
export default function OpenConversation() {
const [text, setText] = useState('')
const setRef = useCallback(node => {
if (node) {
node.scrollIntoView({ smooth: true })
}
}, [])
const { sendMessage, selectedConversation } = useConversations()
function handleSubmit(e) {
e.preventDefault()
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message, index) => {
const lastMessage = selectedConversation.messages.length - 1 === index
return (
<div
ref={lastMessage ? setRef : null}
key={index}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form onSubmit={handleSubmit}>
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={e => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<InputGroup.Append>
<Button type="submit">Send</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
App.js
import React from 'react'
import Login from './Login'
import useLocalStorage from '../hooks/useLocalStorage';
import Dashboard from './Dashboard'
import { ContactsProvider } from '../contexts/ContactsProvider'
import { ConversationsProvider } from '../contexts/ConversationsProvider';
import { SocketProvider } from '../contexts/SocketProvider';
import TopNavBar from './TopNavBar';
import Signup from "./Signup"
import { Container } from "react-bootstrap"
import { AuthProvider } from "../contexts/AuthContext"
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
import PrivateRoute from "./PrivateRoute"
import ForgotPassword from "./ForgotPassword"
import UpdateProfile from "./UpdateProfile"
function App() {
const [id, setId] = useLocalStorage('id', 0)
const AuthM = (
<AuthProvider>
<Router>
<TopNavBar />
<Routes>
<Route
path="/"
element={
<PrivateRoute>
<SocketProvider id={id}>
<ContactsProvider>
<ConversationsProvider id={id}>
<Dashboard id={id} />
</ConversationsProvider>
</ContactsProvider>
</SocketProvider>
</PrivateRoute>
}
>
</Route>
<Route
path="/update-profile"
element={
<PrivateRoute>
<UpdateProfile />
</PrivateRoute>
}
>
</Route>
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login onIdSubmit={setId} />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
</Routes>
</Router>
</AuthProvider>
)
return (
AuthM
)
}
export default App;
i'm getting following error when app is trying to render OpenConversation.js
The above error occurred in the component:
at div
at http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:42187:5
at div
at http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:41901:5
at form
at http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:41543:5
at div
at OpenConversation (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:1386:74)
at div
at Dashboard (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:451:5)
at ConversationsProvider (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3292:5)
at ContactsProvider (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3181:5)
at SocketProvider (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3498:5)
at PrivateRoute (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:1572:5)
at Routes (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:63406:5)
at Router (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:63339:15)
at BrowserRouter (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:62819:5)
at AuthProvider (http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3032:5)
at App (http://localhost:3000/main.ae1831d77cead42fa1a1.hot-update.js:56:89)
And this
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of OpenConversation.
Any idea on what happened there ? Thanks in advance.
Hope this helps to someone else,
As per #BrianThompsons comment, I found it was <InputGroup.Append> causes the error.
I'm doing the exact same tutorial, and had the same issue (and it's not the first time that I've gotten an error while copying the code - there have been some breaking updates since the video came out).
Instead of having <InputGroup.Append>, just stick the button inside the InputGroup, like so:
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={(e) => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<Button type="submit">Send</Button>
</InputGroup>
</Form.Group>
That put the button next to the text box, as we wanted. Hope that helps.
I am trying to fetch coingecko-api to access live price of bitcoin. I am trying to pass return props of getServerSideProps to my <CalculatorBuy /> component which is the part of <Main /> component. I was trying to import async function in calculatorbuy.js but i'm getting undefined object. How to pass props from index.js to main.js and calculatorbuy.js components. In index.js everything work like a charm but i would like to use props value directly in components.
index.js
export default function Home(props) {
const {data} = props.result;
console.log(data);
return (
<div className="container">
<Head>
<title>Buy BTC</title>
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
</Head>
<Header />
<Main />
<Footer />
<style jsx> {`
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
`} </style>
</div>
)
}
export async function getServerSideProps(context) {
const result = await coinGeckoClient.simple.price({
ids: "bitcoin",
vs_currencies: "eur",
});
return {
props: {
result,
},
}
}
main.js
import React, { useState } from 'react';
import Button from '#material-ui/core/Button';
import Calculatorbuy from './calculatorbuy.js'
import Calculatorsell from './calculatorsell.js'
export default function Main() {
const [ showMe, setShowMe ] = useState(true);
function toggle (){
if (!showMe) {
setShowMe(true);
}
else {
setShowMe(true);
}
}
function toggle2 (){
if (showMe) {
setShowMe(false);
}
else {
setShowMe(false);
}
}
return (
<main className="main">
<div className="box">
<div className="buttons">
<Button onClick={toggle} variant="outlined" color="primary" style={{width: 120, marginRight: 10}}>
KUP
</Button>
<Button onClick={toggle2} variant="outlined" color="secondary" style={{width: 120, marginRight: 10}}>
SPRZEDAJ
</Button>
<Button variant="outlined" color="default" style={{width: 120,}}>
HISTORIA
</Button>
</div>
<div style={{ display: showMe?"block":"none" }}>
<Calculatorbuy />
</div>
<div style={{ display: !showMe?"block":"none" }}>
<Calculatorsell />
</div>
</div>
<div className="room-for-socials"></div>
import React, { useState } from 'react';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import Livebsv from './livebsv.js';
export default function Calculatorbuy() {
const [value, setValue] = useState(0);
return (
<form className="calculator" noValidate autoComplete="off">
<div>
<Livebsv />
</div>
<div className="typebox">
<div className="textfield">
<TextField error={false} id="outlined-number" label="PLN" helperText="Min. wartość 100zł"
type="tel"
value={value}
InputProps={{
inputProps: { min: "100", max: "5000", step: "0.01" }
}}
variant="outlined"
onKeyPress={(e) => {
if (!/[0-9]/.test(e.key)) {
e.preventDefault();
}
}}
onChange={(e) => setValue(e.currentTarget.value)}
onKeyPress={(e) => {
if (!/[0-9]/.test(e.key)) {
e.preventDefault();
}
}}
onBlur={(e) => {
if (e.currentTarget.value > 0 & e.currentTarget.value < 100 )
setValue(100);
else if (e.currentTarget.value > 5000)
setValue(5000);
}}
/>
</div>
<div className="textfield">
<TextField disabled id="outlined-disabled" value={(value).toFixed(8)} label="BSV" variant="outlined"
You started well by loading the result on index.js(getServerSideProps).
Then, to pass the data to Main, you have to add it as a property for the component:
<Main data={data} />
Now, as Main expects a parameter, it has to be defined in main.js:
export default function Main(props) {
const data = props.data;
...
}
Then, for the Calculatorbuy component you have to do the same like on Main. Define the props and use it.
I have a project that requires a dialog to be resizable and draggable. Material-UI Dialog documentation has steps on how to make it draggable. I want to find out the resizable part. Any suggestions on how to?
Sample code can be found here.
UPDATE:
Functional and typescript version of #Khabir's answer below
import Button from '#material-ui/core/Button'
import Dialog from '#material-ui/core/Dialog'
import DialogActions from '#material-ui/core/DialogActions'
import DialogContent from '#material-ui/core/DialogContent'
import DialogContentText from '#material-ui/core/DialogContentText'
import DialogTitle from '#material-ui/core/DialogTitle'
import Paper, { PaperProps } from '#material-ui/core/Paper'
import { makeStyles, Theme } from '#material-ui/core/styles'
import TextField from '#material-ui/core/TextField'
import React from 'react'
import Draggable from 'react-draggable'
import { ResizableBox } from 'react-resizable'
const useStyles = makeStyles((theme: Theme) => ({
resizable: {
position: 'relative',
'& .react-resizable-handle': {
position: 'absolute',
width: 20,
height: 20,
bottom: 0,
right: 0,
background:"url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+')",
'background-position': 'bottom right',
padding: '0 3px 3px 0',
'background-repeat': 'no-repeat',
'background-origin': 'content-box',
'box-sizing': 'border-box',
cursor: 'se-resize',
},
},
}))
const PaperComponent = (props: PaperProps) => {
return (
<Draggable
handle="#draggable-dialog-title"
cancel={'[class*="MuiDialogContent-root"]'}
>
<Paper {...props} />
</Draggable>
)
}
export const DialogComponent = () => {
const [open, setOpen] = React.useState<boolean>(false)
const handleClickOpen = () => {
setOpen(true)
}
const handleClose = () => {
setOpen(false)
}
const classes = useStyles()
return (
<div>
<Button onClick={handleClickOpen}>Open dd form dialog</Button>
{open && (
<Dialog
open={true}
onClose={handleClose}
maxWidth={false}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<ResizableBox
height={400}
width={600}
className={classes.resizable}
>
<DialogTitle
style={{ cursor: 'move' }}
id="draggable-dialog-title"
>
Subscribe
</DialogTitle>
<DialogContent>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates occasionally.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Email Address"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Subscribe
</Button>
</DialogActions>
</ResizableBox>
</Dialog>
)}
</div>
)
}
typescript 3.8.3
#material-ui/core 4.9.7
Hi I merged two features together. please check the example. It supports both drag and resize.
import React from "react";
import Button from "#material-ui/core/Button";
import Draggable from "react-draggable";
import {withStyles} from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Dialog from "#material-ui/core/Dialog";
import DialogActions from "#material-ui/core/DialogActions";
import DialogContent from "#material-ui/core/DialogContent";
import DialogContentText from "#material-ui/core/DialogContentText";
import DialogTitle from "#material-ui/core/DialogTitle";
import {ResizableBox} from "react-resizable";
import Paper from "#material-ui/core/Paper";
const styles = theme => ({
resizable: {
position: "relative",
"& .react-resizable-handle": {
position: "absolute",
width: 20,
height: 20,
bottom: 0,
right: 0,
background:
"url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+')",
"background-position": "bottom right",
padding: "0 3px 3px 0",
"background-repeat": "no-repeat",
"background-origin": "content-box",
"box-sizing": "border-box",
cursor: "se-resize"
}
}
});
function PaperComponent(props) {
return (
<Draggable handle="#draggable-dialog-title" cancel={'[class*="MuiDialogContent-root"]'}>
<Paper {...props} />
</Draggable>
);
}
class DraggableResizableDialog extends React.Component {
state = {
open: false
};
handleClickOpen = () => {
this.setState({open: true});
};
handleClose = () => {
this.setState({open: false});
};
render() {
return (
<div>
<Button onClick={this.handleClickOpen}>Open dd form dialog</Button>
{this.state.open && (
<Dialog
open={true}
onClose={this.handleClose}
maxWidth={false}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<ResizableBox
height={400}
width={600}
className={this.props.classes.resizable}
>
<DialogTitle style={{ cursor: 'move' }} id="draggable-dialog-title">Subscribe</DialogTitle>
<DialogContent>
<DialogContentText>
To subscribe to this website, please enter your email address
here. We will send updates occasionally.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Email Address"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleClose} color="primary">
Subscribe
</Button>
</DialogActions>
</ResizableBox>
</Dialog>
)}
</div>
);
}
}
export default withStyles(styles)(DraggableResizableDialog);
Source: Draggable Resizable