Skip to content
10 changes: 10 additions & 0 deletions apps/cms/src/@types/Product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class Product {
constructor(
public id = '',
public name = '',
public colors= '',
public sizes = '',
public price = '',
public category = ''
) { }
}
143 changes: 92 additions & 51 deletions apps/cms/src/admin/views/MerchProducts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,51 @@ 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<Product[]>(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) {
return <div> Loading... </div>;
}

const tableCols = new Array<Column>();
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: {
Expand All @@ -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: <div>Edit</div>,
renderCell: (data: Product) => (
<Button onClick={() => handleEdit(data)}>Edit</Button>
),
},
label: "Edit",
name: "edit",
active: true,
};

const editColumn: Column = {
accessor: "edit",
components: {
Heading: <div>Edit</div>,
renderCell: ({ children }) => (
<Button onClick={() => handleEdit(children as string)}>Edit</Button>
),
},
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: <div>Delete</div>,
renderCell: ({ children }) => (
<Button onClick={() => handleDelete(children as string)}>Delete</Button>
),
},
label: "Delete",
name: "delete",
active: true,
};
const deleteColumn: Column = {
accessor: "delete",
components: {
Heading: <div>Delete</div>,
renderCell: (data: Product) => (
<Button onClick={() => {
void (() => {
handleDelete(data);
})();
}}
>Delete</Button>
),
},
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 = (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
// Implement delete API

// 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 (
<ViewTemplate
Expand All @@ -102,8 +144,7 @@ const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => {
<Button el="link" to={"/admin"} buttonStyle="primary">
Go to Main Admin View
</Button>

<Table data={data} columns={tableCols} />
{data && data.length > 0 && <Table data={data} columns={tableCols} />}
</ViewTemplate>
);
};
Expand Down
105 changes: 52 additions & 53 deletions apps/cms/src/apis/products.api.ts
Comment thread
spaceman03 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,64 +1,63 @@
import { Product } from "types";
// todo turn into real api
class ProductsApi {
// eslint-disable-next-line @typescript-eslint/require-await
async getProducts(): Promise<any> {
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 }
// eslint-disable-next-line @typescript-eslint/require-await
async getProducts(): Promise<any> {
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: "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 }
{
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 }
},
},
];

return res;
},
];
return res;
}
}

export default new ProductsApi();
export default new ProductsApi();
7 changes: 7 additions & 0 deletions packages/eslint-config-custom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -58,6 +63,8 @@ module.exports = {
format: ["camelCase", "PascalCase"],
},
],
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
},
parserOptions: {
tsconfigRootDir: __dirname,
Expand Down