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:
i701 2024-12-26 00:43:39 +05:00
parent 7acd1189ee
commit 0f17800a00
12 changed files with 196 additions and 111 deletions

View File

@ -13,7 +13,7 @@ export default async function DeviceDetails({ params }: {
})
return (
<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'>
{device?.name}
</h3>
@ -22,7 +22,7 @@ export default async function DeviceDetails({ params }: {
<div
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 /> */}
{/* <Filter

View File

@ -21,7 +21,7 @@ export default async function Devices({
const user = await getCurrentUser()
return (
<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 Devices
</h3>
@ -30,13 +30,13 @@ export default async function Devices({
<div
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 />
</div>
<Suspense key={query} fallback={"loading...."}>
<DevicesTable searchParams={searchParams} />
<DevicesTable parentalControl={false} searchParams={searchParams} />
</Suspense>
</div>
);

View File

@ -18,7 +18,7 @@ export default async function ParentalControl({
const query = (await searchParams)?.query || "";
return (
<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>
Parental Control
</h3>
@ -26,7 +26,7 @@ export default async function ParentalControl({
<div
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 />

View File

@ -29,7 +29,7 @@ export default async function PaymentPage({
const formula = await prisma.billFormula.findFirst();
return (
<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>
<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"}

View File

@ -15,13 +15,13 @@ export default async function Devices({
const query = (await searchParams)?.query || "";
return (
<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>
</div>
<div
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 />
</div>

View File

@ -1,7 +1,7 @@
export default async function UserDevcies() {
return (
<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
</h3>
</div>

View File

@ -21,7 +21,7 @@ export default async function VerifyUserPage({
})
return (
<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="">
Verify user
</h3>

View File

@ -38,7 +38,7 @@ export default async function AdminUsers({
return (
<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
</h3>

View File

@ -2,32 +2,24 @@
import { deviceCartAtom } from '@/lib/atoms'
import type { Device } from '@prisma/client'
import { useAtomValue, useSetAtom } from 'jotai'
import { BadgePlus, CheckCheck } from 'lucide-react'
import React from 'react'
import { Button } from './ui/button'
export default function AddDevicesToCartButton({ device }: { device: Device }) {
const setDeviceCart = useSetAtom(deviceCartAtom)
const devices = useAtomValue(deviceCartAtom)
const isChecked = devices.some((d) => d.id === device.id);
return (
<Button
className='w-full mt-2'
disabled={devices.some((d) => d.id === device.id)}
onClick={() => setDeviceCart((prev) => [...prev, device])}
>
{devices.some((d) => d.id === device.id) ? (
<>
Selected
<CheckCheck />
</>
) : (
<>
Select device
<BadgePlus />
</>
<input
type="checkbox"
className='peer accent-[#f49d1b] size-4'
checked={isChecked}
onChange={() => setDeviceCart((prev) =>
isChecked
? prev.filter((d) => d.id !== device.id)
: [...prev, device]
)}
</Button>
/>
)
}

View 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 >
)
}

View File

@ -1,27 +1,48 @@
'use client'
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'
import { Badge } from './ui/badge'
export default function DeviceCard({ device, parentalControl }: { device: Device, parentalControl?: boolean }) {
const [devices, setDeviceCart] = useAtom(deviceCartAtom)
const isChecked = devices.some((d) => d.id === device.id);
return (
<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">
<div
onKeyUp={() => { }}
onClick={() => {
if (parentalControl === true) return
setDeviceCart((prev) =>
devices.some((d) => d.id === device.id)
? prev.filter((d) => d.id !== device.id)
: [...prev, device]
)
}
}
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={"outline"}>
<Badge variant={"secondary"}>
<span className="font-medium">
{device.mac}
</span>
</Badge>
</div>
{device.isActive && (
<span className="text-muted-foreground">
Active until{" "}
{new Date().toLocaleDateString("en-US", {
@ -30,6 +51,8 @@ export default function DeviceCard({ device, parentalControl }: { device: Device
year: "numeric",
})}
</span>
)}
{device.blocked && (
<div className="p-2 rounded border my-2 w-full">
<span>Comment: </span>
@ -38,6 +61,9 @@ export default function DeviceCard({ device, parentalControl }: { device: Device
</p>
</div>
)}
</div>
<div>
{!parentalControl ? (
<AddDevicesToCartButton device={device} />
) : (
@ -45,5 +71,6 @@ export default function DeviceCard({ device, parentalControl }: { device: Device
)}
</div>
</div>
</div>
)
}

View File

@ -11,9 +11,7 @@ import {
import { auth } from "@/lib/auth";
import prisma from "@/lib/db";
import { headers } from "next/headers";
import Link from "next/link";
import AddDevicesToCartButton from "./add-devices-to-cart-button";
import BlockDeviceButton from "./block-device-dialog";
import ClickableRow from "./clickable-row";
import DeviceCard from "./device-card";
import Pagination from "./pagination";
@ -56,7 +54,7 @@ export async function DevicesTable({
paid: false
}
},
isActive: parentalControl ? parentalControl : undefined,
isActive: parentalControl,
blocked: parentalControl !== undefined ? undefined : false,
},
});
@ -89,7 +87,6 @@ export async function DevicesTable({
},
isActive: parentalControl,
blocked: parentalControl !== undefined ? undefined : false,
},
skip: offset,
@ -114,48 +111,49 @@ export async function DevicesTable({
<TableRow>
<TableHead>Device Name</TableHead>
<TableHead>MAC Address</TableHead>
<TableHead>Actions</TableHead>
<TableHead>#</TableHead>
</TableRow>
</TableHeader>
<TableBody className="overflow-scroll">
{devices.map((device) => (
<TableRow key={device.id}>
<TableCell>
<div className="flex flex-col items-start">
<Link
className="font-medium hover:underline"
href={`/devices/${device.id}`}
>
{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>
)}
// <TableRow key={device.id}>
// <TableCell>
// <div className="flex flex-col items-start">
// <Link
// className="font-medium hover:underline"
// href={`/devices/${device.id}`}
// >
// {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} />
) : (
<BlockDeviceButton device={device} />
)}
</TableCell>
</TableRow>
// </div>
// </TableCell>
// <TableCell className="font-medium">{device.mac}</TableCell>
// <TableCell>
// {!parentalControl ? (
// <AddDevicesToCartButton device={device} />
// ) : (
// <BlockDeviceButton device={device} />
// )}
// </TableCell>
// </TableRow>
<ClickableRow key={device.id} device={device} parentalControl={parentalControl} />
))}
</TableBody>
<TableFooter>