OrderManagement
In order to create a ReactJs component we use a client script in in the platform. Clients scripts are used for making client side reusable functions or ReactJs components. Below is the code of the Order Management component. In this example we are using ReactJs client library and for building UI we are using Ant Design React Compnent Library. This component is used for managing orders.
OrderManagement
const { useState, useRef, useEffect, useCallback } = React;
const {
Form,
Input,
InputNumber,
Popconfirm,
Table,
Typography,
Segmented,
Badge,
Descriptions,
Tabs,
Button,
Radio,
Divider,
Select,
Tour,
Result,
Modal,
DatePicker,
Space,
Spin,
ConfigProvider,
theme
} = antd;
const OrderManagement = () => {
const [customers, setCustomers] = useState([]);
const [orderConstruct, setOrderConstruct] = useState({});
const [orderSequence, setOrderSequence] = useState("");
const [showStudentDetails, setShowStudentDetails] = useState(false);
const dispatch = useDispatch();
const [transactionDate, setTransactionDate] = useState(
new Date().toISOString()
);
const [selectedCustomer, setSelectedCustomer] = useState({
class: { label: "" }
});
const ref1 = useRef(null);
const ref2 = useRef(null);
const ref3 = useRef(null);
const ref4 = useRef(null);
const [open, setOpen] = useState(false);
const [studentName, setStudentName] = useState("");
const [studentClass, setStudentClass] = useState("");
const [studentClassGroup, setStudentClassGroup] = useState("");
const [studentMobile, setStudentMobile] = useState("");
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const [orderLines, setOrderLines] = useState([]);
const [count, setCount] = useState(0);
const [editingKey, setEditingKey] = useState("");
const isEditing = record => record.key === editingKey;
const steps = [
{
title: "Add new order item",
description: "Click this button to add new order lines.",
cover: (
<img
alt="tour.png"
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
/>
),
target: () => ref1.current
},
{
title: "Order Lines",
description:
"List of order items that have been added. You can edit/delete as well.",
target: () => ref2.current
},
{
title: "Payment Mode",
description: "Select a payment mode and provide details.",
target: () => ref3.current
},
{
title: "Review",
description:
"Review the order details and finzalize by receiving payment from customer",
target: () => ref4.current
}
];
const edit = record => {
console.log(record);
form.setFieldsValue({
sku: "",
description: "",
quantity: 0,
price: 0,
...record
});
setEditingKey(record.key);
};
const handleDelete = key => {
const newData = orderLines.filter(item => item.key !== key);
setOrderLines([...newData]);
};
const cancel = () => {
setEditingKey("");
};
const handleQuantityChange = (newValue, record) => {
const key = record.key;
// console.log(newValue, record);
const productRef = products.find(val => val.title === record.description);
// console.log(productRef);
const newData = orderLines.map(row => {
if (row.key === key) {
return {
...row,
quantity: newValue,
price: newValue * productRef.last_stock_price
};
}
return row;
});
// console.log(newData);
setOrderLines(newData);
};
const save = async key => {
try {
const row = await form.validateFields();
const newData = [...orderLines];
const index = newData.findIndex(item => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, {
...item,
...row
});
setOrderLines(newData);
setEditingKey("");
} else {
newData.push(row);
setOrderLines(newData);
setEditingKey("");
}
} catch (errInfo) {
console.log("Validate Failed:", errInfo);
}
};
const columns = [
{
title: "SKU",
dataIndex: "sku",
width: "25%",
inputType: "text",
editable: true
},
{
title: "Description",
dataIndex: "description",
width: "15%",
inputType: "list",
editable: true,
render: (_, record) => (
<Select
showSearch
style={{
width: 200
}}
value={record["description"]}
placeholder="Search to Select"
optionFilterProp="children"
onChange={value => handleProductChange(value, record, "description")}
filterOption={(input, option) =>
(option?.label ?? "").includes(input)
}
filterSort={(optionA, optionB) =>
(optionA?.label ?? "")
.toLowerCase()
.localeCompare((optionB?.label ?? "").toLowerCase())
}
options={(products || []).map(d => ({
value: d.title,
label: d.title
}))}
></Select>
)
},
{
title: "Quantity",
dataIndex: "quantity",
width: "20%",
inputType: "number",
editable: true,
render: (_, record) => (
<InputNumber
value={record["quantity"]}
onChange={value => handleQuantityChange(value, record)}
/>
)
},
{
title: "Price",
dataIndex: "price",
width: "20%",
inputType: "number",
editable: false
}
];
const handleProductChange = (value, record, dataIndex) => {
const key = record.key;
// console.log(value, record, dataIndex);
const productRef = products.find(val => val.title === value);
// console.log(productRef);
const newData = orderLines.map(row => {
if (row.key === key) {
return {
...row,
description: productRef.title,
sku: productRef.sku,
quantity: 1,
price: productRef.last_stock_price
};
}
return row;
});
console.log(newData);
setOrderLines(newData);
};
const handleAdd = () => {
const newData = {
key: count,
sku: "",
description: "",
quantity: 0,
price: 0
};
setOrderLines([...orderLines, newData]);
setCount(count + 1);
form.setFieldsValue({ orderLines: orderLines });
};
const mergedColumns = columns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
inputType: col.inputType,
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record)
})
};
});
const [studentId, setStudentId] = useState();
const debouncedFetchData = useCallback(
(delay => {
let timerId;
return searchValue => {
clearTimeout(timerId);
timerId = setTimeout(() => fetchStudentDetails(searchValue), delay);
};
})(800),
[] // Dependencies array
);
const handleSearch = newValue => {
debouncedFetchData(newValue);
// fetchStudentDetails(newValue);
};
const studentAttributes = [
{
key: "1",
label: "Name",
children: studentName
},
{
key: "2",
label: "Class",
children: studentClass
},
{
key: "3",
label: "Mobile Number",
children: studentMobile
}
];
const handleChange = newValue => {
const customerRef = customers.find(val => val._id === newValue);
console.log(customerRef);
setSelectedCustomer(customerRef);
setStudentName(customerRef.name);
setStudentClass(customerRef.class.label);
setStudentClassGroup(customerRef.class.label.split(" ")[0]);
setStudentMobile(customerRef.mobile_number);
setShowStudentDetails(true);
};
useEffect(() => {
fetchProducts(); // This will always use latest value of count
}, [studentClassGroup]);
const fetchProducts = async searchTerms => {
try {
setLoading(true);
const response = await http.get(
`/v1/getProducts?category=${studentClassGroup}&nd=${new Date().getTime()}`
);
setProducts(response.data);
console.log(products);
} catch (error) {
console.error("Error fetching student details:", error);
// Handle error appropriately
} finally {
setLoading(false);
}
};
const fetchStudentDetails = async searchTerms => {
try {
setLoading(true);
const response = await http.get(
`/o/recs/registration?oquery=$or=sequence=*${searchTerms}^class.label=*${searchTerms}^mobile_number=*${searchTerms}&stream=true`
);
setCustomers(response.data);
} catch (error) {
console.error("Error fetching student details:", error);
// Handle error appropriately
} finally {
setLoading(false);
}
};
form.setFieldsValue({ orderLines: orderLines });
/****** Payment Mode */
const [payMode, setPayMode] = useState("Cash");
/****** Review & Finalize */
const [isModalOpen, setIsModalOpen] = useState(false);
const finalizeOrder = values => {
setOrderConstruct({
customerName: studentName,
studentClass,
customerMobile: studentMobile,
totalAmount: values.orderLines.reduce((acc, val) => {
return (acc += val.price);
}, 0),
transactionDate: values.transaction_date,
...values
});
};
useEffect(() => {
console.log(orderConstruct);
}, [orderConstruct]);
const showModal = () => {
setIsModalOpen(true);
};
const handleOk = () => {
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const confirm = () => {
//postAPICall and then show modal
//"/o/om_orders/new"
setLoading(true);
http.post("/v1/postOrders", orderConstruct).then(response => {
console.log(response);
form.resetFields();
dispatch({
type: "UPDATE",
payload: {
orderCreated: true
}
});
showModal();
setLoading(false);
});
};
const reviewItems = [
{
key: "2",
label: "Payment Mode",
children: payMode
},
{
key: "10",
label: "Order Items",
children: (
<>
{orderLines.map(val => {
return (
<>
<span>{val.sku}</span>
<br />
</>
);
})}
</>
)
},
{
key: "11",
label: "Finalize",
children: (
<Form.Item
wrapperCol={{
span: 12,
offset: 6
}}
>
<Space>
<Popconfirm
title="Receive Payment"
description="Are you sure to proceed?"
onConfirm={confirm}
onCancel={cancel}
okText="Yes"
cancelText="No"
>
<Button
type="primary"
htmlType="submit"
ref={ref4}
style={{
marginBottom: 16
}}
>
Receive Payment
</Button>
</Popconfirm>
</Space>
</Form.Item>
)
}
];
const onChange = key => {
console.log(key);
};
const [formLayout, setFormLayout] = useState("inline");
const onFormLayoutChange = ({ layout }) => {
setFormLayout(layout);
};
const onFinish = values => {
console.log("Received values of form: ", values);
finalizeOrder(values);
};
const tabs = [
{
key: "1",
label: "New Order",
children: (
<div
style={{
background: "black",
padding: "20px"
}}
>
<ConfigProvider theme={{ algorithm: theme.darkAlgorithm }}>
<Spin spinning={loading} delay={500}>
<Form
form={form}
layout={formLayout}
onFinish={onFinish}
initialValues={{
layout: "inline"
}}
style={{
maxWidth: "100%"
}}
>
<Form.Item label="Admission#" name="selectedCustomer">
<Select
showSearch
value={studentId}
style={{
width: 360
}}
placeholder="Search"
defaultActiveFirstOption={false}
suffixIcon={null}
filterOption={false}
onSearch={handleSearch}
onChange={handleChange}
notFoundContent={null}
options={(customers || []).map(d => ({
value: d._id,
label: `${d.name}-${d.mobile_number}-${d.class.label}-${d.father_name}`
}))}
/>
</Form.Item>
{showStudentDetails && (
<Button
type="primary"
style={{ position: "absolute", right: "10px", top: "0px" }}
onClick={() => setOpen(true)}
>
Begin Tour
</Button>
)}
{showStudentDetails && (
<React.Fragment>
<Divider>Student Details</Divider>
<Descriptions bordered items={studentAttributes} />
</React.Fragment>
)}
{showStudentDetails && (
<React.Fragment>
<Divider>Order Items</Divider>
<Space direction="vertical">
<Button
ref={ref1}
onClick={handleAdd}
type="primary"
style={{
marginBottom: 16
}}
>
Add a row
</Button>
<Form.Item name="orderLines">
<Table
// components={{
// body: {
// cell: EditableCell
// }
// }}
ref={ref2}
bordered
dataSource={orderLines}
columns={mergedColumns}
style={{ width: "800px" }}
rowClassName="editable-row"
pagination={{
onChange: cancel
}}
/>
</Form.Item>
</Space>
<Divider>Payment Mode</Divider>
<Segmented
ref={ref3}
options={["Cash", "Cheque", "Card", "UPI"]}
value={payMode}
onChange={setPayMode}
/>
{payMode === "Cash" && (
<Space direction="horizontal">
<Form.Item
label="Payment Date"
name="transaction_date"
rules={[
{
required: true,
message: "Please input date!"
}
]}
>
<DatePicker onChange={onChange} />
</Form.Item>
</Space>
)}
{payMode === "Card" && (
<Space direction="horizontal">
<Form.Item
label="Payment Date"
name="transaction_date"
rules={[
{
required: true,
message: "Please input date!"
}
]}
>
<DatePicker
onChange={onChange}
value={transactionDate}
/>
</Form.Item>
<Form.Item
label="Approval code"
name="approval_code"
rules={[
{
required: true,
message: "Please approval code!"
}
]}
>
<Input />
</Form.Item>
<Form.Item
label="Reference No"
name="reference_no"
rules={[
{
required: true,
message: "Reference No"
}
]}
>
<Input />
</Form.Item>
</Space>
)}
{payMode === "UPI" && (
<Space direction="horizontal">
<Form.Item
label="Payment Date"
name="transaction_date"
rules={[
{
required: true,
message: "Please input date!"
}
]}
>
<DatePicker onChange={onChange} />
</Form.Item>
<Form.Item
label="Approval code"
name="approval_code"
rules={[
{
required: true,
message: "Please approval code!"
}
]}
>
<Input />
</Form.Item>
<Form.Item
label="Reference No"
name="reference_no"
rules={[
{
required: true,
message: "Reference No"
}
]}
>
<Input />
</Form.Item>
</Space>
)}
{payMode === "Cheque" && (
<Space direction="horizontal">
<Form.Item
label="Cheque Date"
name="transaction_date"
rules={[
{
required: true,
message: "Please input date!"
}
]}
>
<DatePicker onChange={onChange} />
</Form.Item>
<Form.Item
label="Cheque No"
name="chequeno"
rules={[
{
required: true,
message: "Please input date!"
}
]}
>
<Input />
</Form.Item>
</Space>
)}
<Divider>Review & Finalize</Divider>
<Descriptions bordered items={reviewItems} />
<Tour
open={open}
onClose={() => setOpen(false)}
steps={steps}
/>
<Modal
title="Order Received"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
>
<Result
status="success"
title="Successfully Purchased"
subTitle={`Order number: ${orderSequence}`}
/>
</Modal>
</React.Fragment>
)}
</Form>
</Spin>
</ConfigProvider>
</div>
)
},
{
key: "2",
label: "All Orders",
children: AllOrders()
},
{
key: "3",
label: "Manage",
children: ProductManagement()
},
{
key: "4",
label: "Invoices",
children: "Coming Soon!"
}
];
return <Tabs defaultActiveKey="1" items={tabs} onChange={onChange} />;
};
return OrderManagement;
Last updated