React router: Redirected on left-click but not on right-click - react-hooks

The problem:
Clicking a link to /username from /profile, redirects to /profile. This is only wanted if /currentUser.username. When the same link is clicked from other endpoints, it does not redirect. Also, if right-clicking --> open in new tab, it does not redirect.
What is causing the redirect and how do I avoid it?
Explanation
/profile shows the currently logged in user's profile page and /username shows another user's profile. If the currently logged in user goes to /currentUser.username they will be redirected to /profile.
Both endpoints render the same <Profile /> component. The content depends on whether the current user is visitor or not.
React context API manages state for <Profile />.
Code
The context provider checks if current user is a visitor:
export const ProfileProvider = ({ children }) => {
const [visitor, setVisitor] = useState(null);
const { username } = useParams();
const user = useSelector(selectCurrentUser); // currentUser
console.log('username: ', username) // prints username in initial render.
console.log(visitor); // prints false in initial render. Why?
useEffect(() => {
console.log('useEffect visitor: ', visitor) // prints false in initial render.
setVisitor(username ? username !== user.username : false);
}, [username, user.username]);
// Omit code for brevity
};
In <Profile /> I Have:
export const Profile = () => {
const navigate = useNavigate();
const {username, visitor} = useContext(ProfileContext);
// navigate to ('/profile') if user is looking at their own profile.
useEffect(() => {
if (visitor === false && username) {
navigate('/profile');
}
}, [visitor, navigate, username]);
// Omit code for brevity
}
And the link is in the header, which can be clicked from any endpoint:
<Link to={`/${user.username}`}></Link>
Where user !== currentUser.
Log statements:
ProfileProvider.jsx:19 username: qqqqqq0.6122198309846412
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:38 useEffect visitor: false
ProfileProvider.jsx:19 username: qqqqqq0.6122198309846412
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: true
ProfileProvider.jsx:38 useEffect visitor: true
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: true
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
ProfileProvider.jsx:19 username: undefined
ProfileProvider.jsx:20 visitor: false
Edit: Rephrased the problem.

There are separate routes each rendering their own ProfileProvider, so navigating between them each has their own state and logic independent of the other.
If what you really want is for the Profile component to compare the current authenticated user's username against the username route path parameter then move the const { username } = useParams() logic from the ProfileProvider component into the Profile component.
Example:
App - Move the ProfileProvider to wrap the routes.
<ProfileProvider>
<Routes>
<Route path=":username/*" element={<Profile />} />
<Route path="profile/*" element={<Profile />} />
</Routes>
</ProfileProvider>
Profile
export const Profile = () => {
const navigate = useNavigate();
const { username: currentUser } = useContext(ProfileContext);
const { username } = useParams();
useEffect(() => {
if (currentUser === username) {
navigate("/profile", { replace: true });
}
}, [currentUser, navigate, username]);
const text = username ? username : "Current User";
return (
<>
<header>
<h1>Profile of:</h1>
</header>
<main>
<p>{text}</p>
</main>
</>
);
};

Related

formik initial checkbox value not disabling submit button

In my form, I have a checkbox for captcha that needs toggled for the form to be valid, however on load, the form still shows as valid. I can check the box to enable the form, and then uncheck it again, and THEN the form shows as properly disabled.
I am using the HOC withFormik implementation. I have tried using setTouched & setFieldTouched on the checkbox, and even setting this.props.touched.captcha = true. I have also tried passing isInitialValid: false to withFormik.
Another thing I tried is passing mapPropsToTouched, but that method doesn't get called.
I am using formik v 1.5.8
How can I make the form initially disabled until I engage the checkbox?
export class LoginForm extends React.Component {
render() {
const {
initialValues,
initialTouched,
validationSchema,
onSubmit,
children
} = this.props;
return (
<div>
<Formik
initialValues={initialValues}
initialTouched={initialTouched}
validationSchema={validationSchema}
onSubmit={onSubmit}
render={(formikProps) => {
return (
<Form>
{React.Children.map(children, (child, index) => {
return (
<div className='Form__row'>
{React.cloneElement(child, { index })}
</div>
);
})}
</Form>
);
}}
/>
</div>
);
}
}
const mapDispatchToProps = {};
export function mapStateToProps(state) {
return {};
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withFormik({
// isInitialValid: false,
// mapPropsToTouched: (props) => {
// console.log('🚀 ~ file: LoginForm.jsx ~ line 257 ~ props', props);
// },
mapPropsToValues: (props) => {
return {
username: props.previousUsername ? props.previousUsername : '',
password: '',
rememberMe: true,
captcha: false
};
}
})
)(LoginForm);

How to fix 405 (Method Not Allowed) using vue js and laravel

Hi developers I have currently problem this project is an old project where the developer created. right now, we need to adjust some of there functionality. Right now I already extract the files to my localhost folder and now work without error on run watch and artisan serve. So the problem here is on login on the console it shows that http://localhost:8000/project/oauth/token 405 (Method Not Allowed), I really don't understand why this shows on the localhost however on the live server it works.
This project created using Vue Js and Laravel for the backend.
I will show you guys the authentication function.
Login Function:
authenticate(){
this.login_alert = false
this.$validator.validateAll().then((result)=>{
if(result){
const self = this;
const authUser = {}
try{
const data = {
username: this.email,
password: this.password,
remember: this.remember_me,
client_id: '2',
client_secret: 'secret',
grant_type : 'password',
scope : ''
}
this.$store.dispatch('AUTH_REQUEST',data)
.then(response=>{
console.log(data);
authUser.access_token = response.access_token
authUser.refresh_token = response.refresh_token
authUser.expires_in = response.expires_in
window.localStorage.setItem('project_token',JSON.stringify(authUser))
/*LOGIN*/
this.login_alert = false
this.loading = false
window.location.reload()
})
.catch(error=>{
this.login_alert = true
window.localStorage.removeItem('project_token')
this.loading = false
})
}catch(err){
console.log(err);
}
}
})
}
For the AUTH REQUEST:
AUTH_REQUEST:({commit,dispatch},obj)=>{
return new Promise((resolve,reject) => {
axios({
url: '/project/oauth/token',
data: obj,
method:'post',
config:'JSON'
})
.then(response=>{
if(response.status == 200){
resolve(response.data);
}
})
.catch(error=>{
reject(error);
localStorage.removeItem('project_token');
commit('AUTH_ERROR',error);
})
})
},
Hope some one experience this. thanks.
In my case, the compilation of the route should be specified properly, for example
async purchaseDelete(purchase) {
Csrf.getCookie();
return Api.delete('/api/purchase_settings/${purchase.id}');
},
the single tick on the axios delete method didnt represent correctly
async purchaseDelete(purchase) {
Csrf.getCookie();
return Api.delete(`/api/purchase_settings/${purchase.id}`);
}
When changed to back ticks, it responded with the correct result

How to fix localhost:8000 prompt login after i submit the authentication using Vue Js And Laravel

I have problem regarding on my authentication after I login there is prompt localhost:8000 login or Sign in, this is the first time I encounter this, I don't know what this called, i don't find any reference for this. currently I am using laravel for the backend and vue js for front end. so this project created by old developer. so now I need to revise some module on there project, however i Login on the system in shows this prompt. note that this project is currently working and there is no error and prompt login when I login.
Here is prompt sign shown after I login.
Configuration:
Laravel Passport
Vuex For State Management
Vue Js
METHOD:
methods:{
authenticate(){
this.login_alert = false
this.$validator.validateAll().then((result)=>{
if(result){
const self = this;
const authUser = {}
try{
const data = {
username: this.email,
password: this.password,
remember: this.remember_me,
client_id: '2',
client_secret: 'just secret only',
grant_type : 'password',
scope : ''
}
this.$store.dispatch('AUTH_REQUEST',data)
.then(response=>{
authUser.access_token = response.access_token
authUser.refresh_token = response.refresh_token
authUser.expires_in = response.expires_in
window.localStorage.setItem('project_token',JSON.stringify(authUser))
/*LOGIN*/
this.login_alert = false
this.loading = false
window.location.reload()
})
.catch(error=>{
this.login_alert = true
window.localStorage.removeItem('project_token')
this.loading = false
})
}catch(err){
console.log(err);
}
}
})
}
},
AUTH REQUEST:
AUTH_REQUEST:({commit,dispatch},obj)=>{
return new Promise((resolve,reject) => {
axios({
url: '/oauth/token',
data: obj,
method:'post',
config:'JSON'
})
.then(response=>{
if(response.status == 200){
resolve(response.data);
}
})
.catch(error=>{
reject(error);
localStorage.removeItem('project_token');
commit('AUTH_ERROR',error);
})
})
},
Hope someone can help me to solve this problem.
Thank you.

passing component state to redux-form onSubmit

novice user of redux-form here. I have a signin modal that has 2 different operations: login and register. The role (stored in component state) will be login by default, and the user will be able to click a button to change it to register.
Where I'm stuck, is that I want to pass that piece of state to the onSubmit() function, so that I can dispatch the correct actions depending on if the user is trying to login or register.
My thinking was that I could pass down this piece of state called signInType as a prop to the function. Of course, it is not working as I would have expected. I can pass in a prop via the reduxForm HOC, but from that function I cannot access the component's state.
Here are the relevant parts of my component to help understand what my end goal is here:
const [signInType, setSignInType] = useState('login')
const onSubmit = (data, dispatch, props) => {
console.log('props: ', props);
if (props.signInType === 'login') {
return (
api.post('/Login', data)
.then(json => {
const response = JSON.parse(json.d)
if (!response.userid) {
console.error(response.message)
dispatch(emailLoginFailure(response.message))
return response.message
}
LogRocket.identify(response.userid, {
email: data.email,
})
dispatch(emailLoginSuccess(response))
})
.catch(err => {
console.error(err)
dispatch(emailLoginFailure(err))
})
)
} else if (props.signInType === 'register') {
return (
api.post('/RegisterByEmail', {
email: data.email,
password: data.password,
utm_source: "Development",
utm_medium: "email",
utm_campaign: "Campaign Test",
utm_term: "N/A",
utm_content: "123",
utm_date: "2019-02-11 12:25:36"
})
.then(json => {
const response = JSON.parse(json.d)
if (!response.userid) {
console.error(response.message)
dispatch(emailRegisterFailure(response.message))
return response.message
}
// LogRocket.identify(response.userid, {
// email: data.email,
// })
dispatch(emailRegisterSuccess(response))
})
.catch(err => {
console.error("Unable to register email:", err)
})
)
} else {
console.error("error: No signin type?")
}
}
Thanks for the help :)
Such login/register flow I prefer handling it with different components, in order to respect and follow SRP.
Also, I'm not sure how do you organize your components, but here's how I deal with such a scenario:
Your Modal:
* It will be responsible only for rendering Login or Register forms.
const Modal = () => {
const [signInType, ] = useState('login')
const isLogin = signInType === 'login'
return <>
{ isLogin ? <LoginForm /> : <RegisterForm /> }
<button onClick={() => setSignInType(isLogin ? 'register' : 'login')}>
{ isLogin ? 'Sign up' : 'Sign in' }
</button>
</>
}
LoginForm:
* Now you can pass your login action to onSubmit prop. Login will be your presentation component, while LoginForm decorates Login with reduxForm HOC.
export default reduxForm({
form: 'login',
onSubmit: data => {}
})(Login)
RegisterForm:
* Here we follow the same idea as LoginForm.
export default reduxForm({
form: 'register',
onSubmit: data => {}
})(Register)

In Angular 2, how to setup an asynchronous validator when using template-driven forms?

I've defined a directive for my asynchronous validator:
#Directive({
selector: '[validatorUsername]',
providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: ValidatorUsernameDirective, multi: true }]
})
export class ValidatorUsernameDirective implements Validator {
validate(c: AbstractControl) {
let username = c.value;
return new Promise(resolve => {
setTimeout(() => {
if( username === "nemo" ) {
resolve({
'taken': true
})
} else {
resolve(null);
}
}, 1000);
});
}
}
In template, I've applied it as follows:
<input type="text" [(ngModel)]="username" name="username" required validatorUsername>
Then I've applied validation messages from code (not from template), as described in Angular's Cookbook, chapter Form Validation:
export class App implements OnInit {
#ViewChild('myForm') myForm: NgForm;
name: string;
username: string;
ngOnInit() {
this.myForm.valueChanges.subscribe(_ => this.onValueChanged());
}
onValueChanged() {
// fill 'formErrors' object
}
formErrors = {
'name': '',
'username': ''
};
}
The problem is that onValueChanged() doesn't get called when validator's promise is resolved, thus the validation message for username does not appear. It appears though if you try to edit the name field. What should I do to trigger the update on UI?
Here is the plunker for my code.
References:
Angular2 template driven async validator
https://angular.io/docs/ts/latest/cookbook/form-validation.html
https://netbasal.com/angular-2-forms-create-async-validator-directive-dd3fd026cb45
You can subscribe to statusChanges event that is fired after calling async validator
this.myForm.statusChanges.subscribe(_=> this.onValueChanged());
Modified Plunker

Resources