diff --git a/apps/core/app/dashboard/products/_components/table/product-table-head.tsx b/apps/core/app/dashboard/products/_components/table/product-table-head.tsx
new file mode 100644
index 00000000..1f173328
--- /dev/null
+++ b/apps/core/app/dashboard/products/_components/table/product-table-head.tsx
@@ -0,0 +1,31 @@
+import { Table, TableBody, TableHeader } from "@repo/ui/components/table";
+import { ProdcutTableHead } from "./product-table-head/product-table-head";
+import { ProductTableRow } from "./product-table-row/product-table-row";
+import { ProductTablePages } from "./product-table-pages/product-table-pages";
+
+const ProductTable = () => {
+ return (
+ <>
+
+
+ >
+ );
+};
+export { ProductTable };
diff --git a/apps/core/app/dashboard/products/_components/table/product-table-head/product-table-head.tsx b/apps/core/app/dashboard/products/_components/table/product-table-head/product-table-head.tsx
new file mode 100644
index 00000000..4957240a
--- /dev/null
+++ b/apps/core/app/dashboard/products/_components/table/product-table-head/product-table-head.tsx
@@ -0,0 +1,46 @@
+import { TableHead, TableRow } from "@repo/ui/components/table";
+import Typography from "@repo/ui/components/typography";
+
+const ProdcutTableHead = () => {
+ return (
+
+
+
+ #
+
+
+
+
+ Product Name
+
+
+
+
+ Status
+
+
+
+
+ Sales
+
+
+
+
+ Version
+
+
+
+
+ Earining
+
+
+
+
+ Actions
+
+
+
+ );
+};
+
+export { ProdcutTableHead };
diff --git a/apps/core/app/dashboard/products/_components/table/product-table-pages/product-table-pages.tsx b/apps/core/app/dashboard/products/_components/table/product-table-pages/product-table-pages.tsx
new file mode 100644
index 00000000..fb70f8d8
--- /dev/null
+++ b/apps/core/app/dashboard/products/_components/table/product-table-pages/product-table-pages.tsx
@@ -0,0 +1,53 @@
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@repo/ui/components/select";
+import Typography from "@repo/ui/components/typography";
+import { useState } from "react";
+
+interface ProductTablePageProps {
+ page?: number;
+ limit: number;
+ total: number;
+ onChange?: (pageNum: string) => void;
+}
+
+const ProductTablePages = (props: ProductTablePageProps) => {
+ const { page = 1, total, limit, onChange } = props;
+ const [selectPage, setSelectPage] = useState(String(page));
+ const getPages = () => {
+ const pages: number[] = [];
+ for (let i = 1; i <= Math.floor(total / limit); i++) {
+ pages.push(i);
+ }
+ return pages;
+ };
+ return total === 0 ? null : (
+
+
+ Page
+
+
+ Of {total}
+
+ );
+};
+export { ProductTablePages };
diff --git a/apps/core/app/dashboard/products/_components/table/product-table-row/product-table-row.tsx b/apps/core/app/dashboard/products/_components/table/product-table-row/product-table-row.tsx
new file mode 100644
index 00000000..15006b29
--- /dev/null
+++ b/apps/core/app/dashboard/products/_components/table/product-table-row/product-table-row.tsx
@@ -0,0 +1,117 @@
+import Image from "next/image";
+import IconHeart from "@repo/icons/heart";
+import MessegeIcon from "@repo/icons/message";
+import { TableCell, TableRow } from "@repo/ui/components/table";
+import Typography from "@repo/ui/components/typography";
+import { Badge } from "@repo/ui/components/badge";
+import DotsVerticalIcon from "@repo/icons/dotsVertical";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@repo/ui/components/dropdown-menu";
+
+interface ProductTableRowProps {
+ rowIndex: number;
+ imgSrc?: string;
+ productName: string;
+ likes?: number;
+ comments?: number;
+ status: string;
+ sales: number;
+ version: string;
+ earning: string;
+ totalPrice: string;
+}
+
+const ProductTableRow = (props: ProductTableRowProps) => {
+ const {
+ rowIndex,
+ imgSrc = "/images/product-placeholder.jpg",
+ productName,
+ status,
+ sales,
+ version,
+ earning,
+ likes,
+ comments,
+ totalPrice,
+ } = props;
+ // Crypite - Saas Crypto Currency website design
+ return (
+
+
+ {rowIndex}
+
+
+
+
+
+
+
+
+ {productName}
+
+
+
+
+ {likes || 0}
+
+
+
+ {comments || 0}
+
+
+
+
+
+
+
+ {status}
+
+
+
+
+ {sales}
+ ({totalPrice})
+
+
+
+ {version}
+
+ {earning}
+
+
+
+
+
+
+
+
+ {}} className="cursor-pointer">
+ Edit
+
+ {}} className="cursor-pointer">
+ View product
+
+ {}} className="cursor-pointer">
+
+ Delete
+
+
+
+
+
+
+ );
+};
+
+export { ProductTableRow };
diff --git a/apps/core/app/dashboard/products/_components/tabs/product-tabs.tsx b/apps/core/app/dashboard/products/_components/tabs/product-tabs.tsx
new file mode 100644
index 00000000..f6b1d087
--- /dev/null
+++ b/apps/core/app/dashboard/products/_components/tabs/product-tabs.tsx
@@ -0,0 +1,35 @@
+"use client";
+import { Tabs, TabsList, TabsTrigger } from "@repo/ui/components/tabs";
+import Typography from "@repo/ui/components/typography";
+import { Dispatch, SetStateAction } from "react";
+
+interface ProductTabsProps {
+ tabs: { value: string; label: string }[];
+ setProductTab: Dispatch>;
+}
+
+const ProductTabs = (props: ProductTabsProps) => {
+ const { tabs, setProductTab } = props;
+ const handleValueChange = (value: string) => {
+ setProductTab(value);
+ };
+
+ return (
+
+
+ {tabs.map((tab, index) => (
+
+
+ {tab.label}
+
+ ))}
+
+
+ );
+};
+
+export { ProductTabs };
diff --git a/apps/core/app/dashboard/products/page.tsx b/apps/core/app/dashboard/products/page.tsx
new file mode 100644
index 00000000..440e4f5e
--- /dev/null
+++ b/apps/core/app/dashboard/products/page.tsx
@@ -0,0 +1,33 @@
+"use client";
+import CirclePlusIcon from "@repo/icons/circle-plus";
+import { Button } from "@repo/ui/components/button";
+import Typography from "@repo/ui/components/typography";
+import { useState } from "react";
+import { ProductTabs } from "./_components/tabs/product-tabs";
+import { ProductTable } from "./_components/table/product-table-head";
+
+const tabs = [
+ { value: "all", label: "Products" },
+ { value: "drafts", label: "Drafts" },
+];
+
+const ProductsListPage = () => {
+ const [productTab, setProductTab] = useState(tabs[0]?.value || "");
+
+ return (
+
+ );
+};
+export default ProductsListPage;
diff --git a/packages/apis/src/services/core/shop/products/get/get-shop-product-list.schema.ts b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.schema.ts
new file mode 100644
index 00000000..036cd236
--- /dev/null
+++ b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.schema.ts
@@ -0,0 +1,98 @@
+import { apiResponseSchema } from "#schema/api-response-schema";
+import { z } from "zod";
+
+// Request
+export const getShopProductListRequestSchemaTransformed = z
+ .object({
+ page: z.number(),
+ pageSize: z.number(),
+ })
+ .transform((data) => ({ ...data, page_size: data.pageSize }));
+
+// Response
+export const getShopProductListResponseSchemaTransofrmed = apiResponseSchema
+ .extend({
+ data: z.object({
+ count: z.number(),
+ next: z.string(),
+ previous: z.string(),
+ results: z.array(
+ z.object({
+ id: z.number(),
+ is_published: z.boolean(),
+ created_at: z.date(),
+ created_by: z.object({
+ username: z.string(),
+ email: z.string(),
+ }),
+ versions: z.array(
+ z.object({
+ id: z.number(),
+ version: z.string(),
+ notes: z.string(),
+ name: z.string(),
+ blurb: z.string(),
+ description: z.string(),
+ live_preview: z.string(),
+ embed: z.string(),
+ price: z.string(),
+ highlights: z.object({}),
+ discount: z.number(),
+ tags: z.array(
+ z.object({
+ id: z.number(),
+ title: z.string(),
+ }),
+ ),
+ file_formats: z.array(
+ z.object({
+ id: z.number(),
+ name: z.string(),
+ icon: z.string(),
+ }),
+ ),
+ images: z.array(
+ z.object({
+ id: z.number(),
+ file: z.string(),
+ extension: z.string(),
+ mimetype: z.string(),
+ created_at: z.string(),
+ }),
+ ),
+ previews: z.array(
+ z.object({
+ id: z.number(),
+ file: z.string(),
+ extension: z.string(),
+ mimetype: z.string(),
+ created_at: z.string(),
+ }),
+ ),
+ thumbnail: z.object({
+ id: z.number(),
+ file: z.string(),
+ extension: z.string(),
+ mimetype: z.string(),
+ created_at: z.string(),
+ }),
+ file: z.object({
+ id: z.number(),
+ file: z.string(),
+ extension: z.string(),
+ mimetype: z.string(),
+ created_at: z.string(),
+ }),
+ active: z.boolean(),
+ }),
+ ),
+ }),
+ ),
+ }),
+ })
+ .transform((data) => data);
+
+export const getShopProductListSchema = {
+ response: getShopProductListResponseSchemaTransofrmed,
+ request: getShopProductListRequestSchemaTransformed,
+};
diff --git a/packages/apis/src/services/core/shop/products/get/get-shop-product-list.ts b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.ts
new file mode 100644
index 00000000..797a53b5
--- /dev/null
+++ b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.ts
@@ -0,0 +1,32 @@
+import { coreApi } from "#instance/core-api";
+import path from "path";
+import { ApiResponse } from "@repo/apis/types/api.types";
+import { requestHandler } from "@repo/apis/utils/request-handler";
+import { getShopProductListSchema as schema } from "./get-shop-product-list.schema";
+import {
+ GetShopProductListRequest,
+ GetShopProductListResponse,
+ GetShopProductListResponseTransformed,
+} from "./get-shop-product-list.types";
+
+const getShopProductListURL = () => path.join("/shop/products/");
+
+export const getShopProductList = async (
+ props: GetShopProductListRequest,
+): Promise> => {
+ const payloadParsed = schema.request.parse(props);
+ const URL = getShopProductListURL();
+
+ const response = await requestHandler(
+ () =>
+ coreApi.get(URL, { params: payloadParsed }),
+ schema.response._def.schema,
+ {
+ isMock: false,
+ },
+ );
+
+ const dataParsed = schema.response.parse(response.data);
+
+ return { ...response, data: dataParsed };
+};
diff --git a/packages/apis/src/services/core/shop/products/get/get-shop-product-list.types.ts b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.types.ts
new file mode 100644
index 00000000..090d354c
--- /dev/null
+++ b/packages/apis/src/services/core/shop/products/get/get-shop-product-list.types.ts
@@ -0,0 +1,16 @@
+import { z } from "zod";
+import { getShopProductListSchema } from "./get-shop-product-list.schema";
+
+// Response
+export type GetShopProductListRequest = z.input;
+
+export type GetShopProductListRequestTransofrmed = z.infer<
+ typeof getShopProductListSchema.request
+>;
+
+// Request
+export type GetShopProductListResponse = z.input;
+
+export type GetShopProductListResponseTransformed = z.infer<
+ typeof getShopProductListSchema.response
+>;
diff --git a/packages/apis/src/services/core/shop/products/get/use-get-shop-product-list.ts b/packages/apis/src/services/core/shop/products/get/use-get-shop-product-list.ts
new file mode 100644
index 00000000..b25ff1e8
--- /dev/null
+++ b/packages/apis/src/services/core/shop/products/get/use-get-shop-product-list.ts
@@ -0,0 +1,31 @@
+import {
+ ApiError,
+ ApiResponse,
+ UseQueryProps,
+ WithParams,
+} from "@repo/apis/types/api.types";
+import { useQuery } from "@tanstack/react-query";
+import { getShopProductList } from "./get-shop-product-list";
+import {
+ GetShopProductListRequest,
+ GetShopProductListResponseTransformed,
+} from "./get-shop-product-list.types";
+
+export type UseGetShopProductListProps = UseQueryProps<
+ ApiResponse,
+ WithParams
+>;
+
+export const getShopProductListQueryKey = () => ["getShopProductList"];
+
+export const UseGetShopProductList = (props: UseGetShopProductListProps) => {
+ const { params, ...resProps } = props;
+
+ const query = useQuery, ApiError>({
+ queryKey: getShopProductListQueryKey(),
+ queryFn: () => getShopProductList(params),
+ ...resProps,
+ });
+
+ return query;
+};
diff --git a/packages/icons/src/components/circle-plus.tsx b/packages/icons/src/components/circle-plus.tsx
new file mode 100644
index 00000000..411116c7
--- /dev/null
+++ b/packages/icons/src/components/circle-plus.tsx
@@ -0,0 +1,25 @@
+import { IconProps } from "../types/types";
+const CirclePlusIcon = (props: IconProps) => {
+ const { size = 24, color = "currentColor", ...resProps } = props;
+
+ return (
+
+ );
+};
+
+export default CirclePlusIcon;
diff --git a/packages/icons/src/components/dotsVertical.tsx b/packages/icons/src/components/dotsVertical.tsx
new file mode 100644
index 00000000..21ab118e
--- /dev/null
+++ b/packages/icons/src/components/dotsVertical.tsx
@@ -0,0 +1,39 @@
+import { IconProps } from "../types/types";
+const DotsVerticalIcon = (props: IconProps) => {
+ const { size = 25, color = "currentColor", ...resProps } = props;
+
+ return (
+
+ );
+};
+
+export default DotsVerticalIcon;
diff --git a/packages/icons/src/components/message.tsx b/packages/icons/src/components/message.tsx
new file mode 100644
index 00000000..fd891e44
--- /dev/null
+++ b/packages/icons/src/components/message.tsx
@@ -0,0 +1,25 @@
+import { IconProps } from "../types/types";
+
+const MessegeIcon = (props: IconProps) => {
+ const { size = 20, color = "currentColor", ...resProps } = props;
+
+ return (
+
+ );
+};
+
+export default MessegeIcon;
diff --git a/packages/ui/src/components/atoms/table.tsx b/packages/ui/src/components/atoms/table.tsx
new file mode 100644
index 00000000..aac2ee9c
--- /dev/null
+++ b/packages/ui/src/components/atoms/table.tsx
@@ -0,0 +1,117 @@
+import * as React from "react";
+
+import { cn } from "@repo/ui/lib/utils";
+
+const Table = React.forwardRef<
+ HTMLTableElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+Table.displayName = "Table";
+
+const TableHeader = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableHeader.displayName = "TableHeader";
+
+const TableBody = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableBody.displayName = "TableBody";
+
+const TableFooter = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+ tr]:last:border-b-0",
+ className,
+ )}
+ {...props}
+ />
+));
+TableFooter.displayName = "TableFooter";
+
+const TableRow = React.forwardRef<
+ HTMLTableRowElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableRow.displayName = "TableRow";
+
+const TableHead = React.forwardRef<
+ HTMLTableCellElement,
+ React.ThHTMLAttributes
+>(({ className, ...props }, ref) => (
+ |
+));
+TableHead.displayName = "TableHead";
+
+const TableCell = React.forwardRef<
+ HTMLTableCellElement,
+ React.TdHTMLAttributes
+>(({ className, ...props }, ref) => (
+ |
+));
+TableCell.displayName = "TableCell";
+
+const TableCaption = React.forwardRef<
+ HTMLTableCaptionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableCaption.displayName = "TableCaption";
+
+export {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+};