Wondering if I could get some help. I'm building a job board and I'm using github jobs as my jobs API feed. Here's a codesandbox link to my project so far:
https://codesandbox.io/s/34kzz5k6k1
(You need CORS chrome plugin to make the api work).
Basically:
In my index.js file, I'll calling the API in my 'ComponentDidMount'.
And by default, jobs appear for 'New York, on my page.
When you search for 'developer' jobs in 'london', in my 'HandleSubmit', you can see I'm pushing the results to a new URL '/jobresults'.
I'm using browser router to do this.
The problem I'm having though. So my default jobs are still appearing on /jobresults. As well as my 'London' search results, which appear underneath.
How do I only make 'london' jobs appear on this page?
I thought I could try and build a job board all front end. But now I'm think I need REST routing on the backend as well?
Maybe saving my API call in a database. And then displaying the results on a 'show' route?
Any guidance you can give, would be great!
Thanks.
There's a lot going on here that really needs to be revised. The way you've structured the app is anti-pattern (non-stardard/bad practice) and will cause you more headaches as the application becomes more dynamic.
I've gone ahead and restructured the entire app. I encourage you to deconstruct it and follow the application flow, and then take your project and fix it accordingly.
Working example: https://codesandbox.io/s/v873j0600y (still requires CORS extension)
index.js
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import JobForm from "./components/JobForm";
import JobResults from "./components/JobResults";
import NavHeader from "./components/NavHeader";
import "uikit/dist/css/uikit.min.css";
import "./styles.css";
const App = () => (
<main>
<BrowserRouter>
<section>
<NavHeader />
<Switch>
<Route exact path="/" component={JobForm} />
<Route path="/jobs" component={JobResults} />
<Route path="/jobresults/:id" component={JobResults} />
</Switch>
</section>
</BrowserRouter>
</main>
);
render(<App />, document.getElementById("root"));
NavHeader.js
import React from "react";
import { Link } from "react-router-dom";
export default () => (
<header>
<nav>
<ul style={{ listStyleType: "none" }}>
<li style={{ display: "inline", marginRight: 20 }}>
<Link to="/">Home</Link>
</li>
<li style={{ display: "inline", marginRight: 20 }}>
<Link to="/jobs">Jobs</Link>
</li>
</ul>
</nav>
</header>
);
JobForm.js
import React, { Component } from "react";
export default class JobForm extends Component {
state = { searchData: "", cityData: ""};
// HANDCHANGE FOR JOB SEARCH
handleChange = e => this.setState({ searchData: e.target.value });
// HANDLE CHANGE FOR LOCATION SEARCH
handleChangeLocation = e => this.setState({ cityData: e.target.value });
// HANDLE SUBMIT
handleSubmit = e => {
e.preventDefault();
const { cityData, searchData } = this.state;
if (!cityData || !searchData) return;
this.props.history.push(
`/jobresults/positions?description=${searchData}&location=${cityData}`
);
};
render = () => (
<section className="hero homepage">
<div className="container">
<h1 className="title has-text-white">USA Creative City</h1>
<h2 className="title has-text-white">Start your job search here!</h2>
<form className="level-item" onSubmit={this.handleSubmit}>
<div className="inputstyle field has-addons">
<div className="control ">
<input
className="uk-input"
type="text"
placeholder="Software Engineer..."
onChange={this.handleChange}
style={{ width: 200 }}
/>
</div>
<div className="control ">
<input
className="uk-input"
type="text"
placeholder="City"
onChange={this.handleChangeLocation}
style={{ width: 200 }}
/>
</div>
<div className="control">
<button
style={{ width: 200 }}
className="uk-button uk-button-primary"
>
<i
style={{ marginRight: 10 }}
className="fas fa-search"
aria-hidden="true"
/>Search Jobs
</button>
</div>
</div>
</form>
</div>
</section>
);
}
JobResults.js
import isEmpty from "lodash/isEmpty";
import React, { Component, Fragment } from "react";
import axios from "axios";
import qs from "qs";
import Spinner from "./Spinner";
import ShowResults from "./ShowResults";
import NoResults from "./NoResults";
const getRandomInt = max => Math.floor(Math.random() * Math.floor(max));
const locations = ["Los Angeles", "New York", "San Mateo", "San Francisco"];
const descriptions = ["Developer", "Engineer", "MySQL", "MongoDB"];
export default class JobResults extends Component {
state = { isLoading: true, jobs: [], error: "" };
componentDidUpdate = (prevProps, prevState) => {
if (this.props.location.pathname !== prevProps.location.pathname) {
this.setState({ isLoading: true }, () => this.fetchData());
}
};
componentDidMount = () => this.fetchData();
fetchData = () => {
let { description, location } = qs.parse(this.props.location.search, {
ignoreQueryPrefix: true
});
if (!description || !location) {
description = descriptions[getRandomInt(3)];
location = locations[getRandomInt(3)];
}
axios(`https://jobs.github.com/positions.json?description=${description}&location=${location}`)
.then(({ data }) => this.setState({ isLoading: false, jobs: data.slice(0, 9) }))
.catch(err => this.setState({ isLoading: false, err: err.toString() }));
};
render = () =>
this.state.isLoading
? <Spinner />
: <section>
<h3 style={{ textAlign: "center" }} className="has-text-centered animated shake slow">
RESULTS
</h3>
<div className="columns is-multiline">
{isEmpty(this.state.jobs)
? <NoResults err={this.state.err} />
: <ShowResults jobs={this.state.jobs} />
}
</div>
</section>
);
}
ShowResults.js
import map from "lodash/map";
import React from "react";
export default ({ jobs }) => (
map(jobs, ({ id, created_at, company_logo, title, company, location, url }) => (
<div className="result" key={id}>
<img className="image" src={company_logo} />
<h4 className="has-text-left purple">Location: {title}</h4>
<h5 className="has-text-left purple">
Created on: {created_at}
</h5>
<h5 className="has-text-left purple">Company: {company}</h5>
<h5 className="has-text-left purple">Location: {location}</h5>
<a className="uk-button uk-button-primary" href={url} target="_new">
apply on github
</a>
<a
className="uk-button uk-button-primary"
style={{ marginTop: 10 }}
href={url}
target="_new"
>
apply on creative jobs
</a>
</div>
)
);
NoResults.js
import React from "react";
export default ({ err }) => (
err
? <p style={{ textAlign: "center", color: "red" }}>
<i style={{ marginRight: 5 }} className="fas fa-exclamation-circle" />
{err}
</p>
: <p style={{ textAlign: "center", color: "grey" }}>
<i style={{ fontSize: 22, marginRight: 5 }} className="far fa-calendar-times"/>
No jobs matching that criteria.
</p>
);
Spinner.js
import React from "react";
const spinners = () => {
let children = [];
for (var i = 1; i < 13; i++) {
children.push(<div key={i} className={`sk-circle${i} sk-circle`} />);
}
return children;
};
export default () => <div className="sk-fading-circle">{spinners()}</div>;
Related
I am working on a react app with node/express on the backend.
I want a component to render a video which URL is passed down from its parent component as prop.
the parent component is named : Stepper and its child is named : ChestVideoWorkouts.
The problem I face is that the video does not render to the DOM, whereas its src URL is loaded when I inspect.
I have CORS installed.
I get these errors in the console :
Because a cookie’s SameSite attribute was not set or is invalid, it
defaults to SameSite=Lax, which prevents the cookie from being sent in
a cross-site request. This behavior protects user data from
accidentally leaking to third parties and cross-site request forgery.
Resolve this issue by updating the attributes of the cookie:
Specify SameSite=None and Secure if the cookie should be sent in cross-site requests. This enables third-party use.
Specify SameSite=Strict or SameSite=Lax if the cookie should not be sent in cross-site requests.
Here is the code of Stepper :
import { Button, message, Steps } from "antd";
import React, { useState } from "react";
import { WorkoutInfosDrawer } from "../drawer_content/WorkoutInfosDrawer";
import { InfosvgIcon, RateIcon, VideoPlayer } from "../icons/Icons";
import { RateWorkout } from "../rating/RateWorkout";
import { ChestVideoWorkouts } from "../video_components/ChestVideoWorkouts";
import "./steps_styles.scss";
const { Step } = Steps;
export const Stepper = ({ workoutTitle }) => {
function videoUrl(url) {
let videoUrl =
workoutTitle === "Barbell Flat Bench Press"
? { url: "https://www.youtube.com/watch?v=rT7DgCr-3pg" }
: "";
return videoUrl.url;
}
const steps = [
{
title: "",
content: <WorkoutInfosDrawer workoutTitle={workoutTitle} />,
},
{
title: "",
content: <ChestVideoWorkouts videoUrl={videoUrl()} />,
},
{
title: "",
content: <RateWorkout />,
},
];
const [current, setCurrent] = useState(0);
const next = () => {
setCurrent(current + 1);
};
const prev = () => {
setCurrent(current - 1);
};
const onChange = (value) => {
setCurrent(value);
};
return (
<div className={"stepper-container"}>
<Steps current={current} onChange={onChange}>
<Step icon={<InfosvgIcon />} title={steps[0].title} />
<Step icon={<VideoPlayer />} title={steps[1].title} />
<Step icon={<RateIcon />} title={steps[2].title} />
</Steps>
<div className="steps-content">
{steps[current].content}
<div style={{ display: "inline-block" }}></div>
</div>
<div className="steps-action">
{current < steps.length - 1 && (
<Button type="primary" onClick={() => next()}>
Next
</Button>
)}
{current === steps.length - 1 && (
<Button
type="primary"
onClick={() => message.success("Processing complete!")}
>
Done
</Button>
)}
{current > 0 && (
<Button
style={{
margin: "0 8px",
}}
onClick={() => prev()}
>
Previous
</Button>
)}
</div>
</div>
);
};
{
/* <Divider
style={{ height: "200px" }}
type="vertical"
dashed
/> */
}
and of ChestVideoWorkouts
import React from "react";
export const ChestVideoWorkouts = ({ videoUrl }) => {
return (
<div>
<video
style={{ border: "1px solid red" }}
autoPlay
loop
muted
src={videoUrl}
width={`100%`}
height={`100%`}
></video>
</div>
);
};
Are you trying to play a Youtube video in the the <video> tag? That won't work because a Youtube link gives a web page (eg: .html text) but for playback in a video tag you need a video file (eg: .mp4).
Solution :
(1) Either use an <iframe> to display the Youtube player...
import React from "react";
export const ChestVideoWorkouts = ({ videoUrl }) => {
return (
<div>
<iframe
style={{ border: "1px solid red" }}
src={videoUrl}
width={`100%`} height={`100%`}
frameborder="0"
allow="autoplay; encrypted-media; picture-in-picture" allowfullscreen
></iframe>
</div>
);
};
Where videoUrl looks like: https://www.youtube.com/embed/rT7DgCr-3pg
(2) Or else just pre-save the MP4 using a Youtube downloader.
You can try GetVideo and test the saved MP4 with a <video> tag.
import { Button } from "antd";
import React, { useState } from "react";
import ReactPlayer from "react-player/youtube";
import redirect from "../../assets/img/redirect.png";
import { PlayIcon } from "../icons/Icons";
import "./video_styles.scss";
export const ChestVideoWorkouts = ({ videoUrl }) => {
const [border, setborder] = useState("");
function handlemouseOver() {
setTimeout(() => {
setborder("2px solid gray");
}, 500);
}
return (
<div className="player-wrapper">
<div className="player-wrapper-vid">
<ReactPlayer
width="100%"
height="90%"
className="react-player"
playIcon={<PlayIcon />}
controls
light
url={videoUrl}
style={{ border: border, padding: "2px" }}
// onError={() => console.log("none")}
/>
</div>
<div className="player-wrapper-redirect">
<Button
onMouseOver={handlemouseOver}
className="player-wrapper-red-btn"
>
<a href={videoUrl} target="_blank">
<img src={redirect} alt="" />
</a>
</Button>
</div>
</div>
);
};
I have a simple routing system using hash router in my react app. I have a MainDisplay that Links to the route /assets/id. I also have a component called Trending that Links to the same route /assets/id. The link in MainDisplay works perfectly, but the link in Trending does not. The link for Trending changes the URL when I click on it but doesn't send me to the proper page until I refresh.
The trending component is being rendered by another component called CryptoInfo, which holds information based on the id I got from MainDisplay. Can someone help me understand why my routing isn't working in the Trending component?
// MainDisplay.js
<Link key={index} to={`/assets/${id}`}>
<span>{name}</span>
<span>${current_price}</span>
</Link>
// CryptoInfo
import React, { useState, useEffect } from 'react'
import { useParams } from "react-router-dom"
import '../../styles/CryptoInfo.css'
import MainNav from '../nav/MainNav'
import Chart from './Chart'
import Description from './Description'
import Footer from '../main/Footer'
import Exchanges from './Exchanges'
import News from './News'
import Trending from './Trending'
export default function CryptoInfo() {
const [currentData, setCurrentData] = useState([])
const [image, setImage] = useState("")
const [currentPrice, setCurrentPrice] = useState("")
const [marketCap, setMarketCap] = useState("")
const [marketData, setMarketData] = useState([])
const [days, setDays] = useState(1)
const [usd, setUsd] = useState('')
const [currency, setCurrency] = useState('')
const { id } = useParams()
const api = `https://api.coingecko.com/api/v3/coins/${id}`
async function fetchApi() {
const data = await fetch(api)
const response = await data.json()
setCurrentData(response)
setImage(response.image.small)
setCurrentPrice(response.market_data.current_price.usd)
setMarketData(response.market_data)
setMarketCap(response.market_data.market_cap.usd)
}
useEffect(() => {
fetchApi()
}, [days])
const currentDataDisplay = (
<>
<div className='top-div'>
<div >
<span className='market-rank'>Rank: {market_cap_rank}</span>
</div>
<div className='name-div'>
<img className='coin-image' src={image} alt="" />
<span className='crypto-name'>{name}</span>
<span className="c-info-symbol">{SYMBOL}</span>
</div>
</div>
{/* <div className='todays-range'>
<div>
<progress className='progress-bar' min="0" max="0.14" value="0.1"></progress>
</div>
<div>
<span>{todayLow}</span>
<span>
-
</span>
<span> {todayHigh}</span>
</div>
</div> */}
<div className='price-div'>
<span className='current-price'>${current_price}</span>
<span className='price-change-24' style={{ color: priceChange24h > 0 ? 'green' : 'red' }} > {priceChange24h} %</span>
</div>
</>
)
return (
<>
<MainNav />
<div className="crypto-info-container">
<div className="crypto-info-top-container">
<div>
{currentDataDisplay}
</div>
<Chart />
</div>
<div className='crypto-info-bottom-container'>
<div className='des-container'>
<Description symbol={SYMBOL} />
<Exchanges />
</div>
<News />
</div>
<Trending />
</div>
<Footer />
</>
)
}
// Trending.js
import React, { useEffect, useState } from 'react'
import { Paper } from '#mui/material'
import { Link } from 'react-router-dom'
export default function Trending() {
const [trendingData, setTrendingData] = useState([])
const [trendingStats, setTrendingStats] = useState([])
const api = 'https://api.coingecko.com/api/v3/search/trending'
useEffect(() => {
fetchData()
}, [])
const fetchData = async () => {
const data = await fetch(api)
const response = await data.json()
setTrendingData(response.coins)
}
const fetchMarketData = async () => {
const data = await fetch(fetchAll)
const response = await data.json()
setTrendingStats(response)
}
let coinsArray = []
trendingData && trendingData.forEach((item) => {
const { id } = item.item
coinsArray.push(id + '%2C%20')
})
const allIds = coinsArray.join('').replace(',', '').slice(0, -6)
const fetchAll = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${allIds}&order=market_cap_desc&per_page=100&page=1&sparkline=true`
useEffect(() => {
fetchMarketData()
}, [allIds, trendingStats])
const trendingDivv1 = (
trendingStats && trendingStats.slice(0, 4).map((coin, index) => {
const { name, price_change_percentage_24h, image, id, current_price } = coin
const sparkline = coin.sparkline_in_7d.price
let borderColor
let changePercent = price_change_percentage_24h.toFixed(2)
return (
<Link key={index} to={`/assets/${id}`}>
<Paper className="trending-box" elevation={3}>
<div style={{ display: 'flex' }}>
<div><img style={{ borderRadius: '50%', width: '50px' }} src={image} alt="" /></div>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<span>{name}</span>
<span>${current_price}</span>
</div>
<span style={{ color: borderColor, marginLeft: 'auto' }}>{changePercent}%</span>
</div>
<div className='trending-chart'>
<Sparklines data={sparkline}>
<SparklinesLine color={borderColor} />
</Sparklines>
</div>
</Paper >
</Link>
)
})
const trendingDivv2 = (
trendingStats && trendingStats.slice(4, 8).map((coin, index) => {
const { name, price_change_percentage_24h, image, id, current_price } = coin
const sparkline = coin.sparkline_in_7d.price
let borderColor
let changePercent = price_change_percentage_24h.toFixed(2)
return (
<Link to={`/assets/${id}`}>
<Paper className="trending-box" elevation={3}>
<div style={{ display: 'flex' }}>
<div><img style={{ borderRadius: '50%', width: '50px', height: '50px' }} src={image} alt="" /></div>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<span> {name}</span>
<span>${current_price}</span>
</div>
<span style={{ color: borderColor, marginLeft: 'auto' }}>{changePercent}%</span>
</div>
<div className='trending-chart'>
<Sparklines data={sparkline}>
<SparklinesLine color={borderColor} />
</Sparklines>
</div>
</Paper >
</Link >
)
})
)
return (
<>
<div className='trending-div'>
<h1 style={{ margin: '20px 0' }}>Trending Coins 🔥</h1>
<div className='trending-coins-div'>
<div className='trending-flex-box'>
{trendingDivv1}
</div>
<div className='trending-flex-box'>
{trendingDivv2}
<a href={'/'}>
<div className="trending-box trending-image" >
<h2 style={{ color: 'white', fontWeight: '700', fontSize: '1.5em', verticalAlign: 'center' }}>See More Coins</h2>
</div >
</a>
</div>
</div>
</div>
</>
)
}
//App.js
<>
<Router>
<Switch>
<Route exact path="/" >
<div>
<MainNav />
<InfoNav />
<MainDisplay />
<Footer />
</div>
</Route>
<Route path="/assets/:id">
<CryptoInfo />
</Route>
<Route path="/categories">
<CategoryList />
</Route>
</Switch>
</Router>
</>
So it turns out the link in Trending is working. The issue is that the CryptoInfo component doesn't respond to the id route param updating to fetch any new data.
export default function CryptoInfo() {
...
const [days, setDays] = useState(1); // <-- (3) setDays never called, days never updates
...
const { id } = useParams(); // <-- (1) id param updates
const api = `https://api.coingecko.com/api/v3/coins/${id}`; // <-- (2) api value updated
async function fetchApi() {
...
}
useEffect(() => {
fetchApi(); // <-- (5) no refetch
}, [days]); // <-- (4) dependency doesn't update
...
return (....);
}
To resolve, move the api and fetchApi function into the useEffect and use the correct dependencies, just id in this case. You should also surround any asynchronous code in a try/catch to handle any rejected promises or any other thrown exceptions.
Example:
function CryptoInfo() {
...
const { id } = useParams();
useEffect(() => {
const api = `https://api.coingecko.com/api/v3/coins/${id}`;
async function fetchApi() {
try {
const data = await fetch(api);
const response = await data.json();
setCurrentData(response);
setImage(response.image.small);
setCurrentPrice(response.market_data.current_price.usd);
setMarketData(response.market_data);
setMarketCap(response.market_data.market_cap.usd);
} catch (error) {
// handle error
console.log(error);
}
}
fetchApi();
}, [id]);
...
return (...);
}
I have two api's one is to list categories and other is to list stores. Second api takes category id as input to show stores of that category, I am unable to list stores of specific category. Here's what I have written so far, I am able to hard code category id.
I want user to select category and then the output gives only those stores falling in that category. Can someone help me update this code?
import React, { useState, useEffect } from "react";
import logo from './logo.svg';
import './App.css';
import axios from "axios";
import appstore from './assets/astore.png'
import gplay from './assets/gplay.png'
import closeicon from './assets/closeicon.svg'
import videostore from './assets/videostore.svg'
import bigboxlogo from './assets/bigboxlogo.svg'
import createstore from './assets/createstore.svg'
import gettheapp from './assets/gettheapp.svg'
const App = () => {
const [category, setCategory] = useState([]);
const [store, setStore] = useState([]);
let attribute;
function showCat(catid) {
let attribute = catid.target.attributes.getNamedItem('data-cat').value;
console.log(attribute)
}
let catid = 10;
const fetchData = () => {
const categoryApi = "https://api.bigbox.online/api/v1/users/brand_categories?page=1&limit=10";
const storeApi = `https://api.bigbox.online/api/v1/users/brand_category_stores?brand_category_id=${catid}&page=1&limit=10`;
const getCategory = axios.get(categoryApi);
const getStore = axios.get(storeApi);
axios.all([getCategory, getStore]).then(
axios.spread((...allData) => {
const allCategory = allData[0].data.brand_categories;
const allStore = allData[1].data.stores;
// console.log(allCategory);
// console.log(allStore);
setCategory(allCategory);
setStore(allStore);
})
)
}
useEffect(() => {
fetchData()
}, [])
function removeDiv1() {
document.getElementById("ad1")
.outerHTML = "";
}
function removeDiv2() {
document.getElementById("ad2")
.outerHTML = "";
}
return (
<div className="App">
<div className="header">
<div className="header-left">
<img src={bigboxlogo} alt="" style={{ marginRight: "20px" }} />
<p>shop</p>
<p>what is bigbox?</p>
<p>bigbox app</p>
<p>for business</p>
<p>help</p>
</div>
<div className="header-right">
<img src={gettheapp} alt="" className="header-btn" />
<img src={createstore} alt="" className="header-btn" />
</div>
</div>
<div style={{ paddingLeft: "30px" }}>
<h1 style={{ fontSize: "80px", marginBottom: "5px" }}>video call your favourite brands.</h1>
<h5 style={{ fontSize: "28px", marginTop: "0", marginBottom: "15px", fontWeight: 400 }}>discover, follow and shop from your favourite stores. anytime. anywhere.</h5>
</div>
<div id="ad1" className="promo">
<p>get the shopping experience you deserve with our new and improved bigbox app</p>
<img src={appstore} alt="" className="promo-img" />
<img src={gplay} alt="" className="promo-img" />
<button className="button" onClick={removeDiv1}>
<img src={closeicon} alt="" style={{ cursor: "pointer" }} />
</button>
</div>
<div id="ad2" className="promo">
<p>selling online? setup your video store with bigbox and sell easily through video calls</p>
<img src={videostore} alt="" className="promo-img" />
<button className="button" onClick={removeDiv2}>
<img src={closeicon} alt="" style={{ cursor: "pointer" }} />
</button>
</div>
<div className="body">
<div className="sidebar">
<p style={{ fontSize: "20px", fontWeight: 600, marginTop: "0" }}>categories</p>
{
category.map((item) => (
<div onClick={showCat} data-cat={item.id} style={{ cursor: "pointer" }}>
{item.name}
</div>
))
}
</div>
<div className="centerbody">
<div>
<p className="numberStores">{store.length} stores</p>
</div>
<div className="home-body">
{
store.map((item) => (
<div key={item.id} className="home-store" >
<img src={item.brand_logo_url} alt="" className="brand-logo" />
<a style={{ textDecoration: 'none' }} href={`https://in.bigbox.online/${item.slug}`} target="_blank" >
<img className="home-storeImg" src={item.cover_pic_mobile_url} alt="" />
<h1>{item.brand.name}</h1>
</a>
</div>
))
}
</div>
</div>
</div>
</div>
);
}
export default App;
First of all, I think you should use the react's state, to handle data changes through selected items like you are trying to do. moreover, in showCat function, there is a problem, let's say you are getting the relevant data you need, but you are not using it or storing it for future use, so at the end of the function the data is not stored and you are losing it.
Therefore, you are not holding the selected id that you need for presenting the relevant stores.
Add new useState for holding the current selected catID like so: const [selectedCatID, setSelectedCatID] = useState();
function showCat(catid) {
setSelectedCatID(catid);
}
Then change the div attribute to pass the item.id through the onClick's function at triggering showCat.
3) <div onClick={() => showCat(item.id)} style={{ cursor: "pointer" }}>
Lastly modify the jsx to show the relevant stores by the current selected catid:
store.map((item) => {
if (selectedCatID && item.id === selectedCatID) {
return (
<div key={item.id} className="home-store" >
<img src={item.brand_logo_url} alt="" className="brand-logo" />
<a style={{ textDecoration: 'none' }} href={`https://in.bigbox.online/${item.slug}`} target="_blank" >
<img className="home-storeImg" src={item.cover_pic_mobile_url} alt="" />
<h1>{item.brand.name}</h1>
</a>
</div>
)}
return null; // for the case that does not match the id of the selected store.
)
Or either you can filter the stores before and just show to the screen the filtered stores by the selected catid.
let me know if you understood my explantaion. good luck!
EDIT:
when the catid will change the fetchData will run again, on every cat selected.
useEffect(() => {
fetchData()
}, [selectedCatID])
And also modify the storeApi for using the selectedCatID:
const storeApi = `https://api.bigbox.online/api/v1/users/brand_category_stores?brand_category_id=${selectedCatID}&page=1&limit=10`;
i am tryin to route to localhost/detiled on click on the <li>
when i type in url localhost/detiled my <InnerDetail /> is loading i want the same when i click on the <li> tag
and also how can i access suggestion.id in <InnerDetail />
search.js
<Link to={{ pathname:"/detiled" }}
>
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
onClick={finddoctor(suggestion.id)}
>
{suggestion.firstname}
</li>
</Link>
in my path.js i have this
path.js
<Route path="/detiled">
<InnerDetail />
</Route>
import PersonPhoto from "../img/doctor.png";
import { useLocation } from "react-router-dom";
import axios from "axios";
import React, { useState, useEffect } from "react";
export default function Detail(props) {
const location = useLocation();
const [detail, setDetail] = useState(false);
//const data3 = location.state.data;
//const doctor_id = data3.id;
const inipath = window.location.pathname;
const path = inipath.split("/cdoctor/");
const [data3, setdata3] = useState([]);
console.log(path[1]);
useEffect(() => {
const config = {
headers: {
Authorization: `token ` + localStorage.getItem("token"),
},
};
//remove this date after setting up the admin pannel
axios
.get(
"doctor-filter/?id=" + path[1],
config
// config
)
.then((res) => {
console.log(res.data);
// setdata3(res.data);
});
});
return (
<>
{/* {detail ? (
<InnerDetail />
) : (
<> */}
<h4 style={{ textAlign: "left", marginLeft: "10px" }}>
Top Specialities <i className="fa fa-angle-right"></i> /doctor/Detail
</h4>
<hr
style={{
margin: "30px 10px",
background: "#fff",
height: "1px",
border: "none",
}}
/>
<div style={styles.wrapper}>
{/* begin header */}
<div style={styles.pheader}>
<div>
<div style={styles.pname}>
<strong style={styles.namealigner}>Dr {data3.firstname}</strong>
<br />
<strong style={styles.namealigner}> {data3.lastname}</strong>
</div>
<hr style={styles.hr} />
<div style={{ textAlign: "left", fontSize: "12px" }}>
<span>
{" "}
{data3.speciality} | {data3.experience} years of Experience
</span>
</div>
<hr style={styles.hr} />
</div>
<div>
<img style={{ height: "100px" }} src={PersonPhoto} alt="" />
</div>
</div>
{/* end header */}
{/* begin detail */}
<div style={styles.iflex}>
<div style={styles.innerflex}>
<i className="fa fa-graduation-cap"></i>
<strong> Education</strong>
<br />
<small> {data3.qualification}</small>
</div>
<div style={styles.innerflex}>
<i className="fa fa-map-marker"></i>
<strong> Location</strong>
<br />
<small>{data3.location}</small>
</div>
</div>
<div style={styles.iflex}>
<div style={styles.innerflex}>
<i className="fa fa-user"></i>
<strong> Registeration Number</strong>
<br />
<small>{data3.councilRegNo}</small>
</div>
<div style={styles.innerflex}>
<i className="fa fa-globe"></i>
<strong> Language</strong>
<br />
<small>English Malayalam</small>
</div>
</div>
{/* end detail */}
</div>
</>
// )}
// </>
);
}
this is the dashbord here serch is common in all pages
<Search />
<Specialities />
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faSearch } from "#fortawesome/free-solid-svg-icons";
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
const initialState = {
idaddProducts: "",
};
const Searchclients = () => {
const history = useHistory();
const [showResults, setShowResults] = React.useState(true);
const [poName, pnName] = React.useState(initialState);
const [showSerch, setShowSerch] = React.useState([]);
const [detail, setDetail] = useState(false);
const [inputValue, setInputValue] = React.useState("");
const [filteredSuggestions, setFilteredSuggestions] = React.useState([]);
const [selectedSuggestion, setSelectedSuggestion] = React.useState(0);
const [displaySuggestions, setDisplaySuggestions] = React.useState(false);
function finddoctor(e) {
console.log(e);
setDetail(true);
}
const suggestions = [];
showSerch.forEach(function (data) {
suggestions.push(data);
});
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
//console.log(strung.substring(1, strung.length - 1));
// console.log(JSON.stringify(suggestions));
// var suggestions = suggestions.substring(1, suggestions.length - 1);
// newObj = suggestions;
//console.log(suggestions);
//setFilteredSuggestions({ ...poName, idAddProducts: idAddProducts });
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
// const filteredSuggestions = suggestions.filter((suggestion) =>
// suggestion.toString().toLowerCase().includes(value.toLowerCase())
// );
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
// console.log(props);
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
// console.log(suggestions);
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<Link to={`/detiled/${suggestion.id}`}> //this isthe link
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("all-doctors-list/")
.then((res) => {
const data = res.data;
// pnName(data.data);
// var stringdata = data;
setShowSerch(data);
//console.log(stringdata);
});
// setShowSerch(data);
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
onClick={() => this.nextPath("/detiled")}
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
export default Searchclients;
You can add a route for detail view of the suggestion.
<Switch>
<Route path="/detailed" exact>
list suggestions component
</Route>
<Route path="/detailed/:id" exact}>
DetailComponent
</Route>
</Switch>
Then the link will become:
<Link to={`/detailed/${suggestion.id}`}>
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
And in DetailComponent you can get the id from route params.
import { useParams } from "react-router-dom";
...
const { id } = useParams(); // the id passed in url
its a long explaition it will be easier if you see screenshots first!
i'm trying to make a website, which inside 3 divs, with 3 different backgrounds. under those 3 divs there are 3 rows of buttons with different colors
you click on a color, it changes the background of one of the main divs. it will be more clear with the image/codesandbox i give here
each click you make changes "this.state.color1" or "color2" to the color you clicked on.
what i wanna do is add a "saved selection page", which you can see color combinations you saved by clicking another buttons called "save".
each click on this save button should return the 3 current colors, send them over to "Saved" page, and they should stay there and never change.
and if you click the save button again, it keeps the previous selections, and add the new one under the previous one.
kinda the same way we click on "add to cart" on websites.
i tried over a week to figure it out by many different ways, like putting a new state called "savedColors" and stuff like that but i didnt figure it out.
here it is on codesandbox
main page:
import React from "react";
import "./main.style.css";
import Buttons1 from "../buttons/buttons1-component";
import Buttons2 from "../buttons/buttons2-component";
import Buttons3 from "../buttons/buttons3-component";
import Saved from "../saved/saved.component";
class Main extends React.Component {
constructor(props) {
super(props);
this.changeColor1 = this.changeColor1.bind(this);
this.changeColor2 = this.changeColor2.bind(this);
this.changeColor3 = this.changeColor3.bind(this);
this.changeToSavedPage = this.changeToSavedPage.bind(this);
this.goToMainPage = this.goToMainPage.bind(this);
this.saveScheme = this.saveScheme.bind(this);
this.state = {
color1: "#fff285",
color2: "#38306b",
color3: "#c4cc90",
page: "main"
};
}
changeToSavedPage() {
this.setState({ page: "saved" });
}
goToMainPage() {
this.setState({ page: "main" });
}
changeColor1(id) {
this.setState({
color1: id
});
}
changeColor2(id) {
this.setState({
color2: id
});
}
changeColor3(id) {
this.setState({
color3: id
});
}
saveScheme() {
alert("see notes in the function");
// hey guys thanks for looking at my code,
// so what im trying to, is to get all 3
// current colors thats been seleceted.
// pass them over to "saved page", and show them there,
// each time you click "save selection" button,
// it will show the NEW CURRENT selection in the saved page.
// but will NOT delete the previos selection, just add a new one
// kind a like Add To Cart button!
}
render() {
return (
<div className="container">
{this.state.page === "main" && (
<div>
<div className="main-colors">
<div
className="color"
style={{ backgroundColor: this.state.color1 }}
>
<h1>color 1</h1>
</div>
<div
className="color"
style={{ backgroundColor: this.state.color2 }}
>
<h1>color 2</h1>
</div>
<div
className="color"
style={{ backgroundColor: this.state.color3 }}
>
<h1>color 3</h1>
</div>
</div>
<div className="buttons-container">
<p>change color 1:</p>
<Buttons1 changeColor1={this.changeColor1} />
<p>change color 2:</p>
<Buttons2 changeColor2={this.changeColor2} />
<p>change color 3:</p>
<Buttons3 changeColor3={this.changeColor3} />
</div>
<div className="btns">
<button onClick={() => this.saveScheme()}>save selection</button>
<button onClick={() => this.changeToSavedPage()}>
go to saved page
</button>
</div>
</div>
)}
{/* saved page */}
{this.state.page === "saved" && (
<Saved goToMainPage={this.goToMainPage} />
)}
</div>
);
}
}
export default Main;
saved page:
import React from "react";
import "./saved.styles.scss";
import SavedPiece from "../saved-piece/saved-piece.component";
class Saved extends React.Component {
constructor(props){
super(props);
// this.num = this.props.isClicked;
this.state = {
}
}
render(){
return(
<div className="saved-container">
<h1>saved</h1>
{/*
here we should see the saved combinations....
*/}
</div>
)
}
}
export default Saved;
import React from "react";
const Saved = (props) => {
const {saved} = props
return (
<>
<div className="saved-container">
<h1>saved matches page</h1>
{
saved && saved.map((obj, i) => {
return <div className="main-colors" key = {i}>
<div
className="color"
style={{ backgroundColor: obj.color1 }}
>
<h1>color 1</h1>
</div>
<div
className="color"
style={{ backgroundColor: obj.color2 }}
>
<h1>color 2</h1>
</div>
<div
className="color"
style={{ backgroundColor: obj.color3 }}
>
<h1>color 3</h1>
</div>
</div>
})
}
<button onClick={() =>
props.goToMainPage()}>
back to main page
</button>
</div>
</>
)
}
export default Saved;
import React from "react";
import React from "react";
import "./main.style.css";
import Buttons1 from "../buttons/buttons1-component";
import Buttons2 from "../buttons/buttons2-component";
import Buttons3 from "../buttons/buttons3-component";
import Saved from "../saved/saved.component";
class Main extends React.Component {
constructor(props) {
super(props);
this.changeColor1 = this.changeColor1.bind(this);
this.changeColor2 = this.changeColor2.bind(this);
this.changeColor3 = this.changeColor3.bind(this);
this.changeToSavedPage = this.changeToSavedPage.bind(this);
this.goToMainPage = this.goToMainPage.bind(this);
this.saveScheme = this.saveScheme.bind(this);
this.state = {
color1: "#fff285",
color2: "#38306b",
color3: "#c4cc90",
page: "main",
saved: []
};
}
changeToSavedPage() {
this.setState({ page: "saved" });
}
goToMainPage() {
this.setState({ page: "main" });
}
changeColor1(id) {
this.setState({
color1: id
});
}
changeColor2(id) {
this.setState({
color2: id
});
}
changeColor3(id) {
this.setState({
color3: id
});
}
saveScheme() {
const { color1, color2, color3 } = this.state
this.setState({
saved: [
...this.state.saved,
{
color1,
color2,
color3
}
]
})
}
render() {
return (
<div className="container">
{this.state.page === "main" && (
<div>
<div className="main-colors">
<div
className="color"
style={{ backgroundColor: this.state.color1 }}
>
<h1>color 1</h1>
</div>
<div
className="color"
style={{ backgroundColor: this.state.color2 }}
>
<h1>color 2</h1>
</div>
<div
className="color"
style={{ backgroundColor: this.state.color3 }}
>
<h1>color 3</h1>
</div>
</div>
<div className="buttons-container">
<p>change color 1:</p>
<Buttons1 changeColor1={this.changeColor1} />
<p>change color 2:</p>
<Buttons2 changeColor2={this.changeColor2} />
<p>change color 3:</p>
<Buttons3 changeColor3={this.changeColor3} />
</div>
<div className="btns">
<button onClick={() => {
console.log(this.state.saved)
this.saveScheme()
}}>save selection</button>
<button onClick={() => {
this.changeToSavedPage()
}}>
go to saved page
</button>
</div>
</div>
)}
{/* saved page */}
{this.state.page === "saved" && (
<Saved
goToMainPage={this.goToMainPage}
saved = {this.state.saved}
/>
)}
</div>
);
}
}
export default Main;
We added an array to our main component state called saved, then when a user saves, we update the state by adding the values of the current selections, and using the spread operator to maintain the old selected values and not mutate them. Then we pass our saved array as a prop to our child component, and we map it.