How to change the url for signin page in next-auth? - javascript

In Next.js project I've implemented authentication with Next-Auth.
In index.js (as the Next-Auth documentation explains) I return a User only if there is a session
export default function Home({characters}) {
const {data: session} = useSession()
return (
<>
<Meta
description="Generated by create next app"
title={!session ? "Home - Login" : `Home - ${session.user.name}`}
/>
{session ? <User session={session} /> : <Guest/>}
</>
)
}
In the Guest component I have a Sign In button, and the onClick event points to the signIn method from "next-auth/react"
function Guest() {
return <Layout className="flex flex-col h-screen">
<div className="font-extrabold mb-4 text-3xl">GUEST USER</div>
<Button onClick={() => signIn()}>Sign In</Button>
</Layout>
}
as soon as I click that button I'm redirected to this pages/auth/signin.js page.
This is the page where I can login through EmailProvider or GoogleProvider
import { getCsrfToken, getProviders, signIn } from "next-auth/react"
import { Meta, Layout, Card, InputGroup, Button } from "../../components/ui";
export default function SignIn({ csrfToken, providers }) {
return (
<Layout>
<Meta title="Login"/>
<Card>
<form method="post" action="/api/auth/signin/email">
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<InputGroup
type="email"
htmlFor="email"
label="Email"
name="email"
/>
<Button type="submit">Sign in with Email</Button>
</form>
{Object.values(providers).map((provider) => {
if(provider.name === "Email") {
return
}
return (<div className="mt-3" key={provider.name}>
<Button onClick={() => signIn(provider.id)}>
Sign in with {provider.name}
</Button>
</div>)
})}
</Card>
</Layout>
)
}
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken(context)
const providers = await getProviders()
return {
props: { csrfToken, providers },
}
}
When I'm in this page the url is http://localhost:3000/auth/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000
I wanna know if it's possible to change that url to a more polite one like http://localhost:3000/login or something like this.
This page is already a custom login page as you can see in my [...nextauth].js
pages: {
signIn: '/auth/signin',
},
any suggestions? Thanks guys!

Yes it should work. Lets say you put this in your [...nextauth].js options
pages: {
signIn: '/login'
}
The signIn button will now redirect to /login.
Then you just have to put your login page under pages: pages/login.js.

Related

Handling action in Remix.run without POST

I read up on the Remix docs on action and most of information I can find on action is it uses the the form POST with button submit to trigger the action
export default function Game() {
const counter = useLoaderData();
return (
<>
<div>{counter}</div>
<div>
<Form method="post">
<button type="submit">click</button>
</Form>
</div>
</>
);
}
However, how would the action be triggered in regards to something else like... drag and drop components, where after dropping it should trigger the action post
useSubmit should do what you want.
An example from the docs
import { useSubmit, useTransition } from "remix";
export async function loader() {
await getUserPreferences();
}
export async function action({ request }) {
await updatePreferences(await request.formData());
return redirect("/prefs");
}
function UserPreferences() {
const submit = useSubmit();
const transition = useTransition();
function handleChange(event) {
submit(event.currentTarget, { replace: true });
}
return (
<Form method="post" onChange={handleChange}>
<label>
<input type="checkbox" name="darkMode" value="on" />{" "}
Dark Mode
</label>
{transition.state === "submitting" ? (
<p>Saving...</p>
) : null}
</Form>
);
}

how to change an UseStatus targeting an axios post reponse?

I'm back once more with something that has been breaking my head today.
so I'm making a contact form is almost done except for an animation I want to include that comes in three steps.
1- prompting the user to contact
2-making the waiting for the user-friendlier with a small loader
3-showing either everything went good and the form was sent or something went wrong
so my idea to accomplish this was to use three different icons/loaders and position all of them on top of each other and make them visible or hide them as necessary using UseState.
for now, I can hide the first icon(from step one) as soon as the submit button is clicked, but I haven't been able to make appear the loader or as the API completes the response the last icon
wondering if I should access it any other way?
import styled from "styled-components";
import { RiMailSendFill,FcApproval } from 'react-icons/all';
import '../../Style/styleComponents/Style.css';
import {sendMessage} from '../../Actions/msgAction';
import { useDispatch, useSelector } from 'react-redux';
import { useForm } from "../../Hook/useForm";
const ContactForm = () => {
const dispatch = useDispatch();
const initFormValues =
{
nombre : "nico ",
email : "sasjaja#asdsa ",
telefono : "asda ",
empresa : "dasd",
mensaje : "dasdas",
date: "s"
}
const[formValues, handleInputChange, reset] = useForm(initFormValues);
const{nombre, email, telefono, empresa, mensaje} = formValues
//loader submit buttons
const[mail, setMail]= useState(true);
const[loading, setLoading]= useState(false);
const[approved, setApproved]= useState(false);
const handleSendMsg = ( event ) =>
{
event.preventDefault();
dispatch( sendMessage( formValues ) )
.then( ( result ) =>
{
if( result )
{
console.log(initFormValues);
//closeModal();
console.log('dat')
};
setLoading(true);
});
reset();
}
const showE =()=> {
if (mail) {
setMail(false)
setLoading(true)
console.log("pressed submit");
}
}
const showL=()=>{
if (loading) {
setLoading(false)
console.log("sending email ");
}
}
return (
<Container>
<Left>
<h1>Tráenos tus desafíos</h1>
</Left>
<Right>
<form onSubmit={ handleSendMsg }>
<Label>
<Linput>
<Name>
<label htmlFor="name">Nombre:</label>
<input type="text" id="name" required name="nombre" value={ nombre } onChange={ handleInputChange } />
</Name>
<Tel>
<label htmlFor="name">Telefono:</label>
<input type="text" id="phone" required name="telefono" value={ telefono } onChange={ handleInputChange } />
</Tel>
<Company>
<label htmlFor="company">Empresa:</label>
<input type="text" id="company" name="empresa" value={ empresa} onChange={ handleInputChange }/>
</Company>
</Linput>
<Rinput>
<Email>
<label htmlFor="email">E-mail:</label>
<input type="email" id="email" required name="email" value={ email } onChange={ handleInputChange }/>
</Email>
<Msg>
<label htmlFor="message">Mensaje:</label>
<textarea id="message" required name="mensaje" rows="8" cols="50" value={ mensaje } className="bigger" onChange={ handleInputChange }/>
</Msg>
</Rinput>
</Label>
<Button>
<Send>
<button type="Submit" id ="submit" onClick={showE, showL}>Enviar</button>
</Send>
<Sent>
<RiMailSendFill id="mail" className={ mail ? 'svg': "svg active"}/>
<Loader className={ loading ? 'spin': "spin active"}>
<div class="spin"></div>
</Loader>
{/* <FcApproval id= "approve" className={ approved ? 'approve': "approve active"}/> */}
</Sent>
</Button>
</form>
</Right>
</Container>
);
};
export default ContactForm;
thanks, yall always saving me!
There are ways to make states work with each other easiest way is like this.
1-useStates for each of the
elements you want to be able to switch states to.
const [mail, setMail] = useState(true);
const [approved, setApproved] = useState(false);
2 Main function with smaller functions,
for each one to change accordingly.
function showL( ){
setMail(false);
if(!mail){
return setApproved(true);
}
}
//hide mailIcon / show approve
function showA( ){
setApproved(true);
if(approved){
return setMail(false);
}
}
add an event listener to the specific
the element you will work with to trigger the changes,
here you pass the two functions like this.
<Button>
<Send>
<button type="Submit" id="submit" onClick={() => {showL(); showA();}}>
Enviar
</button>
</Send>
TERNARY EXPRESION if true, render element and false null
<Sent>
<EMail>
{mail ? <RiMailSendFill/> : null}
</EMail>
<Loader>
{approved ? <FcApproval/>: null}
</Loader>
</Sent>
</Button>```

Navigate from one page to another on Button click

Hey I'm trying to make a Student Management System, where I made a Login page,Signup and a Dashboard page.
Now, while clicking a Button 'Fill Details' from my Dashboard page I need to navigate to another page input.js (Which is actually a separate project). I'll link my code below. Please help me to make it!
//input.js
import React, { Component } from 'react';
import web3 from './web3';
import ipfs from './ipfs';
import storehash from './storehash';
import { Button } from 'reactstrap';
class MyComponent extends Component {
state = {
ipfsHash:null,
buffer:'',
ethAddress:'',
transactionHash:'',
txReceipt: ''
};
//Take file input from user
captureFile =(event) => {event.stopPropagation()
event.preventDefault()
const file = event.target.files[0]
let reader = new window.FileReader()
reader.readAsArrayBuffer(file)
reader.onloadend = () => this.convertToBuffer(reader) };
//Convert the file to buffer to store on IPFS
convertToBuffer = async(reader) => {
//file is converted to a buffer for upload to IPFS
const buffer = await Buffer.from(reader.result);
//set this buffer-using es6 syntax
this.setState({buffer});};
//ES6 async
functiononClick = async () => {try{this.setState({blockNumber:"waiting.."});
this.setState({gasUsed:"waiting..."});
await web3.eth.getTransactionReceipt(this.state.transactionHash, (err, txReceipt)=>{
console.log(err,txReceipt);
this.setState({txReceipt});
});
}
catch(error){
console.log(error);
}}
onSubmit = async (event) => {
event.preventDefault();
//bring in user's metamask account address
const accounts = await web3.eth.getAccounts();
//obtain contract address from storehash.js
const ethAddress= await storehash.options.address;
this.setState({ethAddress});
//save document to IPFS,return its hash#, and set hash# to state
await ipfs.add(this.state.buffer, (err, ipfsHash) => {
console.log(err,ipfsHash);
//setState by setting ipfsHash to ipfsHash[0].hash
this.setState({ ipfsHash:ipfsHash[0].hash });
// call Ethereum contract method "sendHash" and .send IPFS hash to etheruem contract
//return the transaction hash from the ethereum contract
storehash.methods.sendhash(this.state.ipfsHash).send({
from: accounts[0]
},
(error, transactionHash) => {
console.log(transactionHash);
this.setState({transactionHash});
});
})
};
render() {
return (
<div className="App">
<header className="App-header">
<h1>EduDecentro</h1>
</header>
<hr/>
<grid>
<h5> Choose Transcript file </h5>
<form onSubmit={this.onSubmit}>
<input
type = "file"
onChange = {this.captureFile}
/>
<Button
bsStyle="primary"
type="submit">
Send it
</Button>
</form>
<tbody>
<tr>
<td>IPFS Hash</td>
<td> : </td>
<td>{this.state.ipfsHash1}</td>
</tr>
</tbody>
<h5> Choose Certificate-1 file </h5>
<form onSubmit={this.onSubmit}>
<input
type = "file"
onChange = {this.captureFile}
/>
<Button
bsStyle="primary"
type="submit">
Send it
</Button>
</form>
<tbody>
<tr>
<td>IPFS Hash</td>
<td> : </td>
<td>{this.state.ipfsHash2}</td>
</tr>
</tbody>
<h5> Choose Certificate-2 file </h5>
<form onSubmit={this.onSubmit}>
<input
type = "file"
onChange = {this.captureFile}
/>
<Button
bsStyle="primary"
type="submit">
Send it
</Button>
</form>
<h5> Choose Resume file </h5>
<form onSubmit={this.onSubmit}>
<input
type = "file"
onChange = {this.captureFile}
/>
<Button
bsStyle="primary"
type="submit">
Send it
</Button>
</form><hr/>
</grid>
</div>
);
}}
export default MyComponent;
import React from 'react';
import {Link } from "react-router-dom";
function Dashboard(props) {
// handle click event of logout button
const handleLogout = () => {
props.history.push('/Sign-in');
}
return (
<div>
Welcome User!<br /><br />
<Link to="/input"><button>
Fill Details
</button>
</Link>
<input type="button" onClick={handleLogout} value="Logout" />
</div>
);
}
export default Dashboard;
All you have to do is to add event listener for your Fill Details button, you don't need to wrap it into the Link component. Here is the example:
<button onClick={() => window.location.href = 'YOUR_LINK_TO_ANOTHER_APP' }>
Fill Details
</button>
<button onClick="window.location.href='Second_App_Page_Link';">Click Here
</button>

Nextjs page refresh always bring me to index.js

I don't understand why when I refresh a page in my nextjs app, I always get back to the index page.
I have an e-commerce SPA with a catalogue page in index.js and and the products are displayed through the dynamic [name].js page. If I navigate through the browser refresh or back button, the routing is a mess. I think I miss something in the good practices of nextjs.
index.js
import Head from "next/head";
import Catalogue from "../../components/Catalogue";
import { getProducts } from "../../utils/api";
const HomePage = ({ products }) => {
return (
<div>
<Head>
<title>Catalogue</title>
<meta
name="description"
content="Classe moyenne éditions publie des livres et multiples d'artistes, émergeants ou reconnus, en France et à l'international."
/>
<meta
name="keywords"
content="Edition d'artiste, Livres, prints, multiples, art books, librairie, concept store, Bookshop, Bookstore"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Head>
<Catalogue products={products} />
</div>
);
};
export async function getStaticProps() {
const products = await getProducts();
return { props: { products } };
}
export default HomePage;
[name].js
const ProductPage = ({ product }) => {
const router = useRouter();
if (router.isFallback) {
return <div>Loading products...</div>;
}
return (
<div className="wrapper">
<Head>
<title>
{product.name} {product.author}
</title>
</Head>
<div className="col right" key={product.id}>
<div className="colophon" key={product.id}>
<p>
{product.annee}
<br />
Format : {product.size} <br />
{product.pages} pages
<br />
{product.cover} <br />
Printing : {product.printing}
<br />
Paper : {product.paper}
<br />
{product.copies} exemplaires
<br />
{product.price} € + Shipping
<br />
<br />
</p>
<div className="colophon">
<p style= {{
width: '50%',
textAlign: 'end',
color: '#6223f5' }}>
The website is under maintenance. To order a book, please send us an email at <a href="mailto:hello#cmeditions.fr" style={{ textDecoration: 'underline' }}>Hello</a>
</p>
{product.status === true ? (
<button
className="snipcart-add-item buy-button "
variant="dark"
onMouseEnter={(e) => handleEnter(e)}
onMouseOut={(e) => handleExit(e)}
data-item-id={product.id}
data-item-price={product.price}
data-item-url={router.asPath}
data-item-image={getStrapiMedia(product.grid_pic.url)}
data-item-name={product.name}
data-item-description={product.author}
v-bind="customFields"
>
BUY ME!
</button>
) : (
<div className="text-center mr-10 mb-1">
<div
className="p-2 bg-indigo-800 items-center text-indigo-100 leading-none lg:rounded-full flex lg:inline-flex"
role="alert"
>
<span className="flex rounded-full bg-indigo-500 uppercase px-2 py-1 text-xs font-bold mr-3">
Coming soon...
</span>
<span className="font-semibold mr-2 text-left flex-auto">
This article is not available yet.
</span>
</div>
</div>
)}
</div>
</div>
</div>
</div >
);
};
export default ProductPage;
export async function getStaticProps({ params }) {
const product = await getProduct(params.name);
return { props: { product } };
}
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get products
const products = await getProducts();
// Get the paths we want to pre-render based on posts
const paths = products.map(
(product) => `/books/${product.name}`
);
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
I read this on the nextjs doc, could it be part of the solution?..
If the page uses an optional catch-all route, supply null, [],
undefined or false to render the root-most route. For example, if you
supply slug: false for pages/[[...slug]], Next.js will statically
generate the page /.
The format of paths on getStaticPaths is wrong.
Here is the documentation.
https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation
export async function getStaticPaths() {
// Call an external API endpoint to get products
const products = await getProducts();
// Get the paths we want to pre-render based on posts
const paths = products.map(
(product) => ({ params: { name: product.name } })
);
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
UPDATE
I've tried your code on local and CSB, and it seemed to work as expected.
You say it only happens in production environment, where are you deploying it?
There might be a problem in the deployment process, so you might want to contact your service provider.
Also, I'm wondering where you put the pages directory. nextjs requires the pages directory to be in the root or src directory.
https://nextjs.org/docs/advanced-features/src-directory
For Basic NGINX Solving:
location / {
try_files $uri $uri.html $uri/ /index.html;
}

How to deal with issue when user doesn't exist

When the user doesn't exist for this rather than redirecting to signup page I got this error, also I
tried something to change but unable to find how I can do it successfully
Menu.js
import React,{Fragment} from 'react';
import { Link ,withRouter} from 'react-router-dom'
import {signout,isAuthenticated} from '../auth'
import {itemTotal} from './CartHelper'
const isActive =(history,path)=>{
if(history.location.pathname === path){
return {color :'#ff9900'}
} else{
return {color:'#ffffff'}
}
}
/* here link component is similar to anchor tag in html */
const Menu =({history})=>{
//const {name,email,role} = isAuthenticated()
console.log('this is my history role ->',isAuthenticated());
return(
<div>
<ul className="nav nav-tabs bg-primary">
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/')} to="/">Home</Link>
</li>
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/shop')} to="/shop">Shop</Link>
</li>
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/cart')} to="/cart">Cart
<sup>
<small className="cart-badge">{itemTotal()}</small>
</sup>
</Link>
</li>
{isAuthenticated() && isAuthenticated().user.role === 0 && (
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/user/dashboard')} to="/user/dashboard">Dashboard</Link>
</li>
)}
{isAuthenticated() && isAuthenticated().user.role === 1 && (
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/admin/dashboard')} to="/admin/dashboard">Dashboard</Link>
</li>
)}
{!isAuthenticated() && (
<Fragment>
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/signin')}to="/signin">Signin</Link>
</li>
<li className="nav-list">
<Link className="nav-link" style={isActive (history,'/signup')} to="/signup">Signup</Link>
</li>
</Fragment>
)}
{isAuthenticated() && (
<li className="nav-list">
<span className="nav-link"
style={{cursor:'pointer',color:'#ffffff'}}
onClick={()=>signout(()=>{
history.push('/');
})
}>SignOut</span>
</li>
)}
</ul>
</div>
);
};
export default withRouter(Menu);
/*
*/
Signin.js
import React,{useState} from 'react';
import { Redirect } from 'react-router-dom'
import Layout from '../core/Layout';
import {signin,authenticate,isAuthenticated} from '../auth'
const Signin =()=>{
const [values,setValues] = useState({
email:'',
password:'',
error:'',
loading:false,
redirectToReferrer:false
})
// here we use redirectToReferrer because when it will be true user will be redirected to home page
// all the fields are streoed in value which is an object so we have to destructure to grab individual values
const {email,password,loading,error,redirectToReferrer} = values
// here we are destructing user and tring to divert user to admin if role === 1 (i.e admin) fir that we are destricting
const {user} = isAuthenticated();
// it is higer order function where one function return anither function
// also here name is like a parameter in which every name,email,apssword is copied to grab current valeu to update the sate
// here we use ...values to tell about our previous state values
const handleChange = name => event =>{
setValues({...values,error:false,[name]:event.target.value});
}
// now we have to send data to backend when user click on submit button so it can be done by this method
// we used preventDefault to stop auto reload of the page after an action is performed
const clickSubmit =(event)=>{
event.preventDefault();
setValues({...values,error:false,loading:true});
signin({email,password})
.then(data=>{
// console.log('my data in signin',data);
if(data.error){
console.log('my signing error after event fired',data.error);
setValues({...values,error:data.error,loading:false});
}
else{
authenticate(data,()=>{
setValues({...values,redirectToReferrer:true})
})
}
})
// we are passing all value as an object to user parameter
// signup({name:name,email:email,password:password})
// when key and values name are same so we can only write values
}
const signinForm =()=>(
<form>
<div className="form-group">
<label className="text-muted">Email</label>
<input onChange={handleChange('email')}
type ="email" className="form-control"
value={email}
/>
</div>
<div className="form-group">
<label className="text-muted">Password</label>
<input onChange={handleChange('password')}
type ="password" className="form-control" value={password}/>
</div>
<button onClick={clickSubmit} className="btn btn-primary">Submit</button>
</form>
);
const showError =()=>{
return <div className="alert alert-danger" style={{display:error?'':'none' }}>{error}</div>
}
const showLoading =()=>
loading && (<div className="alert alert-info"><h2>Loading...</h2></div>);
// here we are redirecting user based on hos role
// we have done authentication already so now if the user role is 1(admin then it will be redirected to admin dashboard else to user dashboard)
const redirectUser =()=>{
if(redirectToReferrer){
if(user && user.role === 1)
return <Redirect to="/admin/dashboard" />
}else{
return <Redirect to="/user/dashboard" />
}
}
if(isAuthenticated()){
return <Redirect to="/" />;
}
return(
<Layout
title="Signin"
description="Signin to Dashboard"
className="container col-md-8 offset-md-2">
{showLoading()}
{showError()}
{signinForm()}
{redirectUser}
</Layout>
)
}
export default Signin;
Signup.js
import React,{useState} from 'react';
import { Link } from 'react-router-dom'
import Layout from '../core/Layout';
import {signup} from '../auth'
const Signup =(user)=>{
const [values,setValues] = useState({
name:'',
email:'',
password:'',
error:'',
success:false
})
// all the fields are streoed in value which is an object so we have to destructure to grab individual values
const {name,email,password,success,error} = values
// it is higer order function where one function return anither function
// also here name is like a parameter in which every name,email,apssword is copied to grab current valeu to update the sate
// here we use ...values to tell about our previous state values
const handleChange = name => event =>{
setValues({...values,error:false,[name]:event.target.value});
}
// now we have to send data to backend when user click on submit button so it can be done by this method
// we used preventDefault to stop auto reload of the page after an action is performed
const clickSubmit =(event)=>{
event.preventDefault();
setValues({...values,error:false});
signup({name,email,password})
//console.log("this is my data ",data);
.then(data=>{
// console.log(data);
if(data.error){
setValues({...values,error:data.error,success:false});
}
else{
setValues({...values,name:'',email:'',password:'',error:'',success:true})
}
})
// we are passing all value as an object to user parameter
// signup({name:name,email:email,password:password})
// when key and values name are same so we can only write values
}
const signupForm =()=>(
<form>
<div className="form-group">
<label className="text-muted">Name</label>
<input onChange={handleChange('name')}
type ="text" className="form-control"
value={name}
/>
</div>
<div className="form-group">
<label className="text-muted">Email</label>
<input onChange={handleChange('email')}
type ="email" className="form-control"
value={email}
/>
</div>
<div className="form-group">
<label className="text-muted">Password</label>
<input onChange={handleChange('password')}
type ="password" className="form-control" value={password}/>
</div>
<button onClick={clickSubmit} className="btn btn-primary">Submit</button>
</form>
);
const showError =()=>{
return <div className="alert alert-danger" style={{display:error?'':'none' }}>{error}</div>
}
const showSuccess =()=>{
return <div className="alert alert-danger" style={{display:success?'':'none' }}>new account is created .Please <Link to="/signin">Signin</Link></div>
}
return(
<Layout
title="Signup"
description="Signup to node React E-commerce App"
className="container col-md-8 offset-md-2"
>
{showSuccess()}
{showError()}
{signupForm()}
</Layout>
)
}
export default Signup;
I have added all relevant file to know about the error also in which file I am getting error I have attached as well
Seems like the issue is that before redirecting the user you are trying to access a value that is undefined which is a no go and crashes the app.
What I try to do is initialize the user values (with strings or null values) and not assign them undefined values if the response from the server is bad.
if(data.error){
console.log('my signing error after event fired',data.error);
setValues({...values,error:data.error,loading:false});
}
This seems to be problematic.

Categories

Resources