feat: add vendor information to device components and update related UI elements
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 9m52s

fix: update sidebar transition duration for smoother experience
chore: update package dependencies and versions for improved stability and features
This commit is contained in:
2025-06-02 09:17:16 +05:00
parent bed426a6b4
commit 8438ceb376
8 changed files with 276 additions and 84 deletions

View File

@ -82,6 +82,7 @@ export default function ClickableRow({
</div>
</TableCell>
<TableCell className="font-medium">{device.mac}</TableCell>
<TableCell className="font-medium">{device?.vendor}</TableCell>
<TableCell>
{!parentalControl ? (
<AddDevicesToCartButton device={device} />

View File

@ -45,7 +45,7 @@ export default function DeviceCard({
<div className="">
<div className="font-semibold flex flex-col items-start gap-2 mb-2">
<Link
className="font-medium hover:underline"
className={cn("font-medium hover:underline ml-0.5", device.is_active ? "text-green-600" : "")}
href={`/devices/${device.id}`}
>
{device.name}
@ -53,10 +53,13 @@ export default function DeviceCard({
<Badge variant={"outline"}>
<span className="font-medium">{device.mac}</span>
</Badge>
<Badge variant={"outline"}>
<span className="font-medium">{device.vendor}</span>
</Badge>
</div>
{device.is_active ? (
<div className="text-muted-foreground">
<div className="text-muted-foreground ml-0.5">
Active until{" "}
<span className="font-semibold">
{new Date(device.expiry_date || "").toLocaleDateString(
@ -70,7 +73,7 @@ export default function DeviceCard({
</span>
</div>
) : (
<p className="text-muted-foreground">Device Inactive</p>
<p className="text-muted-foreground ml-0.5">Device Inactive</p>
)}
{device.has_a_pending_payment && (
<Link href={`/payments/${device.pending_payment_id}`}>

View File

@ -62,6 +62,7 @@ export async function DevicesTable({
<TableRow>
<TableHead>Device Name</TableHead>
<TableHead>MAC Address</TableHead>
<TableHead>Vendor</TableHead>
<TableHead>#</TableHead>
</TableRow>
</TableHeader>
@ -77,7 +78,7 @@ export async function DevicesTable({
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={2}>
<TableCell colSpan={3}>
{query?.length > 0 && (
<p className="text-sm text-muted-foreground">
Showing {meta?.total} devices for &quot;{query}

View File

@ -100,7 +100,7 @@ const SidebarProvider = React.forwardRef<
return isMobile
? setOpenMobile((open) => !open)
: setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]);
}, [isMobile, setOpen,]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
@ -138,7 +138,6 @@ const SidebarProvider = React.forwardRef<
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
],
);
@ -243,7 +242,7 @@ const Sidebar = React.forwardRef<
{/* This is what handles the sidebar gap on desktop */}
<div
className={cn(
"duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear",
"duration-75 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear",
"group-data-[collapsible=offcanvas]:w-0",
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
@ -253,7 +252,7 @@ const Sidebar = React.forwardRef<
/>
<div
className={cn(
"duration-200 fixed inset-y-0 z-0 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex",
"duration-75 fixed inset-y-0 z-0 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex",
side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
@ -458,7 +457,7 @@ const SidebarGroupLabel = React.forwardRef<
ref={ref}
data-sidebar="group-label"
className={cn(
"duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"duration-75 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className,
)}

View File

@ -7,23 +7,34 @@ interface WelcomeBannerProps {
lastName?: string | null;
}
const ANIMATION_DURATION_MS = 500;
export function WelcomeBanner({ firstName, lastName }: WelcomeBannerProps) {
const [isVisible, setIsVisible] = useState(true);
const [isMounted, setIsMounted] = useState(true);
const [isFadingOut, setIsFadingOut] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setIsVisible(false);
const startFadeOutTimer = setTimeout(() => {
setIsFadingOut(true);
}, 3000);
const unmountTimer = setTimeout(() => {
setIsMounted(false);
}, 3000 + ANIMATION_DURATION_MS);
return () => clearTimeout(timer);
return () => {
clearTimeout(startFadeOutTimer);
clearTimeout(unmountTimer);
};
}, []);
if (!isVisible) {
if (!isMounted) {
return null;
}
return (
<div className="text-sm font-mono px-2 p-1 fade-out-10 bg-green-500/10 text-green-900 dark:text-green-400">
<div
className={`text-sm font-mono px-2 p-1 bg-green-500/10 text-green-900 dark:text-green-400 ${isFadingOut ? "animate-out fade-out animate-duration-500 animate-ease-out" : "animate-in fade-in"
}`}
>
Welcome,{" "}
<span className="font-semibold">
{firstName} {lastName}