Skip to content

Instantly share code, notes, and snippets.

@nurmdrafi
Created November 27, 2022 18:13
Show Gist options
  • Save nurmdrafi/4ee08e7fce3985b1fdde536560592013 to your computer and use it in GitHub Desktop.
Save nurmdrafi/4ee08e7fce3985b1fdde536560592013 to your computer and use it in GitHub Desktop.

ParentComponent.js

import React, { useEffect, useState } from "react";
import Highlighter from "react-highlight-words";

// Import Icons
import { SearchOutlined } from "@ant-design/icons";

// Import Components
import { Button, Input, Row, Space, Tag, Col } from "antd";
import Actions from "./components/Actions";
import GlobalSearch from "./components/GlobalSearch";
import TableData from ".";

// Import Actions & Methods
import { useDispatch, useSelector } from "react-redux";
import { deleteOrders, getOrders } from "../../redux/reducers/ordersReducer";

// Import Utils Function
import { setDataSourceWithKey } from "./utils/setDataSourceWithKey";

const ParentComponent = () => {
  const dispatch = useDispatch();

  // Get Data From Redux Store
  const { orders } = useSelector((state) => state.orders);

  const [dataSource, setDataSource] = useState(orders);
  const [isFetched, setIsFetched] = useState(false);

  // Search States
  const [searchText, setSearchText] = useState("");
  const [searchColText, setSearchColText] = useState("");
  const [searchedCol, setSearchedCol] = useState("");

  // Sorted States
  const [sortedInfo, setSortedInfo] = useState({});

  // Selected States
  const [isSelected, setIsSelected] = useState(true);
  const [selectedRows, setSelectedRows] = useState([]);
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);

  // Filter States
  let [filteredData] = useState([]);

  // Get Orders
  useEffect(() => {
    if (!orders) {
      dispatch(getOrders);
      setIsFetched(true);
    }
  }, [orders]);

  // Set Table Data with Keys
  if (isFetched) {
    const data = setDataSourceWithKey(orders);
    setDataSource(data);
    isFetched(false);
  }

  // Handle Search Column
  const _handleSearchCol = (selectedKeys, confirm, dataIndex) => {
    confirm();
    setSearchColText(selectedKeys[0]);
    setSearchedCol(dataIndex);
  };

  // Handle Reset Column Search
  const _handleResetCol = (clearFilters, confirm) => {
    clearFilters();
    setSearchColText("");
    confirm();
  };

  // Get Column Search Props
  const _getColumnSearchProps = (dataIndex) => ({
    filterDropdown: ({
      setSelectedKeys,
      selectedKeys,
      confirm,
      clearFilters,
    }) => (
      <div
        style={{
          padding: 8,
        }}
      >
        <Input
          placeholder={`Search ${dataIndex}`}
          value={selectedKeys[0]}
          onChange={(e) =>
            setSelectedKeys(e.target.value ? [e.target.value] : [])
          }
          onPressEnter={() =>
            _handleSearchCol(selectedKeys, confirm, dataIndex)
          }
          style={{
            marginBottom: 8,
            display: "block",
          }}
        ></Input>
        <Space>
          <Button
            type="primary"
            onClick={() => _handleSearchCol(selectedKeys, confirm, dataIndex)}
            icon={<SearchOutlined />}
            size="small"
            style={{ width: 90 }}
          >
            Search
          </Button>
          <Button
            onClick={() =>
              clearFilters && _handleResetCol(clearFilters, confirm)
            }
            size="small"
            style={{ width: 90 }}
          >
            Reset
          </Button>
        </Space>
      </div>
    ),
    filterIcon: (filtered) => (
      <SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
    ),
    onFilter: (value, record) =>
      record[dataIndex]
        ? record[dataIndex]
            .toString()
            .toLowerCase()
            .includes(value.toLowerCase())
        : "",
    render: (text) =>
      searchedCol === dataIndex ? (
        <Highlighter
          highlightStyle={{
            backgroundColor: "#ffc069",
            padding: 0,
          }}
          searchWords={[searchColText]}
          autoEscape
          textToHighlight={text ? text.toString() : ""}
        />
      ) : (
        text
      ),
  });

  // Set Table Columns
  const columns = [
    {
      key: 1,
      dataIndex: "ordeby",
      title: "Order By",
      fixed: "left",
      sorter: (a, b) => a.ordeby.localeCompare(b.ordeby),
      sortOrder: sortedInfo.columnKey === "ordeby" && sortedInfo.order,
      ..._getColumnSearchProps("ordeby"),
    },
    { key: 2, dataIndex: "orderDate", title: "Order Date" },
    { key: 3, dataIndex: "deliveryDate", title: "Delivery Date" },
    { key: 4, dataIndex: "deliveryAgent", title: "Delivery Agent" },
    { key: 5, dataIndex: "customerInfo", title: "Customer Info" },
    {
      key: 6,
      dataIndex: "status",
      title: "Percel Status",
      align: "center",
      filters: [
        {
          text: "Completed",
          value: "completed",
        },
        {
          text: "Delivery",
          value: "delivery",
        },
        {
          text: "On Pickup",
          value: "on Pickup",
        },
      ],
      onFilter: (value, record) =>
        record.status.toLowerCase().includes(value.toLowerCase()),
      filterSearch: true,
      render: (_, { status }) => {
        let color;
        if (status === "Completed") {
          color = "#417D03";
        } else if (status === "Delivery") {
          color = "#EB843A";
        } else if (status === "On Pickup") {
          color = "#A8361A";
        }
        return (
          <Tag
            style={{
              backgroundColor: `${color}`,
              color: "#fff",
              fontWeight: "bold",
            }}
          >
            {status}
          </Tag>
        );
      },
    },
    { key: 7, dataIndex: "memoCash", title: "Memo" },
    { key: 8, dataIndex: "totalPrice", title: "Total Price" },
    { key: 9, dataIndex: "lastUpdated", title: "Last Updated By" },
    { key: 10, dataIndex: "code", title: "Percel Code" },
  ];

  return (
    <>
      <Row
        style={{
          display: "flex",
          alignItems: "center",
          backgroundColor: "whitesmoke",
        }}
      >
        <Col lg={16}>
          <GlobalSearch
            rawData={orders}
            dataSource={dataSource} // Must Needed
            setDataSource={setDataSource} // Must Needed
            selectedRowKeys={selectedRowKeys} // Selected Row Count
            searchText={searchText} // Global Search Text
            setSearchText={setSearchText} // Set Global Search Text
            setSortedInfo={setSortedInfo} // Set Ascending Descending
          />
        </Col>
        <Col lg={8}>
          <Actions
            dataSource={dataSource} // Must Needed
            setDataSource={setDataSource} // Must Needed
            filteredData={filteredData} // Column Filter
            isSelected={isSelected} // Is Selected (true/false)
            setIsSelected={setIsSelected} // Set Is Selected Row
            selectedRows={selectedRows} // Selected Row
            setSelectedRows={setSelectedRows} // Set Selected Row
            selectedRowKeys={selectedRowKeys} // Selected Row Count
            setSelectedRowKeys={setSelectedRowKeys} // Set Selected Row Count
            dispatchAction={deleteOrders} // Dispatch Action
          />
        </Col>
      </Row>
      <Row>
        <TableData
          columns={columns} // Must Needed
          dataSource={dataSource} // Must Needed
          setSelectedRows={setSelectedRows} // Select Row Checkbox
          selectedRowKeys={selectedRowKeys} // Selected Row Count
          setSelectedRowKeys={setSelectedRowKeys} // Set Selected Row Count
          setSortedInfo={setSortedInfo} // Set Ascending Descending
          setIsSelected={setIsSelected} // Set Is Selected Row
        />
      </Row>
    </>
  );
};

export default ParentComponent;

GlobalSearch.js

import React from "react";

// Import Components
import { Input, Space, Button } from "antd";

// Import Utils Function
import { setDataSourceWithKey } from "../utils/setDataSourceWithKey";

// Import Icons
import { SearchOutlined } from "@ant-design/icons";

const GlobalSearch = ({
  rawData,
  dataSource,
  setDataSource,
  selectedRowKeys,
  searchText,
  setSearchText,
  setSortedInfo,
}) => {
  // Handle Search
  const _handleSearchText = (e) => {
    setSearchText(e.target.value);
    if (e.target.value === "") {
      const data = setDataSourceWithKey(rawData);
      setDataSource(data);
    }
  };

  // Handle Global Search
  const _handleGlobalSearch = (searchText) => {
    const data = dataSource.filter((item) => {
      const valArr = Object.values(item).filter((value) => {
        return value
          .toLowerCase()
          .toLowerCase()
          .includes(searchText.toLowerCase());
      });
      return valArr.length > 0 && item;
    });
    setDataSource(data);
  };

  // On Reset
  const _onReset = () => {
    setSortedInfo({});
    setSearchText("");
    const data = setDataSourceWithKey(rawData);
    setDataSource(data);
  };

  return (
    <Space
      style={{
        display: "flex",
        justifyContent: "flex-start",
      }}
    >
      <Input
        prefix={<SearchOutlined />}
        placeholder="Search Anything..."
        onChange={(e) => _handleSearchText(e)}
        type="text"
        allowClear
        value={searchText}
      />
      <Button type="primary" onClick={() => _handleGlobalSearch(searchText)}>
        Search
      </Button>
      <Button onClick={_onReset}>Reset</Button>
      <span>{`Selected Items: ${selectedRowKeys?.length}, Total ${dataSource?.length}`}</span>
    </Space>
  );
};

export default GlobalSearch;

Actions

import React from "react";
import { CSVLink } from "react-csv";

// Import Components
import { Button, Modal, Space } from "antd";

// Import Icons
import { DownloadOutlined } from "@ant-design/icons";
import { useDispatch } from "react-redux";

const Actions = ({
  dataSource,
  setDataSource,
  filteredData,
  isSelected,
  setIsSelected,
  selectedRows,
  setSelectedRows,
  selectedRowKeys,
  setSelectedRowKeys,
  dispatchAction,
}) => {
  const dispatch = useDispatch();

  // Delete Record
  const _deleteRecord = (record) => {
    Modal.confirm({
      title: "Are you sure, Do you want to delete this record?",
      okText: "Yes",
      okType: "danger",
      onOk: () => {
        dispatch(dispatchAction(record.id));
        record.forEach((data) =>
          setDataSource((prev) => prev.filter((row) => data.key !== row.key))
        );
        setIsSelected(false);
        setSelectedRows([]);
        setSelectedRowKeys([]);
      },
    });
  };

  return (
    <Space
      style={{
        display: "flex",
        justifyContent: "flex-end",
        height: "50px",
        alignItems: "center",
      }}
    >
      <Button disabled={selectedRowKeys?.length === 1 ? false : true}>
        Edit
      </Button>
      <Button
        type="primary"
        danger
        disabled={isSelected}
        onClick={() => _deleteRecord(selectedRows)}
      >
        Delete
      </Button>
      <Button>Print</Button>

      <Button
        style={{ backgroundColor: "#c2115e", color: "#fff" }}
        icon={
          <DownloadOutlined
            style={{
              marginRight: 5,
              color: "#fff",
            }}
          />
        }
      >
        <CSVLink
          style={{ color: "#fff" }}
          data={filteredData?.length > 0 ? filteredData : dataSource}
        >
          Export
        </CSVLink>
      </Button>
    </Space>
  );
};

export default Actions;

Table.index.js

import React from "react";

// Import Components
import { Table } from "antd";


const TableData = ({
  columns,
  dataSource,
  setSelectedRows,
  selectedRowKeys,
  setSelectedRowKeys,
  setSortedInfo,
  setIsSelected,
}) => {
  // On Select Change
  const _onSelectChange = (newSelectedRowKeys, selectedRows) => {
    setSelectedRowKeys(newSelectedRowKeys);
    setSelectedRows(selectedRows);
    if (newSelectedRowKeys.length > 0) {
      setIsSelected(false);
    } else {
      setIsSelected(true);
    }
  };

  const _rowSelection = {
    selectedRowKeys,
    onChange: _onSelectChange,
  };

  // Handle Change
  const _handleChange = (...sorter) => {
    const { order, field } = sorter[2];
    setSortedInfo({ columnKey: field, order });
  };

  return (
    <>
      <Table
        columns={columns}
        dataSource={dataSource}
        rowSelection={_rowSelection}
        onChange={_handleChange}
        pagination={{
          position: ["bottomCenter"],
          defaultPageSize: 10,
          // total: orders.total,
        }}
        scroll={{
          x: 1500,
          y: 600,
        }}
        bordered
      />
    </>
  );
};

export default TableData;

Utility Function

export const setDataSourceWithKey = (dataSoruce) => {
  const source = [];
  dataSoruce.forEach((order) => {
    source.push({ key: order.id, ...order });
  });
  return source;
};

Basic Use Case

import React, { useEffect, useState } from "react";
import AddDeliveryAgent from "./AddDeliveryAgent";
import { Col, Row } from "antd";
import TableData from "../../../../components/TableData";
import { setDataSourceWithKey } from "../../../../components/TableData/utils/setDataSourceWithKey";

const rows = [
  {
    id: 1,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
  {
    id: 2,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
  {
    id: 3,
    name: "Load 1",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "33",
  },
  {
    id: 4,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
  {
    id: 5,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
  {
    id: 6,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
  {
    id: 7,
    name: "Load Balancer 2",
    rule: "DNS delegation",
    status: "Active",
    other: "Test",
    example: "22",
  },
];

const DeliveryMan = () => {
  const [cityInfo, setCityInfo] = useState({});

  const [dataSource, setDataSource] = useState([]);

  // Selected States
  const [isSelected, setIsSelected] = useState(true);
  const [selectedRows, setSelectedRows] = useState([]);
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);

  // Set Table Data with Keys
  useEffect(() => {
    const data = setDataSourceWithKey(rows);
    setDataSource(data);
  }, []);

  // Set Table Columns
  const columns = [
    {
      key: 1,
      dataIndex: "name",
      title: "Name",
      fixed: "left",
    },
    { key: 2, dataIndex: "rule", title: "Rule" },
    { key: 3, dataIndex: "status", title: "Status" },
    { key: 4, dataIndex: "other", title: "Other" },
    { key: 5, dataIndex: "example", title: "Example" },
  ];

  return (
    <div>
      <Row
        style={{
          backgroundColor: "#fff",
          borderRadius: "10px",
          padding: "10px",
          marginBottom: "30px",
        }}
      >
        <Col lg={24} style={{ paddingLeft: 100, paddingRight: 100 }}>
          <AddDeliveryAgent cityName={cityInfo} setCityName={setCityInfo} />
        </Col>
      </Row>
      <Row
        style={{
          backgroundColor: "#fff",
          borderRadius: "10px",
          padding: "10px",
        }}
      >
        <Col lg={24}>
          <TableData
            columns={columns}
            dataSource={dataSource}
            setSelectedRows={setSelectedRows}
            selectedRowKeys={selectedRowKeys}
            setSelectedRowKeys={setSelectedRowKeys}
            setIsSelected={setIsSelected}
          />
        </Col>
      </Row>
    </div>
  );
};

export default DeliveryMan;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment