mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-06-29 15:47:09 +00:00
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:
@ -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>;
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
5
app/(dashboard)/user-devices/page.tsx
Normal file
5
app/(dashboard)/user-devices/page.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function UserDevices() {
|
||||
return <div>UserDevices</div>;
|
||||
}
|
11
app/(dashboard)/user-payments/page.tsx
Normal file
11
app/(dashboard)/user-payments/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
56
app/(dashboard)/users/page.tsx
Normal file
56
app/(dashboard)/users/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
|
Reference in New Issue
Block a user