Make a read more Card with reactstrap - node.js

So I'm almost wrapping up my personal project, but one thing i'm stuck on is this:
I have a following system, where the user can see all other user's he is following (it's working).
I want to implement it in a way, that he has a reactstrap Card on the left, with a small number of users, and a show more button, which open's up the rest of the users.
This is what I got so far:
The screen :
[![enter image description here][1]][1]
And this is the code which is rendering the users (I got it earlier from a get method):
<div className="following">
<Card body outline color="secondary" >
<CardTitle className = "following-list"><following-list>Following list:</following-list></CardTitle>
<CardBody>
{following.length > 0 &&
following.map(usr => {
// return <p>{usr} </p>
return <div>
<Button className = "button-follow" outline color="primary" onClick = {() =>seachUserHandler(usr)}>{usr}</Button>
</div>
})
}
</CardBody>
</Card>
</div>
CSS code:
.following {
position: absolute;
background: whitesmoke; /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
top:87px;
left:2%;
width:15%;
}
.button-follow{
max-width: 100%;
max-height: 100%;
display: block;
}
.following-list {
color:#3a7bd5;
font-size: large;
}
The onClick on which Button just refers me to the followed usr profile page.
How can I implement the card in such a way that the user would see 3-5 users at the start, and then if he clicks "see more.." button he will see the total list? is it even possible with cards?
UPDATED:
For anyone who wanna use the trick that was suggested in the solution by the great guy below, here is the full working code:
import '../App.css';
import { useHistory } from "react-router-dom";
import React , {useState, useEffect} from 'react';
import {Navbar, NavbarBrand, Button, Input, Card,CardTitle, Col, CardBody} from 'reactstrap'
import { getUserPosts,search,getFollowingUsers,getFollowingUsersPosts } from '../fucntions/user_functions'
function Follow(){
let history = useHistory();
var email;
const [length, setLength] = useState(0)
const [following,setFollowing] = useState([])
const [userSearch, setUserSearch] = useState('')
const [followingPosts, setFollowingPosts] = useState([]);
const [showLess, setShowLess] = useState(false)
const [followingData, setFollowingData] = useState({
isInitial: true,
filteredList: following.slice(0,2),
completeList: following,
});
const showMoreUsers = (_evt /*: SyntheticEvent<Event> */) => {
setFollowingData({
...followingData,
filteredList: following,
isInitial: false
});
setShowLess(true)
}
const showLessUsers = (_evt /*: SyntheticEvent<Event> */) => {
setFollowingData({
...followingData,
filteredList: following.slice(0,2),
isInitial: true
});
setShowLess(false)
}
const moreUsersStyle = {
color: 'rgba(0,0,0,0.5)',
textDecoration: 'underline',
marginTop: '10px'
}
const handleSearchUser = e =>{setUserSearch(e.target.value);};
function handleBack(){
history.goBack()
}
function seachUserHandler(usr) {
var tempPosts;
let toSearch = null
if (typeof(usr) == 'undefined'){
toSearch = {
email: userSearch
}
} else {
toSearch = {
email: usr
}
}
search(toSearch).then(res =>{
if (res.data.code.code !== 0){
window.confirm(res.data.code.message)
} else {
const postsOfUser = {
email: toSearch.email
}
tempPosts = postsOfUser
getUserPosts(tempPosts).then(response =>{
localStorage.setItem('searchedUserPosts', JSON.stringify(response.data))
localStorage.setItem('searchedUser', toSearch.email)
localStorage.setItem('searchedUserName', res.data.user.first_name)
var lengthOfPosts = res.data.user.posts.length
localStorage.setItem('numPosts',lengthOfPosts)
history.push('/profile')
})
}
})
}
function getFollowing(){
const container ={
email: email
}
getFollowingUsers(container).then(res =>{
var data = res.data;
setFollowing(data)
setLength(data.length)
getFollowingPosts(data)
setFollowingData({
...followingData,
filteredList: data.slice(0,2),
completeList: following
})
})
}
function getFollowingPosts(data){
const container ={
data: data
}
getFollowingUsersPosts(container).then(res =>{
var data = res.data;
setFollowingPosts(data)
console.log(data)
})
}
useEffect(() =>{
if (localStorage.getItem("usertoken") === null) {
history.push('/errorPage')
} else {
const _email = localStorage.getItem('useremail')
email = _email
localStorage.removeItem('searchedUser') //used to delete the last profile searched
localStorage.removeItem('searchedUserPosts') // used to delete the last profile searched post from cache
getFollowing()
};
},[]);
return (
<div className="box">
<div>
<Navbar color="light" light expand="lg" className="justify-content-flex" style={{ padding: "5" }}>
<div className="header-home">
<NavbarBrand type="text">inTouch</NavbarBrand>
</div>
<div>
<Col>
<Input id="usr" name="user1" type="text" value={userSearch} placeholder="Enter user's email..." onChange={handleSearchUser}></Input>
</Col>
</div>
<div>
<Col>
<Button outline color="primary" onClick={() => seachUserHandler()}>Search</Button>
</Col>
</div>
<div>
<Col>
<NavbarBrand type="button" onClick={handleBack}>Back</NavbarBrand>
</Col>
</div>
</Navbar>
<div className="feed">
<Card body outline color="secondary" >
<CardTitle className = "following-list text-center"><following-list>Feed</following-list></CardTitle>
<CardBody className = "text-center">
Welcome to your feed! Catch up with the people you follow.
</CardBody>
</Card>
</div>
<div className="following">
<Card body outline color="secondary" >
<CardTitle className = "following-list text-center"><following-list>Following list:</following-list></CardTitle>
<CardBody className = "text-center">
{followingData.filteredList.length > 0 &&
followingData.filteredList.map(usr =>
<div>
<Button className = "button-follow"
outline
color="primary"
onClick = {() => seachUserHandler(usr)}>{usr}</Button>
</div>
)
}
{followingData.isInitial ?
<p onClick={showMoreUsers} style={moreUsersStyle}>Show all users...</p>
: null
}
{showLess ?
<p onClick={showLessUsers} style={moreUsersStyle}>Show less...</p>
: null
}
</CardBody>
</Card>
</div>
<div className="wrapper-all-posts">
{length > 0 &&
followingPosts.map(post => {
return <Card body outline color="secondary" className="card-home " >
<CardTitle>Posted at : {post.createdAt} By : {post.email}</CardTitle>
<CardBody>{post.post}</CardBody>
</Card>
})
}
</div>
</div>
</div>
)
}
export default Follow;

Stackblitz demo
The overall idea is using a filtered list in the component. Take a look at the code below.
const {followings} = props;
...
const [followingData, setFollowingData] = useState({
isInigial: true,
filteredList: followings.slice(0,6),
completeList: followings,
});
const _showMoreUsers = (_evt /*: SyntheticEvent<Event> */) => {
setFollowgingData({
...followingData,
filteredList: followingData.completeList,
isInitial: false
});
}
const moreUsersStyle = {
color: 'rgba(0,0,0,0.5)',
textDecoration: 'underline',
marginTop: '10px'
}
...
<div className="following">
<Card body outline color="secondary" >
<CardTitle className="following-list">
<following-list>Following list:</following-list>
</CardTitle>
<CardBody>
{followingData.filteredList.length > 0 &&
followingData.filteredListfollowing.map(usr =>
<div>
<Button className = "button-follow"
outline
color="primary"
onClick = {() => seachUserHandler(usr)}>{usr}</Button>
</div>
)
}
{followingData.isInitial ?
<p onClick={_showMoreUsers} style={moreUsersStyle}>Show More...</p>
: null
}
</CardBody>
</Card>
</div>

Related

this code setting all post to true react js

const likeHandler = (index) => {
const allData = [...urls]
const getMatchingImage = allData.find((_item, i) => i === index);
const getMatchingImageIndex = allData.indexOf(getMatchingImage)
if (index === getMatchingImageIndex) {
setLike(true);
}
console.log('key index handler', index);
console.log('key index getMatchingImage', getMatchingImage)
console.log('key index getMatchingImageIndex', getMatchingImageIndex)
}
<div className={styles.imgContainer}>
{urls.map((url, index) => (
<Box key={index}>
<div className={styles.postHeading}>
<img src='https://placehold.co/70x70' alt=''/>
<div className={styles.postUserName}>Dinesh Kumar</div>
</div>
<div className={styles.imgContainer} style={{backgroundImage: `url(${url})`}}></div>
<div className={styles.actionButtons}>
<div>
{!like ?
<AiOutlineHeart onClick={() => {likeHandler(index)}} className={`me-2`}/> :
<AiFillHeart onClick={() => {unLikeHander(index)}} className={`me-2`} />
}
<AiOutlineMessage className={`me-2`}/>
<FiSend className={`me-2`}/>
</div>
<div>
<FiBookmark/>
</div>
</div>
</Box>
))}
</div>
I am working on post like functionality when I likes a particular post it liked all post. I am consoling all information. Please have a look
I am working on post like functionality when I likes a particular post it liked all post. I am consoling all information. Please have a look
I am working on post like functionality when I likes a particular post it liked all post. I am consoling all information. Please have a look
You should declare the like property as an array of boolean and toggle the values referring to the element with index:
const [like, setLike] = useState(new Array(urls.length).fill(false));
...
const likeHandler = (index) => {
const allData = [...urls];
const getMatchingImage = allData.find((_item, i) => i === index);
const getMatchingImageIndex = allData.indexOf(getMatchingImage);
const updatedLikes = [...like];
updatedLikes[index] = true;
setLike(updatedLikes);
};
...
<div>
{!like[index] ? (
<AiOutlineHeart
onClick={() => {
likeHandler(index);
}}
className={`me-2`}
/>
) : (
<AiFillHeart
onClick={() => {
unLikeHander(index);
}}
className={`me-2`}
/>
)}
<AiOutlineMessage className={`me-2`} />
<FiSend className={`me-2`} />
</div>
It's better to use classes. instead of styles. This is such a conditional standard when you use .module.css
Instead of
<div className={styles.imgContainer}>
better this way :
<div className={classes.imgContainer}>

Wrapping code inside styled component in React.js yields unexpected results on show password button click

App.js:
import './App.css';
import React, { Component } from 'react'
import Register from './Components/Register';
import Greet from './Components/Greet';
class App extends Component {
constructor(props) {
super(props)
this.state = {
isRegistered: false,
name: null,
email: null,
password: null,
showPass:false,
}
}
registerHandler=(e) => {
e.preventDefault();
const name = e.target.name.value;
const email = e.target.email.value;
const password = e.target.password.value;
this.setState({ isRegistered: true,name,email,password});
}
showPassHandler=()=>{
this.setState({showPass:!(this.state.showPass)});
}
render() {
return (
<div>
{this.state.isRegistered?<Greet name={this.state.name} email={this.state.email}/>:<Register submit={this.registerHandler} click ={this.showPassHandler} showPass={this.state.showPass}/>}
</div>
)
}
}
export default App;
/////////////////////////////////////////////////////////////
Register.js:
import React,{useState} from 'react'
import Styled from "styled-components";
export default function Register(props) {
const btnStyle={
backgroundColor:"red",
color:"white",
}
// const savePassword=(val)=>{
// show=val.target.value;
// val.target.value=show;
// inputRef.current.focus();
// val.target.focus();
// console.log(show);
// setPass(show);
// }
// console.log(show);
let btnText;
const btnClasses = ["btn","m-1","mt-2"];
if(props.showPass===true)
{
btnStyle.backgroundColor = "green";
btnText="hide password";
btnClasses.push("btn-primary");
}
else{
btnText="show password";
btnClasses.push("btn-danger");
}
const StyledButton = Styled.button
`
background-color: ${(props)=>props.bgColor};
color: white;
display:${(props)=>props.flag==="1"?"inline-block":"block"};
width:${(props)=>props.flag==="1"?"45%":"100%"};
margin:5px;
`
const StyledRegisterContainer = Styled.div`
width:600px;
&:hover {box-shadow:0px 0px 5px grey};
#media (min-width:0px) and (max-width:600px) {
width:300px;
};
`;
//register-container=> was class inside most outer div
return (
<StyledRegisterContainer className='container card mt-4 p-3 '>
<h1 className='text-center'>
Registration Form
</h1>
<form onSubmit={props.submit}>
<div className='form-group'>
<label className='control-label' htmlFor='name'>Name:</label>
<input type='text' name='name' className='form-control'/>
</div>
<div className='form-group'>
<label className='control-label' htmlFor='email'>Email:</label>
<input type='email' name='email' className='form-control'/>
</div>
<div className='form-group'>
<label className='control-label' htmlFor='password'>password:</label>
<input type={props.showPass?"text":"password"} name='password' required className='form-control' />
</div>
<button type='submit' className='btn btn-primary mt-2 m-1'>
Register
</button>
<button type ="button" className={btnClasses.join(" ")} onClick={props.click}>
{btnText}
</button>
<br/>
<StyledButton flag="1" bgColor="orange">Login</StyledButton>
<StyledButton flag="1" bgColor="blue">Login</StyledButton>
<StyledButton flag="0" bgColor="brown">Login</StyledButton>
</form>
</StyledRegisterContainer>
)
}
//style = {btnStyle}//it was inside button =>show password
inside Register.js file everything was working perfect but when I wrapped the code inside StyledRegisterContainer(a styled component) the functionality of show password button is disturbed and the moment I click on show password button the text from input box disapears.
I want my code to work even after wrapping it inside the above mentioned styled component.
I am not familiar with styled-components, but according to their documentation, it seems like you're importing Styled instead of styled
import styled from 'styled-components';
https://styled-components.com/docs/basics#installation

TypeError: changeChecked is not a function

I am trying to pass changeChecked as prop from parent to this child component to capture the input element id but I am getting this error. I have mentioned the child component and parent component. Please help me to solve this error.
Child Component
import { useState, useEffect } from 'react';
const CheckBox = ({ changeChecked, section }) => {
return (
<>
{section.options.map((option, optionIdx) => (
<div key={option.value} className="flex items-center">
<input
id={`filter-${section.id}-${optionIdx}`}
name={`${section.id}[]`}
defaultValue={option.value}
type="checkbox"
defaultChecked={option.checked}
onChange={() => changeChecked(option.id)}
className="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500"
/>
<label
htmlFor={`filter-${section.id}-${optionIdx}`}
className="ml-3 lg:text-sm min-w-0 flex-1 text-gray-500"
>
{option.label}
</label>
</div>
))}
</>
)
}
export default CheckBox;
Parent Component
import CheckBox from "../pages/collections/checkbox"
export default function App() {
const filters = [
{
id: 'brand',
name: 'Brands',
options: [
{ value: 'Casio', label: 'Casio', checked: false },
{ value: 'Yamaha', label: 'Yamaha', checked: false },
],
},
]
const onChangeChecked = (id)=>{
console.log(id)
}
return (
<div className="App">
{filters.map((section) => (
<CheckBox section={section} changeChecked={onChangeChecked} />
))}
</div>
);
}
This is a full example of passing a function as a prop.
Don't forget to pass the props when you are using the Input component, or you will get the same error as above.
export default function App() {
const onHandleClick = (e)=>{
console.log(e.target.value)
}
return (
<div className="App">
<Input onHandleClick={onHandleClick}/>
</div>
);
}
function Input ({ onHandleClick }) {
return <input onChange={(e) => onHandleClick(e)}/>
}

React component data not saved when submit

Below is my code, the React app is connected to Node js and the data of comment are saved when submit but it's not working for StarRating component.
The comment data is saved in the db table but not the rating
Please pass setRating in starComponent as props
Like below:
<StarRating rating={rating1} updateRating={(e) => setRating1(e)}
onChange={e => setRating1(e.target.value)}></StarRating>
Now you will get updateRating as props in starComponent. So update rating form star component like below:
import React, { useState} from "react";
import { FaStar } from 'react-icons/fa';
const StarRating = ({rating, updateRating}) =>{ // Here you will get setRating state(State of app component) in props
// const [rating, setRating] = useState(null); // not needed this state here. Update rating value in state which comes form props
const [hover, setHover] = useState(null);
return <div>
<p>Rate your experience from 0 to 5 stars</p>
{[... Array(5)].map((star, i)=>{
const ratingValue= i + 1;
return (
<label>
<input
type="radio"
name="rating"
value={rating}
onClick={() =>updateRating(ratingValue)} /> // Update `updateRating` state which comes from app component.
<FaStar
className="star"
color={ratingValue <= (hover || rating) ? "#11C4B0" : "#D3D3D3"}
size={40}
onMouseEnter={() =>setHover(ratingValue)}
onMouseLeave={() =>setHover(null)}
/>
</label>
);
})}
</div>
}
export default StarRating;
You will get updated state in rating1 in app component if any changes occurred from starComponent.
I think the Problem is that you are accessing the rating state in App component but the real state with the value is the rating state of StarRating component. Also, you have passed the props onChange and value to StarRating component but The Props concept is different than the HTML Attributes concept so you definitely need to look into that. Anyway, the possible Solution can be...
import * as React from 'react';
import './App.css';
import StarRating from './StarRating';
import StarRating2 from './StarRating2';
import StarRating3 from './StarRating3';
import { TextArea } from 'semantic-ui-react';
import AlertDialogSlide from './confirmation';
import Dialog from '#mui/material/Dialog';
import DialogActions from '#mui/material/DialogActions';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import Slide from '#mui/material/Slide';
import Button from '#mui/material/Button';
import { useState } from "react";
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
function App() {
const [open, setOpen] = React.useState(false);
const [comment, setComment] = useState("");
const [rating1, setRating1] = useState("");
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const onSubmitForm = async e => {
e.preventDefault();
try {
const body = { rating1, comment };
const response = await fetch("http://localhost:5000/feedback", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
window.location = "/";
} catch (err) {
console.error(err.message);
}
};
return (
<form onSubmit={onSubmitForm} >
<div className="App">
<img src='solavievelogo.png'></img>
<hr/>
<h2>Leave a feedback!</h2>
<StarRating setRating={setRating1} />
<hr2/>
<StarRating2></StarRating2>
<hr2/>
<StarRating3></StarRating3>
<hr2/>
<p>Please leave a comment about your experience below:</p>
<TextArea placeholder=' Type your comment here...'
value={comment}
onChange={e => setComment(e.target.value)}
></TextArea>
<br/>
<button class="Button" type='submit' variant="outlined" onClick={handleClickOpen}><span class="Button-inner">SEND FEEDBACK</span> </button>
<Dialog
open={open}
TransitionComponent={Transition}
keepMounted
onClose={handleClose}
aria-describedby="alert-dialog-slide-description"
>
<DialogContent>
<img src='confirm.png'></img>
<DialogContentText id="alert-dialog-slide-description">
<p>Thank you for your message!</p>
<p> We will be in contact soon..</p>
</DialogContentText>
</DialogContent>
<DialogActions >
<button class="Button" type='submit' onClick={handleClose} ><span class="Button-inner">Close</span> </button>
</DialogActions>
</Dialog>
</div>
</form>
);
}
export default App;
StarRating Component
import React, { useState} from "react";
import { FaStar } from 'react-icons/fa';
const StarRating = ({setRating}) =>{
const [hover, setHover] = useState(null);
return <div>
<p>Rate your experience from 0 to 5 stars</p>
{[... Array(5)].map((star, i)=>{
const ratingValue= i + 1;
return (
<label>
<input
type="radio"
name="rating"
value={ratingValue}
onClick={() =>setRating(ratingValue)} />
<FaStar
className="star"
color={ratingValue <= (hover || rating) ? "#11C4B0" : "#D3D3D3"}
size={40}
onMouseEnter={() =>setHover(ratingValue)}
onMouseLeave={() =>setHover(null)}
/>
</label>
);
})}
</div>
}
export default StarRating;

React - trying to save fetched data in a variable but the variable returns empty

I fetched json data with async await and i wanted to save the fetched data in a variable in order to be able to use it with a map in my component,
the data comes in properly inside the function - i checked with an alert , and also in the variable inside the function it does display all the data , but somehow the variable outside the function returns empty .
here is some code:
both alerts in the following code return the right data.
export let fetchPosts = [];
export async function FetchPosts() {
await axios.get('https://jsonplaceholder.typicode.com/posts').then(
res => {
alert(JSON.stringify(res.data))
fetchPosts = JSON.stringify(res.data);
alert(fetchPosts)
}
).catch(err => {
alert('err');
})
}
import { fetchPosts } from '../services/post';
import { FetchPosts } from '../services/post';
export default function Posts() {
function clickme() {
FetchPosts()
}
return (<>
<button onClick={clickme}>Click me</button>
{fetchPosts.map((post, index) => (
<div key={post.id} className="card" style={{ 'width': '16rem', 'display': 'inline-block', 'margin': '5px' }}>
<div className="card-body">
<h6 className="title">{post.title}</h6>
<p className="card-text">{post.body}</p>
</div>
</div>
))}
</>)
}
State is the issue
React doesn't automatically reload on your singleton fetchPosts.
Instead, try...
export function FetchPosts() {
return axios.get('https://jsonplaceholder.typicode.com/posts');
}
then
import { useState } from 'react';
import { FetchPosts } from '../services/post';
export default function Posts() {
const [posts, setPosts] = useState([]);
function clickme() {
FetchPosts().then(res => {
setPosts(res.data);
});
}
return (<>
<button onClick={clickme}>Click me</button>
{posts.map((post, index) => (
<div key={post.id} className="card" style={{ width: '16rem', display: 'inline-block', margin: '5px' }}>
<div className="card-body">
<h6 className="title">{post.title}</h6>
<p className="card-text">{post.body}</p>
</div>
</div>
))}
</>)
}
https://codesandbox.io/s/jolly-almeida-q4331?fontsize=14&hidenavigation=1&theme=dark
If you want global state, that's another topic you should dive into entirely but you can do it with a singleton, you just need to incorporate it with hooks and an event emitter. I have a bit of a hacked version of this here https://codesandbox.io/s/react-typescript-playground-forked-h8rpu but you should probably stick to redux or mobx or AppContext which is more of a popular pattern.

Resources