Skip to content

Commit

Permalink
feat(cms): Orders api config and edit function (#165)
Browse files Browse the repository at this point in the history
* feat(cms): Orders api config and edit function
* Fix lint
* Added toast for error messages, fix inconsistency issues
  • Loading branch information
limivann authored Sep 4, 2024
1 parent a3b8085 commit 9ffa53b
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 153 deletions.
1 change: 1 addition & 0 deletions apps/cms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"payload": "^2.27.0",
"querystring-es3": "^0.2.1",
"react": "^18.0.0",
"react-toastify": "10.0.5",
"tsconfig": "*"
},
"devDependencies": {
Expand Down
17 changes: 8 additions & 9 deletions apps/cms/src/@types/Order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

export class Order {
constructor(
public order_id = '',
public date = new Date(),
public order_person = '',
public image_url = '',
public item = '',
public qty = 0,
public size = '',
public colour = ''

public id = '',
public transactionId = '',
public transactionTime = '',
public paymentMethod = '',
public customerEmail = '',
public status = '',
public updatedAt = '',
public createdAt = ''
) { }
}
10 changes: 1 addition & 9 deletions apps/cms/src/admin/views/MerchProducts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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 { prettifyKey } from "../../utilities/prettifyKey";

const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => {
// Get data from API
Expand All @@ -18,15 +19,6 @@ const MerchProducts: AdminViewComponent = ({ user, canAccessAdmin }) => {
.catch((error) => console.log(error));
}, []);

// Output human-readable table headers based on the attribute names from the API
function prettifyKey(str: string): string {
let res = "";
for (const i of str.split("_")) {
res += i.charAt(0).toUpperCase() + i.slice(1) + " ";
}
return res;
}

// Do not load table until we receive the data
if (data == null) {
return <div> Loading... </div>;
Expand Down
10 changes: 1 addition & 9 deletions apps/cms/src/admin/views/MerchPromotion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Table } from "payload/dist/admin/components/elements/Table";
import { Promotion } from "types";
import PromotionsApi from "../../apis/promotions.api";
import './MerchPromotion.scss';
import { prettifyKey } from "../../utilities/prettifyKey";

const MerchPromotion: AdminViewComponent = ({ user, canAccessAdmin }) => {
// Get data from API
Expand All @@ -19,15 +20,6 @@ const MerchPromotion: AdminViewComponent = ({ user, canAccessAdmin }) => {
.catch((error) => console.log(error));
}, []);

// Output human-readable table headers based on the attribute names from the API
function prettifyKey(str: string): string {
let res = "";
for (const i of str.split("_")) {
res += i.charAt(0).toUpperCase() + i.slice(1) + " ";
}
return res;
}

// Do not load table until we receive the data
if (data == null) {
return <div> Loading... </div>;
Expand Down
140 changes: 65 additions & 75 deletions apps/cms/src/admin/views/MerchSales.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,102 +5,93 @@ import ViewTemplate from "./ViewTemplate";
import { Column } from "payload/dist/admin/components/elements/Table/types";
import { Order } from "../../@types/Order";
import OrdersApi from "../../apis/orders.api";
import { IOrder } from "../../@types/IOrder";
import { RenderCellFactory } from "../utils/RenderCellFactory";
import SortedColumn from "../utils/SortedColumn";
import { Table } from "payload/dist/admin/components/elements/Table";

import { useHistory } from 'react-router-dom';
import { toast } from "react-toastify";
import { prettifyKey } from "../../utilities/prettifyKey";

const MerchSales: AdminViewComponent = ({ user, canAccessAdmin }) => {
// Get data from API
const [data, setData] = useState<IOrder[]>(null);
useEffect(() => {
OrdersApi.getOrders()
.then((res: IOrder[]) => setData(res))
.catch((error) => console.log(error));
// Get data from API
const [data, setData] = useState<Order[]>(null);
const history = useHistory();
useEffect(() => {
const fetchOrders = async () => {
try {
const orders: Order[] = await OrdersApi.getOrders();
setData(orders);
} 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
fetchOrders();
}, []);

// Output human-readable table headers based on the attribute names from the API
function prettifyKey(str: string): string {
let res = "";
for (const i of str.split("_")) {
res += i.charAt(0).toUpperCase() + i.slice(1) + " ";
}
return res;
}

// Do not load table until we receive the data
if (data == null) {
return <div>Loading...</div>;
}

const tableCols = new Array<Column>();
for (const key of Object.keys(new Order())) {
const renderCellComponent = RenderCellFactory.get(data[0], key);
const renderCell: React.FC<{ children?: React.ReactNode }> =
renderCellComponent instanceof Promise
? renderCellComponent
: renderCellComponent;
if (data && data.length > 0) {
for (const key of Object.keys(new Order())) {
const renderCellComponent = RenderCellFactory.get(data[0], key);
const renderCell: React.FC<{ children?: React.ReactNode }> =
renderCellComponent instanceof Promise
? renderCellComponent
: renderCellComponent;

const col: Column = {
accessor: key,
components: {
Heading: (
<SortedColumn
label={prettifyKey(key)}
name={key}
data={data as never[]}
/>
),
renderCell: renderCell,
},
label: prettifyKey(key), // Assigning the prettified key to the label
name: key,
active: true,
};

tableCols.push(col);
}

const col: Column = {
accessor: key,
// Add the "Edit" column
const editColumn: Column = {
accessor: "edit",
components: {
Heading: (
<SortedColumn
label={prettifyKey(key)}
name={key}
data={data as never[]}
/>
Heading: <div>Edit</div>,
renderCell: (data: Order) => (
<Button onClick={() => handleEdit(data)}>Edit</Button>
),
renderCell: renderCell,
},
label: "",
name: "",
label: "Edit",
name: "edit",
active: true,
};
tableCols.push(col);
}

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 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,
};

tableCols.push(deleteColumn);

const handleEdit = (orderId: string) => {
console.log(`Dummy. Order ID: ${orderId}`);
// Handle Edit functionality
const handleEdit = (data: Order) => {
const orderId = data.id;
// Navigate to the edit page
history.push(`/admin/collections/orders/${orderId}`);
};
}

const handleDelete = (orderId: string) => {
console.log(`Dummy. Order ID: ${orderId}`);
};

console.log(tableCols);

return (
<ViewTemplate
user={user}
Expand All @@ -112,8 +103,7 @@ const MerchSales: 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
2 changes: 2 additions & 0 deletions apps/cms/src/admin/views/ViewTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Eyebrow } from "payload/components/elements";
import { AdminViewComponent } from "payload/config";
import { useStepNav } from "payload/components/hooks";
import { Meta } from "payload/components/utilities";
import { Slide, ToastContainer } from "react-toastify";

type ViewTemplateProps = React.ComponentProps<AdminViewComponent> & {
description: string;
Expand Down Expand Up @@ -54,6 +55,7 @@ const ViewTemplate = ({
<h1>{title}</h1>
{children}
</div>
<ToastContainer icon={false} position="bottom-center" transition={Slide} />
</DefaultTemplate>
);
};
Expand Down
53 changes: 8 additions & 45 deletions apps/cms/src/apis/orders.api.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,13 @@
import { IOrder } from "../@types/IOrder";
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/require-await */
import { Order } from "../@types/Order";

// todo turn into real api
class OrdersApi {
// eslint-disable-next-line @typescript-eslint/require-await
async getOrders(): Promise<IOrder[]> {
const res: IOrder[] = [];
const item1: IOrder = {
colour: "black",
date: new Date("2022-01-31"),
image_url:
"https://i.kym-cdn.com/entries/icons/original/000/033/421/cover2.jpg",
item: "graduation hat",
order_id: "1",
order_person: "kenneth west",
qty: 2,
size: "M",
};
res.push(item1);

const item2: IOrder = {
colour: "white",
date: new Date("2022-02-13"),
image_url:
"https://i.kym-cdn.com/photos/images/newsfeed/002/164/493/b8b.jpg",
item: "scorpion",
order_id: "2",
order_person: "aubrey graham drake",
qty: 1,
size: "L",
};
res.push(item2);

const item3: IOrder = {
colour: "beige",
date: new Date("2010-02-13"),
image_url:
"https://i.pinimg.com/474x/c0/f9/f1/c0f9f10a0061a8dd1080d7d9e560579c.jpg",
item: "dat stick",
order_id: "3",
order_person: "rich brian",
qty: 1,
size: "S",
};
res.push(item3);

return res;
async getOrders(): Promise<Order[]> {
const req = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/orders`);
const orders = await req.json();
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return orders?.docs as Order[];
}
}

Expand Down
6 changes: 3 additions & 3 deletions apps/cms/src/collections/Orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const Orders: CollectionConfig = {
minRows: 1,
},
{
name: "transaction_id",
name: "transactionId",
label: "Transaction ID",
admin: {
description: "Transaction ID provided by Payment Gateway",
Expand All @@ -66,7 +66,7 @@ const Orders: CollectionConfig = {
required: true,
},
{
name: "transaction_time",
name: "transactionTime",
label: "Transaction Time",
type: "date",
admin: {
Expand All @@ -77,7 +77,7 @@ const Orders: CollectionConfig = {
required: true,
},
{
name: "payment_method",
name: "paymentMethod",
label: "Payment Method",
type: "text",
required: true,
Expand Down
6 changes: 3 additions & 3 deletions apps/cms/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ export interface User {
export interface Order {
id: string;
items?: OrderItem;
transaction_id: string;
transaction_time: string;
payment_method: string;
transactionId: string;
transactionTime: string;
paymentMethod: string;
customerEmail: string;
status: 'pending' | 'paid' | 'delivered';
updatedAt: string;
Expand Down
9 changes: 9 additions & 0 deletions apps/cms/src/utilities/prettifyKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
Convert a camelCase string to a human - readable format with proper spacing and capitalization
*/

export function prettifyKey(str: string): string {
let res = str.replace(/([A-Z])/g, ' $1'); // Add a space before each uppercase letter
res = res.charAt(0).toUpperCase() + res.slice(1); // Capitalize the first letter
return res;
}

0 comments on commit 9ffa53b

Please sign in to comment.