ProductTable
ProductTable component client script is also using ReactJs and Ant Design react component library. This component renders the list of all products in the database. User can view information about the product.
const {
Button,
Input,
Space,
Switch,
Table,
GetRef,
Select,
TableColumnsType,
InputNumber,
Popconfirm,
Typography,
TableColumnType,
Spin
} = antd;
const { useState, useEffect, useRef, useMemo } = React;
const { SearchOutlined } = antdIcons;
const ProductTable = ({ products, edit }) => {
const [data, setData] = useState(products);
const [enableEditing, setEnableEditing] = useState(edit);
const [searchText, setSearchText] = useState("");
const [searchedColumn, setSearchedColumn] = useState("");
const searchInput = useRef(null);
const [loading, setLoading] = React.useState(false);
const handleSearch = (selectedKeys, confirm, dataIndex) => {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dataIndex);
};
const handleReset = clearFilters => {
clearFilters();
setSearchText("");
};
const getColumnSearchProps = dataIndex => ({
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
close
}) => (
<div style={{ padding: 8 }} onKeyDown={e => e.stopPropagation()}>
<Input
ref={searchInput}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e =>
setSelectedKeys(e.target.value ? [e.target.value] : [])
}
onPressEnter={() => handleSearch(selectedKeys, confirm, dataIndex)}
style={{ marginBottom: 8, display: "block" }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => clearFilters && handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
setSearchText(selectedKeys[0]);
setSearchedColumn(dataIndex);
}}
>
Filter
</Button>
<Button
type="link"
size="small"
onClick={() => {
close();
}}
>
close
</Button>
</Space>
</div>
),
filterIcon: filtered => (
<SearchOutlined style={{ color: filtered ? "#1677ff" : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase()),
onFilterDropdownOpenChange: visible => {
if (visible) {
setTimeout(() => searchInput.current?.select(), 100);
}
}
});
const options = [
{
label: "NUR",
value: "NUR"
},
{
label: "I",
value: "I"
},
{
label: "II",
value: "II"
},
{
label: "III",
value: "III"
},
{
label: "IV",
value: "IV"
},
{
label: "V",
value: "V"
},
{
label: "VI",
value: "VI"
},
{
label: "VII",
value: "VII"
},
{
label: "VIII",
value: "VIII"
},
{
label: "IX",
value: "IX"
},
{
label: "X",
value: "X"
},
{
label: "XI",
value: "XI"
},
{
label: "XII",
value: "XII"
}
];
const handlePriceChange = (record, parentRecord, newPrice) => {
console.log(
`Price changed ${record.price} ${parentRecord.key} ${newPrice}`
);
const editIndex = data.findIndex(val => val.key === parentRecord.key);
const stockRowIndex = data[editIndex].stock.findIndex(
val => val.key === record.key
);
data[editIndex].stock[stockRowIndex].price = newPrice;
setData([...data]);
};
const expandedRowRender = record => {
const columns = [
{
title: "Price",
dataIndex: "price",
key: "price",
render: (text, _record) => {
return (
<InputNumber
disabled={!enableEditing}
value={_record.price}
onChange={value => {
handlePriceChange(_record, record, value);
}}
/>
);
}
},
{
title: "Quantity",
dataIndex: "quantity",
key: "quantity"
}
];
const data = record.stock;
return <Table columns={columns} dataSource={data} pagination={false} />;
};
const handleDelete = async key => {
const newData = data.filter(item => item.key !== key);
setData(newData);
const removedRecord = data.filter(item => item.key === key);
const delPayload = { oper: "del", _id: removedRecord[0]._id };
console.log(delPayload);
const response = await http.post(`/o/products`, delPayload);
};
const handleCategoryChange = (record, newValue) => {
console.log(`Category changed ${record.category} ${newValue}`);
console.log(newValue instanceof Array);
const editIndex = data.findIndex(val => val.key === record.key);
data[editIndex].category = newValue;
setData([...data]);
};
const update = async record => {
console.log(record);
setLoading(true);
const response = await http.post("v1/postProducts", record);
console.log(response);
setLoading(false);
};
const columns = [
{
title: "SKU",
dataIndex: "sku",
key: "sku"
},
{
title: "Title",
dataIndex: "title",
key: "title",
...getColumnSearchProps("title"),
sortDirections: ["descend", "ascend"]
},
{
title: "Description",
dataIndex: "description",
key: "description"
},
{
title: "Category",
dataIndex: "category",
key: "category",
render: (text, record) => (
<Select
mode="multiple"
allowClear
style={{
width: "100%"
}}
disabled={!enableEditing}
placeholder="Please select"
onChange={value => {
handleCategoryChange(record, value);
}}
defaultValue={record.category}
options={options}
/>
)
},
{
title: "Last Stock Price",
dataIndex: "last_stock_price",
key: "last_stock_price"
},
{
title: "Total Quantity",
dataIndex: "total_quantity",
key: "total_quantity"
},
{
title: "Actions",
dataIndex: "actions",
render: (_, record) =>
data.length >= 1 ? (
<>
<Popconfirm
title="Sure to delete?"
onConfirm={value => handleDelete(record.key, value)}
>
<a>Delete</a>
</Popconfirm>
<Typography.Link style={{marginLeft: "10px"}}onClick={() => update(record)}>
Update
</Typography.Link>
</>
) : null
}
];
useMemo(() => {
// fetchAllProducts(); // This will always use latest value of count
// setData([...products])
setEnableEditing(edit);
}, [edit]);
useMemo(() => {
setData([...products])// This will always use latest value of count
}, [products]);
return (
<>
<Spin spinning={loading} delay={500}>
<Table
dataSource={data}
columns={columns}
expandable={{
expandedRowRender
}}
/>
</Spin>
</>
);
};
return ProductTable;
Last updated