supabase auth-helpers-nextjs package not working properly - authentication

I am using supabase auth helper package in my project. When the user enters the login details it should be redirected to the order page. I am using supabase auth condition in the order page. But when the user enters the login details it is not redirected to the order page.
code for the authentication in the order-page is given below :-
export const getServerSideProps = withPageAuth({ redirectTo: '/admin/login',
async getServerSideProps(ctx) {
// Access the user object
const { user, accessToken } = await getUser(ctx);
return { props: { email: user?.email } };
}
});
login page code is given below:-
async function handleSubmit(e) {
e.preventDefault();
const { user, error } = await supabase.auth.signIn({
email,
password
})
router.push('/orders')
}
return (
<Layout>
<div className="flex items-center justify-center h-screen">
<form onSubmit={handleSubmit}>
<p className="text-center text-[27px] text-white">Admin Login</p>
<div className="mt-4 text-white">
<p className="text-[14px]">Email</p>
<input type="text" className="bg-[#4A4949] rounded-md py-2 px-1 w-[300px]"
placeholder="Email Address"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mt-4 text-white">
<p className="text-[14px]">Password</p>
<input type="password" className="bg-[#4A4949] rounded-md py-2 px-1 w-[300px]"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button className="mt-8 bg-[#4A4949] text-white rounded w-[300px] py-2">Login</button>
</form>
</div>
</Layout >
)
}

You will need to wait for the user object to be defined before calling router.push:
import { useUser } from '#supabase/supabase-auth-helpers/react';
const { user } = useUser();
useEffect(() => {
if (user) {
router.push('/orders');
}
}, [user]);
async function handleSubmit(e) {
e.preventDefault();
const { user, error } = await supabase.auth.signIn({
email,
password
})
}

Related

v-model two way data binding not working in Nuxt 3 web app

I was using Nuxt 3 to create a login and signup page for a web app.
This is the code for the login page:
<template>
<form #submit.prevent="handleSubmit">
<h3>Login</h3>
<label for="email"> Email Address</label>
<input
type="email"
placeholder="The good-old email field"
name="email"
id="email"
v-model="email"
/>
<label for="password"> Password</label>
<input
type="password"
placeholder="Top secret...."
name="password"
id="password"
v-model="password"
/>
<div v-if="error.show" class="error">{{ error.message }}</div>
<button v-if="!isPending" :disabled="!email || !password">Log In</button>
<button v-if="isPending" disabled>Loading</button>
</form>
</template>
<script setup>
import { useGlobalStore } from "#/stores/global";
import { useAccountStore } from "#/stores/account";
const globalStore = useGlobalStore();
const accountStore = useAccountStore();
const error = computed(() => globalStore.error);
const isPending = ref(false);
const email = ref("");
const password = ref("");
const handleSubmit = async () => {
isPending.value = true;
console.log("The user is trying to log in");
await accountStore.login({
email: email.value,
password: password.value,
});
isPending.value = false;
};
</script>
The problem with this is even when email and password have been entered, the submit button still remains disabled. I have been able to figure out the reason as even when user enters the values for both of them, the values of the refs is not updating.
Can anyone help me figure out why?

Vue JS: Forms are not getting cleared when router.push() method is executed after the logout

I am using Flask as a backend and Vue JS as front end for my development. Vuex for state store.
In the logout() I am clearing the authentication token from localStorage via store.dispatch('/logout') and then using router.push('/login') to navigate to Login.vue. I find that the form details entered before are not getting cleared. When the logout() is performed it navigates to the Login.vue with flash message stating 'You have been logged out successfully'.
Below is the code snippet for the same:
logout() {
axios.get(`${this.host}:5000/logout`)
.then((res) => {
this.$store.dispatch('logout')
.then(() => {
this.$router.push('/login');
});
this.flashMessage.success({
message: res.data.msg,
time: 5000,
flashMessageStyle: {
backgroundColor: 'linear-gradient(#e66465, #9198e5)',
},
});
})
.catch((error) => {
this.flashMessage.error({
message: error.toString(),
time: 5000,
flashMessageStyle: {
backgroundColor: 'linear-gradient(#e66465, #9198e5)',
},
});
});
}
logout() is written in App.vue. Here router is an instance of vue-router.
To avoid the issue of form data not being cleared I have used router.go() instead of router.push() in the above code. But because of this implementation, the flash message is not getting displayed as the reload (because of router.go()) is overwriting the displaying of flash message which I don't want.
Please let me if it is possible to erase the form data after logout without getting into the trouble of not showing flash message.
Not sure how you have implemented Login.vue, but here is a Login.vue that I have implemented, and it works. One of the takeaways should be that my form model data values are initialized to empty strings.
<template>
<div id="login">
<form class="form-horizontal">
<div class="form-group">
<label for="username" class="col-md-offset-3 col-md-2 align-right">User Name</label>
<div class="col-md-3">
<input type="input" ref="username" class="form-control" id="username" v-model="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-md-offset-3 col-md-2 align-right">Password</label>
<div class="col-md-3">
<input type="password" class="form-control" id="password" v-model="password" v-on:keyup.enter="login">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-4">
<button type="button" class="btn btn-default"
v-on:click="login">Login</button>
<span class="error-msg" v-if="errorMsg">{{ errorMsg }}</span>
</div>
</div>
</form>
</div>
</template>
<script>
import { loginUrl, axios, processAjaxLoginError } from '../globalvars.js'
export default {
name: 'Login',
data() {
return {
username: '',
password: '',
errorMsg: ''
}
},
methods: {
login() {
axios.post(loginUrl, {
username: this.username,
password: this.password
})
.then(response => {
// Commit the token to the store
this.$store.commit('updateToken', { token: response.data.message });
// Clear error message
this.errorMsg = '';
// Redirect to customer index view
this.$router.push("/customers")
})
.catch(error => {
this.errorMsg = processAjaxLoginError(error);
})
}
},
computed: {
token() {
return this.$store.state.token;
}
},
mounted() {
this.$refs.username.focus();
}
}
</script>

#submit.prevent not working on vue md-input

when I click 'login button' even I don't fill data in md-input it still running,
I test my onSubmit() method by login with my user and it works!
I don't think I do thing wrong in the method so I guess that my form is incorrect.
here is my code :
my form
<form #submit.prevent="onSubmit">
<login-card header-color="green">
<h4 slot="title" class="title">CCRP Sign On</h4>
<p slot="description" class="description">IT solution by เจ้เก๋ IT-PM</p>
<md-field class="md-form-group" slot="inputs">
<md-icon>account_box</md-icon>
<label>ID...</label>
<md-input v-model.trim="userId" type="text"></md-input>
</md-field>
<md-field class="md-form-group" slot="inputs">
<md-icon>lock_outline</md-icon>
<label>Password...</label>
<md-input v-model.trim="password" type="password"></md-input>
</md-field>
<md-field class="md-form-group">
<md-icon>announcement</md-icon>
<label>Password...</label>
</md-field>
<md-button slot="footer" class="md-simple md-success md-lg" type="submit">Login</md-button>
</login-card>
</form>
in scrpit methods
async onSubmit() {
const authData = {
userId: this.userId,
password: this.password
};
await this.login(authData).then(() => {
if (this.isAuthenticated) {
this.$router.push("dashboard");
} else {
console.log("err");
}
});
},
can you help me solve this?
Your understanding of "prevent" key is quite incorrect.
All it does is not reload the form after submit action. However the submit action will be called irrespective of whether the prevent is used or not.
It is just preventing the default functionality of form getting reloaded after each submit.
On the other hand what you need to do is validate your form before actually submitting it.
Example :
//- Requires "vuelidate" - npm install vuelidate
<script>
import { validationMixin } from "vuelidate";
import { required, email } from "vuelidate/lib/validators";
export default {
name: "FormValidation",
mixins: [validationMixin],
data: () => ({
form: {
email: null,
password: null
},
userSaved: false,
sending: false,
lastUser: null
}),
validations: {
form: {
email: {
required,
email
},
password: {
required
}
}
},
methods: {
getValidationClass(fieldName) {
const field = this.$v.form[fieldName];
if (field) {
return {
"md-invalid": field.$invalid && field.$dirty
};
}
},
clearForm() {
this.$v.$reset();
this.form.email = null;
this.form.password = null;
},
saveUser() {
this.sending = true;
// Instead of this timeout, here you can call your API
window.setTimeout(() => {
this.lastUser = `${this.form.email}`;
this.userSaved = true;
this.sending = false;
this.clearForm();
}, 1500);
},
validateUser() {
this.$v.$touch();
if (!this.$v.$invalid) {
this.saveUser();
}
}
}
};
</script>
<style lang="scss" scoped>
.md-progress-bar {
position: absolute;
top: 0;
right: 0;
left: 0;
}
</style>
<template>
<div>
<!-- Calling validateUser insted of submit action -->
<form novalidate class="md-layout" #submit.prevent="validateUser">
<md-card class="md-layout-item md-size-50 md-small-size-100">
<!-- Title of the form -->
<md-card-header>
<div class="md-title">Login</div>
</md-card-header>
<!-- Inputs for the form -->
<md-card-content>
<md-field :class="getValidationClass('email')">
<label for="email">Email</label>
<md-input
type="email"
name="email"
id="email"
autocomplete="email"
v-model="form.email"
:disabled="sending"
/>
<span class="md-error" v-if="!$v.form.email.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
<md-field :class="getValidationClass('password')">
<label for="password">Password</label>
<md-input
type="password"
name="password"
id="password"
autocomplete="password"
v-model="form.password"
:disabled="sending"
/>
<!-- to show errors in case validation fails -->
<span class="md-error" v-if="!$v.form.password.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
</md-card-content>
<md-progress-bar md-mode="indeterminate" v-if="sending"/>
<md-card-actions>
<md-button type="submit" class="md-primary" :disabled="sending">Create user</md-button>
</md-card-actions>
</md-card>
<md-snackbar :md-active.sync="userSaved">The user {{ lastUser }} was saved with success!</md-snackbar>
</form>
</div>
</template>

How to prevent default, then submit default with VueJS

I am submitting a form using VueJS and i need to submit two actions on the final submit, one after the other.
Either one works when running just one.
What i am trying to do, is signup a user for firebase, wait, then submit the form with the same email/password as normal and signup that user with another sign in system.
The delimiters have been changed, so just over look that.
How to do this with Jquery
<form #submit="checkForm" #submit.prevent="register" action="#" method="post" novalidate="true" ref="form">
<h1 class="text-center">{{ 'customer.register.title' | t }}</h1>
<h1 v-if="authUser">
Is authed in
</h1>
<h1 v-else>
Not auth
</h1>
<div class="form-group">
<ul>
<li v-for="error in errors">
${ error }
</li>
</ul>
</div>
<p>
<label for="CustomerFirstName">${ firstName }</label>
<input id="name" v-model="name" type="name" name="customer[first_name]" autocomplete="name"
autocorrect="off" autocapitalize="off">
</p>
<p>
<label for="CustomerEmail">${ loginEmailName }</label>
<input id="email" v-model="email" type="email" name="customer[email]" autocomplete="email"
autocorrect="off" autocapitalize="off">
</p>
<p>
<label for="CustomerPassword">${ loginPasswordName }</label>
<input id="password" v-model="password" type="password" name="customer[password]">
</p>
<p>
<button type="submit" value="Create" class="btn btn-primary">Submit</button>
</p>
</form>
Then the JS that works on either one but not together.
const appTwo = new Vue({
delimiters: ["${", "}"],
el: "#create_customer_vue",
data: {
errors: ["1", "2", "3"],
email: '',
password: '',
name: null,
firstName: "First name",
loginEmailName: emailTitle,
loginPasswordName: passwordTitle,
title: registerTitle,
authUser: null
},
methods: {
register: function() {
firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
},
submitForm: function(){
this.$refs.form.submit()
},
created() {
firebase.auth().onAuthStateChanged(user => { this.authUser = user })
},
checkForm: function(e) {
if (this.email && this.password) {
return true;
}
this.errors = [];
if (!this.email) {
this.errors.push("Valid email required");
}
if (!this.password) {
this.errors.push("Valid password required");
}
e.preventDefault();
}
}
});
Just call the one submit handler then submit the form normally after the Firebase operation completes.
For example
<form #submit.prevent="register" ... >
methods: {
checkForm () {
if (this.email && this.password) {
return true;
}
this.errors = [];
if (!this.email) {
this.errors.push("Valid email required");
}
if (!this.password) {
this.errors.push("Valid password required");
}
return false
},
async register ($event) {
if (this.checkForm()) {
await firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
$event.target.submit() // or use this.$refs.form.submit() if you prefer
}
}
}

Vue not updating on property change

I've got an index component that contains this, in part:
<template>
<ul class="nav navbar-nav navbar-right">
<li v-if="state.user"><a #click.stop="do_logout" v-link="{ path: '/'}">Logout {{ state.user.display_name }}</a></li>
<li v-else v-link-active><a v-link="{ path: '/login' }">Login</a></li>
</ul>
<router-view></router-view>
<template>
<script>
import state from '../state';
import { logout } from '../actions';
export default {
data() {
return {
state
};
},
methods: {
do_logout() {
logout().then(() => this.$router.go('/'));
}
}
}
</script>
And I've got a login component that looks like this:
<template>
<form class="form-signin" #submit.prevent="do_login">
<input type="email" v-model="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<input type="password" v-model="password" id="inputPassword" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign In</button>
</form>
</template>
<script>
import { login } from '../../actions';
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
do_login() {
login(this.email, this.password).then(() => this.$router.go('/'));
}
}
}
</script>
My login and logout methods look like this:
import state from './state';
export const login = (email, pwd) => {
return fetch_post_json('/api/login', {
email,
pwd
}).then(j => state.user = j.user);
};
export const logout = () => _fetch('/api/logout', 'GET', null, false).then(() => state.user = null);
Logging out works fine; clicking the link changes the text and presents the "Login" link. Logging in succeeds in logging in, in the Javascript, but doesn't update the link. I'm forced to reload the page to get the page to render correctly. Why?