#school-portal

11 messages · Page 1 of 1 (latest)

gusty hollow
#

//app/layout.tsx
import { ConvexAuthNextjsServerProvider } from "@convex-dev/auth/nextjs/server";
import './globals.css';
import { ConvexClientProvider } from "./ConvexClientProvider";

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<ConvexAuthNextjsServerProvider>
<html lang="en">
<ConvexClientProvider>{children}</ConvexClientProvider>
</html>
</ConvexAuthNextjsServerProvider>
);
}

#

// app/ConvexClientProvider.tsx
"use client";

import { ConvexAuthNextjsProvider } from "@convex-dev/auth/nextjs";
import { ConvexReactClient } from "convex/react";
import { ReactNode } from "react";

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

export function ConvexClientProvider({ children }: { children: ReactNode }) {
return (
<ConvexAuthNextjsProvider client={convex}>
{children}
</ConvexAuthNextjsProvider>
);
}

#

// convex/auth.ts
import { Password } from "@convex-dev/auth/providers/Password";
import { convexAuth } from "@convex-dev/auth/server";
import { MutationCtx, query } from "./_generated/server";
import { DataModel, Id } from "./_generated/dataModel";
import { GenericQueryCtx } from "convex/server";

export const { auth, signIn, signOut, store } = convexAuth({
providers: [Password],
});

#

import { httpRouter } from "convex/server";
import { auth } from "./auth";

const http = httpRouter();

auth.addHttpRoutes(http);

export default http;

#

// convex/users.ts
import { query } from "./_generated/server";
import { v } from "convex/values";
import { User } from "./type/userType";

export const getUser = query({
args: {
email: v.string(),
},
handler: async ({ db }, { email }) => {
const user = await db.query("users").filter(q => q.eq("email", email)).first();
return user || null;
},
});

#

// convex/admin.ts
export const storeUser = mutation({
args: {
user: v.object({
email: v.string(),
name: v.optional(v.string()),
image: v.optional(v.string()),
role: v.optional(v.string()),
password: v.optional(v.string()), // Include password for students
}),
},
handler: async ({ db }, { user }) => {
const name = user.name || "Default Name"; // Provide a default value if name is undefined

    if (user.role === "admin") {
        await db.insert("admin", {
            email: user.email,
            name: name,
            tokenIdentifier: "", // Initialize with an empty string or generate a token
        });
    } else if (user.role === "student") {
        await db.insert("students", {
            email: user.email,
            role: user.role,
            password: user.password || "", // Ensure password is provided for students
        });
    } else {
        await db.insert("users", user);
    }
},

});

// Define a common user type

export const signUpAdmin = mutation({
args: {
email: v.string(),
name: v.string(),
password: v.string(),
},
handler: async ({ db }, { email, name, password }) => {
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);

    // Insert the admin user into the admin table
    await db.insert("admin", {
        email,
        name,
        password: hashedPassword,
        tokenIdentifier: "", // Initialize with an empty string or generate a token
    } as { email: string; name: string; password: string; tokenIdentifier: string });
},

});

#

//admin/auth/login
export default function CreateAdminAndSignIn() {
const { signIn } = useAuthActions();
const [flow, setFlow] = useState<"signIn" | "signUp">("signIn");
const { toast } = useToast();
const [submitting, setSubmitting] = useState(false);
const storeAdmin = useMutation(api.admin.storeUser);
const router = useRouter();

const renderForm = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setSubmitting(true);
    const formData = new FormData(event.currentTarget);
    const email = formData.get("email") as string;
    const password = formData.get("password") as string;

    console.log("Form Data:", { email, password });

    try {
        if (flow === "signUp") {
            // Sign in the user first to ensure authentication
            await signIn("password", formData);
            // Now call the storeAdmin mutation
            await storeAdmin({ user: { email, name: "Admin", password, role: "admin" } });
        } else {
            await signIn("password", formData);
        }

        router.push('/admin/dashboard');
    } catch (error) {
        console.error(error);
        const title =
            flow === "signIn"
                ? "Could not sign in, did you mean to sign up?"
                : "Could not sign up, did you mean to sign in?";
        toast({ title, variant: "destructive" });
        setSubmitting(false);
    }
};
#

return (
<form className="flex flex-col" onSubmit={renderForm}>
<label htmlFor="email">Email</label>
<Input name="email" id="email" className="mb-4" autoComplete="email" />
<Input
type="password"
name="password"
id="password"
className="mb-4"
autoComplete={flow === "signIn" ? "current-password" : "new-password"}
/>
<input name="flow" value={flow} type="hidden" />
<Button type="submit" disabled={submitting}>
{flow === "signIn" ? "Sign in" : "Sign up"}
</Button>
<Button
variant="link"
type="button"
onClick={() => {
setFlow(flow === "signIn" ? "signUp" : "signIn");
}}
>
{flow === "signIn"
? "Don't have an account? Sign up"
: "Already have an account? Sign in"}
</Button>
</form>
);
}

#

undefined
page.tsx:60 undefined
page.tsx:60 null

#

after logged in i get this response from my console
undefined
page.tsx:60 undefined
page.tsx:60 null

weary moon
#

I'm not exactly sure what the problem you are experience is based on the shared log outputs or what expected behavior is not occurring.

That said, you seem to be doing work that convex auth does for you, like create users.

Also you are exposing things like admin signup publicly, so anyone on the internet could create an admin account with your approach.

I would get a basic implementation working without admin role support first, and then separately approach that, as that deviation from the example seems to be where you are getting into problems.