mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-05-14 08:14:28 +00:00
Merge branch 'main' into PRWLR-4393-Setup-NextAuth-client-session
This commit is contained in:
@@ -33,7 +33,7 @@ export const getErrorMessage = (error: unknown): string => {
|
||||
} else if (typeof error === "string") {
|
||||
message = error;
|
||||
} else {
|
||||
message = "Wops! Something when wrong.";
|
||||
message = "Oops! Something went wrong.";
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@ export const getErrorMessage = (error: unknown): string => {
|
||||
} else if (typeof error === "string") {
|
||||
message = error;
|
||||
} else {
|
||||
message = "Wops! Something when wrong.";
|
||||
message = "Oops! Something went wrong.";
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ export const getErrorMessage = (error: unknown): string => {
|
||||
} else if (typeof error === "string") {
|
||||
message = error;
|
||||
} else {
|
||||
message = "Wops! Something when wrong.";
|
||||
message = "Oops! Something went wrong.";
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { parseStringify } from "@/lib";
|
||||
|
||||
export const getUsers = async ({ page = 1 }) => {
|
||||
if (isNaN(Number(page)) || page < 1) redirect("/users");
|
||||
const keyServer = process.env.LOCAL_SITE_URL;
|
||||
|
||||
try {
|
||||
const users = await fetch(
|
||||
`${keyServer}/api/users?page%5Bnumber%5D=${page}`,
|
||||
);
|
||||
const data = await users.json();
|
||||
const parsedData = parseStringify(data);
|
||||
revalidatePath("/users");
|
||||
return parsedData;
|
||||
} catch (error) {
|
||||
console.error("Error fetching Users:", error);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const getErrorMessage = (error: unknown): string => {
|
||||
let message: string;
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else if (error && typeof error === "object" && "message" in error) {
|
||||
message = String(error.message);
|
||||
} else if (typeof error === "string") {
|
||||
message = error;
|
||||
} else {
|
||||
message = "Oops! Something went wrong.";
|
||||
}
|
||||
return message;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
|
||||
import { Header } from "@/components/ui";
|
||||
|
||||
export default async function Categories() {
|
||||
return (
|
||||
<>
|
||||
<Header title="Categories" icon="material-symbols:folder-open-outline" />
|
||||
<Spacer y={4} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import React from "react";
|
||||
|
||||
import { Header } from "@/components/ui";
|
||||
|
||||
export default function Integration() {
|
||||
export default function Integrations() {
|
||||
return (
|
||||
<>
|
||||
<Header title="Integration" icon="tabler:puzzle" />
|
||||
<Header title="Integrations" icon="tabler:puzzle" />
|
||||
|
||||
<p>Hi hi from Integration page</p>
|
||||
</>
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
import { redirect } from "next/navigation";
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { getUsers } from "@/actions/users";
|
||||
import { Header } from "@/components/ui";
|
||||
import {
|
||||
ColumnsUser,
|
||||
DataTableUser,
|
||||
SkeletonTableUser,
|
||||
} from "@/components/users";
|
||||
import { searchParamsProps } from "@/types";
|
||||
|
||||
export default async function Users({ searchParams }: searchParamsProps) {
|
||||
return (
|
||||
<>
|
||||
<Header title="User Management" icon="ci:users" />
|
||||
<Spacer y={4} />
|
||||
<div className="flex flex-col items-end w-full">
|
||||
<Spacer y={6} />
|
||||
<Suspense key={searchParams.page} fallback={<SkeletonTableUser />}>
|
||||
<SSRDataTable searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const SSRDataTable = async ({ searchParams }: searchParamsProps) => {
|
||||
const page = searchParams.page ? parseInt(searchParams.page) : 1;
|
||||
const usersData = await getUsers({ page });
|
||||
const [users] = await Promise.all([usersData]);
|
||||
|
||||
if (users?.errors) redirect("/users");
|
||||
|
||||
return (
|
||||
<DataTableUser
|
||||
columns={ColumnsUser}
|
||||
data={users?.users?.data ?? []}
|
||||
metadata={users?.meta}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
|
||||
import { Header } from "@/components/ui";
|
||||
|
||||
export default async function Workloads() {
|
||||
return (
|
||||
<>
|
||||
<Header title="Workloads" icon="lucide:tags" />
|
||||
<Spacer y={4} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import data from "../../../dataUsers.json";
|
||||
|
||||
export async function GET() {
|
||||
// Simulate fetching data with a delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
return NextResponse.json({ users: data });
|
||||
}
|
||||
@@ -126,12 +126,6 @@ export const sectionItems: SidebarItem[] = [
|
||||
// />
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
key: "services",
|
||||
href: "/services",
|
||||
icon: "material-symbols:linked-services-outline",
|
||||
title: "Services",
|
||||
},
|
||||
{
|
||||
key: "compliance",
|
||||
href: "/compliance",
|
||||
@@ -143,6 +137,24 @@ export const sectionItems: SidebarItem[] = [
|
||||
</Chip>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "services",
|
||||
href: "/services",
|
||||
icon: "material-symbols:linked-services-outline",
|
||||
title: "Services",
|
||||
},
|
||||
{
|
||||
key: "categories",
|
||||
href: "/categories",
|
||||
icon: "material-symbols:folder-open-outline",
|
||||
title: "Categories",
|
||||
},
|
||||
{
|
||||
key: "workloads",
|
||||
href: "/workloads",
|
||||
icon: "lucide:tags",
|
||||
title: "Workloads",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -190,10 +202,10 @@ export const sectionItems: SidebarItem[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "integration",
|
||||
href: "/integration",
|
||||
key: "integrations",
|
||||
href: "/integrations",
|
||||
icon: "tabler:puzzle",
|
||||
title: "Integration",
|
||||
title: "Integrations",
|
||||
},
|
||||
{
|
||||
key: "settings",
|
||||
@@ -213,9 +225,9 @@ export const sectionItemsWithTeams: SidebarItem[] = [
|
||||
items: [
|
||||
{
|
||||
key: "users",
|
||||
href: "#",
|
||||
href: "/users",
|
||||
title: "Users",
|
||||
startContent: <TeamAvatar name="Users page" />,
|
||||
icon: "ci:users",
|
||||
},
|
||||
{
|
||||
key: "roles",
|
||||
|
||||
@@ -7,7 +7,9 @@ type Status =
|
||||
| "cancelled"
|
||||
| "fail"
|
||||
| "success"
|
||||
| "muted";
|
||||
| "muted"
|
||||
| "active"
|
||||
| "inactive";
|
||||
|
||||
const statusColorMap: Record<
|
||||
Status,
|
||||
@@ -19,6 +21,8 @@ const statusColorMap: Record<
|
||||
fail: "danger",
|
||||
success: "success",
|
||||
muted: "default",
|
||||
active: "success",
|
||||
inactive: "default",
|
||||
};
|
||||
|
||||
export const StatusBadge = ({ status }: { status: Status }) => {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./table/ColumnsUser";
|
||||
export * from "./table/DataTableColumnHeader";
|
||||
export * from "./table/DataTablePagination";
|
||||
export * from "./table/DataTableUser";
|
||||
export * from "./table/SkeletonTableUser";
|
||||
@@ -0,0 +1,83 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { VerticalDotsIcon } from "@/components/icons";
|
||||
import { DateWithTime } from "@/components/providers";
|
||||
import { StatusBadge } from "@/components/ui";
|
||||
import { UserProps } from "@/types";
|
||||
|
||||
const getUserData = (row: { original: UserProps }) => {
|
||||
return row.original;
|
||||
};
|
||||
|
||||
export const ColumnsUser: ColumnDef<UserProps>[] = [
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: "Email",
|
||||
cell: ({ row }) => {
|
||||
const { email } = getUserData(row);
|
||||
return <p className="font-semibold">{email}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Name",
|
||||
cell: ({ row }) => {
|
||||
const { name } = getUserData(row);
|
||||
return <p className="font-semibold">{name}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "role",
|
||||
header: "Role",
|
||||
cell: ({ row }) => {
|
||||
const { role } = getUserData(row);
|
||||
return <p className="font-semibold">{role}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "added",
|
||||
header: "Added",
|
||||
cell: ({ row }) => {
|
||||
const { dateAdded } = getUserData(row);
|
||||
return <DateWithTime dateTime={dateAdded} showTime={false} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const { status } = getUserData(row);
|
||||
return <StatusBadge status={status} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "actions",
|
||||
header: () => <div className="text-right">Actions</div>,
|
||||
id: "actions",
|
||||
cell: () => {
|
||||
return (
|
||||
<div className="relative flex justify-end items-center gap-2">
|
||||
<Dropdown className="bg-background border-1 border-default-200">
|
||||
<DropdownTrigger>
|
||||
<Button isIconOnly radius="full" size="sm" variant="light">
|
||||
<VerticalDotsIcon className="text-default-400" />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu>
|
||||
<DropdownItem>Edit</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Button } from "@nextui-org/react";
|
||||
import { Column } from "@tanstack/react-table";
|
||||
import {
|
||||
ArrowDownIcon,
|
||||
ArrowUpIcon,
|
||||
ChevronsLeftRightIcon,
|
||||
} from "lucide-react";
|
||||
import { HTMLAttributes } from "react";
|
||||
|
||||
interface DataTableColumnHeaderProps<TData, TValue>
|
||||
extends HTMLAttributes<HTMLDivElement> {
|
||||
column: Column<TData, TValue>;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const DataTableColumnHeader = <TData, TValue>({
|
||||
column,
|
||||
title,
|
||||
className,
|
||||
}: DataTableColumnHeaderProps<TData, TValue>) => {
|
||||
const renderSortIcon = () => {
|
||||
const sort = column.getIsSorted();
|
||||
if (!sort) {
|
||||
return <ChevronsLeftRightIcon className="ml-2 h-4 w-4 rotate-90" />;
|
||||
}
|
||||
return sort === "desc" ? (
|
||||
<ArrowDownIcon className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowUpIcon className="ml-2 h-4 w-4" />
|
||||
);
|
||||
};
|
||||
|
||||
if (!column.getCanSort()) {
|
||||
return <div className={className}>{title}</div>;
|
||||
}
|
||||
return (
|
||||
<div className={className}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-8"
|
||||
onClick={column.getToggleSortingHandler()}
|
||||
>
|
||||
<span>{title}</span>
|
||||
{renderSortIcon()}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
DoubleArrowLeftIcon,
|
||||
DoubleArrowRightIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
|
||||
import { extractPaginationInfo } from "@/lib";
|
||||
import { MetaDataProps } from "@/types";
|
||||
|
||||
interface DataTablePaginationProps {
|
||||
pageSizeOptions?: number[];
|
||||
metadata?: MetaDataProps;
|
||||
}
|
||||
|
||||
export function DataTablePagination({ metadata }: DataTablePaginationProps) {
|
||||
if (!metadata) return null;
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const { currentPage, totalPages, totalEntries } =
|
||||
extractPaginationInfo(metadata);
|
||||
|
||||
const createPageUrl = (pageNumber: number | string) => {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
|
||||
if (pageNumber === "...") return `${pathname}?${params.toString()}`;
|
||||
|
||||
if (+pageNumber > totalPages) {
|
||||
return `${pathname}?${params.toString()}`;
|
||||
}
|
||||
|
||||
params.set("page", pageNumber.toString());
|
||||
return `${pathname}?${params.toString()}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col-reverse items-center justify-between gap-4 overflow-auto p-1 sm:flex-row sm:gap-8">
|
||||
<div className="whitespace-nowrap text-sm font-medium">
|
||||
{totalEntries} entries in Total.
|
||||
</div>
|
||||
<div className="flex flex-col-reverse items-center gap-4 sm:flex-row sm:gap-6 lg:gap-8">
|
||||
<div className="flex items-center justify-center text-sm font-medium">
|
||||
Page {currentPage} of {totalPages}
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Link
|
||||
aria-label="Go to first page"
|
||||
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
|
||||
href={createPageUrl(1)}
|
||||
aria-disabled="true"
|
||||
>
|
||||
<DoubleArrowLeftIcon className="size-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<Link
|
||||
aria-label="Go to previous page"
|
||||
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
|
||||
href={createPageUrl(currentPage - 1)}
|
||||
aria-disabled="true"
|
||||
>
|
||||
<ChevronLeftIcon className="size-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<Link
|
||||
aria-label="Go to next page"
|
||||
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
|
||||
href={createPageUrl(currentPage + 1)}
|
||||
>
|
||||
<ChevronRightIcon className="size-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<Link
|
||||
aria-label="Go to last page"
|
||||
className="page-link relative block py-1.5 px-3 border-0 bg-transparent outline-none transition-all duration-300 rounded text-gray-800 hover:text-gray-800 hover:bg-gray-200 focus:shadow-none"
|
||||
href={createPageUrl(totalPages)}
|
||||
>
|
||||
<DoubleArrowRightIcon className="size-4" aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataTablePagination } from "@/components/providers";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui";
|
||||
import { MetaDataProps } from "@/types";
|
||||
|
||||
interface DataTableUserProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
metadata?: MetaDataProps;
|
||||
}
|
||||
|
||||
export function DataTableUser<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
metadata,
|
||||
}: DataTableUserProps<TData, TValue>) {
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
enableSorting: true,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
state: {
|
||||
sorting,
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<div className="rounded-md border w-full">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex items-center w-full space-x-2 py-4">
|
||||
<DataTablePagination metadata={metadata} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableUser = () => {
|
||||
return (
|
||||
<Card className="w-full h-full space-y-5 p-4" radius="sm">
|
||||
{/* Table headers */}
|
||||
<div className="hidden md:flex justify-between">
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
{[...Array(10)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col md:flex-row justify-between items-center space-x-0 md:space-x-4"
|
||||
>
|
||||
<Skeleton className="w-full md:w-2/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-full md:w-2/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="hidden sm:flex md:w-2/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="hidden sm:flex md:w-2/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="hidden sm:flex md:w-2/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="hidden sm:flex md:w-1/12 rounded-lg mb-2 md:mb-0">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"links": {
|
||||
"first": "http://localhost:8080/api/v1/users?page%5Bnumber%5D=1",
|
||||
"last": "http://localhost:8080/api/v1/users?page%5Bnumber%5D=1",
|
||||
"next": null,
|
||||
"prev": null
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"id": "001",
|
||||
"email": "john.doe@example.com",
|
||||
"name": "John Doe",
|
||||
"role": "Admin",
|
||||
"dateAdded": "2024-08-14T10:00:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "002",
|
||||
"email": "jane.smith@example.com",
|
||||
"name": "Jane Smith",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-15T11:30:00.000000Z",
|
||||
"status": "inactive"
|
||||
},
|
||||
{
|
||||
"id": "003",
|
||||
"email": "will.johnson@example.com",
|
||||
"name": "Will Johnson",
|
||||
"role": "Admin",
|
||||
"dateAdded": "2024-08-16T09:15:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "004",
|
||||
"email": "emily.davis@example.com",
|
||||
"name": "Emily Davis",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-17T14:00:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "005",
|
||||
"email": "michael.brown@example.com",
|
||||
"name": "Michael Brown",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-18T08:45:00.000000Z",
|
||||
"status": "inactive"
|
||||
},
|
||||
{
|
||||
"id": "006",
|
||||
"email": "sarah.miller@example.com",
|
||||
"name": "Sarah Miller",
|
||||
"role": "Admin",
|
||||
"dateAdded": "2024-08-19T13:25:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "007",
|
||||
"email": "david.wilson@example.com",
|
||||
"name": "David Wilson",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-20T10:50:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "008",
|
||||
"email": "lisa.moore@example.com",
|
||||
"name": "Lisa Moore",
|
||||
"role": "Admin",
|
||||
"dateAdded": "2024-08-21T07:30:00.000000Z",
|
||||
"status": "inactive"
|
||||
},
|
||||
{
|
||||
"id": "009",
|
||||
"email": "james.taylor@example.com",
|
||||
"name": "James Taylor",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-22T12:10:00.000000Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "010",
|
||||
"email": "anna.anderson@example.com",
|
||||
"name": "Anna Anderson",
|
||||
"role": "User",
|
||||
"dateAdded": "2024-08-23T11:00:00.000000Z",
|
||||
"status": "inactive"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"count": 10
|
||||
},
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
@@ -80,3 +80,12 @@ export interface MetaDataProps {
|
||||
};
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface UserProps {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
role: string;
|
||||
dateAdded: string;
|
||||
status: "active" | "inactive";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user