Refactor authentication and dashboard components

- Updated login and signup pages to include session checks and redirection based on user authentication status.
- Introduced QueryProvider for managing server state in the application.
- Enhanced user experience by integrating session management in the devices and payments dashboard.
- Added new user management features with role-based access control in the sidebar.
- Created new components for user devices and payments, improving the overall structure and maintainability of the dashboard.
- Implemented a table component for better data presentation in user-related views.
This commit is contained in:
2024-11-27 14:18:17 +05:00
parent 8e6f802218
commit 0322bee567
16 changed files with 713 additions and 372 deletions

View File

@ -1,19 +1,29 @@
import LoginForm from "@/components/auth/login-form";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import Image from "next/image";
import { redirect } from "next/navigation";
import React from "react";
export default function LoginPage() {
return <div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image alt="Sar Link Logo" src="/logo.png" width={100} height={100} />
<div className="mt-4 flex flex-col items-center justify-center">
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">Pay for your devices and track your bills.</p>
export default async function LoginPage() {
const session = await auth.api.getSession({
headers: await headers(),
});
if (session) {
return redirect("/devices");
}
return (
<div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image alt="Sar Link Logo" src="/logo.png" width={100} height={100} />
<div className="mt-4 flex flex-col items-center justify-center">
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">
Pay for your devices and track your bills.
</p>
</div>
<LoginForm />
</div>
<LoginForm />
</div>
</div>;
);
}

View File

@ -1,25 +1,51 @@
import SignUpForm from "@/components/auth/signup-form";
import { auth } from "@/lib/auth";
import prisma from "@/lib/db";
import { headers } from "next/headers";
import Image from "next/image";
import { redirect } from "next/navigation";
import React from "react";
export default async function LoginPage() {
const atolls = await prisma.atoll.findMany({
include: {
islands: true
}
})
return <div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image priority alt="Sar Link Logo" src="/logo.png" width={100} height={100} />
<div className="mt-4 flex flex-col items-center justify-center">
export default async function SignupPage({
searchParams,
}: {
searchParams: Promise<{ phone_number: string }>;
}) {
const session = await auth.api.getSession({
headers: await headers(),
});
if (session) {
return redirect("/devices");
}
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">Pay for your devices and track your bills.</p>
</div>
<SignUpForm atolls={atolls} />
</div>
</div>;
const phone_number = (await searchParams).phone_number;
if (!phone_number) {
return redirect("/login");
}
const atolls = await prisma.atoll.findMany({
include: {
islands: true,
},
});
return (
<div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image
priority
alt="Sar Link Logo"
src="/logo.png"
width={100}
height={100}
/>
<div className="mt-4 flex flex-col items-center justify-center">
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">
Pay for your devices and track your bills.
</p>
</div>
<SignUpForm atolls={atolls} />
</div>
</div>
);
}

View File

@ -1,24 +1,34 @@
import VerifyOTPForm from "@/components/auth/verify-otp-form";
import Image from "next/image";
import { redirect } from "next/navigation";
import React from "react";
export default async function VerifyOTP({
searchParams,
searchParams,
}: {
searchParams: Promise<{ phone_number: string }>
searchParams: Promise<{ phone_number: string }>;
}) {
const phone_number = (await searchParams).phone_number
return <div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image alt="Sar Link Logo" src="/logo.png" width={100} height={100} />
<div className="mt-4 flex flex-col items-center justify-center">
const phone_number = (await searchParams).phone_number;
if (!phone_number) {
return redirect("/login");
}
console.log(
"phone number from server page params (verify otp page)",
phone_number,
);
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">Pay for your devices and track your bills.</p>
</div>
<VerifyOTPForm phone_number={phone_number} />
</div>
</div>;
return (
<div className="bg-gray-100 dark:bg-black w-full h-screen flex items-center justify-center font-sans">
<div className="flex flex-col items-center justify-center w-full h-full ">
<Image alt="Sar Link Logo" src="/logo.png" width={100} height={100} />
<div className="mt-4 flex flex-col items-center justify-center">
<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
<p className="text-gray-500">
Pay for your devices and track your bills.
</p>
</div>
<VerifyOTPForm phone_number={phone_number} />
</div>
</div>
);
}

View File

@ -1,5 +1,15 @@
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
export default async function Devices() {
return <div>
<h2>Devices</h2>
</div>;
const session = await auth.api.getSession({
headers: await headers(),
});
return (
<div>
<h2>Server session</h2>
<pre>{JSON.stringify(session?.user, null, 2)}</pre>
</div>
);
}

View File

@ -1,17 +1,14 @@
'use client'
import { PhoneInput } from '@/components/ui/phone-input'
import React from 'react'
"use client";
import { authClient } from "@/lib/auth-client";
import React from "react";
export default function MyPayments() {
return (
<div>
<PhoneInput
id="phone-number"
name="phoneNumber"
placeholder="Enter phone number"
defaultCountry="MV"
/>
</div>
const session = authClient.useSession();
)
return (
<div>
<h3>Client session</h3>
<pre>{JSON.stringify(session.data, null, 2)}</pre>
</div>
);
}

View File

@ -0,0 +1,5 @@
import React from "react";
export default function UserDevices() {
return <div>UserDevices</div>;
}

View File

@ -0,0 +1,11 @@
import { AdminAuthGuard } from "@/lib/auth-guard";
import React from "react";
export default async function UserPayments() {
await AdminAuthGuard();
return (
<div>
<h3>User Payments</h3>
</div>
);
}

View File

@ -0,0 +1,56 @@
import Filter from "@/components/filter";
import Search from "@/components/search";
import { UsersTable } from "@/components/user-table";
import { AdminAuthGuard } from "@/lib/auth-guard";
import { CheckCheck, Hourglass, Minus } from "lucide-react";
import React, { Suspense } from "react";
export default async function AdminUsers({
searchParams,
}: {
searchParams: Promise<{
query: string;
page: number;
sortBy: string;
status: string;
}>;
}) {
await AdminAuthGuard();
return (
<div>
<h3 className="border-b-2 text-2xl font-bold title-bg py-4 px-2 mb-4">
Users
</h3>
<div
id="user-filters"
className=" border-b-2 pb-4 gap-4 flex items-center justify-start"
>
<Search />
<Filter
options={[
{
value: "all",
label: "ALL",
icon: <Minus size={14} />,
},
{
value: "unverified",
label: "Unverfieid",
icon: <CheckCheck size={14} />,
},
{
value: "verified",
label: "Verified",
icon: <Hourglass size={14} />,
},
]}
defaultOption="all"
queryParamKey="status"
/>
</div>
<Suspense fallback={"loading...."}>
<UsersTable searchParams={searchParams} />
</Suspense>
</div>
);
}

View File

@ -1,10 +1,11 @@
import type { Metadata } from "next";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
import { Barlow } from "next/font/google";
import NextTopLoader from 'nextjs-toploader';
import { Toaster } from 'sonner'
import type { Metadata } from "next";
import { Barlow } from "next/font/google";
import NextTopLoader from "nextjs-toploader";
import { Toaster } from "sonner";
import "./globals.css";
import QueryProvider from "@/components/query-provider";
const barlow = Barlow({
subsets: ["latin"],
weight: ["100", "300", "400", "500", "600", "700", "800", "900"],
@ -32,7 +33,7 @@ export default function RootLayout({
enableSystem
disableTransitionOnChange
>
{children}
<QueryProvider>{children}</QueryProvider>
</ThemeProvider>
</body>
</html>