Next.js Discord

Discord Forum

Present message in a modal

Answered
D34dlyK1ss posted this in #help-forum
Open in Discord
As of now I wanted to present a message/error to the user if the login credentials don't match the database. I got every piece of code sorted out aside from the actual presentation. I wanted to know how do I make the message come from the login function into the page without messing up client-side and server-side, in which I have been losing quite a lot of time enough to make me quit for a while XD
Answered by D34dlyK1ss
View full answer

89 Replies

@D34dlyK1ss As of now I wanted to present a message/error to the user if the login credentials don't match the database. I got every piece of code sorted out aside from the actual presentation. I wanted to know how do I make the message come from the login function into the page without messing up client-side and server-side, in which I have been losing quite a lot of time enough to make me quit for a while XD
them form for entering the credentials is normally handled clientside. Then you submit a function and this function returns a value. This value can be read by your client (the form is handled clientside) and like that you can update a clientside state to display a modal
I'll be posting what I have atm
Login page
import "@/app/globals.css";
import { login } from "@/utils/userController";

export default async function LoginPage() {

    return (
        <div>
            <div id="divLogin" className="row justify-content-md">
                <h1>Login</h1>
                <form action={login}>
                    <div id="loginUser" className="col-12">
                        <label htmlFor="inputUsername">Username / Email</label>
                        <input id="inputUsername" name="username" type="text" placeholder="Username / Email" autoComplete="on" required />
                        <span id="spanErrorUsername" className="spanError"></span>
                    </div>
                    <div id="loginPass" className="col-12">
                        <label htmlFor="inputPassword">Password</label>
                        <input id="inputPassword" name="password" type="password" placeholder="Password" autoComplete="on" required />
                        <span id="spanErrorPassword" className="spanError"></span>
                    </div>
                    <div id="loginButton" className="col-12">
                        <input className="btn btn-primary" type="submit" value="Login" />
                    </div>
                </form>
                <div className="col-12">
                    <a href="/recover">Forgot password?</a>
                    <br />
                    <a href="/register">I want to register</a>
                </div>
            </div>
        </div>
    );
}
Notification Modal
import "@/app/globals.css";
import React from "react";

export default function NotificationModal(message: any) {
    return (
        <div className="modal fade show" id="notificationModal" tabIndex={-1} data-bs-backdrop="static" data-bs-keyboard="false" aria-modal="true" role="dialog" style={{ display: "block" }}>
            <div className="modal-dialog modal-dialog-centered">
                <div className="modal-content">
                    <div id="notificationModalBody" className="modal-body">
                        {message}
                    </div>
                    <div className="modal-footer border-0">
                        <button id="notificationModalButton" type="button" className="btn btn-primary" data-bs-dismiss="modal">
                            OK
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
}
Login function
"use server"

export async function login(formData: FormData): Promise<any> {
    try {
        const [rows] = await db.execute<UserRow[]>(
            `SELECT id, username, email 
             FROM user 
             WHERE (username = ? OR email = SHA2(?, 256)) 
             AND password = SHA2(?, 256)`,
            [formData.get("username"), formData.get("username"), formData.get("password")]
        );

        if (!rows.length) return { message: "Username/Email and Password combination does not match an existing user" };

        const user = { id: rows[0].id, username: rows[0].username, email: rows[0].email };
        const expires = new Date(Date.now() + 30 * 60 * 1000);
        const session = await encrypt({ user, expires });

        cookies().set("session", session, {
            expires: expires,
            httpOnly: true,
            secure: true
        });
    } catch (err) {
        console.error(err);
        return { message: "Server Error" };
    }
}
when I was using WS, I was exposing all the code on the DevTools
but the whole code was easier to mess with even though it wasn't the correct way
so I decided to start using Next.js for the most part, and only WS for the actual gameplay (I'm doing a multiplayer game)
when I arrived on this problem, I got stuck for half a month 😅
I keep getting errors like "this can't be used unless use server" or the other way around
been stuck in a loop cause of that
@D34dlyK1ss idk how to work with states yet
ok leave everything like it is and just move the actions though the onSubmit event and mark your form as clientside ('use client').

Then call the action inside your onSubmit event:
onSubmit={(e) => {
  e.preventDefault();
  const result = await login(e); // read the result
}}

Like that the formdata should be transfered correctly. Also you can read the result from the server action.
@D34dlyK1ss the login action was on another file already
yea and it can stay there. The import is the same
yep
I did this
onSubmit={async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);
    const result = await login(formData); // read the result
}}
but now I want the result to trigger the modal if it's a string for example
no one in here sticks to the end
last time I got stuck for a long time because I had no people coming to help
jesus
it's been 2 weeks
@"use php"
this should be simpler than it looks
explain how then
useState?
you are returning a message
a string
Just result.message should be the message
exactly
I want to render my modal
how do I do that in the page
+ I want to distinguish what sohuld be client or server
useState
says I can't use objects in React children
when I do {result && <NotificationModal message={result}/>}
change type to string
const [message, setMessage] = useState<null | string>(null)
still the same
the conditional rendering isn't working
but it's defined already as null/string up there! 🤦🏻‍♂️
how can it lose track of this
That doesn't matter
It is supposed to be string
it means parent component can pass any type
so how do I infer the type?
as?
replace any with string
there's no any
oh
so now
how can it be an object
if I'm only passing a string around?
no object involved
@D34dlyK1ss Click to see attachment
you are setting message to {message: string;} clearly
thats why you're getting the erro
I'm returning a string
It should be
const data = await login(formData)
setMessage(data.message
in which line are you getting the error?
its 40, but highlight in code
this is throwing me off so badly 😂
Can you send your full code of notification mode again?
As a screenshot
I'm accepting a string
and I am sending a string to the modal, supposedly
@D34dlyK1ss Click to see attachment
I’ll check it tomorrow
damn, alright
@"use php" fixed
Answer
thank you
you made me look at things a different way 😄
not to close the modal will be a different problem
but I should get this alone
Mark solution