diff --git a/apps/cms/src/@types/Product.ts b/apps/cms/src/@types/Product.ts new file mode 100644 index 00000000..d5fe3e74 --- /dev/null +++ b/apps/cms/src/@types/Product.ts @@ -0,0 +1,10 @@ +export class Product { + constructor( + public id = '', + public name = '', + public colors= '', + public sizes = '', + public price = '', + public category = '' + ) { } +} \ No newline at end of file diff --git a/apps/cms/src/admin/views/MerchProducts.tsx b/apps/cms/src/admin/views/MerchProducts.tsx index c06a44f9..8b09b768 100644 --- a/apps/cms/src/admin/views/MerchProducts.tsx +++ b/apps/cms/src/admin/views/MerchProducts.tsx @@ -3,21 +3,36 @@ import { Button } from "payload/components/elements"; import { AdminViewComponent } from "payload/config"; import ViewTemplate from "./ViewTemplate"; import { Column } from "payload/dist/admin/components/elements/Table/types"; +import { Product } from "../../@types/Product"; +import ProductsApi from "../../apis/products.api"; import { RenderCellFactory } from "../utils/RenderCellFactory"; import SortedColumn from "../utils/SortedColumn"; import { Table } from "payload/dist/admin/components/elements/Table"; -import { Product } from "types"; -import ProductsApi from "../../apis/products.api"; +import { useHistory } from 'react-router-dom'; +import { toast } from "react-toastify"; import { prettifyKey } from "../../utilities/prettifyKey"; const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => { // Get data from API const [data, setData] = useState(null); + const history = useHistory(); useEffect(() => { - ProductsApi.getProducts() - .then((res: Product[]) => setData(res)) - .catch((error) => console.log(error)); - }, []); + const fetchProducts = async () => { + try { + const products: Product[] = await ProductsApi.getProducts(); + setData(products); + } catch (error) { + setData([]); + if (error instanceof Error) { + toast.error(error.message); + } else { + toast.error("An unknown error occurred"); + } + } + }; + // eslint-disable-next-line @typescript-eslint/no-floating-promises + fetchProducts(); + }, []); // Do not load table until we receive the data if (data == null) { @@ -25,12 +40,14 @@ const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => { } const tableCols = new Array(); - if (data && data.length > 0) { - const sampleProduct = data[0]; - const keys = Object.keys(sampleProduct); - for (const key of keys) { + if (data && data.length > 0) { + for (const key of Object.keys(new Product())) { + const renderCellComponent = RenderCellFactory.get(data[0], key); const renderCell: React.FC<{ children?: React.ReactNode }> = - RenderCellFactory.get(sampleProduct, key); + renderCellComponent instanceof Promise + ? renderCellComponent + : renderCellComponent; + const col: Column = { accessor: key, components: { @@ -43,53 +60,78 @@ const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => { ), renderCell: renderCell, }, - label: "", - name: "", + label: prettifyKey(key), // Assigning the prettified key to the label + name: key, active: true, }; + tableCols.push(col); } - } + + const editColumn: Column = { + accessor: "edit", + components: { + Heading:
Edit
, + renderCell: (data: Product) => ( + + ), + }, + label: "Edit", + name: "edit", + active: true, + }; - const editColumn: Column = { - accessor: "edit", - components: { - Heading:
Edit
, - renderCell: ({ children }) => ( - - ), - }, - label: "Edit", - name: "edit", - active: true, - }; + tableCols.push(editColumn); - tableCols.push(editColumn); + const handleEdit = (data: Product) => { + const productId = data.id; + // Navigate to the edit page + history.push(`/admin/collections/products/${productId}`); + }; - const deleteColumn: Column = { - accessor: "delete", - components: { - Heading:
Delete
, - renderCell: ({ children }) => ( - - ), - }, - label: "Delete", - name: "delete", - active: true, - }; + const deleteColumn: Column = { + accessor: "delete", + components: { + Heading:
Delete
, + renderCell: (data: Product) => ( + + ), + }, + label: "Delete", + name: "delete", + active: true, + }; - tableCols.push(deleteColumn); + tableCols.push(deleteColumn); - const handleEdit = (orderId: string) => { - console.log(`Dummy. Order ID: ${orderId}`); - }; - - const handleDelete = (orderId: string) => { - console.log(`Dummy. Order ID: ${orderId}`); - }; - - console.log(tableCols); + const handleDelete = async (data: Product) => { + const productId = data.id; + try { + // Show a confirmation prompt (optional) + if (window.confirm('Are you sure you want to delete this product?')) { + // Call the delete API + await ProductsApi.deleteProduct(productId); + + // After deletion, update the data state to reflect the removal + setData((prevData) => prevData.filter((product) => product.id !== productId)); + + // Optionally, show a success message + toast.success('Product deleted successfully'); + } + } catch (error) { + if (error instanceof Error) { + toast.error(error.message); + } else { + toast.error('An unknown error occurred'); + } + } + }; + } return ( { - - + {data && data.length > 0 &&
} ); }; diff --git a/apps/cms/src/apis/products.api.ts b/apps/cms/src/apis/products.api.ts index 62e10ef7..f7dcd837 100644 --- a/apps/cms/src/apis/products.api.ts +++ b/apps/cms/src/apis/products.api.ts @@ -1,64 +1,28 @@ -import { Product } from "types"; +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/require-await */ +import { Product } from "../@types/Product"; // todo turn into real api class ProductsApi { - // eslint-disable-next-line @typescript-eslint/require-await - async getProducts(): Promise { - const res: Product[] = [ - { - id: "1", - name: "product1", - price: 1000, - images: [ - "https://i.kym-cdn.com/entries/icons/original/000/033/421/cover2.jpg", - "https://i.pinimg.com/474x/c0/f9/f1/c0f9f10a0061a8dd1080d7d9e560579c.jpg", - ], - sizes: ["s", "m", "l", "xl"], - category: "shirt", - is_available: true, - colors: ["black,white,blue"], - stock: { - black: { S: 10, M: 15, L: 20, XL: 5 }, - white: { S: 12, M: 17, L: 22, XL: 7 }, - blue: { S: 8, M: 13, L: 18, XL: 3 } - }, - }, - { - id: "2", - name: "product2", - price: 2000, - images: [ - "https://i.kym-cdn.com/photos/images/newsfeed/002/164/493/b8b.jpg", - "https://i.kym-cdn.com/entries/icons/original/000/033/421/cover2.jpg", - ], - sizes: ["s", "m"], - category: "sweater", - is_available: true, - colors: ["blue"], - stock: { - blue: { S: 8, M: 13, L: 18, XL: 3 } - }, - }, - { - id: "3", - name: "product3", - price: 3000, - images: [ - "https://i.kym-cdn.com/entries/icons/original/000/033/421/cover2.jpg", - "https://i.kym-cdn.com/photos/images/newsfeed/002/164/493/b8b.jpg", - "https://i.pinimg.com/474x/c0/f9/f1/c0f9f10a0061a8dd1080d7d9e560579c.jpg", - ], - sizes: ["xs", "s", "m", "l"], - category: "hat", - is_available: false, - colors: ["white"], - stock: { - white: { S: 12, M: 17, L: 22, XL: 7 } - }, - }, - ]; + async getProducts(): Promise { + const req = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/products`); + const products = await req.json(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + return products?.docs as Product[]; + } - return res; + async deleteProduct(id: string): Promise { + try { + const response = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/products/${id}`, { + method: 'DELETE', + }); + if (!response.ok) { + throw new Error('Failed to delete product'); + } + } catch (error) { + throw new Error(error instanceof Error ? error.message : 'An unknown error occurred'); + } } + } export default new ProductsApi(); diff --git a/packages/eslint-config-custom/index.js b/packages/eslint-config-custom/index.js index 813bb43c..5dc0e585 100644 --- a/packages/eslint-config-custom/index.js +++ b/packages/eslint-config-custom/index.js @@ -46,6 +46,11 @@ module.exports = { ], plugins: ["@typescript-eslint"], rules: { + "@typescript-eslint/no-misused-promises": ["error", { + "checksVoidReturn": { + "attributes": false + } + }], "@typescript-eslint/no-empty-interface": ["off", "never"], "@typescript-eslint/no-unused-vars": [ "error",