I'm having an issue where cookies are not being set and popup message doesn't seem to hide itself I would admit I'm an amateur with javascript and this is my first time dealing with cookies. I had it working at one point but I can't seem to recreate what made it work
#consent-popup {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: .5rem;
background-color: #717171;
color: white;
opacity: 1;
transition: opacity .8s ease;
&.hidden {
opacity: 0;
}
}
<div id="consent-popup" class="hidden">
<p>short View our Terms and conditions and Privacy policy. I <a id="accept" href="#">ACCEPT</a></p>
</div>
const cookieStorage = {
getItem: (key) => {
const cookies = document.cookie
.split(';')
.map(cookie => cookie.split('='))
.reduce((acc, [key, value]) => ({ ...acc, [key.trim()]: value}), {});
return cookies[key];
},
setItem(key, value) {
document.cookie = `${key}=${value}`;
},
};
const storageType = cookieStorage;
const consentPropertyName = 'rnc_cookies';
const shouldShowPopup = () => !storageType.getItem(consentPropertyName);
const saveToStorage = () => storageType.setItem(consentPropertyName, true);
window.onload = () => {
const consentPopup = document.getElementById('consent-popup');
const acceptBtn = document.getElementById('accept');
const acceptFn = event => {
saveToStorage(storageType)
consentPopup.classList.add('hidden');
};
acceptBtn.addEventListener('click', acceptFn);
if (shouldShowPopup(storageType)) {
setTimeout(() => {
consentPopup.classList.remove('hidden');
}, 2000);
}
};
Related
can someone help me debug this issue?
I am at the VueJS course and I have this weird issue (it happens even if I copy-paste source code from the course and it seems like the guy does not have it).
So here is the app image:
When I click on teams in the navigation it opens me all the available teams with some info and the option to see members of each team.
When I click on Team 2 it should go to team 2 and its details.
Here is the working code:
<template>
<section>
<h2>{{ teamName }}</h2>
<ul>
<user-item
v-for="member in members"
:key="member.id"
:name="member.fullName"
:role="member.role"
></user-item>
</ul>
</section>
<router-link to="/teams/t2">Team 2</router-link>
</template>
<script>
import UserItem from '../users/UserItem.vue';
export default {
components: {
UserItem
},
inject: ['users', 'teams'],
data() {
return {
teamName: '',
members: []
};
},
methods: {
loadMembersData(route) {
const teamId = route.params.teamId;
const selectedTeam = this.teams.find((team) => team.id === teamId);
const foundMembers = selectedTeam.members;
const selectedMembers = [];
for (const member of foundMembers) {
const selectedUser = this.users.find((user) => user.id === member);
selectedMembers.push(selectedUser);
}
this.members = selectedMembers;
this.teamName = selectedTeam.name;
}
},
created() {
this.loadMembersData(this.$route);
},
watch: {
$route(newRoute) {
this.loadMembersData(newRoute);
}
}
};
</script>
<style scoped>
section {
margin: 2rem auto;
max-width: 40rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
padding: 1rem;
border-radius: 12px;
}
h2 {
margin: 0.5rem 0;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
</style>
But when I add watcher then my navigation does not work and I get this issue:
Any ideas on how to solve this?
Thanks
Note: I am working with VueJS 3 if it means anything :)
SOLVED:
methods: {
loadMembersData(route) {
const teamId = route.params.teamId;
const selectedTeam = this.teams.find((team) => team.id === teamId);
if (selectedTeam) {
const foundMembers = selectedTeam.members;
const selectedMembers = [];
for (const member of foundMembers) {
const selectedUser = this.users.find((user) => user.id === member);
selectedMembers.push(selectedUser);
}
this.members = selectedMembers;
this.teamName = selectedTeam.name;
}
}
},
Solution that solved the issue:
methods: {
loadMembersData(route) {
const teamId = route.params.teamId;
const selectedTeam = this.teams.find((team) => team.id === teamId);
if (selectedTeam) {
const foundMembers = selectedTeam.members;
const selectedMembers = [];
for (const member of foundMembers) {
const selectedUser = this.users.find((user) => user.id === member);
selectedMembers.push(selectedUser);
}
this.members = selectedMembers;
this.teamName = selectedTeam.name;
}
}
},
I am new to ReactJS and I am trying to create a search feature with react by fetching data from multiple API. Below is the Search.js file. I tried so many times to make it functions and make the results appear live while typing. I however keep on getting this error message TypeError: values.map is not a function. Where am I going wrong and how do I fix it?
function Search() {
const [input, setInput] = useState("");
const [results, setResults] = useState([]);
const urls = [
'https://jsonplaceholder.typicode.com/posts/1/comments',
'https://jsonplaceholder.typicode.com/comments?postId=1'
]
Promise.all(urls.map(url => fetch(url)
.then((values) => Promise.all(values.map(value => value.json())))
.then((response) => response.json())
.then((data) => setResults(data))
.catch(error => console.log('There was a problem!', error))
), [])
const handleChange = (e) => {
e.preventDefault();
setInput(e.target.value);
}
if (input.length > 0) {
results.filter((i) => {
return i.name.toLowerCase().match(input);
})
}
return ( <
div className = "search"
htmlFor = "search-input" >
<
input type = "text"
name = "query"
value = {
input
}
id = "search"
placeholder = "Search"
onChange = {
handleChange
}
/> {
results.map((result, index) => {
return ( <
div className = "results"
key = {
index
} >
<
h2 > {
result.name
} < /h2> <
p > {
result.body
} < /p> {
result
} <
/div>
)
})
} </div>
)
}
.search {
position: relative;
left: 12.78%;
right: 26.67%;
top: 3%;
bottom: 92.97%;
}
.search input {
/* position: absolute; */
width: 40%;
height: 43px;
right: 384px;
margin-top: 50px;
top: 1.56%;
bottom: 92.97%;
background: rgba(0, 31, 51, 0.02);
border: 1px solid black;
border-radius: 50px;
float: left;
outline: none;
font-family: 'Montserrat', sans-serif;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
/* identical to box height */
display: flex;
align-items: center;
/* Dark */
color: #001F33;
}
/* Search Icon */
input#search {
background-repeat: no-repeat;
text-indent: 50px;
background-size: 18px;
background-position: 30px 15px;
}
input#search:focus {
background-image: none;
text-indent: 0px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Issue
The response you get from fetch(url) is just the one single response, so there's nothing to map.
The data fetching occurs in the function body of the component, so when working this causes render looping since each render cycle fetches data and updates state.
The input.length > 0 filtering before the return does nothing since the returned filtered array isn't saved, and it also incorrectly searches for sub-strings.
Attempt to render result object in the render function, objects are invalid JSX
Solution
Skip the .then((values) => Promise.all(values.map((value) => value.json()))) step and just move on to accessing the JSON data.
Move the data fetching into a mounting useEffect hook so it's run only once.
Move the filter function inline in the render function and use string.prototype.includes to search.
Based on other properties rendered and what is left on the result object I'll assume you probably wanted to render the email property.
Code:
function Search() {
const [input, setInput] = useState("");
const [results, setResults] = useState([]);
useEffect(() => {
const urls = [
"https://jsonplaceholder.typicode.com/posts/1/comments",
"https://jsonplaceholder.typicode.com/comments?postId=1"
];
Promise.all(
urls.map((url) =>
fetch(url)
.then((response) => response.json())
.then((data) => setResults(data))
.catch((error) => console.log("There was a problem!", error))
),
[]
);
}, []);
const handleChange = (e) => {
e.preventDefault();
setInput(e.target.value.toLowerCase());
};
return (
<div className="search" htmlFor="search-input">
<input
type="text"
name="query"
value={input}
id="search"
placeholder="Search"
onChange={handleChange}
/>
{results
.filter((i) => i.name.toLowerCase().includes(input))
.map((result, index) => {
return (
<div className="results" key={index}>
<h2>{result.name}</h2>
<p>{result.body}</p>
{result.email}
</div>
);
})}
</div>
);
}
The element works when using an external node module but not when using a locally downloaded node module but I can't work out why?
here's the Swipi-cards library:
https://github.com/riolcrt/swipi-cards/blob/master/demo/index.html
My code so far(working) but when I use local node module as source it doesn't any fixes?
import React, { useState, useEffect } from 'react';
import Data from '../Data/webApps_data';
function Webapps() {
const [loading_animation, setloading_animation] = useState(false);
const [arrayChecker, set_arrayChecker] = useState(0);
useEffect(() => {
if (loading_animation === false) {
setTimeout(() => {
setloading_animation(!loading_animation);
console.log()
}, 100);
}
const script = document.createElement('script');
script.src = "https://unpkg.com/swipi-cards#1.0.0/dist/swipi-cards/swipi-cards.js";
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
}
}, [loading_animation]);
const arrayLimiter = () => {
if (arrayChecker < (Data.length - 1)) {
set_arrayChecker(arrayChecker + 1)
} else {
set_arrayChecker(0)
}
console.log(Data);
};
const filteredData = Data[arrayChecker];
const textTransition = loading_animation ? 'text_transition ease' : 'text_transition';
const elementTransition = loading_animation ? 'element_transition ease' : 'element_transition';
//swipicard script
return (
<div className='webAppStyles'>
<rg-swipi-cards stack-offset-y="0.3" class='hydrated'>
<rg-swipi-card left-color='green' right-color='green' class='hydrated'>
<p>test1</p>
</rg-swipi-card>
<rg-swipi-card left-color='green' right-color='green' class='hydrated'>
<p>test2</p>
</rg-swipi-card>
</rg-swipi-cards>
</div>
)
}
scss styles:
rg-swipi-cards {
display: flex;
align-self: center;
background: chocolate;
width: 350px !important;
height: 400px !important;
align-items: center;
justify-content: center;
rg-swipi-card {
width: 100%;
position: absolute;
transition: all 0.5s ease-in-out 0s;
z-index: 4;
opacity: 1.33333;
}
p {
text-align: center;
}
}
ok so using this as the source works but I don't know why this must mean the node module doesn't work any ideas?
script.src = "https://unpkg.com/swipi-cards#1.0.0/dist/swipi-cards/swipi-cards.js";
const {useState, useEffect, useRef} = React;
const App = () => {
const [pressed, setPressed] = useState(false);
const [shoot, setShoot] = useState(false);
const [seconds, setSeconds] = useState(0);
useInterval(() => {
// Your custom logic here
pressed && seconds < 3 && setSeconds((prev)=> Number((prev+0.1).toFixed(1)));
}, 100);
useInterval(()=>{
!pressed && seconds > 0 && setSeconds((prev)=>{
if( Number((prev-0.5).toFixed(1)) < 0){
return 0;
}
return Number((prev-0.5).toFixed(1))
});
}, 20)
return (
<div>
<button
onMouseDown={()=>{
console.log('mouseDown')
setShoot(false);
setPressed(true);
}}
onMouseUp={()=>{
console.log('mouseUp')
setShoot(true);
setPressed(false);
}}
style={{
transform: `rotate(-${seconds*15}deg)`
}}
>Press</button>
<span className={`dot ${shoot ? '--shooted' : ''}`} />
<p>{seconds}</p>
</div>
)
};
ReactDOM.render(<App />, document.getElementById('root'));
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
.dot{
position: absolute;
width: 16px;
height: 16px;
border-radius:100%;
background: red;
}
.dot.--shooted{
animation: test 1s;
}
#keyframes test{
0%{
transform: translateX(0px);
}
100%{
transform: translateX(200px); // it should be dynamic px.
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root" />
I'd like to move the red dot as much as the seconds I pressed the button.
but I am using animation so I can't control the px in CSS.
If I pressed the button for 3seconds, the red dot should be moved to 300px.
If I pressed the button for 1seconds, the red dot should be moved to 100px.
This is an example. But you need to add a logic to move it back.
const {
useState,
useEffect,
useRef
} = React;
const App = () => {
const [pressed, setPressed] = useState(false);
const [shoot, setShoot] = useState(false);
const [seconds, setSeconds] = useState(0);
const dotRef = useRef();
useInterval(() => {
// Your custom logic here
pressed && seconds < 3 && setSeconds((prev) => Number((prev + 0.1).toFixed(1)));
}, 100);
useInterval(() => {
!pressed && seconds > 0 && setSeconds((prev) => {
if (Number((prev - 0.5).toFixed(1)) < 0) {
return 0;
}
return Number((prev - 0.5).toFixed(1))
});
}, 20)
const handleMouseUp = () => {
dotRef.current.style.transform = `translateX(${seconds * 100}px)`;
}
return ( <
div >
<
button onMouseDown = {
() => {
console.log('mouseDown')
setShoot(false);
setPressed(true);
}
}
onMouseUp = {
() => {
console.log('mouseUp')
setShoot(true);
setPressed(false);
handleMouseUp();
}
}
style = {
{
transform: `rotate(-${seconds*15}deg)`
}
} >
Press < /button> <
span className = {
`dot ${shoot ? '--shooted' : ''}`
}
ref = {
dotRef
}
/> <
p > {
seconds
} < /p> < /
div >
)
};
ReactDOM.render( < App / > , document.getElementById('root'));
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
.dot {
position: absolute;
width: 16px;
height: 16px;
border-radius: 100%;
background: red;
transition: transform 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root" />
I have literally tried for a few hours to replicate a clickable ticker, much like they have at the very top of this site: https://www.thebay.com/
I'm confused about what triggers useEffect and long story short, I can't come up with a solution that keeps the ticker moving AND also gives the option of clicking forward/backwards via arrows. Clicking the arrow should not permanently pause the ticker.
function Ticker() {
const [tickerDisplay, setTickerDisplay] = useState('Free In-store Pickup')
const [tickerIndex, setTickerIndex] = useState(0)
const [arrowClicked, setArrowClicked] = useState(false)
const notices = [
'Easy Returns within 30 Days of Purchase',
'Free Shipping on $99+ Orders',
'Free In-store Pickup',
]
const handleClick = (side) => {
setArrowClicked(true)
switch (side) {
case 'left':
setTickerIndex(
tickerIndex === 0 ? notices.length - 1 : tickerIndex - 1
)
break
case 'right':
setTickerIndex(
tickerIndex === notices.length - 1 ? 0 : tickerIndex + 1
)
break
default:
console.log('something went wrong')
break
}
}
useEffect(() => {
if (arrowClicked) {
setTickerDisplay(notices[tickerIndex])
setTickerIndex(
tickerIndex === notices.length - 1 ? 0 : tickerIndex + 1
)
setArrowClicked(false)
return
}
setTimeout(() => {
setTickerDisplay(notices[tickerIndex])
setTickerIndex(
tickerIndex === notices.length - 1 ? 0 : tickerIndex + 1
)
console.log('This will run every 6 seconds!')
}, 6000)
}, [tickerIndex, notices, tickerDisplay, arrowClicked])
return (
<IconContext.Provider value={{ className: 'ticker-icons-provider' }}>
<div className='ticker'>
<FaChevronLeft onClick={() => handleClick('left')} />
<div className='ticker_msg-wrapper'>{tickerDisplay}</div>
<FaChevronRight onClick={() => handleClick('right')} />
</div>
</IconContext.Provider>
)
}
export default Ticker
What is the best way to code this component?
This is not a work of art and probably some things could've been done better.
Hope that suits you.
const { useRef, useState, useEffect } = React;
const getItems = () => Promise.resolve(['All of our questions are now open', 'Answers extended: 72 hours after questions open', 'Post a question or get an answer', 'Free badges on 20k points'])
const Ticker = ({onPrevious, onNext, items, currentIndex}) => {
const ref = useRef(null);
const [size, setSize] = useState({
width: 0,
widthPx: '0px',
height: 0,
heightPx: '0px'
})
useEffect(() => {
if(ref && ref.current) {
const {width, height} = ref.current.getBoundingClientRect();
setSize({
width,
widthPx: `${width}px`,
height,
height: `${height}px`
})
}
}, [ref]);
const calculateStyleForItem = (index) => {
return {
width: size.width,
transform: `translateX(${0}px)`
}
}
const calculateStyleForContainer = () => {
return {
width: `${size.width * (items.length + 1)}px`,
transform: `translateX(${-currentIndex * size.width + 2 * size.width}px)`
}
}
return <div ref={ref} className="ticker">
<div style={{width: size.widthPx, height: size.heightPx}} className="ticker__foreground">
<div onClick={onPrevious} className="arrow">{'<'}</div>
<div onClick={onNext} className="arrow">{'>'}</div>
</div>
<div>
<div style={calculateStyleForContainer()} className="ticker__values">
{items.map((value, index) => <div key={index} style={calculateStyleForItem(index)}className="ticker__value">{value}</div>)}
</div>
</div>
</div>
}
const App = () => {
const [items, setItems] = useState([]);
const [currentIndex, setCurrentIndex] = useState(0);
const [clicked, setClicked] = useState(false);
useEffect(() => {
let isUnmounted = false;
getItems()
.then(items => {
if(isUnmounted) {
return
}
setItems(items);
})
return () => {
isUnmounted = true;
}
}, [])
useEffect(() => {
if(!items.length) {
return () => {
}
}
let handle = null;
const loop = () => {
if(!clicked) {
onNext(null);
}
setClicked(false);
handle = setTimeout(loop, 2000);
}
handle = setTimeout(loop, 2000);
return () => {
clearTimeout(handle);
}
}, [items, clicked])
const onPrevious = () => {
setClicked(true);
setCurrentIndex(index => (index - 1) > -1 ? index - 1 : items.length - 1)
}
const onNext = (programmatically) => {
if(programmatically) {
setClicked(programmatically);
}
setCurrentIndex(index => (index + 1) % items.length)
}
return <div>
{items.length ? <Ticker onPrevious={onPrevious} onNext={onNext} currentIndex={currentIndex} items={items}/> : 'Loading'}
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
html, body {
box-sizing: border-box;
margin: 0;
}
.ticker {
display: flex;
justify-content: center;
align-items: center;
background: black;
font-size: 1rem;
color: white;
font-weight: bold;
padding: 1rem;
overflow: hidden;
}
.ticker__foreground {
position: absolute;
z-index: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.ticker__values {
transition: all .3s ease-in;
}
.ticker__value {
text-align: center;
display: inline-block;
vertical-align: middle;
float: none;
}
.arrow {
font-size: 1.5rem;
cursor: pointer;
padding: 1rem;
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>