How to build Tabs component Reactjs - reactjs

I'm trying to build a Tabs component with ReactJS and I'm following a CSS stylesheet.So, I would love to have this as render :
<div data-container="" class="tabs tabs-horizontal">
<div class="tabs-header">
<div class="tabs-header-tab ph active" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Personal
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Job
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">
Salary</div>
</div>
<div data-container="" class="tabs-content">
<div data-container="" class="tabs-content-tab open" data-tab="0">
<div>I am a HR Specialist.</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>No records have been added yet</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>This type of information needs to be added by your manager</div>
</div>
</div>
</div>
And this is what the components looks like now :
<Tabs>
<TabHeaders>
<TabHeadersItem text="Personal" state="active" />
<TabHeadersItem text="Job" />
<TabHeadersItem text="Salary" />
</TabHeaders>
<TabContents>
<TabContentsItem
content="I am a HR Specialist."
open="open"
/>
<TabContentsItem content="No records have been added yet" />
<TabContentsItem content="This type of information needs to be added by your manager" />
</TabContents>
</Tabs>
So, I'm trying to find a solution, when user clicks on a header it becomes "active" and its content "open" while the others should be closed and not active.

Ok so since you've edited your question, I'll do with mine. The idea is the same: To keep the state of which tab is open, and since you don't want to keep your tabs in a list, then you need to link a TabHeader to a TabContent:
const TabHeaderItem = props => {
return (
<div
onClick={() => props.changeTab(props.text.toLowerCase())}
className={props.state ? "active" : ""}
>
{props.text}
</div>
);
};
const TabContentsItem = props => {
return <div className={props.open ? "open" : "closed"}>{props.content}</div>;
};
const TabComponent = () {
const [active, setActive] = useState("personal");
const changeTab = tab => {
console.log("tab", tab);
setActive(tab);
};
return (
<div className="App">
<div className="tabs">
<TabHeaderItem
changeTab={changeTab}
text="Personal"
state={active === "personal"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Job"
state={active === "job"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Salary"
state={active === "salary"}
/>
</div>
<div className="tabs-content">
<TabContentsItem
content="I am a HR Specialist."
open={active === "personal"}
/>
<TabContentsItem
content="No records have been added yet"
open={active === "job"}
/>
<TabContentsItem
content="This type of information needs to be added by your manager"
open={active === "salary"}
/>
</div>
</div>
);
}
You can check out the working example here: https://codesandbox.io/s/exciting-gauss-lbghq

Related

Update on Async Rendering- ReactJs

Following a tutorial-
Console Warning:
componentWillUpdate has been renamed, and is not recommended for use. Move data fetching code or side effects to componentDidUpdate.Rename componentWillUpdate UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. Please update the following components: Identicon
At first, the app correctly displayed "Welcome Username", but after refreshing I got the warning on the console.
Now, when I type something into Username... and click on Set Nickname nothing happens.
I am expecting to see "Welcome Username"
<div className={styles.welcome}>Wecome {username}</div>
I do not think there is anything wrong with my handleSetUsername function, because it worked previously.
On the Moralis app I see that there are 4 users correctly connected from my Metamask account.
Sidebar.js
const {
isAuthenticated,
nickname,
setNickname,
username,
setUsername,
handleSetUsername,
} = useContext(AmazonContext)
return (
<div className={styles.container}>
<div className={styles.profile}>
{isAuthenticated && (
<>
<div className={styles.profilePicContainer}>
<Image
src={`https://avatars.dicebear.com/api/pixel-art/${username}.svg`}
alt='profile'
className={styles.profilePic}
height={100}
width={100}
/>
</div>
{!username ? (
<>
<div className={styles.username}>
<input
type='text'
placeholder='Username....'
className={styles.usernameInput}
value={nickname}
onChange={e => setNickname(e.target.value)}
/>
</div>
<button
className={styles.setNickname}
onClick={handleSetUsername}
>
Set Nickname
</button>
</>
) : (
<div>
<div className={styles.welcome}>Wecome {username}</div>
</div>
)}
</>
)}
<div className={styles.connectButton}>
<ConnectButton />
</div>
</div>
<div className={styles.menu}>
<Link href='/'>
<div className={styles.menuItem}>
<Image
src={logo}
height={30}
width={30}
className={styles.amazonLogo}
/>
My Amazon
<br /> Board
</div>
</Link>
<div className={styles.menuItem}>
<FaBox />
Collections
</div>
<div className={styles.menuItem}>
<BsFillBookmarkFill />
Saved
</div>
<div className={styles.menuItem}>
<BsFillPersonFill />
Profile
</div>
<Link href='/history'>
<div className={styles.menuItem}>
<AiOutlineHistory />
Transaction History
</div>
</Link>
</div>
<div className={styles.companyName}>
<Image src={logofull} alt='amazon' height={100} width={100} />
</div>
</div>
)
}
export default Sidebar

How to add a link to images based on some condition using typescript and react?

i want to add a link to the image based on some condition using javascript and react.
what i am trying to do?
i have mobile and desktop images.
under mobile image i have text saying switch to mobile and
is clickable if the users current url is not matching mobile_url.
if the users current url matches the mobile_url then the text would be "current version" and is not clickable.
under desktop image i have text saying switch to desktop and
is clickable if the users current url is not matching desktop_url
if the users current url matches the desktop_url then the text would be "current version" and is not clickable.
below is my code that works,
function Parent () {
const currentUrl = window.location.origin + '/';
return (
<div className="Wrapper">
<Dialog>
<span>Select Version</span>
<div className="container">
<div className="block">
<span>Mobile</span>
<div className="image_wrapper"> // want to add a link here too
<img src={mobile} width={50} />
</div>
<span>
{current_url === mobile_url ? (
'Current version'
) : (
<a href={mobile_url}>Switch to mobile</a>
)}
</span>
</div>
<div className="block">
<span>Desktop</span>
<div className="image_wrapper"> //want to add a link here too
<img src={desktop} width={50} />
</div>
<span>
{current_url === desktop_url ? (
'Current version'
) : (
<a href={desktop_url}>Switch to desktop</a>
)}
</span>
</div>
</div>
</div>
);
}
Now what i want to do is as the texts switch to mobile and switch to desktops are clickable and have a link to an url. similarly i want to have links to the images mobile and desktop and should be clickable based on same conditions like texts have.
so for mobile image if current url is same as mobile_url then image is not clickable. if current url doesnt match with mobile_url then image is clickable and redirects to mobile_url
and for desktop image if current_url is same as desktop_url then image is not clickable. if current url doesnt match with desktop_url then image is clickable and redirects to desktop_url
how can i do it. could someone help me with this. thanks.
EDIT:
i have tried like below and the images are not seen.
import desktop from '../image/desktop.svg';
import mobile from '../image/mobile.svg';
interface Props {
src: any; //what should be the type here
width: any; //what should be the type here
}
function RenderImage({src, width}: Props) {
return (
<div className="image_wrapper">
<img src={src} width={width}/>
</div>
);
}
function Parent () {
const currentUrl = window.location.origin + '/';
return (
<div className="Wrapper">
<Dialog>
<span>Select Version</span>
<div className="container">
<div className="block">
<span>Mobile</span>
{current_url === mobile_url ? (
<a href={mobile_url}>
<Image src={mobile} width={50}/>
</a> ): (
<Image src={mobile} width={50} />
)
}
<span>
{current_url === mobile_url ? (
'Current version'
) : (
<a href={mobile_url}>Switch to mobile</a>
)}
</span>
</div>
<div className="block">
<span>Desktop</span>
{current_url === desktop_url ? (
<a href={desktop_url}>
<Image src={desktop} width={width}/>
</a> ) : (
<Image src={desktop} width={width} />
}
<span>
{current_url === desktop_url ? (
'Current version'
) : (
<a href={desktop_url}>Switch to desktop</a>
)}
</span>
</div>
</div>
</div>
);
}
this works fine but what should be the types for src and width in this case thanks.
I would decide what component renders before your return.
export default function Parent() {
const pathname = window.location.pathname;
const customElement = pathname === 'your mobile url'? // Check if matches
<a href={mobile_url}>Switch to mobile</a> : // if so return this one
<a href={desktop_url}>Switch to desktop</a> //else this
return (
<div className="Wrapper">
<Dialog>
<span>Select Version</span>
<div className="container">
<div className="block">
<span>Mobile</span>
<div className="image_wrapper">
<img src={mobile} width={50} />
</div>
<span>{customElement}</span>
</div>
</div>
</Dialog>
</div>
);
}
You can do the same with the images if you want a different one to display based upon current path.

ReactjS - const loads all states before being fetched

Hey guys I am trying to pass a URL for background image into the ResultsItem component. My problem is that the state of places is not defined until data are fetched. The problem is with the const Thumbnail. I always get an error of "TypeError: Cannot read property 'photos' of undefined".
render() {
const Thumbnail = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos.photoreference}&key=MYAPIKEY
`;
return (
<div>
<div className="flex align-center">
<div className="search">
<SearchInput
id="autocomplete"
placeholder="Search by address"
width="100%"
height={56}
/>
<Script
url="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=places,geometry&callback=initAutocomplete"
onLoad={this.handleScriptLoad}
/>
</div>
<div className="current-location">
<Tooltip content="Use current location">
<IconButton
icon="locate"
iconSize={16}
height={32}
onClick={this.currentLocationOnClick}
>
{this.state.lat} & {this.state.lng}
</IconButton>
</Tooltip>
</div>
</div>
<div className="results">
{this.state.places.map(places => (
<div className="results-item" onClick={this.props.sideBarOpen}>
<ResultsItem name={places.name} image={Thumbnail} />
</div>
))}
</div>
</div>
);
}
}
The fact that places is available in an async manner, the best solution is to resolve Thumbnail within the map function itself.
That way it will only be required and resolved when places is available
render() {
return (
<div>
<div className="flex align-center">
<div className="search">
<SearchInput
id="autocomplete"
placeholder="Search by address"
width="100%"
height={56}
/>
<Script
url="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=places,geometry&callback=initAutocomplete"
onLoad={this.handleScriptLoad}
/>
</div>
<div className="current-location">
<Tooltip content="Use current location">
<IconButton
icon="locate"
iconSize={16}
height={32}
onClick={this.currentLocationOnClick}
>
{this.state.lat} & {this.state.lng}
</IconButton>
</Tooltip>
</div>
</div>
<div className="results">
{this.state.places.map(places => {
const Thumbnail = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos.photoreference}&key=MYAPIKEY
`;
return(
<div className="results-item" onClick={this.props.sideBarOpen}>
<ResultsItem name={places.name} image={Thumbnail} />
</div>
)})}
</div>
</div>
);
}
}
You should prevent to load data before they are actually loaded from server, so you should render a loader before use your result in this way:
if(isLoading) { // You should set the loading state before to load data from server
return <span>Loading</span>
}
return ( // This shows your data after loading goes to false
<div>Your code here</div>
)

put elements into variable for naming (react)

I tried to put elements into CustomModal variable:
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
and used it in render() like this:
render() {
//...
{ CustomModal }
//...
but, got an error:
react-dom.development.js:57 Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {CustomModal}). If you meant to render a collection of children, use an array instead.
Is there are any way to put elements into variable for naming?
Thanks.
----update-----
This is my full code of render :
render() {
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
const { people } = this.props.people.state;
return (
<React.Fragment>
{/* check login */}
{this.props.auth.state.isLoggedIn ? (
{ CustomModal }
) : (
<div />
)}
<div className="peoplelistpage-main">
<h1 className="peoplelistpage-title">people list</h1>
<div className="peoplelistpage-list-container">
{people.map((person, index) => (
<ul className="peoplelistpage-list-ul" key={index}>
<li className="peoplelistpage-list-li">
{`${index + 1}.`}{" "}
<Link to={`${this.props.location.pathname}/${person.id}`}>
{person.kr_name}
</Link>{" "}
<button onClick={this.handlePersonDeleteBtn(person.id)}>
<DeleteUserIcon />
</button>
</li>
</ul>
))}
</div>
<button onClick={this.openModal}>add</button>
</div>
</div>
) : (
<CustomNotPermittedForm />
)}
</React.Fragment>
);
}
Yes, you can use a div or a React.Fragment to group elements together. divs are added to the DOM while Fragments are not. But in order for this work with state, you will have to use a function, as a static variable does not get updated with state values.
const CustomModal = () => (
<React.Fragment> // <-- or div
<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>
</React.Fragment>
);
Usage
render() {
// ...
<CustomModal />
// ...

making reusable component in reactjs

I have the following code, want to remove the repeated content code inside <ReactCSSTransitionGroup to a separate file - does not look straight forward to pass props to and fro from child/parent, how do I do it? is it do-able?
<div className="container">
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
<span key={this.state.showChild1} className="plus_icon">
<a onClick={() => this.onClick('child1')}>
<Img className={this.state.showChild1 ? 'plus_icon' : 'minus_icon'} />
</a>
</span>
</ReactCSSTransitionGroup>
{this.state.child1 ? <Child1-New /> : <div onClick={() => this.onClick('child1')}><Child1 /></div>}
</div>
<div className="container">
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
<span key={this.state.showChild2} className="plus_arrow">
<a onClick={() => this.onClick('child2')}>
<img className={this.state.child2 ? 'plus_icon' : 'minus_icon'} />
</a>
</span>
</ReactCSSTransitionGroup>
{this.state.child2 ? <Child2-New /> : <div onClick={() => this.onClick('child2')}><Child2 /></div>}
</div>
onClick(name) {
if (name === 'child1') {
this.setState({
showChild1: !this.state.showChild1,
});
} else if (name === 'child2') {
this.setState({
showChild2: !this.state.showChild2,
});
}
planning to achieve something like:
<div className="container">
<ToggleView />
{this.state.child2 ? <Child2-New /> : <div onClick={() => this.onClick('child2')}><Child2 /></div>}
</div>
If you're using Node.js it's quite simple to manage your components in separate JS files.
Create a new JS file - ToggleView.js - as an example.
var React = require('react');
module.exports = React.createClass({
render: function() {
return (
<div>
... Your markup etc here
</div>
);
});
And then you can require it from within the JS where you want to use it:
var ToggleView = require('ToggleView.js');
And then use it:
<div className="container">
<ToggleView />
</div>
Secondly, if your state is managed at the parent which you need your children to have access to, you can simply prop down to them.
function thisFunc(val) {
// do something
};
Prop the function to the child
<ToggleView handleFunc={this.thisFunc} />
And in ToggleView.js, if you needed your to trigger on click:
...
<a onClick={this.prop.handleFunc}>
<img ... />
</a>
...
In this scenario, we prop thisFunc down to the child which will allow you to set the logic at the parent, whether you need to set state or whatever.
Hopefully this helps!

Resources