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