Pull Request branch dev-clone to main #1
|
|
@ -30,7 +30,7 @@ interface User {
|
||||||
// image: "https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-5.png",
|
// image: "https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-5.png",
|
||||||
// };
|
// };
|
||||||
|
|
||||||
export default function AppHeader({toggle}: Props) {
|
export default function AppHeader({ toggle }: Props) {
|
||||||
const [userMenuOpened, setUserMenuOpened] = useState(false);
|
const [userMenuOpened, setUserMenuOpened] = useState(false);
|
||||||
|
|
||||||
const { user }: { user: User | null } = useAuth();
|
const { user }: { user: User | null } = useAuth();
|
||||||
|
|
@ -40,7 +40,7 @@ export default function AppHeader({toggle}: Props) {
|
||||||
// ));
|
// ));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="fixed top-0 left-0 w-full h-[60px] bg-white z-50 border">
|
<header className="fixed top-0 left-0 w-full h-16 bg-white z-50 border">
|
||||||
<div className="flex h-full justify-between w-full items-center">
|
<div className="flex h-full justify-between w-full items-center">
|
||||||
<Button
|
<Button
|
||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
|
|
@ -51,37 +51,36 @@ export default function AppHeader({toggle}: Props) {
|
||||||
|
|
||||||
<img src={logo} alt="" className="w-fit h-full px-8 py-5" />
|
<img src={logo} alt="" className="w-fit h-full px-8 py-5" />
|
||||||
|
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modal={false}
|
modal={false}
|
||||||
open={userMenuOpened}
|
open={userMenuOpened}
|
||||||
onOpenChange={setUserMenuOpened}
|
onOpenChange={setUserMenuOpened}
|
||||||
>
|
>
|
||||||
<DropdownMenuTrigger asChild className="flex">
|
<DropdownMenuTrigger asChild className="flex">
|
||||||
<button
|
<button
|
||||||
className={cx(classNames.user, {
|
className={cx(classNames.user, {
|
||||||
[classNames.userActive]: userMenuOpened,
|
[classNames.userActive]: userMenuOpened,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Avatar>
|
<Avatar>
|
||||||
{user?.photoProfile ? (
|
{user?.photoProfile ? (
|
||||||
<AvatarImage src={user.photoProfile} />
|
<AvatarImage src={user.photoProfile} />
|
||||||
) : (
|
) : (
|
||||||
<AvatarFallback>{user?.name?.charAt(0) ?? "A"}</AvatarFallback>
|
<AvatarFallback>{user?.name?.charAt(0) ?? "A"}</AvatarFallback>
|
||||||
)}
|
)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
align="end"
|
align="end"
|
||||||
className="transition-all duration-200 z-50 border bg-white"
|
className="transition-all duration-200 z-50 border bg-white w-64"
|
||||||
style={{ width: '260px' }}
|
|
||||||
>
|
>
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link to="/logout">Logout</Link>
|
<Link to="/logout">Logout</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import AppHeader from "./AppHeader";
|
||||||
*
|
*
|
||||||
* @returns A React element representing the application's navigation bar.
|
* @returns A React element representing the application's navigation bar.
|
||||||
*/
|
*/
|
||||||
export default function AppNavbar(){
|
export default function AppNavbar() {
|
||||||
// const {user} = useAuth();
|
// const {user} = useAuth();
|
||||||
|
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
|
@ -28,68 +28,60 @@ export default function AppNavbar(){
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ["sidebarData"],
|
queryKey: ["sidebarData"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await client.dashboard.getSidebarItems.$get();
|
const res = await client.dashboard.getSidebarItems.$get();
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
console.error("Error:", res.status, res.statusText);
|
console.error("Error:", res.status, res.statusText);
|
||||||
throw new Error("Error fetching sidebar data");
|
throw new Error("Error fetching sidebar data");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
if (window.innerWidth < 768) { // Ganti 768 dengan breakpoint mobile Anda
|
if (window.innerWidth < 768) { // Ganti 768 dengan breakpoint mobile Anda
|
||||||
setSidebarOpen(false);
|
setSidebarOpen(false);
|
||||||
} else {
|
} else {
|
||||||
setSidebarOpen(true);
|
setSidebarOpen(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
handleResize(); // Initial check
|
handleResize(); // Initial check
|
||||||
|
|
||||||
return () => window.removeEventListener('resize', handleResize);
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleMenuItemClick = () => {
|
const handleMenuItemClick = () => {
|
||||||
if (window.innerWidth < 768) {
|
if (window.innerWidth < 768) {
|
||||||
setSidebarOpen(false);
|
setSidebarOpen(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<AppHeader toggle={toggleSidebar} openNavbar={isSidebarOpen} />
|
<AppHeader toggle={toggleSidebar} openNavbar={isSidebarOpen} />
|
||||||
|
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<div
|
|
||||||
className={`fixed lg:relative w-64 bg-white top-[60px] left-0 h-full z-40 px-3 py-4 transition-transform border-x
|
|
||||||
${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`}
|
|
||||||
>
|
|
||||||
<ScrollArea className="flex flex-1 h-full">
|
|
||||||
{data?.map((menu, i) => (
|
|
||||||
<MenuItem
|
|
||||||
key={i}
|
|
||||||
menu={menu}
|
|
||||||
isActive={pathname === menu.link}
|
|
||||||
onClick={handleMenuItemClick}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</ScrollArea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Overlay to close sidebar on mobile */}
|
|
||||||
{isSidebarOpen && (
|
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black bg-opacity-50 z-30 hidden lg:visible"
|
className={`fixed lg:relative w-64 bg-white top-16 left-0 h-full z-40 px-3 py-4 transition-transform border-x
|
||||||
onClick={toggleSidebar}
|
${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`}
|
||||||
/>
|
>
|
||||||
)}
|
<ScrollArea className="flex flex-1 h-full">
|
||||||
</div>
|
{data?.map((menu, i) => (
|
||||||
|
<MenuItem
|
||||||
|
key={i}
|
||||||
|
menu={menu}
|
||||||
|
isActive={pathname === menu.link}
|
||||||
|
onClick={handleMenuItemClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,15 @@ interface Props<TData> {
|
||||||
|
|
||||||
export default function DashboardTable<T>({ table }: Props<T>) {
|
export default function DashboardTable<T>({ table }: Props<T>) {
|
||||||
return (
|
return (
|
||||||
<ScrollArea className="w-full max-w-full">
|
<div className="w-full max-w-full overflow-x-auto border rounded-lg">
|
||||||
<Table className="min-w-full divide-y divide-gray-200">
|
<Table className="min-w-full divide-y divide-muted-foreground bg-white">
|
||||||
<TableHeader className="bg-gray-50">
|
<TableHeader>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<TableRow key={headerGroup.id}>
|
<TableRow key={headerGroup.id}>
|
||||||
{headerGroup.headers.map((header) => (
|
{headerGroup.headers.map((header) => (
|
||||||
<TableHead
|
<TableHead
|
||||||
key={header.id}
|
key={header.id}
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
className="px-6 py-3 text-left text-sm font-medium text-muted-foreground"
|
||||||
style={{
|
style={{
|
||||||
maxWidth: `${header.column.columnDef.maxSize}px`,
|
maxWidth: `${header.column.columnDef.maxSize}px`,
|
||||||
width: `${header.getSize()}`,
|
width: `${header.getSize()}`,
|
||||||
|
|
@ -38,14 +38,14 @@ export default function DashboardTable<T>({ table }: Props<T>) {
|
||||||
))}
|
))}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
|
|
||||||
<TableBody className="bg-white divide-y divide-gray-200">
|
<TableBody>
|
||||||
{table.getRowModel().rows.length > 0 ? (
|
{table.getRowModel().rows.length > 0 ? (
|
||||||
table.getRowModel().rows.map((row) => (
|
table.getRowModel().rows.map((row) => (
|
||||||
<TableRow key={row.id}>
|
<TableRow key={row.id}>
|
||||||
{row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
<TableCell
|
<TableCell
|
||||||
key={cell.id}
|
key={cell.id}
|
||||||
className="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
|
className="px-6 py-4 whitespace-nowrap text-sm text-black"
|
||||||
style={{
|
style={{
|
||||||
maxWidth: `${cell.column.columnDef.maxSize}px`,
|
maxWidth: `${cell.column.columnDef.maxSize}px`,
|
||||||
}}
|
}}
|
||||||
|
|
@ -64,6 +64,6 @@ export default function DashboardTable<T>({ table }: Props<T>) {
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</ScrollArea>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import {
|
||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious,
|
||||||
} from "@/shadcn/components/ui/pagination"
|
} from "@/shadcn/components/ui/pagination"
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -82,7 +82,7 @@ const createCreateButton = (
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex bg-white w-full text-black border items-center justify-center hover:bg-muted-foreground hover:text-white"
|
className="flex bg-white w-full text-black border items-center justify-center hover:bg-muted-foreground hover:text-white"
|
||||||
onClick={() => navigate({ to: `${window.location.pathname}`, search: { create: true } })}
|
onClick={() => navigate({ to: `${window.location.pathname}`, search: { create: true } })}
|
||||||
>
|
>
|
||||||
|
|
@ -96,15 +96,15 @@ const createCreateButton = (
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex bg-white w-full text-black border items-center justify-between hover:bg-muted-foreground hover:text-white"
|
className="flex bg-white w-full text-black border items-center justify-between hover:bg-muted-foreground hover:text-white"
|
||||||
onClick={() => navigate({ to: `${window.location.pathname}`, search: { create: true } })}
|
onClick={() => navigate({ to: `${window.location.pathname}`, search: { create: true } })}
|
||||||
>
|
>
|
||||||
<span className="flex items-center justify-between gap-2">
|
<span className="flex items-center justify-between gap-2">
|
||||||
{property}
|
{property}
|
||||||
<TbPlus />
|
<TbPlus />
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return property;
|
return property;
|
||||||
|
|
@ -122,64 +122,62 @@ const CustomPagination = ({
|
||||||
totalPages,
|
totalPages,
|
||||||
onPageChange,
|
onPageChange,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
}: {
|
}: {
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
onPageChange: (page: number) => void;
|
onPageChange: (page: number) => void;
|
||||||
hasNextPage: boolean;
|
hasNextPage: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Pagination>
|
<Pagination>
|
||||||
<PaginationContent>
|
<PaginationContent>
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationPrevious
|
<PaginationPrevious
|
||||||
onClick={() => onPageChange(currentPage - 1)}
|
onClick={() => onPageChange(currentPage - 1)}
|
||||||
className={`${
|
className={`${currentPage === 1
|
||||||
currentPage === 1
|
? 'bg-white text-muted-foreground cursor-not-allowed'
|
||||||
? 'bg-white text-muted-foreground cursor-not-allowed'
|
: 'bg-white text-black hover:bg-muted hover:text-black'
|
||||||
: 'bg-white text-black hover:bg-muted hover:text-black'
|
}`}
|
||||||
}`}
|
aria-disabled={currentPage === 1}
|
||||||
aria-disabled={currentPage === 1}
|
>
|
||||||
>
|
Previous
|
||||||
Previous
|
</PaginationPrevious>
|
||||||
</PaginationPrevious>
|
</PaginationItem>
|
||||||
</PaginationItem>
|
|
||||||
|
{Array.from({ length: totalPages }, (_, index) => index + 1).map((page) => (
|
||||||
{Array.from({ length: totalPages }, (_, index) => index + 1).map((page) => (
|
<PaginationItem key={page}>
|
||||||
<PaginationItem key={page}>
|
<PaginationLink
|
||||||
<PaginationLink
|
href="#"
|
||||||
href="#"
|
onClick={() => onPageChange(page)}
|
||||||
onClick={() => onPageChange(page)}
|
className={page === currentPage ? 'border text-black' : ''}
|
||||||
className={page === currentPage ? 'border text-black' : ''}
|
>
|
||||||
>
|
{page}
|
||||||
{page}
|
</PaginationLink>
|
||||||
</PaginationLink>
|
</PaginationItem>
|
||||||
</PaginationItem>
|
))}
|
||||||
))}
|
|
||||||
|
{totalPages > 1 && currentPage < totalPages && (
|
||||||
{totalPages > 1 && currentPage < totalPages && (
|
<PaginationItem>
|
||||||
<PaginationItem>
|
<PaginationEllipsis />
|
||||||
<PaginationEllipsis />
|
</PaginationItem>
|
||||||
</PaginationItem>
|
)}
|
||||||
)}
|
|
||||||
|
<PaginationItem>
|
||||||
<PaginationItem>
|
<PaginationNext
|
||||||
<PaginationNext
|
onClick={() => onPageChange(currentPage + 1)}
|
||||||
onClick={() => onPageChange(currentPage + 1)}
|
className={`${!hasNextPage || currentPage === totalPages
|
||||||
className={`${
|
? 'bg-white text-muted-foreground cursor-not-allowed'
|
||||||
!hasNextPage || currentPage === totalPages
|
: 'bg-white text-black hover:bg-muted hover:text-black'
|
||||||
? 'bg-white text-muted-foreground cursor-not-allowed'
|
}`}
|
||||||
: 'bg-white text-black hover:bg-muted hover:text-black'
|
aria-disabled={!hasNextPage || currentPage === totalPages}
|
||||||
}`}
|
>
|
||||||
aria-disabled={!hasNextPage || currentPage === totalPages}
|
Next
|
||||||
>
|
</PaginationNext>
|
||||||
Next
|
</PaginationItem>
|
||||||
</PaginationNext>
|
</PaginationContent>
|
||||||
</PaginationItem>
|
</Pagination>
|
||||||
</PaginationContent>
|
|
||||||
</Pagination>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PageTemplate component for displaying a paginated table with search and filter functionality.
|
* PageTemplate component for displaying a paginated table with search and filter functionality.
|
||||||
|
|
@ -204,10 +202,10 @@ export default function PageTemplate<
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
...(typeof props.queryOptions === "function"
|
...(typeof props.queryOptions === "function"
|
||||||
? props.queryOptions(
|
? props.queryOptions(
|
||||||
filterOptions.page,
|
filterOptions.page,
|
||||||
filterOptions.limit,
|
filterOptions.limit,
|
||||||
filterOptions.q
|
filterOptions.q
|
||||||
)
|
)
|
||||||
: props.queryOptions),
|
: props.queryOptions),
|
||||||
placeholderData: keepPreviousData,
|
placeholderData: keepPreviousData,
|
||||||
});
|
});
|
||||||
|
|
@ -218,8 +216,8 @@ export default function PageTemplate<
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
defaultColumn: {
|
defaultColumn: {
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<span className="text-base font-medium text-gray-700">
|
<span className="text-base font-medium text-muted-foreground">
|
||||||
{props.getValue() as ReactNode}
|
{props.getValue() as ReactNode}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -245,45 +243,41 @@ export default function PageTemplate<
|
||||||
*/
|
*/
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page: number) => {
|
||||||
if (page >= 1 && page <= (query.data?._metadata.totalPages ?? 1)) {
|
if (page >= 1 && page <= (query.data?._metadata.totalPages ?? 1)) {
|
||||||
setFilterOptions((prev) => ({
|
setFilterOptions((prev) => ({
|
||||||
page: page - 1, // Adjust for zero-based index
|
page: page - 1, // Adjust for zero-based index
|
||||||
limit: prev.limit,
|
limit: prev.limit,
|
||||||
q: prev.q,
|
q: prev.q,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default values when query.data is undefined
|
// Default values when query.data is undefined
|
||||||
const totalPages = query.data?._metadata.totalPages ?? 1;
|
const totalPages = query.data?._metadata.totalPages ?? 1;
|
||||||
const hasNextPage = query.data
|
const hasNextPage = query.data
|
||||||
? filterOptions.page < totalPages - 1
|
? filterOptions.page < totalPages - 1
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col space-y-4">
|
<div className="flex flex-col space-y-4">
|
||||||
<h1 className="text-2xl font-bold">{props.title}</h1>
|
<h1 className="text-2xl font-bold">{props.title}</h1>
|
||||||
<Card className="p-4 border-hidden">
|
<Card className="p-4 border-hidden">
|
||||||
{/* Top Section */}
|
|
||||||
|
|
||||||
|
|
||||||
{/* Table Functionality */}
|
{/* Table Functionality */}
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
{/* Search and Create Button */}
|
{/* Search and Create Button */}
|
||||||
<div className="flex flex-col md:flex-row lg:flex-row pb-4 justify-between">
|
<div className="flex flex-col md:flex-row lg:flex-row pb-4 justify-between">
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<TbSearch
|
<TbSearch
|
||||||
className="absolute top-1/2 left-3 transform -translate-y-1/2 text-gray-500"
|
className="absolute top-1/2 left-3 transform -translate-y-1/2 text-muted-foreground pointer-events-none"
|
||||||
style={{ pointerEvents: 'none' }} // Ensure the icon doesn't capture click events
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
className="w-full max-w-xs pl-10"
|
||||||
className="w-full max-w-xs pl-10"
|
value={filterOptions.q}
|
||||||
value={filterOptions.q}
|
onChange={(e) =>
|
||||||
onChange={(e) =>
|
handleSearchQueryChange(e.target.value)
|
||||||
handleSearchQueryChange(e.target.value)
|
}
|
||||||
}
|
placeholder="Search..."
|
||||||
placeholder="Search..."
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{createCreateButton(props.createButton)}
|
{createCreateButton(props.createButton)}
|
||||||
|
|
@ -300,27 +294,27 @@ export default function PageTemplate<
|
||||||
<label className="block text-sm font-medium text-muted-foreground">Per Page</label>
|
<label className="block text-sm font-medium text-muted-foreground">Per Page</label>
|
||||||
<Select
|
<Select
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setFilterOptions((prev) => ({
|
setFilterOptions((prev) => ({
|
||||||
page: prev.page,
|
page: prev.page,
|
||||||
limit: parseInt(value ?? "10"),
|
limit: parseInt(value ?? "10"),
|
||||||
q: prev.q,
|
q: prev.q,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
defaultValue="10"
|
defaultValue="10"
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-fit p-4 gap-4">
|
<SelectTrigger className="w-fit p-4 gap-4">
|
||||||
<SelectValue placeholder="Per Page" />
|
<SelectValue placeholder="Per Page" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="5">5</SelectItem>
|
<SelectItem value="5">5</SelectItem>
|
||||||
<SelectItem value="10">10</SelectItem>
|
<SelectItem value="10">10</SelectItem>
|
||||||
<SelectItem value="50">50</SelectItem>
|
<SelectItem value="50">50</SelectItem>
|
||||||
<SelectItem value="100">100</SelectItem>
|
<SelectItem value="100">100</SelectItem>
|
||||||
<SelectItem value="500">500</SelectItem>
|
<SelectItem value="500">500</SelectItem>
|
||||||
<SelectItem value="1000">1000</SelectItem>
|
<SelectItem value="1000">1000</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<CustomPagination
|
<CustomPagination
|
||||||
currentPage={filterOptions.page + 1}
|
currentPage={filterOptions.page + 1}
|
||||||
totalPages={totalPages}
|
totalPages={totalPages}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { Navigate, Outlet, createFileRoute } from "@tanstack/react-router";
|
import { Navigate, Outlet, createFileRoute } from "@tanstack/react-router";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
|
||||||
import AppHeader from "../components/AppHeader";
|
import AppHeader from "../components/AppHeader";
|
||||||
import AppNavbar from "../components/AppNavbar";
|
import AppNavbar from "../components/AppNavbar";
|
||||||
import useAuth from "@/hooks/useAuth";
|
import useAuth from "@/hooks/useAuth";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import fetchRPC from "@/utils/fetchRPC";
|
import fetchRPC from "@/utils/fetchRPC";
|
||||||
import client from "@/honoClient";
|
import client from "@/honoClient";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
export const Route = createFileRoute("/_dashboardLayout")({
|
export const Route = createFileRoute("/_dashboardLayout")({
|
||||||
component: DashboardLayout,
|
component: DashboardLayout,
|
||||||
|
|
@ -38,7 +38,10 @@ function DashboardLayout() {
|
||||||
enabled: isAuthenticated,
|
enabled: isAuthenticated,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [openNavbar, { toggle }] = useDisclosure(false);
|
const [openNavbar, setNavbarOpen] = useState(true);
|
||||||
|
const toggle = () => {
|
||||||
|
setNavbarOpen(!openNavbar);
|
||||||
|
};
|
||||||
|
|
||||||
return isAuthenticated ? (
|
return isAuthenticated ? (
|
||||||
<div className="flex flex-col h-screen">
|
<div className="flex flex-col h-screen">
|
||||||
|
|
@ -51,9 +54,7 @@ function DashboardLayout() {
|
||||||
<AppNavbar />
|
<AppNavbar />
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<main className={`flex-1 mt-[60px] p-6 bg-white overflow-auto ${
|
<main className={"flex-1 mt-16 p-6 bg-white overflow-auto"}>
|
||||||
openNavbar ? 'lg:ml-64' : 'lg:ml-0'
|
|
||||||
}`}>
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user