Im new to NextJS and try to implement a symple Login Page. When the user types in valid credentials than he gets redirected to another page, else he gets an error. I use an MongoDB Database to check with the credentials the user provided. I followed a Video from the MongoDB YouTube Channel and ChatGPT helped as well but now I`m stuck with the error that a module was not found: Module not found: Can't resolve 'dns'.
Has somebody an idea what Im doing wrong?
This is my Login Page, the functions get called when the user submits the form.
`
import Head from "next/head"
import styles from "../styles/Login.module.scss"
import { connectToDatabase } from '../util/mongodb';
export default function Login() {
async function checkCredentials(username, password) {
try {
//Connect to Database
const { db } = await connectToDatabase()
//get Data from Collection userdata
const collection = db.collection('userdata');
// Find the user with the specified username and password
const user = await collection.findOne({ username, password });
if (user) {
// User was found, credentials are valid
console.log('Valid credentials');
return true;
} else {
// User was not found, credentials are invalid
console.log('Invalid credentials');
return false;
}
} catch (error) {
console.error(error);
}
finally {
db.close();
}
}
function handleSubmit(event) {
event.preventDefault();
const username = event.target.elements.username.value;
const password = event.target.elements.password.value;
checkCredentials(username, password).then((result) => {
if (result) {
// Credentials are valid, log the user in
// ...
console.log("Login succesfull")
} else {
// Credentials are invalid, show an error message
// ...
console.log("Login not successfull")
}
});
}
return (
<div>
<Head>
<title>Login</title>
</Head>
<main className={styles.login}>
<section>
<img src="/images/Bild_SD.jpg" alt="Beispielbild Squaredance" />
</section>
<section>
<h1>Login</h1>
<p>Hier kannst du dich einloggen, um auf Interne Informationen zugreifen zu koennen. </p>
<form onSubmit={handleSubmit}>
<label htmlFor="username">Benutzername:</label>
<input type="text" id="username" name="username" />
<br />
<label htmlFor="password">Passwort:</label>
<input type="password" id="password" name="password" />
<br />
<button type="submit">Anmelden</button>
</form>
</section>
</main>
</div>
)
}
And here is the mongodb.js file, where I connect with the database. The code here is entirely from a YouTube Video from the official MongoDB Channel and I use it on another Page, so there should be nothing wrong there.
import { MongoClient } from "mongodb";
const { MONGODB_URI, MONGODB_DB } = process.env
if (!MONGODB_URI) {
throw new Error(
'Bitte bestimme die MONGODB_URI Variable in .env.local'
)
}
if (!MONGODB_DB) {
throw new Error(
'Bitte bestimme die MONGODB_DB Variable in .env.local'
)
}
/**
* Globall is used here to maintain a chached connection across hot reloads
* in development. This prevents connections growing exponentially
* during api Route usage.
*/
let cached = global.mongo
if (!cached) {
cached = global.mongo = { conn: null, promise: null }
}
export async function connectToDatabase() {
if (cached.conn) {
return cached.conn
}
if (!cached.promise) {
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
}
cached.promise = MongoClient.connect(MONGODB_URI, opts).then((client) => {
return {
client,
db: client.db(MONGODB_DB),
}
})
cached.conn = await cached.promise
return cached.conn
}
}
`
I looked a bit for myself and found out the error occurs probably because I connect to the Database in Frontend. I have a folder called api inside the pages folder. Should I put the checkCredentials function in a file there? Is the function then in the backend? How could this look like?
It would be great if somebody could help!
Related
I have a deno fresh boiler plate app with an added view called create. You land on a simple (but ugly) form view where you make a new user by typing in an email and key then pressing submit. This is the screen:
When I hit submit, the screen doesn't change but I get this in my web console.
What's even weirder is that when I check my database I have 6 entries of the same email and key. I have no idea why this is happening. I only pressed the button once:
The three files where pretty much all of the create page logic is happening is create.tsx, createUser.tsx and Creator.tsx
create.tsx:
import Layout from '../components/layouts.tsx';
import Creator from "../islands/Creator.tsx"
export default function User(props: PageProps) {
return (
<Layout>
<Creator />
</Layout>
)
}
createUser.tsx:
import { Handlers, PageProps } from "$fresh/server.ts";
import UserDb from "../../database.ts";
export const handler = {
POST: async (request, ctx) => {
const reqJsn = (await request.json());
const body = reqJsn;
const email = body.email;
const key = body.key;
console.log(email);
console.log(key);
if (!email || !key) {
ctx.status = 422;
ctx.body = { msg: "Incorrect user data. Email and key are required" };
return;
}
const userId = await UserDb.create({
email: email,
key: key,
created_at: new Date()
});
ctx.body = { msg: "User created", userId };
}
}
Creator.tsx:
// import { useState } from "preact/hooks";
import { useState, useEffect } from "preact/hooks";
import { Handlers, PageProps } from "$fresh/server.ts";
import UserDb from "../database.ts";
interface CreatorProps {
email: string,
key: string
}
export default function Creator(props: CreatorProps) {
async function handleSubmit(event) {
event.preventDefault();
const emailInput = event.target.email;
const ageInput = event.target.key;
console.log(emailInput.value);
console.log(ageInput.value);
const resp = await createNewUser(emailInput.value, ageInput.value);
return resp
};
async function createNewUser(email, key) {
const rawPosts = await fetch('http://localhost:8000/api/createUser', {
"method": "POST",
"headers": {
"content-type": "text/plain"
},
"body": JSON.stringify({
email: email,
key: key,
})
});
console.log(rawPosts);
}
return (
<div>
<h1 class="text rounded-lg p-4 my-8"> Search </h1>
<form method="post" onSubmit={async (e) => handleSubmit(e)}>
<input class="center rounded-lg p-4 my-8" id="email" name="email" />
<input class="center rounded-lg p-4 my-8" id="key" name="key" />
<br />
<button
class="px-5 py-2.5 text-sm font-medium bg-blue-600 rounded-md shadow disabled:(bg-gray-800 border border-blue-600 opacity-50 cursor-not-allowed)"
type="submit">Submit
</button>
</form>
<br />
{/* <ul>
{results.map((name) => <li key={name}>{name}</li>)}
</ul> */}
</div>
);
};
Again, I provided a minimal reproducible example. to run it you need a postgres instance running, create a .env file in the root directory of the project and add your postgres variables like this:
.env:
POSTGRES_USER=postgresuserone
POSTGRES_PASSWORD=pass2woR3d
POSTGRES_DB=postgresdbone
go to the root directory of the repo and type deno task start in your terminal and it works. Remember to navigate to localhost:8000/create, fill in the 2 field and press submit. You will now have 6 entries in your db.
I fixed it, the key was that the POST request action was never actually returning. I added:
const res = new Response(null, {
status: 302,
headers: new Headers({
location: 'localhost' + '../../../create',
}),
});
return res;
to the end of createUser.tsx (also renamed createUser.tsx to createUser.ts) and it only posted 1 new user to the database.
I'm trying to implement MongoDB, Next.JS and Passport.js, However upon starting my app and while trying to login, I get this 500 status error:
Cannot access 'getSession' before initialization
The preamble for all this is I am using a hook which calls/api/user to see if the req.user has been set by passport thus creating the 'user' below. And if one exists you get access to the other links/routes in the app.
This is the function declaration regarding the getSession function in the session.js file. So I suspect this is what is causing the circular dependencies issue, naturally.
import MongoStore from "connect-mongo";
import nextSession from 'next-session';
import { getMongoClient } from "./mongodb";
const mongoStore = MongoStore.create({
clientPromise: getMongoClient(),
stringify: false,
});
const getSession = nextSession({
store: mongoStore,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
maxAge: 2 * 7 * 24 * 60 * 60, // 2 weeks,
path: "/",
sameSite: "strict",
},
touchAfter: 1 * 7 * 24 * 60 * 60, // 1 week
});
export default function session(req, res, next) {
getSession(req, res);
next();
}
And this is the auth file with the passport file, passport initialization and session.
import passport from '../lib/passport'
import session from '../lib/session'
const auths = [session, passport.initialize(), passport.session()];
export default auths;
/component/Layout
export default function Layout({ children, showFooter = false }) {
const [user, { mutate }] = useCurrentUser();
async function handleLogout() {
axios
.get('/api/logout').then(() => {
mutate({ user: null })
Router.push('/',)
}).catch(err => console.log('err', err))
}
return <>
<div className="shadow bg-base-200 drawer h-screen">
<div className="flex-none hidden lg:block">
<ul className="menu horizontal">
{user
?
<>
<li>
<Link href="/profile">
<a>Profile</a>
</Link>
</li>
<li>
<Link href="/dashboard">
<a>Dashboard</a>
</Link>
</li>
<li>
<a role="button" onClick={handleLogout}>
Logout
</a>
</li>
<li className="avatar">
<div className="rounded-full w-10 h-10 m-1">
<img src="https://i.pravatar.cc/500?img=32" />
</div>
</li></>
:
<>
<li>
<Link href="/login">
<a>Login</a>
</Link>
</li>
<li>
<Link href="/registration">
<a>Register</a>
</Link>
</li>
</>
}
</ul>
</div>
</div>
</>;
}
This is the hook itself:
import useSWR from 'swr';
export const fetcher = (url) => {
try {
return fetch(url).then((res) => {
console.log('res', res)
return res.json()
})
} catch (error) {
console.log('error', error)
}
}
export function useCurrentUser() {
const { data, mutate } = useSWR('/api/user', fetcher);
const user = data?.user;
return [user, { mutate }];
}
export function useUser(id) {
const { data } = useSWR(`/api/users/${id}`, fetcher, {
revalidateOnFocus: false,
});
return data?.user;
}
And this is the api: /api/user:
import nextConnect from 'next-connect'
import auth from '/middleware/auth'
const handler = nextConnect()
handler
.use(auth)
.get((req, res) => {
console.log("req.user ", req.user);
if (req.user) {
res.json({ user: req.user })
} else {
res.json({ user: null })
}
})
export default handler
Also this is my repo
And this is a link to the app on vercel.
I'm learning react and nextjs, the page works perfectly without the integration of a UI library, since i installed react suite my page with the login form doesn't work anymore, it returns me an error: TypeError: Cannot read property 'value 'of undefined
My code is:
import React, { useState } from "react"
import { setCookie, parseCookies } from "nookies"
import { useRouter } from "next/router"
import { Form, FormGroup, FormControl, ControlLabel, HelpBlock, Button, Input } from 'rsuite';
const Login = () => {
// set initial const
const router = useRouter()
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// handle event submit
const handleSubmit = async (e) => {
e.preventDefault();
// fetch user
const response = await fetch( process.env.urlHeadless + '/api/cockpit/authUser', {
method: "post",
headers: {
"Content-Type": "application/json",
'Cockpit-Token': process.env.loginKey,
},
body: JSON.stringify({
user: username,
password: password
})
})
// if user exists
if (response.ok) {
const loggedUser = await response.json()
// set cookie with api_key
setCookie("", "tokenId", loggedUser._id, {
maxAge: 30 * 24 * 60 * 60,
path: "/"
})
// redirect to dashboard
return (router.push("/dashboard"))
} else if (response.status === 412) {
alert('compila il form')
} else if (response.status === 401) {
alert('credenziali di accesso errate')
}
}
return (
<>
<Form>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<FormControl type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
<HelpBlock>Required</HelpBlock>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<FormControl type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
</FormGroup>
<FormGroup>
<Button appearance="primary" onClick={handleSubmit}>Submit</Button>
</FormGroup>
</Form>
</>
)
}
// async function
export async function getServerSideProps(context) {
// get cookie value
const cookies = parseCookies(context).token;
// if cookie has value
if (cookies) {
return {
// redirect to dashboard
redirect: {
destination: '/dashboard',
permanent: false,
},
}
}
return { props: {} };
}
export default Login;
I also tried using useRef instead of useState, but it didn't work ... where am I wrong? thank you in advance
Looks like rsuite components might have a different onChange implementation, as described in their docs
onChange (formValue:Object, event:Object) => void Callback fired when data changing
If you want the event, try changing the onChange callback in your code to take the second parameter:
<FormControl
...
onChange={(value, e) => setUsername(e.target.value)}
/>
I am working on a frontend application with Angular 5 and using rest api from backend. Actually, I am developing admin platforme and I have two web pages, one for displaying list of customers and each one has list of feedbacks and one other get you to specific feedback details.
The feedback details display these properties: account, feedback itself and the loyalty point if existed.
There is two ways, if a feedback has its loyalty point then the feedback details will show details with loyalty point value else it will show empty input for this property and if the input is successful, it will return to main list with changed value of status of feedback from false to true.
I am using rest api and for this operation I successfully tested the API:
API: PATCH /Feedbacks/:id
Here is my code:
account.service.ts:
#Injectable()
export class AccountService {
constructor(private http: Http) {}
headers: Headers = new Headers({ 'Content-Type': 'application/json' });
options: RequestOptionsArgs = new RequestOptions({headers: this.headers});
// API: PATCH /Feedbacks/:id
updateStatus(feedback: Feedback) {
let url = "http://localhost:3000/api/Feedbacks";
return this.http.patch(url + feedback.id, feedback, this.options)
.map(res => res.json())
.catch(err => {
return Observable.throw(err)
});
}
}
component.html:
<form *ngIf="feedback">
<div class="form-group">
<label for="InputAccount">Account</label>
<input type="text" class="form-control" id="InputAccount" value="{{feedback.account}}">
</div>
<div class="form-group">
<label for="InputFeedback">Feedback</label>
<textarea class="form-control" id="InputFeedback" rows="3" placeholder="Feedback">{{feedback.feedback}}</textarea>
</div>
<div class="form-group">
<label for="InputLP">LP</label>
<input type="text" class="form-control" id="InputLP" placeholder="LP" [(ngModel)]="account.lp" name="lp">
</div>
<div class="form-group" *ngIf="!edited; else showBack">
<button (click)="addLP(account,feedback)" class="btn btn-primary" data-dismiss="alert">Add LP</button>
</div>
</form>
component.ts:
#Component({
selector: 'app-add',
templateUrl: './add.component.html',
styleUrls: ['./add.component.scss']
})
export class AddComponent implements OnInit {
feedback = {};
account = {};
edited:boolean;
status: boolean;
constructor(private route: ActivatedRoute, private accountService: AccountService,
private router: Router) { }
ngOnInit() {
this.route.paramMap
.switchMap((params: ParamMap) =>
this.accountService.getFeedback(+params.get('idF')))
.subscribe(feedback => this.feedback = feedback);
this.route.paramMap
.switchMap((params: ParamMap) =>
this.accountService.getAccount(params.get('idC')))
.subscribe(account => this.account = account);
}
addLP(account:Account,feedback:Feedback){
this.accountService.updateAccount(account)
.subscribe(res => {
this.account = res as Account;
console.log(res);
if (account.lp == null){
console.log(res);
this.edited = false;
} else {
this.edited = true;
this.accountService.updateStatus(feedback)
.subscribe(res => {
feedback.status = true;
this.feedback = res as Feedback;
console.log(this.feedback);
}, err => {
console.log(err);
});
}
}, err => {
console.log(err);
});
}
back() {
this.router.navigate(['list']);
}
}
the feedback property:
public id?: number,
public feedback?: string,
public account?: string,
public status?: boolean
Where the account is a foreign key to account table:
public account?: string,
public lp?: string
When I try to switch status value automatically from false to true, the console log will return:
PATCH http://localhost:3000/api/Feedbacks2 404 (Not Found)
Any help would be appreciated! I really need to solve it. Thanks
I modified the code in account.service.ts:
updateStatus(feedback: Feedback) {
let url = "http://localhost:3000/api/Feedbacks";
var body = {status: true};
return this.http.patch(url +"/"+ feedback.id, body, this.options)
.map(res => res.json())
.catch(err => {
return Observable.throw(err)
});
}
And it worked !
I am following a ReactJS tutorial to set up a login form. Semantic ui is used and imported. The email and password are passed into the value attribute inside the form. When this happens, I cannot type anything into the form. As soon as I remove it, I can type information in but I assume it won't get passed into anywhere.
Cannot seem to find this issues anywhere else. Has anyone experienced this issue before?
import React from 'react';
import PropTypes from 'prop-types';
import { Form, Button } from 'semantic-ui-react';
import Validator from 'validator';
import InlineError from '../messages/InlineError';
class LoginForm extends React.Component {
state = {
data: {
email: "",
password: ""
},
loading: false,
errors: {}
};
//... is called spread
onChange = e => this.setState({
data: {...this.state.data, [e.target.name]: e.target.value }
});
//() means function takes no params
onSubmit = () => {
const errors = this.validate(this.state.data);
this.setState({errors}); //if there are errors, display them
if(Object.keys(errors).length === 0){
this.props.submit(this.state.data);
}
};
validate = (data) => {
const errors = {};
if(!Validator.isEmail(data.email))
errors.email = "Invalid email";
if(!data.password)
errors.password = "Can't be blank";
return errors;
};
render() {
const { data, errors } = this.state; // import variables into html
return (
<div>
<Form onSubmit={ this.onSubmit }>
<Form.Field error={!!errors.email}>
<label htmlFor="email">Email</label>
<input type="email"
id="email"
placeholder="example#abc.com"
value={ data.email }
onChange={ this.onChange }/>
{errors.email && <InlineError text={errors.email}/>}
</Form.Field>
<Form.Field error={!!errors.email}>
<label htmlFor="password">Password</label>
<input type="password"
id="password"
value={ data.password }
onChange={this.onChange}/>
{errors.password && <InlineError text={errors.password}/>}
</Form.Field>
<Button primary>Login</Button>
</Form>
</div>
);
}
}
LoginForm.propTypes = {
submit: PropTypes.func.isRequired
};
export default LoginForm;
tutorial: https://www.youtube.com/watch?v=NO2DaxhoWHk&t=879s
onChange = e => this.setState({
data: {...this.state.data, [e.target.name]: e.target.value }
});
This function is setting the state to a variable that shares the name of your input field. Hence e.target.name. But your input fields do not have a name attribute.
You can fix that with:
import React from 'react';
import PropTypes from 'prop-types';
import { Form, Button } from 'semantic-ui-react';
import Validator from 'validator';
import InlineError from '../messages/InlineError';
class LoginForm extends React.Component {
state = {
data: {
email: "",
password: ""
},
loading: false,
errors: {}
};
//... is called spread
onChange = e => this.setState({
data: {...this.state.data, [e.target.name]: e.target.value }
});
//() means function takes no params
onSubmit = () => {
const errors = this.validate(this.state.data);
this.setState({errors}); //if there are errors, display them
if(Object.keys(errors).length === 0){
this.props.submit(this.state.data);
}
};
validate = (data) => {
const errors = {};
if(!Validator.isEmail(data.email))
errors.email = "Invalid email";
if(!data.password)
errors.password = "Can't be blank";
return errors;
};
render() {
const { data, errors } = this.state; // import variables into html
return (
<div>
<Form onSubmit={ this.onSubmit }>
<Form.Field error={!!errors.email}>
<label htmlFor="email">Email</label>
<input type="email"
id="email"
name="email"
placeholder="example#abc.com"
value={ data.email }
onChange={ this.onChange }/>
{errors.email && <InlineError text={errors.email}/>}
</Form.Field>
<Form.Field error={!!errors.email}>
<label htmlFor="password">Password</label>
<input type="password"
id="password"
name="password"
value={ data.password }
onChange={this.onChange}/>
{errors.password && <InlineError text={errors.password}/>}
</Form.Field>
<Button primary>Login</Button>
</Form>
</div>
);
}
}
LoginForm.propTypes = {
submit: PropTypes.func.isRequired
};
export default LoginForm;