Good afternoon) Help please. How to make the modal pop up once a day when the site loads. I have 2 options with localstorage and cookie, but I don't know how to make the logic correct.
project link
https://codesandbox.io/s/kind-torvalds-e315y?file=/src/App.vue:2283-2284
hey I think this should work
// modalService.js
const STORAGE_KEY = "LS_LAST_UPDATE";
const getStorageValue = () => {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY));
} catch {
return "";
}
};
const setStorageValue = (value = "") =>
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
const dateIsOld = () => {
const today = new Date().toLocaleDateString();
return getStorageValue() !== today;
};
const updateDate = () => {
setStorageValue(new Date().toLocaleDateString());
};
export { dateIsOld, updateDate };
export default {
dateIsOld,
updateDate,
};
and in your vue component you do something like this
import { dateIsOld, updateDate } from "./path/to/modalService.js"
export default {
name: "App",
data() {
return {
showModal: false,
};
},
mounted() {
//this.runModalTimer()
this.showModal = dateIsOld()
},
methods: {
close() {
this.showModal = false;
updateDate()
},
};
}
Related
I Created array that contains functions and now I am trying to call a function from that array, I tried this code but it's not working and I have no idea how can I do it becuase I am pretty new at react js. Can someone help me with this?
here is my code
import React, { Component } from "react";
import "../App.css";
export default class Chart extends Component {
constructor(props) {
super(props);
this.state = {
stockChartXValues: "",
stockChartYValues: "",
type: props.data,
};
}
getBTC = () => {
// .....
};
getETH = () => {
// .....
};
getADA = () => {
// .....
};
componentDidMount() {
// here I am trying to run a function according to the "type" variable
var options = ["BTC", "ETH", "ADA"];
var functions = [this.getBTC, this.getETH, this.getADA];
var func = functions.indexOf(options.indexOf(this.state.type));
func.call();
}
render() {
return (
<div>
<h1>Hello world</h1>
</div>
);
}
}
you need to get function with the index you found;
var func = functions.indexOf(options.indexOf(this.state.type));// this returns index not the actual func
functions[func] && functions[func]()
My Approach would be like;
getBTC = () => {
// .....
};
getETH = () => {
// .....
};
getADA = () => {
// .....
};
getCoin = (type) => {
switch(type) {
case "BTC": this.getBTC()
return
case "ADA":...
...
...
}
componentDidMount() {
this.getCoin(this.state.type)
}
I am trying to clear localstorage with a button and an addEventListener. But its not working, and I cant figure out why. Thanks.
const clearStorage = document.querySelector(".clear-button");
clearStorage.addEventListener("click", (function(){
localStorage.clear();
}));
};
This code gets imported to the script below:
import { getFavourites } from "./utils/getFavs.js";
import createMenu from "./components/createMenu.js";
import displayMessage from "./components/displayMessage.js";
import { clearFavList } from "./components/clearFavList.js"
createMenu();
getFavourites();
const favouriteList = getFavourites();
const articlesContainer = document.querySelector(".favourites-container");
if(!favouriteList.length) {
displayMessage("error", "You don't have any saved favourites yet.", ".favourites-container");
}
favouriteList.forEach((favourite) => {
articlesContainer.innerHTML += `<div class="article">
<div class="article-content-text">
<h2 class="article-title fav-wrapper-text">Title: ${favourite.title}</h2>
</div>
<div>
<i class="fas fa-heart favButton"></i>
</div>
</div>`;
});
clearFavList(favouriteList);
This code, from a React auth component, have all the basic functions to handle storage.
// you can create multiple storage stores
const LOCAL_STORAGE_STORE = 'storage_sample';
export const getHasLocalStorageAuth = () => {
// check local storage
const localStorage = __getLocalStorage(LOCAL_STORAGE_STORE);
return { status: !!localStorage, data: localStorage.auth };
};
export const clearLocalStorageAuth = () => {
__clearLocalStorage(LOCAL_STORAGE_STORE);
return;
};
export const setLocalStorageAuth = (newLocalStorage: any) => {
__setLocalStorage(LOCAL_STORAGE_STORE, newLocalStorage);
return;
};
// setting data to localstorage
export function __setLocalStorage(
localStorageName: string,
localStorageValue: any,
isJson = true
) {
if (isJson) {
localStorage.setItem(localStorageName, JSON.stringify(localStorageValue));
} else {
localStorage.setItem(localStorageName, localStorageValue);
}
}
// getting data from localstorage
export function __getLocalStorage(localStorageName: string): any {
let localStorageValue: any;
if (localStorage.getItem(localStorageName) !== null) {
localStorageValue = localStorage.getItem(localStorageName);
} else {
localStorageValue = false;
}
return JSON.parse(localStorageValue);
}
// clear data from localstorage
export function __clearLocalStorage(localStorageName: string | null) {
localStorage.clear();
}
How can I turn the following code into a function component with hooks?
In my example I use a class component
And I want to change the code to a function component form
export default class Modal2 extends Component {
state = {
placeName: "",
errorMsg: null
};
placeNameChangedHandler = val => {
this.setState({
placeName: val,
errorMsg: null
});
};
onConfirm = () => {
const { placeName } = this.state;
const { onConfirm, onHideModal } = this.props;
if (placeName.trim().length > 5) {
onConfirm("Cancel", placeName);
onHideModal();
this.setState({ placeName: "", errorMsg: null })
} else {
this.setState({ errorMsg: "must 5 letters" });
}
};
}
That's how it should look after converting it.
import React, { useState } from 'react';
function Modal2(props) {
const [desiredStateName, setDesiredStateName] = useState({
placeName: "",
errorMsg: null
});
placeNameChangedHandler = val => {
setDesiredStateName({
placeName: val,
errorMsg: null
});
};
onConfirm = () => {
const { placeName } = desiredStateName.placeName;
const { onConfirm, onHideModal } = props;
if (placeName.trim().length > 5) {
onConfirm("Cancel", placeName);
onHideModal();
setDesiredStateName({ placeName: "", errorMsg: null })
} else {
setDesiredStateName((prevState)=>{
return{ ...prevState,errorMsg: "must 5 letters" }
})
}
};
}
export default Modal2;
Also, a quick guide of how you are able to do it by yourself
Have a try by replacing your code with the below code:
import React, { useState } from 'react';
export default Modal2 = props => {
const [placeName, setPlaceName] = useState("")
const [errorMsg, setErrorMsg] = useState(null)
placeNameChangedHandler = val => {
setPlaceName(val)
setErrorMsg(null)
};
onConfirm = () => {
const { onConfirm, onHideModal } = props;
if (placeName.trim().length > 5) {
onConfirm("Cancel", placeName);
onHideModal();
setPlaceName("")
setErrorMsg(null)
} else {
setErrorMsg("must 5 letters")
}
};
}
I am simply looking to save and restore a search term(form data) when a page is refreshed/reloaded. I have tried several solutions to no avail.
Flow: A user submits a search term and is taken to Spotify to retrieve an accessToken, if it is not already available. The initial page is refreshed once the accessToken is retrieved, but the search must be re-entered. This is not good UX.
I concluded that Web Storage was they way to go, of course it is not the only route. I am not sure if this is something that should be relegated to Lifecycle methods: componentDidMount() & componentDidUpdate(). Perhaps that is overkill? In any event, I attempted to employ both localStorage and sessionStorage. My implementation is obviously off as I am not getting the expected result. React dev tools displays the state of the SearchBar term, but it is not being saved. Also of note is the following: React dev tools shows that the onSubmit event handler is registering as bound () {} instead of the expected bound handleInitialSearchTerm() {}. The console also shows that there are no errors.
No third-party libraries please.
SearchBar.js
import React from 'react';
import "./SearchBar.css";
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: this.handleInitialSearchTerm
};
this.search = this.search.bind(this);
this.handleInitialSearchTerm = this.handleInitialSearchTerm.bind(this);
this.setSearchTerm = this.setSearchTerm.bind(this);
this.handleSearchOnEnter = this.handleSearchOnEnter.bind(this);
this.handleTermChange = this.handleTermChange.bind(this);
}
handleInitialSearchTerm = (event) => {
if (typeof (Storage) !== "undefined") {
if (localStorage.term) {
return localStorage.term
} else {
return this.setSearchTerm(String(window.localStorage.getItem("term") || ""));
}
}
};
setSearchTerm = (term) => {
localStorage.setItem("term", term);
this.setState({ term: term });
}
search() {
this.props.onSearch(this.state.term);
}
handleSearchOnEnter(event) {
if (event.keyCode === 13) {
event.preventDefault();
this.search();
}
}
handleTermChange(event) {
this.setState({
term: event.target.value
});
}
render() {
return (
<div className="SearchBar">
<input
placeholder="Enter A Song, Album, or Artist"
onChange={this.handleTermChange}
onKeyDown={this.handleSearchOnEnter}
onSubmit={this.handleInitialSearchTerm}
/>
<button className="SearchButton" onClick={this.search}>
SEARCH
</button>
</div>
);
}
}
export default SearchBar;
Motify.js
let accessToken;
const clientId = "SpotifyCredentialsHere";
const redirectUri = "http://localhost:3000/";
const CORS = "https://cors-anywhere.herokuapp.com/"; // Bypasses CORS restriction
const Motify = {
getAccessToken() {
if (accessToken) {
return accessToken;
}
// if accessToken does not exist check for a match
const windowURL = window.location.href;
const accessTokenMatch = windowURL.match(/access_token=([^&]*)/);
const expiresInMatch = windowURL.match(/expires_in=([^&]*)/);
if (accessTokenMatch && expiresInMatch) {
accessToken = accessTokenMatch[1]; //[0] returns the param and token
const expiresIn = Number(expiresInMatch[1]);
window.setTimeout(() => accessToken = "", expiresIn * 1000);
// This clears the parameters, allowing us to grab a new access token when it expires.
window.history.pushState("Access Token", null, "/");
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
search(term) {
const accessToken = Motify.getAccessToken();
const url = `${CORS}https://api.spotify.com/v1/search?type=track&q=${term}`;
return fetch(url, { headers: { Authorization: `Bearer ${accessToken}` }
}).then(response => response.json()
).then(jsonResponse => {
if (!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map(track => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
uri: track.uri,
preview_url: track.preview_url
}));
})
}
...
Please check the code I have added.
Changes I did are below:
1)
this.state = {
term: JSON.parse(localStorage.getItem('term')) || '';
};
setSearchTerm = (term) => {
this.setState({
term: term
},
() => {
localStorage.setItem('term', JSON.stringify(this.state.term)));
}
import React from 'react';
import "./SearchBar.css";
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: JSON.parse(localStorage.getItem('term')) || '';
};
this.search = this.search.bind(this);
this.handleInitialSearchTerm = this.handleInitialSearchTerm.bind(this);
this.setSearchTerm = this.setSearchTerm.bind(this);
this.handleSearchOnEnter = this.handleSearchOnEnter.bind(this);
this.handleTermChange = this.handleTermChange.bind(this);
}
handleInitialSearchTerm = (event) => {
if (typeof(Storage) !== "undefined") {
if (localStorage.term) {
return localStorage.term
} else {
return this.setSearchTerm(String(window.localStorage.getItem("term") || ""));
}
}
};
setSearchTerm = (term) => {
this.setState({
term: term
},
() => {
localStorage.setItem('term', JSON.stringify(this.state.term)));
}
search() {
this.props.onSearch(this.state.term);
}
handleSearchOnEnter(event) {
if (event.keyCode === 13) {
event.preventDefault();
this.search();
}
}
handleTermChange(event) {
this.setState({
term: event.target.value
});
}
render() {
return ( <
div className = "SearchBar" >
<
input placeholder = "Enter A Song, Album, or Artist"
onChange = {
this.handleTermChange
}
onKeyDown = {
this.handleSearchOnEnter
}
onSubmit = {
this.handleInitialSearchTerm
}
/> <
button className = "SearchButton"
onClick = {
this.search
} >
SEARCH <
/button> <
/div>
);
}
}
export default SearchBar;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
If it is in hooks i would have done like below:
import React, {
useEffect,
useState,
useRef,
} from 'react';
function App() {
const [value, setValue] = useState(() => {
if (localStorage.getItem('prevCount') === null) {
return 0;
} else {
return localStorage.getItem('prevCount');
}
});
const countRef = useRef();
useEffect(() => {
countRef.current = value;
if (countRef.current) {
localStorage.setItem('prevCount', countRef.current);
} else {
localStorage.setItem('prevCount', 0);
}
});
const handleIncrement = () => {
setValue((value) => +value + 1);
};
const handleDecrement = () => {
if (value === 0) {
return;
} else {
setValue((value) => value - 1);
}
};
return (
<div className="card">
<label className="counterLabel">Simple Counter</label>
<button
className="button"
onClick={handleIncrement}
>
Increment
</button>
<span className="count">{value}</span>
<button
className="button"
onClick={handleDecrement}
>
Decrement
</button>
</div>
);
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
So what the above code is doing is that when we inititalize the state value we first check the localStorage , if "term" has value in localStorage we will use that value or else an empty string is initialized.
Using callback of setState inside the method setSearchTerm we set the term value immediately
Try the useLocalStorage hook to save search client side.
// useLocalStorage Hook to persist values client side
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === "undefined") {
return initialValue;
}
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
credit: Brandon Baars
Trying to calculate width of my scatterplot on the fly so I can pass it as props to my d3 component. I'm having no problem console logging in the handleResize function that is being called by window.addEventListener('resize', this.handleResize) in my ComponentDidMount but I can't setState in the handleResize function or seem to access anything outside of it. I've also tried var self = this; to rebind it but am still getting either a this.setState is not a function or self.setState is not a function.
import React, { PropTypes, Component } from 'react';
import { getDataRange, getTeams, getFile, getAllHitsData, getPlayers} from 'api/index.js';
import {Table, Thead, Th, Tr, Td} from 'components/Reactable';
import Autosuggest from 'react-autosuggest';
import { Link } from 'react-router';
import ScatterChart from 'components/scatterchart';
import DashboardStats from 'components/dashboard-stats';
import DateRangeComponent from 'components/date-range';
import AdminSquare from 'components/admin-square';
import { connect } from 'react-redux';
import { changeStartDate, changeEndDate } from '../../redux/modules/redux-date-change';
import { sendHitData } from '../../redux/modules/send-hit.js';
import { Loading } from 'react-loading';
let allHitDatas = [];
let hitDatas = [];
let teams = [];
// let selectedTeamID = null;
// let selectedTeamName = 'all_teams';
let newFile = '';
// let teamId = '';
let players = [];
let width;
class Dashboard extends Component {
static propTypes = {
team: PropTypes.object.isRequired,
startDate: PropTypes.string.isRequired,
endDate: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired
};
static contextTypes = {
router: PropTypes.object
};
constructor(props, context) {
super(props, context);
this.state = {
showRangePicker: false,
hitDatas: [],
teams: [],
start: "",
end: "",
team: this.props.team,
selectedTeamID: null,
selectedTeamName: "",
newFileConfirmation: false,
players: [],
allHitDatas: [],
suggestions: this.getSuggestions(''),
selected: '',
showDatePickerControls: false,
// maxHic: 0
// showScatterPlot: true
};
this.onChange = this.onChange.bind(this);
this.onSuggestionsUpdateRequested = this.onSuggestionsUpdateRequested.bind(this);
}
componentWillReceiveProps() {
this.setState({
maxHic: 0,
team: this.props.team,
selectedTeamID: this.props.team.id,
startDate: this.props.startDate,
endDate: this.props.endDate
// allHitDatas: []
}, () => {
// this.getDomains();
this.dataChangeHelper();
return this.state;
});
}
componentDidMount() {
this.dataChangeHelper();
window.addEventListener('resize', this.handleResize);
getTeams().then((response) => {
teams = response.data;
this.setState({teams: teams});
});
getPlayers().then((response) => {
players = response.data;
this.setState({
players: players
}, () => {
return this.state;
});
});
}
getDomains() {
let dates = [];
let hicArray = [];
console.log(this.state.allHitDatas);
if (this.state.allHitDatas.length === 0) {
return allHitDatas.map((hitData) => {
let date = Date.parse(hitData.EventTime);
dates.push(date);
hicArray.push(hitData.Hic);
let maxDate = Math.max.apply(null, dates);
let maxHic = 0;
let minDate = Math.min.apply(null, dates);
let minHic = 0;
this.setState({
minDate: minDate,
maxDate: maxDate,
minHic: minHic,
maxHic: maxHic
}, () => {
console.log(this.state.maxHic);
return this.state;
});
});
}
return this.state.allHitDatas.map((hitData) => {
let date = Date.parse(hitData.EventTime);
dates.push(date);
hicArray.push(hitData.Hic);
let maxDate = Math.max.apply(null, dates);
let maxHic = Math.max.apply(null, hicArray);
let minDate = Math.min.apply(null, dates);
let minHic = Math.min.apply(null, hicArray);
this.setState({
minDate: minDate,
maxDate: maxDate,
minHic: minHic,
maxHic: maxHic
}, () => {
console.log(this.state.maxHic)
return this.state;
});
});
}
dataChangeHelper() {
const newConfig = {
start: this.props.startDate,
end: this.props.endDate,
team: this.props.team.id
};
getDataRange(newConfig)
.then((response) => {
hitDatas = response.data;
this.setState({
hitDatas: hitDatas
}, () => {
return this.state;
});
});
getAllHitsData(newConfig)
.then((response) => {
allHitDatas = response.data;
this.setState({
allHitDatas: allHitDatas
}, () => {
this.getDomains();
return this.state;
});
});
}
handleResize() {
// const self = this;
let elem = document.getElementById('scatter-chart');
width = elem.offsetWidth * 0.9;
console.log(width);
this.setState({
scatterWidth: width
}, () => {
console.log(this.state.scatterWidth);
});
}
render () {
if (this.state.teams.length === 0 || this.state.players.length === 0) {
return (
<div className="no-data-container">
<div className="no-data-message">We don't have any data for you right now. Would you like
to add some players, teams, or devices?
</div>
<ul className="no-data-links">
<AdminSquare title="PLAYER ADMIN" icon="person" link="/player"/>
<AdminSquare title="TEAM ADMIN" icon="group" link="/team"/>
<AdminSquare title="DEVICE ADMIN" icon="sd_storage" link="/device"/>
</ul>
</div>
);
}
const { value, suggestions } = this.state;
const inputProps = {
placeholder: 'Search for a player',
value,
onChange: this.onChange
};
return (
<div>
<ScatterChart
data={this.state.allHitDatas}
domain={{x: [this.state.minDate, this.state.maxDate], y: [this.state.maxHic, 0]}}
statOneTitle="HIC"
sendHitData={(d) => this.handleImpactClick(d)}
width={ width }
/>
</div>
);
}
}
function mapStateToProps(state) {
console.log(state);
return {
startDate: state.startDate,
endDate: state.endDate
};
}
export default connect(mapStateToProps)(Dashboard);
handleResize doesn't have Dashboard object associated with 'this'. You need to bind to the event hanler
replace window.addEventListener('resize', this.handleResize); with
window.addEventListener('resize',this.handleResize.bind(this));
which will bind the this keyword..so that you can do like this.setState or access any object defined in Dashboard
If you plan on using this inside of a method and the method is not a part of react component's lifecycle, then you need to set it's context to the component instance. In your case you haven't set the correct context for the handleResize, getDomains, dataChangeHelper methods, so the constructor needs some additional bindings:
this.handleResize = this.handleResize.bind(this);
getDomains ...
dataChangeHelper ...