Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI Testing

on:
push:
branches: [ main ]
branches: [ main, UTS ]
pull_request:
branches: [ main ]
branches: [ main, UTS ]

jobs:
test:
Expand Down
71 changes: 35 additions & 36 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions src/components/dashboard/BinCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ export default function BinCard({ id, gedung, lantai, ruang, level, capacity, st

return (
<Link href={`/monitoring/${id}`}>
<div className="group cursor-pointer rounded-2xl border border-gray-100 bg-white p-5 shadow-sm transition-all hover:border-emerald-300 sm:p-6">
<div className="group cursor-pointer rounded-2xl border border-gray-100 bg-white p-3 shadow-sm transition-all hover:border-emerald-300 sm:p-5">
{/* Header: ID & Status Wifi */}
<div className="mb-5 flex items-start justify-between gap-3 sm:mb-6">
<div>
<h3 className="text-lg font-black uppercase leading-none text-gray-800 transition-colors group-hover:text-emerald-600 sm:text-xl">
<div className="mb-3 flex flex-wrap items-start justify-between gap-1.5 sm:mb-5 sm:gap-3">
<div className="min-w-0 flex-1">
<h3 className="text-sm font-black uppercase leading-none text-gray-800 transition-colors group-hover:text-emerald-600 sm:text-lg md:text-xl">
{id}
</h3>
<div className="flex items-center gap-1 text-gray-400 text-[10px] mt-2 font-medium">
<div className="flex items-center gap-1 text-gray-400 text-[9px] mt-1.5 font-medium sm:mt-2 sm:text-[10px]">
<FiMapPin size={10} className="shrink-0" />
<span className="max-w-[180px] truncate sm:max-w-full">{gedung} - {lantai} {ruang ? `• ${ruang}` : ''}</span>
<span className="max-w-[150px] truncate sm:max-w-full">{gedung} - {lantai} {ruang ? `• ${ruang}` : ''}</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<div className="ml-auto flex items-center gap-1.5 whitespace-nowrap">
{isOnline ? <FiWifi className="text-green-400" size={16}/> : <FiWifiOff className="text-gray-300" size={16}/>}
<span className={`rounded-lg px-2 py-1 text-[10px] font-bold uppercase ${theme.bgLabel} ${theme.text}`}>
<span className={`rounded-lg px-1.5 py-0.5 text-[8px] font-bold uppercase ${theme.bgLabel} ${theme.text} sm:px-2 sm:py-1 sm:text-[10px]`}>
{theme.label}
</span>
</div>
Expand All @@ -63,27 +63,27 @@ export default function BinCard({ id, gedung, lantai, ruang, level, capacity, st
{/* Progress Bar Level Isi */}
<div className="space-y-2">
<div className="flex justify-between items-end">
<span className="text-xs text-gray-400 font-medium tracking-tight">Level Isi</span>
<span className={`text-lg font-black sm:text-xl ${theme.text}`}>
<span className="text-[11px] text-gray-400 font-medium tracking-tight sm:text-xs">Level Isi</span>
<span className={`text-sm font-black sm:text-lg md:text-xl ${theme.text}`}>
{isOnline ? `${level}%` : '--'}
</span>
</div>

<div className="w-full bg-gray-100 rounded-full h-2.5 overflow-hidden">
<div className="w-full bg-gray-100 rounded-full h-2 overflow-hidden sm:h-2.5">
<div
className={`h-full transition-all duration-1000 ${theme.color}`}
style={{ width: `${isOnline ? (level > 100 ? 100 : level < 0 ? 0 : level) : 0}%` }}
/>
</div>

<div className="flex justify-between text-[9px] font-bold text-gray-400 uppercase mt-1 tracking-widest">
<div className="flex justify-between text-[8px] font-bold text-gray-400 uppercase mt-1 tracking-widest sm:text-[9px]">
<span>0L</span>
<span>{capacity}L</span>
</div>
</div>

{/* Footer Card */}
<div className="mt-5 flex items-center justify-between border-t border-gray-50 pt-4 text-[10px] text-gray-400">
<div className="mt-3 flex items-center justify-between border-t border-gray-50 pt-2 text-[8px] text-gray-400 sm:mt-5 sm:pt-4 sm:text-[10px]">
<div className="flex items-center gap-1.5">
<FiClock size={12} />
<span>Update: {getLastUpdateLabel(lastUpdate)}</span>
Expand Down
8 changes: 4 additions & 4 deletions src/components/dashboard/StatCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ interface StatCardProps {

export default function StatCard({ title, value, icon, textColor }: StatCardProps) {
return (
<div className="bg-white p-6 rounded-2xl border border-gray-100 shadow-sm flex flex-col justify-between h-32">
<div className="bg-white p-3 rounded-2xl border border-gray-100 shadow-sm flex flex-col justify-between h-24 sm:h-32 sm:p-6">
<div className="flex justify-between items-start">
<span className="text-gray-500 font-medium text-sm">{title}</span>
<span className="text-gray-500 font-medium text-xs sm:text-sm">{title}</span>
<div className={textColor}>
{icon}
</div>
</div>
<div className="mt-4">
<span className={`text-4xl font-bold ${textColor}`} suppressHydrationWarning>
<div className="mt-2 sm:mt-4">
<span className={`text-2xl font-bold ${textColor} sm:text-4xl`} suppressHydrationWarning>
{value}
</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/PageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface PageContainerProps {

export default function PageContainer({ children, className = '' }: PageContainerProps) {
return (
<div className={`mx-auto min-h-screen w-full max-w-[1440px] space-y-6 px-0 py-0 font-sans text-left sm:space-y-8 ${className}`}>
<div className={`mx-auto min-h-screen w-full max-w-[1440px] space-y-3 px-0 py-0 font-sans text-left sm:space-y-6 lg:space-y-8 ${className}`}>
{children}
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/layout/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode } from 'react';

Check warning on line 1 in src/components/layout/PageHeader.tsx

View workflow job for this annotation

GitHub Actions / test (20.x)

'ReactNode' is defined but never used

Check warning on line 1 in src/components/layout/PageHeader.tsx

View workflow job for this annotation

GitHub Actions / test (18.x)

'ReactNode' is defined but never used

interface PageHeaderProps {
title: string;
Expand All @@ -8,12 +8,12 @@

export default function PageHeader({ title, subtitle, className = '' }: PageHeaderProps) {
return (
<div className={`flex flex-col gap-1 ${className}`}>
<h1 className="text-2xl lg:text-3xl font-black text-gray-800 tracking-tight">
<div className={`flex flex-col gap-0.5 sm:gap-1 ${className}`}>
<h1 className="text-xl sm:text-2xl lg:text-3xl font-black text-gray-800 tracking-tight">
{title}
</h1>
{subtitle && (
<p className="text-sm text-gray-400">
<p className="text-xs text-gray-400 sm:text-sm">
{subtitle}
</p>
)}
Expand Down
49 changes: 22 additions & 27 deletions src/components/layout/navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,68 +34,63 @@
}, []);

return (
<header className="flex flex-col gap-4 px-4 py-4 sm:px-6 lg:h-20 lg:flex-row lg:items-center lg:justify-between lg:px-8">
<div className="flex items-center justify-between gap-3 lg:hidden">
<header className="grid grid-cols-[auto,1fr,auto] items-center gap-2 px-2 py-2 sm:gap-4 sm:px-5 sm:py-4 lg:h-20 lg:flex lg:flex-row lg:items-center lg:justify-between lg:px-8">
<div className="col-span-2 flex items-center justify-between gap-1.5 sm:gap-2">
<button
onClick={onMenuClick || (() => {})}
className="inline-flex h-10 w-10 items-center justify-center rounded-xl border border-gray-200 bg-white text-gray-700 shadow-sm transition hover:bg-gray-50"
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-gray-200 bg-white text-gray-700 shadow-sm transition hover:bg-gray-50 sm:h-10 sm:w-10 sm:rounded-xl"
aria-label="Buka menu"
>
<FiMenu />
</button>
<div className="min-w-0 flex-1 text-right">
<p className="truncate text-sm font-bold text-gray-800">{userName}</p>
<p className="text-xs capitalize text-gray-400">{userRole}</p>
<div className="flex items-center gap-4 text-gray-500">
<button onClick={handleBellClick} className="relative hover:text-emerald-500 cursor-pointer transition-colors group">
<FiBell size={20} />
{notificationCount > 0 && (
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[8px] w-4 h-4 flex items-center justify-center rounded-full border-2 border-[#F9FAFB] font-bold group-hover:bg-red-600 transition-colors">
{notificationCount > 9 ? "9+" : notificationCount}
</span>
)}
</button>
</div>
</div>

{/* Search Bar Group */}
<div className="relative w-full lg:max-w-2xl">
<div className="col-span-full row-start-2 relative w-full mt-1 sm:mt-0 lg:row-start-auto lg:col-span-auto lg:max-w-2xl">
{/* 2. Gunakan Conditional Rendering */}
{!shouldHideSearch ? (
<>
<span className="absolute inset-y-0 left-4 flex items-center text-gray-400">
<span className="absolute inset-y-0 left-3 flex items-center text-gray-400 sm:left-4">
<FiSearch />
</span>
<input
type="text"
placeholder="Search bins, locations..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full rounded-full border-none bg-white py-2.5 pl-12 pr-4 text-sm shadow-soft outline-none transition-all focus:ring-2 focus:ring-emerald-500"
className="w-full rounded-full border-none bg-white py-1.5 pl-9 pr-2 text-[11px] shadow-soft outline-none transition-all focus:ring-2 focus:ring-emerald-500 sm:py-2.5 sm:pl-12 sm:pr-4 sm:text-sm"
/>
</>
) : (
/* Bisa dikosongkan atau ganti jadi Breadcrumb/Judul Kecil */
<div className="h-10"></div>
<div className="h-9 sm:h-10"></div>
)}
</div>

{/* Sisi Kanan (Bell, Profile, dll) tetap muncul di semua page */}
{/* Right Side Icons & Profile */}
<div className="flex items-center justify-between gap-4 sm:justify-end lg:gap-6">
<div className="flex items-center gap-4 text-gray-500">
<button onClick={handleBellClick} className="relative hover:text-emerald-500 cursor-pointer transition-colors group">
<FiBell size={20} />
{notificationCount > 0 && (
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[8px] w-4 h-4 flex items-center justify-center rounded-full border-2 border-[#F9FAFB] font-bold group-hover:bg-red-600 transition-colors">
{notificationCount > 9 ? "9+" : notificationCount}
</span>
)}
</button>
</div>

<div className="col-start-3 row-start-1 flex items-center justify-end gap-1.5 sm:gap-4 lg:gap-6">
{/* User Profile */}
<div className="flex items-center gap-3 border-l pl-4 sm:pl-6 border-gray-200">
<div className="flex items-center gap-1.5 border-l pl-2 sm:gap-3 sm:pl-6 border-gray-200">
<button onClick={() => router.push("/profile")} className="flex items-center gap-3 hover:opacity-80 transition">
<div className="hidden text-right sm:block">
<p className="text-sm font-bold text-gray-800">{userName}</p>
<p className="text-xs text-gray-400 capitalize">{userRole}</p>
<p className="text-xs font-bold text-gray-800 sm:text-sm">{userName}</p>
<p className="text-[11px] text-gray-400 capitalize sm:text-xs">{userRole}</p>
</div>
{session?.user?.image ? (
<img src={session.user.image} alt="avatar" className="w-10 h-10 rounded-full object-cover border-2 border-white shadow-sm" />
<img src={session.user.image} alt="avatar" className="w-8 h-8 rounded-full object-cover border-2 border-white shadow-sm sm:h-10 sm:w-10" />

Check warning on line 91 in src/components/layout/navbar/index.tsx

View workflow job for this annotation

GitHub Actions / test (20.x)

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element

Check warning on line 91 in src/components/layout/navbar/index.tsx

View workflow job for this annotation

GitHub Actions / test (18.x)

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
) : (
<div className="w-10 h-10 bg-emerald-100 rounded-full flex items-center justify-center text-emerald-600 font-bold border-2 border-white shadow-sm">
<div className="w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center text-emerald-600 font-bold text-xs border-2 border-white shadow-sm sm:h-10 sm:w-10 sm:text-sm">
{(session?.user?.name || "").split(" ").map((n: string) => n[0]).slice(0,2).join("")}
</div>
)}
Expand Down
Loading
Loading