I'm find a problem about a text in the navBar.
I use router-flux.
My problem is that I have insert the Logout at the right in the navBar, but I would show this button only at a category of user.
So If your role is "user1": You can logout.
If your role is "user2": You can't logout and you shouldn't see the "logout" text.
This is the code that I use to show the logout button:
App.js
export default class App extends Component {
static redirectLogout() {
Alert.alert("Logout", "Logout effettuato con successo");
Actions.authentication();
}
static logout() {
Utente.clearUtenteLoggato();
App.redirectLogout();
}
<Scene
key="homepageutente"
component={HomepageUtente}
type="reset"
leftTitle="Home"
leftButtonTextStyle={{color: "#ffffff"}}
onLeft={() => Actions.authentication()}
rightButtonTextStyle={{color: "#ffffff"}}
rightTitle="Logout"
onRight={() => App.logout()}
navigationBarStyle={{ backgroundColor: "#64c7c0" }}
/>
Do you know how can I do? If more information is needed, I will provide it immediately. Thank you very much
EDIT:
This is the structure of the App:
First page:
Authentication:
(you can go to)
--> LoginConsumer
--> LoginPlus
I Use a White page that is load after click on one button to check if you are logged in and what kind of user you are.
Starting.js
class Starting extends Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
}
componentWillMount() {
Utente.getUtenteLoggato()
.then(dataUtenteLoggato => {
if (dataUtenteLoggato !== null) {
global.utente = new Utente(JSON.parse(dataUtenteLoggato));
Actions.homepageutente()({type: 'reset'});
} else if(Roles == "ROLE_PLUS") { // But this doesn't work :(
console.log(Roles)
Actions.loginplus();
}
else {
Actions.loginconsumer()
}
})
.catch(err => {
console.log(err);
})
.finally(() => {
this.setState({ loading: false });
});
}
So If you are and Role_Plus you can't logout.
Starting.js call the "getUtenteLoggato" from Utente:
static async getUtenteLoggato() {
try {
return await AsyncStorage.getItem("#UtenteLoggato");
} catch (error) {
console.log(error.message);
return null;
}
}
You could use a simple ternary condition to determine the state of this by checking on the user1 state:
<Scene
key="homepageutente"
component={HomepageUtente}
type="reset"
leftTitle="Home"
leftButtonTextStyle={{color: "#ffffff"}}
onLeft={() => Actions.authentication()}
rightButtonTextStyle={{color: "#ffffff"}}
rightTitle={user === "user1" ? "Logout" : ""}
onRight={user === "user1" ? () => App.logout() : () => {}}
navigationBarStyle={{ backgroundColor: "#64c7c0" }}
/>
Related
I have this simple react app, where I fetch the Flickr public feed. So, I can scroll to the end of the page and new content is going to show. So I would like to scroll until there is nothing else new, and the app stops trying to load more content, because it has reached the last item of the list, which is not happening if I try to scroll (you can see that on the loading message). How can I fix this?
Check the code below:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import $ from "jquery";
import PhotoListItem from "./photoListItem";
import "./photoApp.css";
export default class PhotoApp extends Component {
constructor(props) {
super(props);
this.state = {
photoList: [],
searchTerm: "cyanotype",
items: 8,
loadingState: false,
loadingMessage: ""
};
}
componentDidMount() {
this.getPhotoList();
this.onInfiniteScroll();
}
/* get data from Flickr public feed */
getPhotoList = () => {
const flickrApiPoint =
"https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?&tags=" +
this.state.searchTerm;
try {
$.ajax({
url: flickrApiPoint,
dataType: "jsonp",
data: { format: "json" },
success: function(data) {
this.setState({ photoList: data.items });
}.bind(this)
});
} catch (err) {
console.log(err);
}
};
/* code for infinite scroll */
onInfiniteScroll = () => {
this.refs.iScroll.addEventListener("scroll", () => {
if (
this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=
this.refs.iScroll.scrollHeight - 20
) {
this.loadMoreItems();
}
});
};
/* code for infinite scroll */
loadMoreItems = () => {
if (this.state.loadingState) {
return;
}
this.setState({
loadingState: true,
loadingMessage: "Loading photos..."
});
setTimeout(() => {
this.setState(prevState => ({
items: prevState.items + 8,
loadingState: false,
loadingMessage: "No more photos to show."
}));
}, 1000);
};
render() {
console.log(this.state.photoList)
return (
<div className="appContainer" ref="iScroll">
<div className="appHeader">
<h1 className="headerTitle">
Welcome to Flickr Alternative Photography Feed!
</h1>
</div>
<div className="gridContainer">
{this.state.photoList
.slice(0, this.state.items)
.map((photo, index) => {
const author = photo.author.split(/"/)[1];
const authorLink = photo.description.split(/"/)[1];
const description = photo.description.split(/"/)[13];
return (
<PhotoListItem
key={index}
url={photo.media.m}
photoLink={photo.link}
title={photo.title}
author={author}
authorLink={authorLink}
description={description}
tags={photo.tags}
/>
);
})}
</div>
<React.Fragment>
{this.state.loadingState ? (
<p className="loading">{this.state.loadingMessage}</p>
) : (
<p className="loading">{this.state.loadingMessage}</p>
)}
</React.Fragment>
</div>
);
}
}
LIVE EXAMPLE HERE
Thank you!
You could check if the item that you've loaded exceeds your items in your ajax request
/* code for infinite scroll */
loadMoreItems = () => {
// hasMore = data.items.length (you may want to rename this more appropriately)
if (this.state.loadingState || (this.state.items > this.state.hasMore)) {
// Do not load if there's no more items
return;
}
...
Your onInfiniteScroll doesn't have any code right now that checks whether it should load more items, it just blindly does. So: at the end of getPhotoList you probably want to check whether that's the last page of results and if so, do a setState({ exhausted: true }) or something similar, so you can check that value in your onInfiniteScroll and not do anything if you see this.state.exhausted === true.
In the below code when i enter a search string and press enter, this is becoming undefined and as a result the function is not getting called.Can anybody please help me understand why? I have tried almost everything but nothing seems to be working neither could i find any pointers to the problem i am facing.
class HomepageBody extends Component{
constructor(props){
super(props);
this.state = {
value :'',
error: null,
isLoaded: false,
array: [],
mobile: ''
}
this.readSearchString = this.readSearchString.bind(this);
this.doSomething = this.doSomething.bind(this);
}
readSearchString(event){
if(event.target.value === ''){
this.setState({
error: null,
array: ''
});
}
else{
this.setState ({
value : event.target.value
});
}
}
doSomething = () => {
fetch(`http://localhost:8080/items?search=${this.state.value}&page=1`,
{
headers: {
'Accept': 'application/json'
}
})
.then(res => res.json())
.then(
(result) => {
if(result.length != 0){
this.setState({
isLoaded: true,
array: result,
error: null
});
}
else{
this.setState({
isLoaded: true,
error : "No matches found",
array: ''
})
}
},
(error) => {
this.setState({
isLoaded: true,
error: "We are experiencing some temporary problem, please try again later"
});
}
)
}
render () {
const {mobile} = this.props;
return(
<Container>
<Header
as='h1'
content='Title'
style={{
fontSize: mobile ? '1.2em' : '3em',
fontWeight: 'normal',
marginBottom: 0,
marginTop: mobile ? '5em' : '3em',
display:'block'
}}
/>
<Input icon={<Icon name='search' inverted circular link />}
placeholder='Search .....'
style={{
fontSize: mobile ? '1em' : '1em',
fontWeight: 'normal',
marginTop: mobile ? '1em' : '1em',
width: mobile ? '280px' : '600px',
}}
onChange={ this.readSearchString }
onKeyPress={(event) => {
if(event.key === 'Enter'){
this.doSomething()
}
}}
focus
/>
</Container>
)
}
}
HomepageBody.propTypes = {
mobile: PropTypes.bool,
}
Thanks,
Vikram
Yes, thats what i had done. But it didn't work. However i figured out a solution. If i'm not using the semantic ui framework's component, then i can define the function inline for onKeyPress and it works without any problems, but when i use the semantic ui framework and use the <Input> component, i have to override the function call. So this is how i did it
<Input>
..........
.........
onKeyPress = {this.onKeyPress}
</Input>
onKeyPress= (e) => {
if(e.key === 'Enter')
this.doSomething();
}
So i presume its got to something to do with semantic ui and the way it handles events within the component.
Set an attribute of tabIndex="0" and it will work.
tabindex="0" allows elements besides links and form elements to
receive keyboard focus. It does not change the tab order, but places
the element in the logical navigation flow, as if it were a link on
the page.
I am attempting to validate an input manually by passing up the chain the input of a text field. Some magic is supposed to happen whereby the following conditions are checked:
if input text matches that already held in an array - error = "already exists" & the text isn't added to the list
if input text is blank - error = "no text input" & the text isn't added to the list
if input text is not blank and does not already exist - run another method to add text to the list
The error is set to null by default
Currently in the input.js file, the {this.props.renderError} line causes an "underfined" output in the console before anything happens. I understand why this occurs, but I wondered if there was any way to stop it?
Functionality-wise: I can get the error message to output, however this appears to run after the text is already placed in the list of tasks...
Checkout the sandbox for this code
App.js (parent)
const tasks = [
{ name: 'task1', isComplete: false },
{ name: 'task2', isComplete: true },
{ name: 'task3', isComplete: false },
]
class App extends React.Component {
constructor() {
super();
this.state = {
error: null,
}
}
render() {
return (
<div>
<Input
createTask={this.createTask.bind(this)}
renderError={this.renderError.bind(this)}
taskList={this.state.tasks}
throwError={this.throwError.bind(this)}
/>
</div>
)
}
createTask(task, errorMsg) {
this.throwError(errorMsg);
if (this.state.error) {
return;
} else {
this.setState((prevState) => {
prevState.tasks.push({ name: task, isComplete: false });
return {
tasks: prevState.tasks
}
})
}
}
throwError(errorMsg) {
if (errorMsg) {
this.setState((prevState) => {
prevState.error = errorMsg;
return {
error: prevState.error
}
})
}
return;
}
renderError() {
if (this.state.error) {
return <div style={{ color: 'red' }}>{this.state.error}</div>
}
}
Input.js (child)
render() {
return (
<form ref="inputForm" onSubmit={this.handleCreate.bind(this)}>
<TextField placeholder="Input.js"/>
<Button type="submit">Click me</Button>
{this.props.renderError()}
</form>
)
}
validateInput(taskName) {
if (!taskName) {
return '*No task entered';
} else if (this.props.taskList.find(todo => todo.name.toLowerCase() === taskName.toLowerCase())) {
return '*Task already exists'
} else {
return null;
}
}
handleCreate(event) {
event.preventDefault();
// Determine task entered
var newTask = this.refs.inputForm[0].value;
// Constant for error message returned
const validInput = this.validateInput(newTask);
// If error message produced - trigger error to be shown & end
if (newTask) {
this.props.createTask(newTask, validInput);
this.refs.inputForm.reset();
}
}
Update
I have since found that I can make this work if I move the renderError and throwError methods to input.js and also transfer across the state property error.
I want in my react-native app detect if user have a touch ID sensor or not and then if he have I want to display button with native element action instead of just normal action button. When I created if statement it shows me an error. I'm using 'create-react-native-app' with expo client SDK.
error message
Code
class LoginButton extends React.Component {
state = {
waiting: false,
};
render() {
let authFunction;
if (NativeModules.ExponentFingerprint.hasHardwareAsync() === true) {
if (Platform.OS === 'android') {
authFunction = async () => {
this.setState({waiting: true});
try {
let result = await NativeModules.ExponentFingerprint.authenticateAsync();
if (result.success) {
alert('Udało Ci się zalogować')
} else {
alert('Logowanie nie udane')
}
}
finally {
this.setState({waiting: false})
}
};
} else if (Platform.OS === 'ios') {
authFunction = async () => {
let result = await NativeModules.ExponentFingerprint.authenticateAsync(
'Zaloguj się przy użyciu TouchID'
);
if (result.success) {
alert('Udało Ci się zalogować')
} else {
alert('Logowanie nie udane')
}
};
}
return (
<Button onPress={authFunction} title="Zaloguj się przy użyciu odcisku palca" style={styles.buttonStyle}>
{this.state.waiting
? 'Czekam na TouchID...'
: 'Zalogowano przy użyciu TouchID'}
</Button>
)
} else if (NativeModules.ExponentFingerprint.hasHardwareAsync() === false) {
return (
<Button onPress={} title="Zaloguj się" style={styles.buttonStyle}/>
)
}
}
}
The issue is here
<Button
onPress={} <--- here
title="Zaloguj się"
style={styles.buttonStyle}
/>
React doesn't allow you to assign empty expressions to JSX attributes.
In order to fix it, just remove it
<Button title="Zaloguj się" style={styles.buttonStyle}/>
or assign it, for example, to authFunction which will be null.
<Button onPress={authFunction} title="Zaloguj się" style={styles.buttonStyle}/>
I'm building a component which proceeds according to the selections of the users. I have completed it successfully but facing some issues when trying to implement a back button to go back.
My code is like follows.
class ReportMainCat extends Component {
constructor(props) {
super(props);
this.state = {
postType: null,
}
this.changeType = this.changeType.bind(this);
this.report_next = this.report_next.bind(this);
};
report_next() {
if (this.state.postType == null) {
return <ReportFirst changeType={this.changeType}/>
}
else if (this.state.postType === 'sexual') {
return <ReportXContent changeType={this.changeType}/>
} else if (this.state.postType === 'selfharm') {
return <ReportThreatContent changeType={this.changeType}/>
}
}
changeType = (postType) => {
this.setState({postType})
this.setState({
showMainReportCats: false,
})
}
render() {
return (
<div className="top_of_overlay">
<div className="section_container text_align_center padding_10px">
<a className="">Report Category</a>
{this.report_next()}
</div>
</div>
)
}
}
I'm binding the postType value as follows.
class ReportXContent extends Component {
constructor(props) {
super(props);
this.state = {
postType: '',
}
};
textType(postType) {
this.props.changeType(postType);
}
render() {
return (
<div className="text_align_left">
<div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="nudity" onClick={this.textType.bind(this,'nudity')}/>
<a>Nudity or Pornography</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="minor" onClick={this.textType.bind(this,'minor')}/>
<a>Includes Minors</a>
</div>
</div>
<ReportButtons/>
</div>
)
}
}
My back button
<div>
<button className="float_right margin_left5px" onClick={this.props.back_report}>Back</button>
</div>
So basically what i'm trying to do is this.
Ex: If the user selects postType as sexual it will return the ReportXContent component. How can i return to the first page when the user clicks the back button.
Thanks.
You could implement the back button click handler like this in the ReportMainCat component:
handleBackClick() {
this.setState({ postType: null });
}
, and that would show the ReportFirst view again.
If you don't want the first view, but the last view, simply change your changeType implementation to save lastPostType to state like this:
changeType = (postType) => {
this.setState({
lastPostType: this.state.postType,
postType,
showMainReportCats: false,
});
}
Edit
If you want full history of changes - let's say if you want to implement a full back button history - you can simply rename lastPostType to postTypeHistory and implement it like a stack (like the browser history is):
changeType = (postType) => {
this.setState({
postTypeHistory: [...this.state.postTypeHistory, this.state.postType],
postType,
showMainReportCats: false,
});
}
handleBackClick() {
const { postTypeHistory } = this.state;
const postType = postTypeHistory.pop();
this.setState({
postType,
postTypeHistory,
});
}