mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-02-22 09:02:01 +00:00
Refactor UI components for improved consistency and functionality
- Removed unnecessary border styles from various dashboard components including Devices, DeviceDetails, Parental Control, Payments, and Users pages to enhance visual consistency. - Updated DevicesTable to utilize a new ClickableRow component for better device interaction and management. - Refactored AddDevicesToCartButton to use a checkbox for selecting devices, improving user experience. - Enhanced DeviceCard component to streamline device information display and interaction. - Overall improvements to the layout and responsiveness of the dashboard components. These changes enhance the user interface and improve the maintainability of the codebase.
This commit is contained in:
parent
7acd1189ee
commit
0f17800a00
@ -13,7 +13,7 @@ export default async function DeviceDetails({ params }: {
|
|||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-col justify-between items-start border-b-2 text-gray-500 title-bg py-4 px-2 mb-4">
|
<div className="flex flex-col justify-between items-start text-gray-500 title-bg py-4 px-2 mb-4">
|
||||||
<h3 className='text-2xl font-bold'>
|
<h3 className='text-2xl font-bold'>
|
||||||
{device?.name}
|
{device?.name}
|
||||||
</h3>
|
</h3>
|
||||||
@ -22,7 +22,7 @@ export default async function DeviceDetails({ params }: {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
id="user-filters"
|
id="user-filters"
|
||||||
className=" border-b-2 pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
className=" pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
||||||
>
|
>
|
||||||
{/* <Search /> */}
|
{/* <Search /> */}
|
||||||
{/* <Filter
|
{/* <Filter
|
||||||
|
@ -21,7 +21,7 @@ export default async function Devices({
|
|||||||
const user = await getCurrentUser()
|
const user = await getCurrentUser()
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between items-center border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<div className="flex justify-between items-center text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
<h3>
|
<h3>
|
||||||
My Devices
|
My Devices
|
||||||
</h3>
|
</h3>
|
||||||
@ -30,13 +30,13 @@ export default async function Devices({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
id="user-filters"
|
id="user-filters"
|
||||||
className=" border-b-2 pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
className=" pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
||||||
>
|
>
|
||||||
<Search />
|
<Search />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Suspense key={query} fallback={"loading...."}>
|
<Suspense key={query} fallback={"loading...."}>
|
||||||
<DevicesTable searchParams={searchParams} />
|
<DevicesTable parentalControl={false} searchParams={searchParams} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -18,7 +18,7 @@ export default async function ParentalControl({
|
|||||||
const query = (await searchParams)?.query || "";
|
const query = (await searchParams)?.query || "";
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between items-center border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<div className="flex justify-between items-center text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
<h3>
|
<h3>
|
||||||
Parental Control
|
Parental Control
|
||||||
</h3>
|
</h3>
|
||||||
@ -26,7 +26,7 @@ export default async function ParentalControl({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
id="user-filters"
|
id="user-filters"
|
||||||
className=" border-b-2 pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
className=" pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
||||||
>
|
>
|
||||||
<Search />
|
<Search />
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export default async function PaymentPage({
|
|||||||
const formula = await prisma.billFormula.findFirst();
|
const formula = await prisma.billFormula.findFirst();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between items-center border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<div className="flex justify-between items-center text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
<h3>Payment</h3>
|
<h3>Payment</h3>
|
||||||
<span className={cn("text-sm border px-4 py-2 rounded-md uppercase font-semibold", payment?.paid ? "text-green-500 bg-green-500/20" : "text-yellow-500 bg-yellow-500/20")}>
|
<span className={cn("text-sm border px-4 py-2 rounded-md uppercase font-semibold", payment?.paid ? "text-green-500 bg-green-500/20" : "text-yellow-500 bg-yellow-500/20")}>
|
||||||
{payment?.paid ? "Paid" : "Pending"}
|
{payment?.paid ? "Paid" : "Pending"}
|
||||||
|
@ -15,13 +15,13 @@ export default async function Devices({
|
|||||||
const query = (await searchParams)?.query || "";
|
const query = (await searchParams)?.query || "";
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between items-center border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<div className="flex justify-between items-center text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
<h3>My Payments</h3>
|
<h3>My Payments</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="user-filters"
|
id="user-filters"
|
||||||
className=" border-b-2 pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
className=" pb-4 gap-4 flex sm:flex-row flex-col items-start justify-start"
|
||||||
>
|
>
|
||||||
<Search />
|
<Search />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export default async function UserDevcies() {
|
export default async function UserDevcies() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="border-b-2 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<h3 className="text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
User Devices
|
User Devices
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +21,7 @@ export default async function VerifyUserPage({
|
|||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='flex items-center justify-between border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4'>
|
<div className='flex items-center justify-between text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4'>
|
||||||
<h3 className="">
|
<h3 className="">
|
||||||
Verify user
|
Verify user
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -38,7 +38,7 @@ export default async function AdminUsers({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="border-b-2 text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
<h3 className="text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4">
|
||||||
Users
|
Users
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -2,32 +2,24 @@
|
|||||||
import { deviceCartAtom } from '@/lib/atoms'
|
import { deviceCartAtom } from '@/lib/atoms'
|
||||||
import type { Device } from '@prisma/client'
|
import type { Device } from '@prisma/client'
|
||||||
import { useAtomValue, useSetAtom } from 'jotai'
|
import { useAtomValue, useSetAtom } from 'jotai'
|
||||||
import { BadgePlus, CheckCheck } from 'lucide-react'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Button } from './ui/button'
|
|
||||||
|
|
||||||
export default function AddDevicesToCartButton({ device }: { device: Device }) {
|
export default function AddDevicesToCartButton({ device }: { device: Device }) {
|
||||||
const setDeviceCart = useSetAtom(deviceCartAtom)
|
const setDeviceCart = useSetAtom(deviceCartAtom)
|
||||||
const devices = useAtomValue(deviceCartAtom)
|
const devices = useAtomValue(deviceCartAtom)
|
||||||
|
|
||||||
|
const isChecked = devices.some((d) => d.id === device.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<input
|
||||||
className='w-full mt-2'
|
type="checkbox"
|
||||||
disabled={devices.some((d) => d.id === device.id)}
|
className='peer accent-[#f49d1b] size-4'
|
||||||
onClick={() => setDeviceCart((prev) => [...prev, device])}
|
checked={isChecked}
|
||||||
>
|
onChange={() => setDeviceCart((prev) =>
|
||||||
{devices.some((d) => d.id === device.id) ? (
|
isChecked
|
||||||
<>
|
? prev.filter((d) => d.id !== device.id)
|
||||||
Selected
|
: [...prev, device]
|
||||||
<CheckCheck />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
Select device
|
|
||||||
<BadgePlus />
|
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</Button>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
68
components/clickable-row.tsx
Normal file
68
components/clickable-row.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
import {
|
||||||
|
TableCell,
|
||||||
|
TableRow
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { deviceCartAtom } from "@/lib/atoms";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { Device } from "@prisma/client";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import Link from 'next/link';
|
||||||
|
import AddDevicesToCartButton from "./add-devices-to-cart-button";
|
||||||
|
import BlockDeviceDialog from "./block-device-dialog";
|
||||||
|
export default function ClickableRow({ device, parentalControl }: { device: Device, parentalControl?: boolean }) {
|
||||||
|
const [devices, setDeviceCart] = useAtom(deviceCartAtom)
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
key={device.id}
|
||||||
|
className={cn(parentalControl === false && "cursor-pointer hover:bg-muted",)}
|
||||||
|
onClick={() => {
|
||||||
|
|
||||||
|
if (parentalControl === true) return
|
||||||
|
setDeviceCart((prev) =>
|
||||||
|
devices.some((d) => d.id === device.id)
|
||||||
|
? prev.filter((d) => d.id !== device.id)
|
||||||
|
: [...prev, device]
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableCell>
|
||||||
|
<div className="flex flex-col items-start">
|
||||||
|
<Link
|
||||||
|
className="font-medium hover:underline"
|
||||||
|
href={`/devices/${device.id}`}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{device.name}
|
||||||
|
</Link>
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
Active until{" "}
|
||||||
|
{new Date().toLocaleDateString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
{parentalControl && (
|
||||||
|
<div className="p-2 rounded border my-2">
|
||||||
|
<span>Comment: </span>
|
||||||
|
<p className="text-neutral-500">
|
||||||
|
blocked because he was watching youtube
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">{device.mac}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{!parentalControl ? (
|
||||||
|
<AddDevicesToCartButton device={device} />
|
||||||
|
) : (
|
||||||
|
<BlockDeviceDialog device={device} />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow >
|
||||||
|
)
|
||||||
|
}
|
@ -1,48 +1,75 @@
|
|||||||
|
'use client'
|
||||||
|
import { deviceCartAtom } from '@/lib/atoms'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import type { Device } from '@prisma/client'
|
import type { Device } from '@prisma/client'
|
||||||
|
import { useAtom } from 'jotai'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import AddDevicesToCartButton from './add-devices-to-cart-button'
|
import AddDevicesToCartButton from './add-devices-to-cart-button'
|
||||||
import BlockDeviceDialog from './block-device-dialog'
|
import BlockDeviceDialog from './block-device-dialog'
|
||||||
import { Badge } from './ui/badge'
|
import { Badge } from './ui/badge'
|
||||||
|
|
||||||
export default function DeviceCard({ device, parentalControl }: { device: Device, parentalControl?: boolean }) {
|
export default function DeviceCard({ device, parentalControl }: { device: Device, parentalControl?: boolean }) {
|
||||||
return (
|
const [devices, setDeviceCart] = useAtom(deviceCartAtom)
|
||||||
<div>
|
|
||||||
<div className="flex text-sm shadow flex-col items-start p-2 border rounded border-dashed">
|
|
||||||
<div className="font-semibold flex gap-2 mb-2">
|
|
||||||
<Link
|
|
||||||
className="font-medium hover:underline"
|
|
||||||
href={`/devices/${device.id}`}
|
|
||||||
>
|
|
||||||
{device.name}
|
|
||||||
</Link>
|
|
||||||
<Badge variant={"outline"}>
|
|
||||||
<span className="font-medium">
|
|
||||||
{device.mac}
|
|
||||||
</span>
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className="text-muted-foreground">
|
const isChecked = devices.some((d) => d.id === device.id);
|
||||||
Active until{" "}
|
|
||||||
{new Date().toLocaleDateString("en-US", {
|
return (
|
||||||
month: "short",
|
<div
|
||||||
day: "2-digit",
|
onKeyUp={() => { }}
|
||||||
year: "numeric",
|
onClick={() => {
|
||||||
})}
|
if (parentalControl === true) return
|
||||||
</span>
|
setDeviceCart((prev) =>
|
||||||
{device.blocked && (
|
devices.some((d) => d.id === device.id)
|
||||||
<div className="p-2 rounded border my-2 w-full">
|
? prev.filter((d) => d.id !== device.id)
|
||||||
<span>Comment: </span>
|
: [...prev, device]
|
||||||
<p className="text-neutral-500">
|
)
|
||||||
blocked because he was watching youtube
|
}
|
||||||
</p>
|
}
|
||||||
|
className="w-full">
|
||||||
|
<div className={cn("flex text-sm justify-between items-center my-2 p-4 border rounded-md", isChecked ? "bg-accent" : "bg-")}>
|
||||||
|
<div className=''>
|
||||||
|
<div className="font-semibold flex flex-col items-start gap-2 mb-2">
|
||||||
|
<Link
|
||||||
|
className="font-medium hover:underline"
|
||||||
|
href={`/devices/${device.id}`}
|
||||||
|
>
|
||||||
|
{device.name}
|
||||||
|
</Link>
|
||||||
|
<Badge variant={"secondary"}>
|
||||||
|
<span className="font-medium">
|
||||||
|
{device.mac}
|
||||||
|
</span>
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
{!parentalControl ? (
|
{device.isActive && (
|
||||||
<AddDevicesToCartButton device={device} />
|
<span className="text-muted-foreground">
|
||||||
) : (
|
Active until{" "}
|
||||||
<BlockDeviceDialog device={device} />
|
{new Date().toLocaleDateString("en-US", {
|
||||||
)}
|
month: "short",
|
||||||
|
day: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{device.blocked && (
|
||||||
|
<div className="p-2 rounded border my-2 w-full">
|
||||||
|
<span>Comment: </span>
|
||||||
|
<p className="text-neutral-500">
|
||||||
|
blocked because he was watching youtube
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{!parentalControl ? (
|
||||||
|
<AddDevicesToCartButton device={device} />
|
||||||
|
) : (
|
||||||
|
<BlockDeviceDialog device={device} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -11,9 +11,7 @@ import {
|
|||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import prisma from "@/lib/db";
|
import prisma from "@/lib/db";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import Link from "next/link";
|
import ClickableRow from "./clickable-row";
|
||||||
import AddDevicesToCartButton from "./add-devices-to-cart-button";
|
|
||||||
import BlockDeviceButton from "./block-device-dialog";
|
|
||||||
import DeviceCard from "./device-card";
|
import DeviceCard from "./device-card";
|
||||||
import Pagination from "./pagination";
|
import Pagination from "./pagination";
|
||||||
|
|
||||||
@ -56,7 +54,7 @@ export async function DevicesTable({
|
|||||||
paid: false
|
paid: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isActive: parentalControl ? parentalControl : undefined,
|
isActive: parentalControl,
|
||||||
blocked: parentalControl !== undefined ? undefined : false,
|
blocked: parentalControl !== undefined ? undefined : false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -89,7 +87,6 @@ export async function DevicesTable({
|
|||||||
},
|
},
|
||||||
isActive: parentalControl,
|
isActive: parentalControl,
|
||||||
blocked: parentalControl !== undefined ? undefined : false,
|
blocked: parentalControl !== undefined ? undefined : false,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
skip: offset,
|
skip: offset,
|
||||||
@ -114,48 +111,49 @@ export async function DevicesTable({
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Device Name</TableHead>
|
<TableHead>Device Name</TableHead>
|
||||||
<TableHead>MAC Address</TableHead>
|
<TableHead>MAC Address</TableHead>
|
||||||
<TableHead>Actions</TableHead>
|
<TableHead>#</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody className="overflow-scroll">
|
<TableBody className="overflow-scroll">
|
||||||
{devices.map((device) => (
|
{devices.map((device) => (
|
||||||
<TableRow key={device.id}>
|
// <TableRow key={device.id}>
|
||||||
<TableCell>
|
// <TableCell>
|
||||||
<div className="flex flex-col items-start">
|
// <div className="flex flex-col items-start">
|
||||||
<Link
|
// <Link
|
||||||
className="font-medium hover:underline"
|
// className="font-medium hover:underline"
|
||||||
href={`/devices/${device.id}`}
|
// href={`/devices/${device.id}`}
|
||||||
>
|
// >
|
||||||
{device.name}
|
// {device.name}
|
||||||
</Link>
|
// </Link>
|
||||||
<span className="text-muted-foreground">
|
// <span className="text-muted-foreground">
|
||||||
Active until{" "}
|
// Active until{" "}
|
||||||
{new Date().toLocaleDateString("en-US", {
|
// {new Date().toLocaleDateString("en-US", {
|
||||||
month: "short",
|
// month: "short",
|
||||||
day: "2-digit",
|
// day: "2-digit",
|
||||||
year: "numeric",
|
// year: "numeric",
|
||||||
})}
|
// })}
|
||||||
</span>
|
// </span>
|
||||||
{parentalControl && (
|
// {parentalControl && (
|
||||||
<div className="p-2 rounded border my-2">
|
// <div className="p-2 rounded border my-2">
|
||||||
<span>Comment: </span>
|
// <span>Comment: </span>
|
||||||
<p className="text-neutral-500">
|
// <p className="text-neutral-500">
|
||||||
blocked because he was watching youtube
|
// blocked because he was watching youtube
|
||||||
</p>
|
// </p>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
|
|
||||||
</div>
|
// </div>
|
||||||
</TableCell>
|
// </TableCell>
|
||||||
<TableCell className="font-medium">{device.mac}</TableCell>
|
// <TableCell className="font-medium">{device.mac}</TableCell>
|
||||||
<TableCell>
|
// <TableCell>
|
||||||
{!parentalControl ? (
|
// {!parentalControl ? (
|
||||||
<AddDevicesToCartButton device={device} />
|
// <AddDevicesToCartButton device={device} />
|
||||||
) : (
|
// ) : (
|
||||||
<BlockDeviceButton device={device} />
|
// <BlockDeviceButton device={device} />
|
||||||
)}
|
// )}
|
||||||
</TableCell>
|
// </TableCell>
|
||||||
</TableRow>
|
// </TableRow>
|
||||||
|
<ClickableRow key={device.id} device={device} parentalControl={parentalControl} />
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
<TableFooter>
|
<TableFooter>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user