586 lines
21 KiB
JavaScript
586 lines
21 KiB
JavaScript
|
|
|
|
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
import { useDispatch } from 'react-redux';
|
|
import { Space, DatePicker, Checkbox, Input } from 'antd';
|
|
import {
|
|
PlusOutlined,
|
|
} from '@ant-design/icons';
|
|
import {
|
|
changeBreadCrumb,
|
|
} from '../../Features/AppPage/CenterPage.js';
|
|
import { Tables } from '../../Components/Tables/Table';
|
|
import FormHeader from '../PageComponents/FormHeader.jsx';
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
|
|
import Buttons from '../../Components/Forms/Buttons';
|
|
import { getSession } from '../../Services/Others';
|
|
import { Messages } from '../../Components/Notifications/Messages';
|
|
import dayjs from 'dayjs';
|
|
import { SearchIcon } from 'lucide-react';
|
|
import { DropDowns } from '../../Components/Forms/DropDown.jsx';
|
|
import "./stockinhand.scss"
|
|
import { getConfigTypeData } from '../../Features/ConfigMasterPage/ConfigMasterPage.js';
|
|
import { getStocksinHand } from '../../Features/StockinHand/StockinHand.js';
|
|
import { Search } from '../../../ownLib/my-ui-lib.js';
|
|
const subDirectory = import.meta.env.BASE_URL;
|
|
const { RangePicker } = DatePicker;
|
|
const items = [
|
|
{
|
|
name: 'Home',
|
|
link: `${subDirectory}app-page/home`,
|
|
},
|
|
|
|
{
|
|
name: 'Stock In Hand',
|
|
link: `${subDirectory}report/stock-in-hand`,
|
|
},
|
|
];
|
|
|
|
|
|
const StockInhand = () => {
|
|
|
|
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const dispatch = useDispatch();
|
|
const AppId = getSession('AppId');
|
|
const CompId = getSession('CompId');
|
|
const BranchId = getSession('BranchId');
|
|
|
|
const [messageType, setMessageType] = useState(null);
|
|
const [messageData, setMessageData] = useState(null);
|
|
const [TableData, setTableData] = useState([]);
|
|
const [filteredInfo, setFilteredInfo] = useState({});
|
|
const [sortedInfo, setSortedInfo] = useState({});
|
|
const [searchedText, setSearchedText] = useState('');
|
|
const [searchedTextdata, setsearchedTextdata] = useState('');
|
|
const [sortConfig, setSortConfig] = useState({ key: null, direction: null });
|
|
|
|
const [page, setpage] = useState(1);
|
|
|
|
const [OrderFromDate, setOrderFromDate] = useState(null);
|
|
const [OrderToDate, setOrderToDate] = useState(null);
|
|
const [selectedOptionData, setselectedOptionData] = useState(null);
|
|
const [SearchMethodDatas, setSearchMethodDatas] = useState([]);
|
|
const [Checkgodown, setCheckgodown] = useState(null)
|
|
|
|
|
|
console.log(Checkgodown, "Checkgodown")
|
|
|
|
|
|
useEffect(() => {
|
|
getSearchMethods()
|
|
if (location.state?.message) {
|
|
setMessageType(location.state.type);
|
|
setMessageData(location.state.message);
|
|
}
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
|
|
|
|
}, []);
|
|
|
|
async function getSearchMethods() {
|
|
try {
|
|
let Res = await dispatch(getConfigTypeData({ TypeName: "Stock In Hand Search Methods" })).unwrap()
|
|
if (Res?.data?.statusCode == 1) {
|
|
setSearchMethodDatas(Res?.data?.data)
|
|
let Data = Res?.data?.data?.find((e) => e?.ConfigName == "Product Name")
|
|
setselectedOptionData(Data?.ConfigId)
|
|
setCheckgodown(Data?.ConfigName)
|
|
}
|
|
}
|
|
catch (err) {
|
|
console.log('error', err?.message)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// const handleChange = (pagination, filters, sorter) => {
|
|
// setFilteredInfo(filters);
|
|
// setSortedInfo(sorter);
|
|
// };
|
|
|
|
// const handlePageChange = (current) => {
|
|
// setpage(current);
|
|
// };
|
|
|
|
|
|
const handleSort = (key) => {
|
|
let direction = 'asc';
|
|
if (sortConfig.key === key && sortConfig.direction === 'asc') {
|
|
direction = 'desc';
|
|
}
|
|
setSortConfig({ key, direction });
|
|
};
|
|
|
|
const filteredTableData = useMemo(() => {
|
|
let filtered = TableData;
|
|
if (searchedTextdata) {
|
|
filtered = TableData.filter(item =>
|
|
item?.ProductName?.toLowerCase().includes(searchedTextdata.toLowerCase())
|
|
);
|
|
}
|
|
|
|
if (!sortConfig.key) return filtered;
|
|
|
|
return [...filtered].sort((a, b) => {
|
|
const aValue = a[sortConfig.key] ? new Date(a[sortConfig.key]) : new Date(0);
|
|
const bValue = b[sortConfig.key] ? new Date(b[sortConfig.key]) : new Date(0);
|
|
|
|
if (sortConfig.direction === 'asc') {
|
|
return aValue - bValue;
|
|
}
|
|
return bValue - aValue;
|
|
});
|
|
}, [TableData, searchedTextdata, sortConfig]);
|
|
|
|
|
|
const onSearch = (value) => {
|
|
|
|
setSearchedText(value);
|
|
};
|
|
const onSearchChange = (e) => {
|
|
|
|
setSearchedText(e?.target?.value);
|
|
};
|
|
const onSearchData = (value) => {
|
|
setsearchedTextdata(value);
|
|
};
|
|
const onSearchChangeData = (e) => {
|
|
setsearchedTextdata(e?.target?.value); s
|
|
};
|
|
|
|
|
|
// {
|
|
// title: 'Brand',
|
|
// key: 'Brand',
|
|
// dataIndex: 'Brand',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
|
|
// },
|
|
|
|
|
|
// const columns = [
|
|
// {
|
|
// title: 'Sl.No',
|
|
// key: 'sno',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text, object, index) => (
|
|
// <a style={{ color: 'black', fontWeight: 450 }}>{(page - 1) * 10 + index + 1}</a>
|
|
// ),
|
|
// },
|
|
|
|
// {
|
|
// title: 'Name',
|
|
// key: 'ProductName',
|
|
// dataIndex: 'ProductName',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
// // {
|
|
// // title: 'Category',
|
|
// // key: 'ProdCatName',
|
|
// // dataIndex: 'ProdCatName',
|
|
// // align: 'center',
|
|
// // width: '80px',
|
|
// // render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// // },
|
|
// // {
|
|
// // title: 'Sub.Category',
|
|
// // key: 'ProdSubCatName',
|
|
// // dataIndex: 'ProdSubCatName',
|
|
// // align: 'center',
|
|
// // width: '80px',
|
|
// // render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// // },
|
|
// {
|
|
// title: 'Variant',
|
|
// key: 'ProdVariantName',
|
|
// dataIndex: 'ProdVariantName',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
|
|
// {
|
|
// title: 'Qty',
|
|
// key: 'BalanceQty',
|
|
// dataIndex: 'BalanceQty',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text, record, index) => {
|
|
// return <span style={{ fontWeight: 600, color: (typeof text === 'number' && text <= 0) || !text ? 'red' : 'black' }}> {text ?? 0} </span>
|
|
// }
|
|
|
|
// },
|
|
// {
|
|
// title: 'Batch',
|
|
// key: 'BatchRef',
|
|
// dataIndex: 'BatchRef',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
|
|
// {
|
|
// title: 'Barcode',
|
|
// key: 'QRCode',
|
|
// dataIndex: 'QRCode',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
|
|
// {
|
|
// title: 'IMEI 1',
|
|
// key: 'IMEI1',
|
|
// dataIndex: 'IMEI1',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
// {
|
|
// title: 'IMEI 2',
|
|
// key: 'IMEI2',
|
|
// dataIndex: 'LegalName',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
// {
|
|
// title: 'Rack',
|
|
// key: 'RackName',
|
|
// dataIndex: 'RackName',
|
|
// align: 'center',
|
|
// width: '80px',
|
|
// render: (text) => <span style={{ color: text ? 'black' : '#999', fontWeight: 450 }}>{text ?? ''}</span>
|
|
|
|
// },
|
|
|
|
|
|
|
|
// {
|
|
// title: 'Received Date',
|
|
// key: 'InwardDate',
|
|
// dataIndex: 'InwardDate',
|
|
// align: 'center',
|
|
// width: '120px',
|
|
// render: (text, record) => (
|
|
// <span style={{ color: record?.InwardDate ? 'black' : '#999', fontWeight: 450 }}>{record?.InwardDate ? dayjs(record?.InwardDate).format('DD-MM-YYYY') : ''}</span>
|
|
// ),
|
|
// sorter: (a, b) => {
|
|
// const da = a?.InwardDate ? new Date(a.InwardDate) : 0;
|
|
// const db = b?.InwardDate ? new Date(b.InwardDate) : 0;
|
|
// return da - db;
|
|
// },
|
|
// sortDirections: ['ascend', 'descend'],
|
|
|
|
// },
|
|
// {
|
|
// title: 'Mfg Date',
|
|
// key: 'MfgDate',
|
|
// dataIndex: 'MfgDate',
|
|
// align: 'center',
|
|
// width: '120px',
|
|
// render: (text, record) => (
|
|
// <span style={{ color: record?.MfgDate ? 'black' : '#999', fontWeight: 450 }}>{record?.MfgDate ? dayjs(record?.MfgDate).format('DD-MM-YYYY') : ''}</span>
|
|
// ),
|
|
// sorter: (a, b) => {
|
|
// const da = a?.MfgDate ? new Date(a.MfgDate) : 0;
|
|
// const db = b?.MfgDate ? new Date(b.MfgDate) : 0;
|
|
// return da - db;
|
|
// },
|
|
// sortDirections: ['ascend', 'descend'],
|
|
|
|
// },
|
|
// {
|
|
// title: 'Exp Date',
|
|
// key: 'ExpDate',
|
|
// dataIndex: 'ExpDate',
|
|
// align: 'center',
|
|
// width: '120px',
|
|
// render: (text, record) => (
|
|
// <span style={{ color: record?.ExpDate ? 'black' : '#999', fontWeight: 450 }}>{record?.ExpDate ? dayjs(record?.ExpDate).format('DD-MM-YYYY') : ''}</span>
|
|
// ),
|
|
// sorter: (a, b) => {
|
|
// const da = a?.ExpDate ? new Date(a.ExpDate) : 0;
|
|
// const db = b?.ExpDate ? new Date(b.ExpDate) : 0;
|
|
// return da - db;
|
|
// },
|
|
// sortDirections: ['ascend', 'descend'],
|
|
|
|
// },
|
|
|
|
|
|
|
|
// ];
|
|
|
|
|
|
|
|
const onComplete = useCallback(() => {
|
|
setMessageData(null);
|
|
setMessageType(null);
|
|
}, []);
|
|
|
|
|
|
|
|
const OrderDateRangeFetch = (dates, dateStrings) => {
|
|
const [from, to] = dates || [];
|
|
const [fromStr, toStr] = dateStrings || [];
|
|
|
|
if (!from || !fromStr) {
|
|
setOrderFromDate(undefined);
|
|
} else {
|
|
const DateFrom = `${fromStr.split('-').reverse().join('-')}T00:00:00`;
|
|
|
|
setOrderFromDate(DateFrom);
|
|
}
|
|
|
|
if (!to || !toStr) {
|
|
setOrderToDate(undefined);
|
|
} else {
|
|
const toIso = `${toStr.split('-').reverse().join('-')}T23:59:59`;
|
|
setOrderToDate(toIso);
|
|
}
|
|
};
|
|
|
|
const searchMethodDropDownChange = (e) => {
|
|
setselectedOptionData(e);
|
|
setSearchedText('')
|
|
const isCheckGodown = SearchMethodDatas?.find(item => item?.ConfigId == e)?.ConfigName
|
|
setCheckgodown(isCheckGodown);
|
|
|
|
|
|
}
|
|
const handlePost = async () => {
|
|
|
|
if (!searchedText) {
|
|
setMessageData('Please enter the search text')
|
|
setMessageType('warning')
|
|
return
|
|
}
|
|
let GetData = {
|
|
CompId: CompId,
|
|
AppId: AppId,
|
|
BranchId: BranchId,
|
|
SearchType: selectedOptionData,
|
|
SearchText: searchedText,
|
|
OrderFromDate: OrderFromDate?.split("T")?.[0],
|
|
OrderToDate: OrderToDate?.split("T")?.[0]
|
|
|
|
}
|
|
try {
|
|
let Res = await dispatch(getStocksinHand(GetData)).unwrap()
|
|
if (Res?.data?.statusCode == 1) {
|
|
setTableData(Res?.data?.data)
|
|
setsearchedTextdata('') // Clear search input
|
|
}
|
|
else {
|
|
setTableData([])
|
|
setsearchedTextdata('') // Clear search input
|
|
setMessageData(Res?.data?.response)
|
|
setMessageType('error')
|
|
}
|
|
}
|
|
catch (err) {
|
|
console.log('error', err?.message)
|
|
}
|
|
|
|
|
|
}
|
|
return (
|
|
<div className="userPageTable">
|
|
<div className="userPageContentStockInHand">
|
|
<Messages
|
|
messageType={messageType}
|
|
messageData={messageData}
|
|
onComplete={onComplete}
|
|
/>
|
|
<div>
|
|
|
|
|
|
<div className='stockinhandInputHeader'>
|
|
<FormHeader title={'Stock In Hand'} />
|
|
<div className='stockinhandInputHeader2'>
|
|
<div>
|
|
<DropDowns
|
|
options={SearchMethodDatas?.map((option) => ({
|
|
value: option?.ConfigId,
|
|
label: option?.ConfigName,
|
|
}))}
|
|
label={<label>Method Type</label>}
|
|
id="searchMethod"
|
|
field="searchMethod"
|
|
fieldState={true}
|
|
fieldApi={true}
|
|
className="field-DropDown-Emp"
|
|
onChangeFunction={(e) => searchMethodDropDownChange(e)}
|
|
isOnchanges={selectedOptionData ? true : false}
|
|
valueData={selectedOptionData}
|
|
|
|
/>
|
|
</div>
|
|
<div className="formSearch">
|
|
<Input
|
|
// ref={ref}
|
|
maxLength={50}
|
|
value={searchedText}
|
|
className="searchDiv"
|
|
placeholder={`${Checkgodown?.toLowerCase() === "godown"
|
|
? "Search By Godown Products"
|
|
: `Enter the ${Checkgodown}`
|
|
}`}
|
|
// onPressEnter={onSearch}
|
|
onChange={onSearchChange}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<RangePicker
|
|
format="DD-MM-YYYY"
|
|
allowClear
|
|
|
|
disabledDate={(current) => current && current > dayjs()} // Disable future dates
|
|
onChange={(dates, dateStrings) => {
|
|
OrderDateRangeFetch(dates, dateStrings);
|
|
}}
|
|
placeholder={['From Date', 'To Date']}
|
|
style={{ width: "200px" }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<Buttons
|
|
buttonText={'Search'}
|
|
handleSubmit={handlePost}
|
|
color="901D77"
|
|
icon={<SearchIcon size={16} />}
|
|
>
|
|
OPEN
|
|
</Buttons>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div className='searchProInputSH'>
|
|
<Search
|
|
value={searchedTextdata}
|
|
placeholder={`Search`}
|
|
onSearch={onSearchData}
|
|
onSearchChange={onSearchChangeData}
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
{/* <div className="reportTable stockinhandTable">
|
|
<Tables
|
|
columns={columns}
|
|
data={filteredTableData}
|
|
dataSource={filteredTableData}
|
|
pagination={handlePageChange}
|
|
onChange={handleChange}
|
|
/>{' '}
|
|
</div> */}
|
|
<div className='StockinHand-table'>
|
|
<table className="product-table-stockinHand">
|
|
<thead>
|
|
<tr>
|
|
<th>Sl.No</th>
|
|
<th>Name</th>
|
|
<th>Variant</th>
|
|
<th>Balance Qty</th>
|
|
<th>Batch</th>
|
|
<th>Barcode</th>
|
|
<th>IMEI 1</th>
|
|
<th>IMEI 2</th>
|
|
<th>Rack</th>
|
|
<th>Received Date</th>
|
|
<th onClick={() => handleSort('MfgDate')} style={{ cursor: 'pointer' }}>
|
|
Mfg Date {sortConfig.key === 'MfgDate' && (sortConfig.direction === 'asc' ? '↑' : '↓')}
|
|
</th>
|
|
<th onClick={() => handleSort('ExpDate')} style={{ cursor: 'pointer' }}>
|
|
Exp Date {sortConfig.key === 'ExpDate' && (sortConfig.direction === 'asc' ? '↑' : '↓')}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
{filteredTableData?.length > 0 ? (
|
|
filteredTableData?.map((item, index) => (
|
|
<tr key={index}>
|
|
<td>{(page - 1) * 10 + index + 1}</td>
|
|
|
|
<td>{item?.ProductName || ""}</td>
|
|
|
|
<td>{item?.ProdVariantName || ""}</td>
|
|
|
|
<td
|
|
style={{
|
|
fontWeight: 600,
|
|
color: !item?.BalanceQty || item?.BalanceQty <= 0 ? "red" : "black",
|
|
textAlign: "center"
|
|
}}
|
|
>
|
|
{item?.BalanceQty ?? 0}
|
|
</td>
|
|
|
|
<td>{item?.BatchRef || ""}</td>
|
|
|
|
<td>{item?.QRCode || ""}</td>
|
|
|
|
<td>{item?.IMEI1 || ""}</td>
|
|
|
|
<td>{item?.IMEI2 || ""}</td>
|
|
|
|
<td>{item?.RackName || ""}</td>
|
|
|
|
<td>
|
|
{item?.InwardDate
|
|
? dayjs(item.InwardDate).format("DD-MM-YYYY")
|
|
: ""}
|
|
</td>
|
|
|
|
<td>
|
|
{item?.MfgDate
|
|
? dayjs(item.MfgDate).format("DD-MM-YYYY")
|
|
: ""}
|
|
</td>
|
|
|
|
<td>
|
|
{item?.ExpDate
|
|
? dayjs(item.ExpDate).format("DD-MM-YYYY")
|
|
: ""}
|
|
</td>
|
|
</tr>
|
|
))) : (<tr>
|
|
<td colSpan="12" className="no-data" style={{ textAlign: "center", padding: "20px", color: "#888", fontWeight: "500" }}>
|
|
No products found
|
|
</td>
|
|
</tr>)
|
|
}
|
|
</tbody>
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default StockInhand;
|