added a tax, brand, sub-category, category adding in turbo add
This commit is contained in:
parent
3e9b910616
commit
0268282eb1
|
|
@ -205,6 +205,17 @@ export const getProdSubCatData = createAsyncThunk(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getActiveProdSubCatData = createAsyncThunk(
|
||||||
|
'product/getActiveProdSubCatData',
|
||||||
|
async ({ AppId }) => {
|
||||||
|
if (AppId !== null && AppId !== undefined) {
|
||||||
|
return await axiosRetailInstanceData.get(
|
||||||
|
`/configMaster?TypeName=Product Sub-Category&AppId=${AppId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const getProductData = createAsyncThunk(
|
export const getProductData = createAsyncThunk(
|
||||||
'product/getProductData',
|
'product/getProductData',
|
||||||
async (ProdData) => {
|
async (ProdData) => {
|
||||||
|
|
@ -661,6 +672,7 @@ const initialState = {
|
||||||
uomData: [],
|
uomData: [],
|
||||||
prodCatData: [],
|
prodCatData: [],
|
||||||
prodSubCatData: [],
|
prodSubCatData: [],
|
||||||
|
allProdSubCatData: [],
|
||||||
productData: [],
|
productData: [],
|
||||||
prodTaxData: [],
|
prodTaxData: [],
|
||||||
taxData: [],
|
taxData: [],
|
||||||
|
|
@ -723,6 +735,13 @@ const productSlice = createSlice({
|
||||||
state.prodSubCatData = [];
|
state.prodSubCatData = [];
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
builder.addCase(getActiveProdSubCatData.fulfilled, (state, action) => {
|
||||||
|
if (action?.payload?.status) {
|
||||||
|
state.allProdSubCatData = action?.payload?.data?.data;
|
||||||
|
} else {
|
||||||
|
state.allProdSubCatData = [];
|
||||||
|
}
|
||||||
|
}),
|
||||||
builder.addCase(getBrandData.fulfilled, (state, action) => {
|
builder.addCase(getBrandData.fulfilled, (state, action) => {
|
||||||
if (action?.payload?.status) {
|
if (action?.payload?.status) {
|
||||||
state.brandData = action?.payload?.data?.data;
|
state.brandData = action?.payload?.data?.data;
|
||||||
|
|
@ -768,6 +787,8 @@ export const uomDataSelector = (state) => state.productPage?.uomData;
|
||||||
export const prodCatDataSelector = (state) => state.productPage?.prodCatData;
|
export const prodCatDataSelector = (state) => state.productPage?.prodCatData;
|
||||||
export const prodSubCatDataSelector = (state) =>
|
export const prodSubCatDataSelector = (state) =>
|
||||||
state.productPage?.prodSubCatData;
|
state.productPage?.prodSubCatData;
|
||||||
|
export const allProdSubCatDataSelector = (state) =>
|
||||||
|
state.productPage?.allProdSubCatData;
|
||||||
export const productDataSelector = (state) => state.productPage?.productData;
|
export const productDataSelector = (state) => state.productPage?.productData;
|
||||||
export const brandDataSelector = (state) => state.productPage?.brandData;
|
export const brandDataSelector = (state) => state.productPage?.brandData;
|
||||||
export const taxSelector = (state) => state.productPage?.taxData;
|
export const taxSelector = (state) => state.productPage?.taxData;
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ function BSReprint({ setOpenModel = () => {} }) {
|
||||||
const SettingDataSelector = useSelector(PreferenceData);
|
const SettingDataSelector = useSelector(PreferenceData);
|
||||||
const salesBillEdit = useSelector(GlobalSalesBillEdit);
|
const salesBillEdit = useSelector(GlobalSalesBillEdit);
|
||||||
const custDisable = useSelector(GlobalSelectedCustDisable);
|
const custDisable = useSelector(GlobalSelectedCustDisable);
|
||||||
console.log(SettingDataSelector, 'SettingDataSelectoraa');
|
console.log(DefReason, 'DefReason');
|
||||||
const MobileA4Print = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
|
const MobileA4Print = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
|
||||||
(setting) =>
|
(setting) =>
|
||||||
setting?.SettingIdName?.toLowerCase() === 'mobilea4' &&
|
setting?.SettingIdName?.toLowerCase() === 'mobilea4' &&
|
||||||
|
|
@ -292,6 +292,7 @@ function BSReprint({ setOpenModel = () => {} }) {
|
||||||
} else {
|
} else {
|
||||||
setDefReason({});
|
setDefReason({});
|
||||||
reprintReasonRef?.current?.resetFields();
|
reprintReasonRef?.current?.resetFields();
|
||||||
|
reprintReasonRef?.current?.setFieldsValue({ SetAsDefault: false });
|
||||||
setIsDuplicate('Original');
|
setIsDuplicate('Original');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1054,7 +1055,7 @@ function BSReprint({ setOpenModel = () => {} }) {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AiFillPrinter className="BSC1Payment-icon" />
|
<AiFillPrinter color={Object.keys(DefReason)?.length > 0 ? '#52c41a' : ''} className="BSC1Payment-icon" />
|
||||||
Bill Without Token
|
Bill Without Token
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|
@ -1072,13 +1073,14 @@ function BSReprint({ setOpenModel = () => {} }) {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AiFillPrinter className="BSC1Payment-icon" />
|
<AiFillPrinter color={Object.keys(DefReason)?.length > 0 ? '#52c41a' : ''} className="BSC1Payment-icon" />
|
||||||
Bill With Token
|
Bill With Token
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<AiFillPrinter
|
<AiFillPrinter
|
||||||
style={{ fontSize: '22px', cursor: 'pointer' }}
|
style={{ fontSize: '22px', cursor: 'pointer' }}
|
||||||
|
color={Object.keys(DefReason)?.length > 0 ? '#52c41a' : ''}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setReprintData([row]);
|
setReprintData([row]);
|
||||||
if (Object.keys(DefReason)?.length > 0) {
|
if (Object.keys(DefReason)?.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ import {
|
||||||
import RackForm from '../Rack/RackForm.jsx';
|
import RackForm from '../Rack/RackForm.jsx';
|
||||||
import { isMobile } from 'react-device-detect';
|
import { isMobile } from 'react-device-detect';
|
||||||
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
||||||
|
import AddCategoryModal from './Utils/AddCategoryModal.jsx';
|
||||||
|
import AddSubCategoryModal from './Utils/AddSubCategoryModal.jsx';
|
||||||
|
import AddBrandModal from './Utils/AddBrandModal.jsx';
|
||||||
|
import AddTaxModal from './Utils/AddTaxModal.jsx';
|
||||||
const subDirectory = import.meta.env.ENV_BASE_URL;
|
const subDirectory = import.meta.env.ENV_BASE_URL;
|
||||||
|
|
||||||
const ProductForm = ({ formType }) => {
|
const ProductForm = ({ formType }) => {
|
||||||
|
|
@ -1008,20 +1012,11 @@ const ProductForm = ({ formType }) => {
|
||||||
setMessageData('Please add at least one Sub-Category.');
|
setMessageData('Please add at least one Sub-Category.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const subCategoryData = await formSubCategoryRef?.current?.validateFields();
|
|
||||||
const subCategoryTypeId = await dispatch(
|
const subCategoryTypeId = await dispatch(
|
||||||
getConfigTypeData({ TypeName: 'Product Sub-Category' })
|
getConfigTypeData({ TypeName: 'Product Sub-Category' })
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
// const addSubCategoryData = {
|
|
||||||
// TypeId: subCategoryTypeId?.data?.data?.[0]?.TypeId,
|
|
||||||
// ConfigName: subCategoryData?.SubConfigName,
|
|
||||||
// AlphaNumFId: AppId,
|
|
||||||
// NumFId: SelectedCategory,
|
|
||||||
// // SmallIcon: imageSubCategoryUrl,
|
|
||||||
// CreatedBy: UserId,
|
|
||||||
// }
|
|
||||||
|
|
||||||
const addSubCategoryData = {
|
const addSubCategoryData = {
|
||||||
TypeId: subCategoryTypeId?.data?.data?.[0]?.TypeId || 0,
|
TypeId: subCategoryTypeId?.data?.data?.[0]?.TypeId || 0,
|
||||||
ConfigDetails: Tabledata.map((item) => ({
|
ConfigDetails: Tabledata.map((item) => ({
|
||||||
|
|
@ -1980,67 +1975,7 @@ const ProductForm = ({ formType }) => {
|
||||||
// setOpenTour(false)
|
// setOpenTour(false)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
const Columns = [
|
|
||||||
{
|
|
||||||
title: 'Sl.No',
|
|
||||||
key: 'sno',
|
|
||||||
align: 'center',
|
|
||||||
render: (text, object, index) => (
|
|
||||||
<a style={{ color: 'black' }}>{(page - 1) * 10 + index + 1}</a>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'SubCategory Name',
|
|
||||||
dataIndex: 'SubCategory',
|
|
||||||
key: 'SubCategory',
|
|
||||||
editable: true,
|
|
||||||
render: (text) => <a style={{ color: 'black' }}>{text}</a>,
|
|
||||||
filteredValue: [searchedText],
|
|
||||||
onFilter: (value, record) => {
|
|
||||||
return (
|
|
||||||
String(record.TableName)
|
|
||||||
?.toLowerCase()
|
|
||||||
?.includes(value?.toLowerCase()) ||
|
|
||||||
String(record.TableName)
|
|
||||||
?.toLowerCase()
|
|
||||||
?.includes(value?.toLowerCase()) ||
|
|
||||||
String(record.ChairCount)
|
|
||||||
?.toLowerCase()
|
|
||||||
?.includes(value?.toLowerCase()) ||
|
|
||||||
String(record.ChairLevelSer)
|
|
||||||
?.toLowerCase()
|
|
||||||
?.includes(value?.toLowerCase()) ||
|
|
||||||
String(record.DineInTypeName)
|
|
||||||
?.toLowerCase()
|
|
||||||
?.includes(value?.toLowerCase())
|
|
||||||
);
|
|
||||||
},
|
|
||||||
sorter: (a, b) => a?.ProdName?.length - b?.ProdName?.length,
|
|
||||||
sortOrder:
|
|
||||||
sortedInfo.columnKey === 'SubCategory' ? sortedInfo.order : null,
|
|
||||||
ellipsis: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
key: 'Action',
|
|
||||||
dataIndex: 'Action',
|
|
||||||
align: 'center',
|
|
||||||
render: (_, record, index) => (
|
|
||||||
// Tabledata.length >= 1 ? (
|
|
||||||
<Space size="middle">
|
|
||||||
<a>
|
|
||||||
{/* {record.ActiveStatus === "A" ? ( */}
|
|
||||||
<DeleteFilled
|
|
||||||
style={{
|
|
||||||
color: '#FF4D4F',
|
|
||||||
}}
|
|
||||||
onClick={() => statusFormatter(record, index)}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const Onchangeoffertype = (a) => {
|
const Onchangeoffertype = (a) => {
|
||||||
setDiscountType(a);
|
setDiscountType(a);
|
||||||
|
|
||||||
|
|
@ -2634,8 +2569,7 @@ const ProductForm = ({ formType }) => {
|
||||||
<div className="productonlineImg">
|
<div className="productonlineImg">
|
||||||
{imagedata?.map((item, index) => (
|
{imagedata?.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
className={`singleimg ${
|
className={`singleimg ${selectedImage === item ? 'selected' : ''
|
||||||
selectedImage === item ? 'selected' : ''
|
|
||||||
}`}
|
}`}
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => setSelectedImage(item)}
|
onClick={() => setSelectedImage(item)}
|
||||||
|
|
@ -4063,184 +3997,17 @@ const ProductForm = ({ formType }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
<AddCategoryModal
|
||||||
<DefaultModal
|
ref={formCategoryRef}
|
||||||
title="Add Category"
|
|
||||||
open={OpenCategoryModel}
|
open={OpenCategoryModel}
|
||||||
footer={true}
|
close={setOpenCategoryModel}
|
||||||
buttonText="Submit"
|
|
||||||
children={
|
|
||||||
<Form ref={formCategoryRef} className="formDivAnt">
|
|
||||||
<div className="ProSubRowFlex">
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div>
|
|
||||||
<Form.Item
|
|
||||||
name="ConfigName"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
pattern: /^(?!\s*$).+/,
|
|
||||||
message: 'Please Enter Category Name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: async (_, value) => {
|
|
||||||
await validateSafeInput(value);
|
|
||||||
|
|
||||||
if (value && value.length > 50) {
|
|
||||||
return Promise.reject(
|
|
||||||
'Category Name should not exceed 50 characters'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputField
|
|
||||||
label={
|
|
||||||
<label class="required">Category Name</label>
|
|
||||||
}
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
<AddSubCategoryModal
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div className="upload_btn">
|
|
||||||
<p>Upload Icon</p>
|
|
||||||
<br></br>
|
|
||||||
<div style={{ width: 'max-content' }}>
|
|
||||||
<Imageupload
|
|
||||||
singleImage={true}
|
|
||||||
updateImageUrl={updateCategoryImageUrl}
|
|
||||||
ImageLink={imageCategoryUrl ? imageCategoryUrl : ''}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
handleSubmit={submitCategory}
|
|
||||||
handleCancel={handleCategory}
|
|
||||||
></DefaultModal>
|
|
||||||
|
|
||||||
<DefaultModal
|
|
||||||
title="Add SubCategory"
|
|
||||||
open={OpenSubCategoryModel}
|
open={OpenSubCategoryModel}
|
||||||
footer={true}
|
close={setOpenSubCategoryModel}
|
||||||
buttonText="Submit"
|
categoryData={ProdCatData}
|
||||||
handleSubmit={submitSubCategory}
|
ref={formSubCategoryRef}
|
||||||
handleCancel={handleSubCategory}
|
|
||||||
children={
|
|
||||||
<Form ref={formSubCategoryRef} className="formDivAnt">
|
|
||||||
<div className="ProSubRowFlex">
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div className="subProdCatData">
|
|
||||||
<Form.Item
|
|
||||||
name="CategoryId"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please select a Category',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<DropDowns
|
|
||||||
options={ProdCatData?.map((option) => ({
|
|
||||||
value: option.ConfigId,
|
|
||||||
label: option.ConfigName,
|
|
||||||
}))}
|
|
||||||
label={<label class="required">Category</label>}
|
|
||||||
className="field-DropDown"
|
|
||||||
onChangeFunction={handleCatDropDownChange}
|
|
||||||
valueData={SelectedCategory}
|
|
||||||
disabled={Tabledata.length >= 1}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{/* <div className="upload_btn">
|
|
||||||
<p>Upload Icon</p>
|
|
||||||
<br></br>
|
|
||||||
<Imageupload singleImage={true} updateImageUrl={updateSubCategoryImageUrl} ImageLink={imageSubCategoryUrl ? imageSubCategoryUrl : ""} />
|
|
||||||
</div> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div>
|
|
||||||
<Form.Item name="SubConfigName">
|
|
||||||
<InputField
|
|
||||||
label={
|
|
||||||
<label class="required">SubCategory Name</label>
|
|
||||||
}
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ fontSize: '25px' }}>
|
|
||||||
<Tooltip title="Add Products" placement="top">
|
|
||||||
<PlusCircleOutlined
|
|
||||||
className="product-add-iconMargin"
|
|
||||||
onClick={async () => {
|
|
||||||
try {
|
|
||||||
const values =
|
|
||||||
await formSubCategoryRef.current?.validateFields(
|
|
||||||
['CategoryId', 'SubConfigName']
|
|
||||||
);
|
|
||||||
const trimmedValue = values?.SubConfigName
|
|
||||||
? values.SubConfigName.trim()
|
|
||||||
: '';
|
|
||||||
if (!values?.CategoryId) {
|
|
||||||
throw new Error('Please Select Category');
|
|
||||||
}
|
|
||||||
if (!trimmedValue) {
|
|
||||||
throw new Error('SubCategory Name is required');
|
|
||||||
}
|
|
||||||
await validateSafeInput(trimmedValue);
|
|
||||||
if (trimmedValue.length > 50) {
|
|
||||||
throw new Error(
|
|
||||||
'SubCategory Name should not exceed 50 characters'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
!editDataval ? handleEdit() : handleadd();
|
|
||||||
} catch (error) {
|
|
||||||
message.error(
|
|
||||||
error.message || 'Please fill required fields'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="Quotation-tables"
|
|
||||||
style={{
|
|
||||||
maxwidth: '500px',
|
|
||||||
overflowX: 'auto',
|
|
||||||
scrollbarWidth: 'thin',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Table
|
|
||||||
bordered
|
|
||||||
// components={components}
|
|
||||||
// rowClassName="editable-row"
|
|
||||||
columns={Columns}
|
|
||||||
dataSource={Tabledata}
|
|
||||||
// pagination={handlePageChange}
|
|
||||||
// onChange={handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
></DefaultModal>
|
|
||||||
|
|
||||||
<DefaultModal
|
<DefaultModal
|
||||||
open={OpenRackModel}
|
open={OpenRackModel}
|
||||||
footer={false}
|
footer={false}
|
||||||
|
|
@ -4250,195 +4017,18 @@ const ProductForm = ({ formType }) => {
|
||||||
}
|
}
|
||||||
></DefaultModal>
|
></DefaultModal>
|
||||||
|
|
||||||
<DefaultModal
|
<AddBrandModal
|
||||||
title="Add Brand"
|
|
||||||
open={OpenBrandModel}
|
open={OpenBrandModel}
|
||||||
footer={true}
|
close={setOpenBrandModel}
|
||||||
buttonText="Submit"
|
subCategories={ProdSubCatData}
|
||||||
handleSubmit={submitBrand}
|
ref={formBrandRef}
|
||||||
handleCancel={handleBrand}
|
|
||||||
children={
|
|
||||||
<Form ref={formBrandRef} className="formDivAnt">
|
|
||||||
<div className="ProSubRowFlex">
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div className="subProdCatData">
|
|
||||||
<Form.Item
|
|
||||||
name="SubCategoryId"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please Select Sub-Category',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<DropDowns
|
|
||||||
options={ProdSubCatData?.map((option) => ({
|
|
||||||
value: option.ConfigId,
|
|
||||||
label: option.ConfigName,
|
|
||||||
}))}
|
|
||||||
label={<label class="required">Sub-Category</label>}
|
|
||||||
className="field-DropDown"
|
|
||||||
onChangeFunction={handleSubCatDropDownChange}
|
|
||||||
valueData={SelectedSubCategory}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
<AddTaxModal
|
||||||
|
|
||||||
<div className="upload_btn">
|
|
||||||
<p>Upload Icon</p>
|
|
||||||
<br></br>
|
|
||||||
<div style={{ width: 'max-content' }}>
|
|
||||||
<Imageupload
|
|
||||||
singleImage={true}
|
|
||||||
updateImageUrl={updateBrandImageUrl}
|
|
||||||
ImageLink={imageBrandUrl ? imageBrandUrl : ''}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="subColumnFlex">
|
|
||||||
<div>
|
|
||||||
<Form.Item
|
|
||||||
name="SubConfigName"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
pattern: /^(?!\s*$).+/,
|
|
||||||
message: 'Please Enter Brand Name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: async (_, value) => {
|
|
||||||
await validateSafeInput(value);
|
|
||||||
|
|
||||||
if (value && value.length > 50) {
|
|
||||||
return Promise.reject(
|
|
||||||
'Brand Name should not exceed 50 characters'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputField
|
|
||||||
label={<label class="required">Brand Name</label>}
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
></DefaultModal>
|
|
||||||
|
|
||||||
<DefaultModal
|
|
||||||
title="Add Tax"
|
|
||||||
open={OpenTaxModel}
|
open={OpenTaxModel}
|
||||||
footer={true}
|
close={setOpenTaxModel}
|
||||||
buttonText="Submit"
|
prodTaxData={ProdTaxData}
|
||||||
children={
|
ref={formTaxRef}
|
||||||
<Form ref={formTaxRef} className="formDivAnt">
|
|
||||||
<div className="ProSubRowFlex">
|
|
||||||
<Form.Item name="TaxName">
|
|
||||||
<DropDowns
|
|
||||||
options={ProdTaxData?.map((option) => ({
|
|
||||||
value: option.ConfigId,
|
|
||||||
label: option.ConfigName,
|
|
||||||
}))}
|
|
||||||
label="Tax Name"
|
|
||||||
className="field-DropDown"
|
|
||||||
onChangeFunction={handleTaxNameDropDownChange}
|
|
||||||
valueData={SelectedTaxNameId}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="TaxPercentage"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
pattern: /^(?:100(?:\.0+)?|\d{1,2}(?:\.\d+)?)$/,
|
|
||||||
message: 'Please Enter Valid Percentage',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: async (_, value) => {
|
|
||||||
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputField
|
|
||||||
autoComplete="off"
|
|
||||||
label="Tax Percentage"
|
|
||||||
inputMode="decimal"
|
|
||||||
onInput={(e) => {
|
|
||||||
let cleanedValue = e.target.value.replace(
|
|
||||||
/[^0-9.]/g,
|
|
||||||
''
|
|
||||||
); // Remove invalid characters
|
|
||||||
const parts = cleanedValue.split('.');
|
|
||||||
|
|
||||||
if (cleanedValue.startsWith('.')) {
|
|
||||||
cleanedValue = '0' + cleanedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.target.value =
|
|
||||||
parts.length > 2
|
|
||||||
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
||||||
: cleanedValue;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="Reference"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
pattern: /^(?!\s*$).+/,
|
|
||||||
message: 'Please Enter Reference',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: async (_, value) => {
|
|
||||||
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputField label="Reference No" autoComplete="off" />
|
|
||||||
</Form.Item>
|
|
||||||
<div>
|
|
||||||
<label className="required">Effective From :</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="EffectiveFrom"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please Enter Effective From',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<DatePic
|
|
||||||
field="EffectiveFrom"
|
|
||||||
type="number"
|
|
||||||
min={1}
|
|
||||||
max={100}
|
|
||||||
fieldState={true}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
handleSubmit={submitTax}
|
|
||||||
handleCancel={handleTax}
|
|
||||||
></DefaultModal>
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title="Is this the product you were searching for?"
|
title="Is this the product you were searching for?"
|
||||||
open={QrcodeExistsDataOpen}
|
open={QrcodeExistsDataOpen}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
getCommonAppPreference,
|
getCommonAppPreference,
|
||||||
} from '../../Features/BrachLogin/BranchLogin.js';
|
} from '../../Features/BrachLogin/BranchLogin.js';
|
||||||
import {
|
import {
|
||||||
|
allProdSubCatDataSelector,
|
||||||
bulkpostdata,
|
bulkpostdata,
|
||||||
getBrandData,
|
getBrandData,
|
||||||
getFieldSetupData,
|
getFieldSetupData,
|
||||||
|
|
@ -23,6 +24,7 @@ import {
|
||||||
postFieldSetup,
|
postFieldSetup,
|
||||||
prodCatDataSelector,
|
prodCatDataSelector,
|
||||||
prodSubCatDataSelector,
|
prodSubCatDataSelector,
|
||||||
|
prodTaxDataSelector,
|
||||||
productTypeDataSelector,
|
productTypeDataSelector,
|
||||||
putProductData,
|
putProductData,
|
||||||
uomDataSelector,
|
uomDataSelector,
|
||||||
|
|
@ -57,6 +59,11 @@ import { BiBarcodeReader } from 'react-icons/bi';
|
||||||
import BarcodeScanner from '../BookingScreen/Components/UtillComponents/BarcodeScanner.jsx';
|
import BarcodeScanner from '../BookingScreen/Components/UtillComponents/BarcodeScanner.jsx';
|
||||||
import BarcodeScannerTurbo from '../BookingScreen/Components/UtillComponents/BarcodeScannerTurbo.jsx';
|
import BarcodeScannerTurbo from '../BookingScreen/Components/UtillComponents/BarcodeScannerTurbo.jsx';
|
||||||
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
||||||
|
import AddCategoryModal from './Utils/AddCategoryModal.jsx';
|
||||||
|
import { getConfigTypeData, postConfiguration } from '../../Features/ConfigMasterPage/ConfigMasterPage.js';
|
||||||
|
import AddSubCategoryModal from './Utils/AddSubCategoryModal.jsx';
|
||||||
|
import AddBrandModal from './Utils/AddBrandModal.jsx';
|
||||||
|
import AddTaxModal from './Utils/AddTaxModal.jsx';
|
||||||
|
|
||||||
const subDirectory = import.meta.env.ENV_BASE_URL;
|
const subDirectory = import.meta.env.ENV_BASE_URL;
|
||||||
const items = [
|
const items = [
|
||||||
|
|
@ -153,9 +160,13 @@ const createValidationRules = (products) => ({
|
||||||
const TurboAddForm = () => {
|
const TurboAddForm = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
// Redux selectors
|
// Redux selectors
|
||||||
const taxData = useSelector(taxSelector);
|
const taxRef = useRef();
|
||||||
|
const brandRef = useRef();
|
||||||
|
const categoryRef = useRef();
|
||||||
|
const subCategoryRef = useRef();
|
||||||
const scannerRef = useRef();
|
const scannerRef = useRef();
|
||||||
console.log(taxData, 'taxData');
|
const prodTaxData = useSelector(prodTaxDataSelector);
|
||||||
|
const taxData = useSelector(taxSelector);
|
||||||
const UomData = useSelector(uomDataSelector);
|
const UomData = useSelector(uomDataSelector);
|
||||||
const productTypeData = useSelector(productTypeDataSelector);
|
const productTypeData = useSelector(productTypeDataSelector);
|
||||||
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
|
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
|
||||||
|
|
@ -164,8 +175,8 @@ const TurboAddForm = () => {
|
||||||
)?.PreferredCatId;
|
)?.PreferredCatId;
|
||||||
const prodCategories = useSelector(prodCatDataSelector);
|
const prodCategories = useSelector(prodCatDataSelector);
|
||||||
const prodSubCategories = useSelector(prodSubCatDataSelector);
|
const prodSubCategories = useSelector(prodSubCatDataSelector);
|
||||||
|
const allProdSubCategories = useSelector(allProdSubCatDataSelector);
|
||||||
const searchText = useSelector(GlobalSearchData);
|
const searchText = useSelector(GlobalSearchData);
|
||||||
|
|
||||||
// Session data
|
// Session data
|
||||||
const AppId = useMemo(() => getSession('AppId'), []);
|
const AppId = useMemo(() => getSession('AppId'), []);
|
||||||
const CompId = useMemo(() => getSession('CompId'), []);
|
const CompId = useMemo(() => getSession('CompId'), []);
|
||||||
|
|
@ -173,6 +184,11 @@ const TurboAddForm = () => {
|
||||||
const UserId = useMemo(() => getSession('UserId'), []);
|
const UserId = useMemo(() => getSession('UserId'), []);
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
const [openTaxModal, setOpenTaxModal] = useState(false);
|
||||||
|
const [openCategoryModal, setOpenCategoryModal] = useState(false);
|
||||||
|
const [openSubCategoryModal, setOpenSubCategoryModal] = useState(false);
|
||||||
|
const [openBrandModal, setOpenBrandModal] = useState(false);
|
||||||
|
const [imageCategoryUrl, setImageCategoryUrl] = useState('');
|
||||||
const [voiceData, setVoiceData] = useState(null);
|
const [voiceData, setVoiceData] = useState(null);
|
||||||
const [messageType, setMessageType] = useState(null);
|
const [messageType, setMessageType] = useState(null);
|
||||||
const [messageData, setMessageData] = useState(null);
|
const [messageData, setMessageData] = useState(null);
|
||||||
|
|
@ -372,6 +388,8 @@ const TurboAddForm = () => {
|
||||||
[UomPreference, taxData, prodCategories, prodSubCategories]
|
[UomPreference, taxData, prodCategories, prodSubCategories]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(selectOptions?.tax, taxData, "selectOptions tax");
|
||||||
|
|
||||||
// Filtered products for search
|
// Filtered products for search
|
||||||
const filteredProducts = useMemo(() => {
|
const filteredProducts = useMemo(() => {
|
||||||
if (!searchTerm.trim()) return products;
|
if (!searchTerm.trim()) return products;
|
||||||
|
|
@ -2022,6 +2040,12 @@ const TurboAddForm = () => {
|
||||||
field="category"
|
field="category"
|
||||||
options={defaultCategories}
|
options={defaultCategories}
|
||||||
onSubmit={handleDefaultSetting}
|
onSubmit={handleDefaultSetting}
|
||||||
|
triggerModal={setOpenCategoryModal}
|
||||||
|
Component={<AddCategoryModal
|
||||||
|
ref={categoryRef}
|
||||||
|
open={openCategoryModal}
|
||||||
|
close={setOpenCategoryModal}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
{hasField('Sub Category') && (
|
{hasField('Sub Category') && (
|
||||||
|
|
@ -2039,6 +2063,15 @@ const TurboAddForm = () => {
|
||||||
? `Selected Category : ${defaultCategories?.find((cat) => cat.value === selectedDefaultCategory)?.label}`
|
? `Selected Category : ${defaultCategories?.find((cat) => cat.value === selectedDefaultCategory)?.label}`
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
triggerModal={setOpenSubCategoryModal}
|
||||||
|
Component={<AddSubCategoryModal
|
||||||
|
open={openSubCategoryModal}
|
||||||
|
close={setOpenSubCategoryModal}
|
||||||
|
categoryData={prodCategories}
|
||||||
|
products={products}
|
||||||
|
ref={subCategoryRef}
|
||||||
|
setProducts={setProducts}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
|
|
@ -2060,6 +2093,16 @@ const TurboAddForm = () => {
|
||||||
checkBoxHeading={
|
checkBoxHeading={
|
||||||
'Apply to all selected sub-category rows'
|
'Apply to all selected sub-category rows'
|
||||||
}
|
}
|
||||||
|
triggerModal={setOpenBrandModal}
|
||||||
|
needAllSubCategories={true}
|
||||||
|
Component={<AddBrandModal
|
||||||
|
open={openBrandModal}
|
||||||
|
close={setOpenBrandModal}
|
||||||
|
subCategories={allProdSubCategories}
|
||||||
|
products={products}
|
||||||
|
setProducts={setProducts}
|
||||||
|
ref={brandRef}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
|
|
@ -2090,6 +2133,14 @@ const TurboAddForm = () => {
|
||||||
options={selectOptions.tax}
|
options={selectOptions.tax}
|
||||||
onSubmit={handleDefaultSetting}
|
onSubmit={handleDefaultSetting}
|
||||||
currentDefault={defaults.tax}
|
currentDefault={defaults.tax}
|
||||||
|
triggerModal={setOpenTaxModal}
|
||||||
|
Component={<AddTaxModal
|
||||||
|
open={openTaxModal}
|
||||||
|
close={setOpenTaxModal}
|
||||||
|
prodTaxData={prodTaxData}
|
||||||
|
ref={taxRef}
|
||||||
|
flag={true}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
import { Form } from 'antd';
|
||||||
|
import { DefaultModal } from '../../../Components/Modal/DefaultModal';
|
||||||
|
import { getSession, validateSafeInput } from '../../../Services/Others';
|
||||||
|
import { DropDowns } from '../../../Components/Forms/DropDown';
|
||||||
|
import Imageupload from '../../../Components/Forms/Upload.jsx';
|
||||||
|
import { InputField } from '../../../../ownLib/my-ui-lib';
|
||||||
|
import { forwardRef, useCallback, useState } from 'react';
|
||||||
|
import { getConfigTypeData, postConfiguration } from '../../../Features/ConfigMasterPage/ConfigMasterPage.js';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { getBrandData } from '../../../Features/ProductPage/ProductPage.js';
|
||||||
|
import { Messages } from '../../../Components/Notifications/Messages.jsx';
|
||||||
|
|
||||||
|
const AddBrandModal = forwardRef((
|
||||||
|
{
|
||||||
|
open = false,
|
||||||
|
close = () => { },
|
||||||
|
subCategories = [],
|
||||||
|
products = [],
|
||||||
|
setProducts = () => { },
|
||||||
|
}, ref) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const AppId = getSession('AppId');
|
||||||
|
const UserId = getSession('UserId');
|
||||||
|
|
||||||
|
const [messageType, setMessageType] = useState(null);
|
||||||
|
const [messageData, setMessageData] = useState(null);
|
||||||
|
const [imageBrandUrl, setBrandImageUrl] = useState('');
|
||||||
|
const [selectedSubCategory, setSelectedSubCategory] = useState(null);
|
||||||
|
|
||||||
|
const handleBrandModalClose = () => {
|
||||||
|
close(false);
|
||||||
|
setBrandImageUrl('');
|
||||||
|
setSelectedSubCategory(null);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBrandImageUrlUpdate = (url) => {
|
||||||
|
setBrandImageUrl(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubCatDropDownChange = (value) => {
|
||||||
|
setSelectedSubCategory(value);
|
||||||
|
ref?.current?.setFieldsValue({ SubCategoryId: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBrandSubmit = async () => {
|
||||||
|
|
||||||
|
const subBrandData = await ref?.current?.validateFields();
|
||||||
|
const subBrandTypeId = await dispatch(
|
||||||
|
getConfigTypeData({ TypeName: 'Product Brand' })
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
const addBrandData = {
|
||||||
|
TypeId: subBrandTypeId?.data?.data?.[0]?.TypeId,
|
||||||
|
ConfigName: subBrandData?.SubConfigName,
|
||||||
|
AlphaNumFId: AppId,
|
||||||
|
NumFId: selectedSubCategory,
|
||||||
|
SmallIcon: imageBrandUrl,
|
||||||
|
CreatedBy: UserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await dispatch(postConfiguration(addBrandData)).unwrap();
|
||||||
|
if (response?.data?.statusCode == 1) {
|
||||||
|
setBrandImageUrl('');
|
||||||
|
setMessageType('success');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
close(false);
|
||||||
|
const brandResponse = await dispatch(getBrandData({ ConfigId: selectedSubCategory }))?.unwrap();
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
if (products?.length > 0) {
|
||||||
|
const hasTheSubCategory = products.some(product => product.subCategory === selectedSubCategory);
|
||||||
|
if (hasTheSubCategory) {
|
||||||
|
if (brandResponse?.data?.statusCode == 1) {
|
||||||
|
const brands = brandResponse?.data?.data || [];
|
||||||
|
const availableBrands = brands?.filter(
|
||||||
|
(subCat) =>
|
||||||
|
subCat.NumFId === parseInt(selectedSubCategory) && !!subCat?.ConfigName
|
||||||
|
)?.map((subCat) => ({
|
||||||
|
label: subCat.ConfigName,
|
||||||
|
value: subCat.ConfigId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const updatedProducts = products?.map((product) => {
|
||||||
|
if (product.subCategory === selectedSubCategory) {
|
||||||
|
return {
|
||||||
|
...product,
|
||||||
|
availableBrands,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
});
|
||||||
|
|
||||||
|
setProducts(updatedProducts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSelectedSubCategory(null);
|
||||||
|
} else {
|
||||||
|
setBrandImageUrl('');
|
||||||
|
setSelectedSubCategory(null);
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onComplete = useCallback(() => {
|
||||||
|
setMessageType(null);
|
||||||
|
setMessageData(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Messages messageData={messageData} messageType={messageType} onComplete={onComplete} />
|
||||||
|
<DefaultModal
|
||||||
|
title="Add Brand"
|
||||||
|
open={open}
|
||||||
|
footer={true}
|
||||||
|
buttonText="Submit"
|
||||||
|
handleSubmit={handleBrandSubmit}
|
||||||
|
handleCancel={handleBrandModalClose}
|
||||||
|
children={
|
||||||
|
<Form ref={ref} className="formDivAnt">
|
||||||
|
<div className="ProSubRowFlex">
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div className="subProdCatData">
|
||||||
|
<Form.Item
|
||||||
|
name="SubCategoryId"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please Select Sub-Category',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<DropDowns
|
||||||
|
options={subCategories?.map((option) => ({
|
||||||
|
value: option.ConfigId,
|
||||||
|
label: option.ConfigName,
|
||||||
|
}))}
|
||||||
|
label={<label class="required">Sub-Category</label>}
|
||||||
|
className="field-DropDown"
|
||||||
|
onChangeFunction={handleSubCatDropDownChange}
|
||||||
|
valueData={selectedSubCategory}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<div className="upload_btn">
|
||||||
|
<p>Upload Icon</p>
|
||||||
|
<br></br>
|
||||||
|
<div style={{ width: 'max-content' }}>
|
||||||
|
<Imageupload
|
||||||
|
singleImage={true}
|
||||||
|
updateImageUrl={handleBrandImageUrlUpdate}
|
||||||
|
ImageLink={imageBrandUrl ? imageBrandUrl : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div>
|
||||||
|
<Form.Item
|
||||||
|
name="SubConfigName"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
pattern: /^(?!\s*$).+/,
|
||||||
|
message: 'Please Enter Brand Name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: async (_, value) => {
|
||||||
|
await validateSafeInput(value);
|
||||||
|
|
||||||
|
if (value && value.length > 50) {
|
||||||
|
return Promise.reject(
|
||||||
|
'Brand Name should not exceed 50 characters'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
label={<label class="required">Brand Name</label>}
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AddBrandModal
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
import { forwardRef, useCallback, useState } from "react";
|
||||||
|
import Imageupload from '../../../Components/Forms/Upload.jsx';
|
||||||
|
import { DefaultModal } from "../../../Components/Modal/DefaultModal";
|
||||||
|
import { InputField } from "../../../Components/Forms/InputField";
|
||||||
|
import { Form } from "antd";
|
||||||
|
import { getSession, validateSafeInput } from "../../../Services/Others.js";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { getConfigTypeData, postConfiguration } from "../../../Features/ConfigMasterPage/ConfigMasterPage.js";
|
||||||
|
import { getProdCatData } from "../../../Features/ProductPage/ProductPage.js";
|
||||||
|
import { Messages } from "../../../Components/Notifications/Messages.jsx";
|
||||||
|
|
||||||
|
const AddCategoryModal = forwardRef((
|
||||||
|
{
|
||||||
|
open = false,
|
||||||
|
close = () => { },
|
||||||
|
}, ref) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const AppId = getSession('AppId');
|
||||||
|
const UserId = getSession('UserId');
|
||||||
|
|
||||||
|
const [messageType, setMessageType] = useState('');
|
||||||
|
const [messageData, setMessageData] = useState('');
|
||||||
|
|
||||||
|
const [imageCategoryUrl, setImageCategoryUrl] = useState('');
|
||||||
|
|
||||||
|
const handleImageCategoryUrlUpdate = (url) => {
|
||||||
|
setImageCategoryUrl(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitCategory = async () => {
|
||||||
|
try {
|
||||||
|
const values = await ref?.current?.validateFields();
|
||||||
|
|
||||||
|
const categoryTypeId = await dispatch(
|
||||||
|
getConfigTypeData({ TypeName: 'Product Category' })
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
TypeId: categoryTypeId?.data?.data?.[0]?.TypeId,
|
||||||
|
ConfigName: values?.ConfigName,
|
||||||
|
AlphaNumFId: AppId,
|
||||||
|
SmallIcon: imageCategoryUrl,
|
||||||
|
CreatedBy: UserId,
|
||||||
|
};
|
||||||
|
const response = await dispatch(postConfiguration(data)).unwrap();
|
||||||
|
if (response?.data?.statusCode === 1) {
|
||||||
|
await dispatch(getProdCatData({ AppId: AppId }));
|
||||||
|
close(false);
|
||||||
|
setImageCategoryUrl('');
|
||||||
|
setMessageType('success');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log('Error:', error?.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
close(false);
|
||||||
|
setImageCategoryUrl('');
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onComplete = useCallback(() => {
|
||||||
|
setMessageData(null);
|
||||||
|
setMessageType(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Messages messageData={messageData} messageType={messageType} onComplete={onComplete} />
|
||||||
|
<DefaultModal
|
||||||
|
title="Add Category"
|
||||||
|
open={open}
|
||||||
|
footer={true}
|
||||||
|
buttonText="Submit"
|
||||||
|
children={
|
||||||
|
<Form ref={ref} className="formDivAnt">
|
||||||
|
<div className="ProSubRowFlex">
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div>
|
||||||
|
<Form.Item
|
||||||
|
name="ConfigName"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
pattern: /^(?!\s*$).+/,
|
||||||
|
message: 'Please Enter Category Name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: async (_, value) => {
|
||||||
|
await validateSafeInput(value);
|
||||||
|
|
||||||
|
if (value && value.length > 50) {
|
||||||
|
return Promise.reject(
|
||||||
|
'Category Name should not exceed 50 characters'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
label={
|
||||||
|
<label class="required">Category Name</label>
|
||||||
|
}
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div className="upload_btn">
|
||||||
|
<p>Upload Icon</p>
|
||||||
|
<br></br>
|
||||||
|
<div style={{ width: 'max-content' }}>
|
||||||
|
<Imageupload
|
||||||
|
singleImage={true}
|
||||||
|
updateImageUrl={handleImageCategoryUrlUpdate}
|
||||||
|
ImageLink={imageCategoryUrl ? imageCategoryUrl : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
handleSubmit={handleSubmitCategory}
|
||||||
|
handleCancel={handleModalClose}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AddCategoryModal;
|
||||||
|
|
@ -0,0 +1,337 @@
|
||||||
|
import { Form, Table } from 'antd';
|
||||||
|
import { forwardRef, useCallback, useState } from 'react';
|
||||||
|
import { DropDowns } from '../../../Components/Forms/DropDown';
|
||||||
|
import { getSession, validateSafeInput } from '../../../Services/Others';
|
||||||
|
import { InputField } from '../../../Components/Forms/InputField';
|
||||||
|
import { PlusCircleOutlined, DeleteFilled } from '@ant-design/icons';
|
||||||
|
import { Tooltip, message, Space } from 'antd';
|
||||||
|
import { DefaultModal } from '../../../Components/Modal/DefaultModal';
|
||||||
|
import { Messages } from '../../../Components/Notifications/Messages';
|
||||||
|
import { getProdSubCatData, postConfigurationmultiple } from '../../../Features/ProductPage/ProductPage';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { getConfigTypeData } from '../../../Features/ConfigMasterPage/ConfigMasterPage';
|
||||||
|
|
||||||
|
const AddSubCategoryModal = forwardRef((
|
||||||
|
{
|
||||||
|
open = false,
|
||||||
|
close = () => { },
|
||||||
|
categoryData = [],
|
||||||
|
products = [],
|
||||||
|
setProducts = () => { },
|
||||||
|
flag = false,
|
||||||
|
}, ref) => {
|
||||||
|
|
||||||
|
const AppId = getSession('AppId');
|
||||||
|
const UserId = getSession('UserId');
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [searchedText, setSearchedText] = useState('');
|
||||||
|
const [sortedInfo, setSortedInfo] = useState({});
|
||||||
|
const [editDataval, setEditDataVal] = useState(true);
|
||||||
|
const [messageType, setMessageType] = useState('');
|
||||||
|
const [messageData, setMessageData] = useState('');
|
||||||
|
const [imageSubCategoryUrl, setSubCategoryImageUrl] = useState('');
|
||||||
|
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState(null);
|
||||||
|
const [tableData, setTableData] = useState([]);
|
||||||
|
|
||||||
|
const Columns = [
|
||||||
|
{
|
||||||
|
title: 'Sl.No',
|
||||||
|
key: 'sno',
|
||||||
|
align: 'center',
|
||||||
|
render: (text, object, index) => (
|
||||||
|
<a style={{ color: 'black' }}>{(page - 1) * 10 + index + 1}</a>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'SubCategory Name',
|
||||||
|
dataIndex: 'SubCategory',
|
||||||
|
key: 'SubCategory',
|
||||||
|
editable: true,
|
||||||
|
render: (text) => <a style={{ color: 'black' }}>{text}</a>,
|
||||||
|
filteredValue: [searchedText],
|
||||||
|
onFilter: (value, record) => {
|
||||||
|
return (
|
||||||
|
String(record.TableName)
|
||||||
|
?.toLowerCase()
|
||||||
|
?.includes(value?.toLowerCase()) ||
|
||||||
|
String(record.TableName)
|
||||||
|
?.toLowerCase()
|
||||||
|
?.includes(value?.toLowerCase()) ||
|
||||||
|
String(record.ChairCount)
|
||||||
|
?.toLowerCase()
|
||||||
|
?.includes(value?.toLowerCase()) ||
|
||||||
|
String(record.ChairLevelSer)
|
||||||
|
?.toLowerCase()
|
||||||
|
?.includes(value?.toLowerCase()) ||
|
||||||
|
String(record.DineInTypeName)
|
||||||
|
?.toLowerCase()
|
||||||
|
?.includes(value?.toLowerCase())
|
||||||
|
);
|
||||||
|
},
|
||||||
|
sorter: (a, b) => a?.ProdName?.length - b?.ProdName?.length,
|
||||||
|
sortOrder:
|
||||||
|
sortedInfo.columnKey === 'SubCategory' ? sortedInfo.order : null,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'Action',
|
||||||
|
dataIndex: 'Action',
|
||||||
|
align: 'center',
|
||||||
|
render: (_, record, index) => (
|
||||||
|
// Tabledata.length >= 1 ? (
|
||||||
|
<Space size="middle">
|
||||||
|
<a>
|
||||||
|
{/* {record.ActiveStatus === "A" ? ( */}
|
||||||
|
<DeleteFilled
|
||||||
|
style={{
|
||||||
|
color: '#FF4D4F',
|
||||||
|
}}
|
||||||
|
onClick={() => statusFormatter(record, index)}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleAddSubCategory = async () => {
|
||||||
|
const subCategoryData = await ref?.current?.validateFields();
|
||||||
|
|
||||||
|
const alreadyExists = tableData.some(
|
||||||
|
(item) => item.SubCategory === subCategoryData?.SubConfigName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!alreadyExists) {
|
||||||
|
setTableData((prev) => {
|
||||||
|
const newIndex = prev.length + 1;
|
||||||
|
|
||||||
|
const datas = {
|
||||||
|
category: selectedCategory,
|
||||||
|
SubCategory: subCategoryData?.SubConfigName,
|
||||||
|
key: newIndex, // Push index here
|
||||||
|
};
|
||||||
|
|
||||||
|
return [...prev, datas];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Sub Category Already Exist');
|
||||||
|
}
|
||||||
|
ref.current.resetFields(['SubConfigName']);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitSubCategory = async () => {
|
||||||
|
if (!tableData || tableData.length === 0) {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Please add at least one Sub-Category.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subCategoryTypeId = await dispatch(
|
||||||
|
getConfigTypeData({ TypeName: 'Product Sub-Category' })
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
const addSubCategoryData = {
|
||||||
|
TypeId: subCategoryTypeId?.data?.data?.[0]?.TypeId || 0,
|
||||||
|
ConfigDetails: tableData.map((item) => ({
|
||||||
|
ConfigName: item.SubCategory,
|
||||||
|
})),
|
||||||
|
AlphaNumFId: AppId,
|
||||||
|
NumFId: selectedCategory,
|
||||||
|
CreatedBy: UserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await dispatch(
|
||||||
|
postConfigurationmultiple(addSubCategoryData)
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
if (response?.data?.statusCode == 1) {
|
||||||
|
setSubCategoryImageUrl('');
|
||||||
|
setMessageType('success');
|
||||||
|
setMessageData('Sub-Category Added Successfully');
|
||||||
|
close(false);
|
||||||
|
setSelectedCategory(null);
|
||||||
|
const subCatResponse = await dispatch(getProdSubCatData({ ConfigId: selectedCategory })).unwrap();
|
||||||
|
setTableData([]);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
if (products?.length > 0) {
|
||||||
|
const hasTheCategory = products.some(product => product.category === selectedCategory);
|
||||||
|
if (hasTheCategory) {
|
||||||
|
if (subCatResponse?.data?.statusCode == 1) {
|
||||||
|
const subCategories = subCatResponse?.data?.data || [];
|
||||||
|
const availableSubCategories = subCategories?.filter(
|
||||||
|
(subCat) =>
|
||||||
|
subCat.NumFId === parseInt(selectedCategory) && !!subCat?.ConfigName
|
||||||
|
)?.map((subCat) => ({
|
||||||
|
label: subCat.ConfigName,
|
||||||
|
value: subCat.ConfigId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const updatedProducts = products?.map((product) => {
|
||||||
|
if (product.category === selectedCategory) {
|
||||||
|
return {
|
||||||
|
...product,
|
||||||
|
availableSubCategories,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
});
|
||||||
|
|
||||||
|
setProducts(updatedProducts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(products, "selectedCategory", selectedCategory)
|
||||||
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCatDropDownChange = (value) => {
|
||||||
|
setSelectedCategory(value);
|
||||||
|
ref?.current?.setFieldsValue({ CategoryId: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusFormatter = (record, index) => {
|
||||||
|
let filteredData = tableData.filter(
|
||||||
|
(item) => item.SubCategory != record?.SubCategory
|
||||||
|
);
|
||||||
|
setTableData(filteredData);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubCatModalClose = () => {
|
||||||
|
close(false);
|
||||||
|
setSubCategoryImageUrl('');
|
||||||
|
setSelectedCategory(null);
|
||||||
|
setTableData([]);
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const onComplete = useCallback(() => {
|
||||||
|
setMessageData(null);
|
||||||
|
setMessageType(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Messages messageData={messageData} messageType={messageType} onComplete={onComplete} />
|
||||||
|
<DefaultModal
|
||||||
|
title="Add SubCategory"
|
||||||
|
open={open}
|
||||||
|
footer={true}
|
||||||
|
buttonText="Submit"
|
||||||
|
handleSubmit={handleSubmitSubCategory}
|
||||||
|
handleCancel={handleSubCatModalClose}
|
||||||
|
children={
|
||||||
|
<Form ref={ref} className="formDivAnt">
|
||||||
|
<div className="ProSubRowFlex">
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div className="subProdCatData">
|
||||||
|
<Form.Item
|
||||||
|
name="CategoryId"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please select a Category',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<DropDowns
|
||||||
|
options={categoryData?.map((option) => ({
|
||||||
|
value: option?.ConfigId,
|
||||||
|
label: option?.ConfigName,
|
||||||
|
}))}
|
||||||
|
label={<label class="required">Category</label>}
|
||||||
|
className="field-DropDown"
|
||||||
|
onChangeFunction={handleCatDropDownChange}
|
||||||
|
valueData={selectedCategory}
|
||||||
|
disabled={tableData?.length >= 1}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="subColumnFlex">
|
||||||
|
<div>
|
||||||
|
<Form.Item name="SubConfigName">
|
||||||
|
<InputField
|
||||||
|
label={
|
||||||
|
<label class="required">SubCategory Name</label>
|
||||||
|
}
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ fontSize: '25px' }}>
|
||||||
|
<Tooltip title="Add Products" placement="top">
|
||||||
|
<PlusCircleOutlined
|
||||||
|
className="product-add-iconMargin"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
const values =
|
||||||
|
await ref.current?.validateFields(
|
||||||
|
['CategoryId', 'SubConfigName']
|
||||||
|
);
|
||||||
|
const trimmedValue = values?.SubConfigName
|
||||||
|
? values.SubConfigName.trim()
|
||||||
|
: '';
|
||||||
|
if (!values?.CategoryId) {
|
||||||
|
throw new Error('Please Select Category');
|
||||||
|
}
|
||||||
|
if (!trimmedValue) {
|
||||||
|
throw new Error('SubCategory Name is required');
|
||||||
|
}
|
||||||
|
await validateSafeInput(trimmedValue);
|
||||||
|
if (trimmedValue.length > 50) {
|
||||||
|
throw new Error(
|
||||||
|
'SubCategory Name should not exceed 50 characters'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
!editDataval ? handleEdit() : handleAddSubCategory();
|
||||||
|
} catch (error) {
|
||||||
|
message.error(
|
||||||
|
error.message || 'Please fill required fields'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="Quotation-tables"
|
||||||
|
style={{
|
||||||
|
maxwidth: '500px',
|
||||||
|
overflowX: 'auto',
|
||||||
|
scrollbarWidth: 'thin',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
bordered
|
||||||
|
columns={Columns}
|
||||||
|
dataSource={tableData}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AddSubCategoryModal
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
import { forwardRef, useCallback, useState } from "react";
|
||||||
|
import { DefaultModal } from "../../../Components/Modal/DefaultModal";
|
||||||
|
import { Form } from "antd";
|
||||||
|
import { DropDowns } from "../../../Components/Forms/DropDown";
|
||||||
|
import { InputField } from "../../../Components/Forms/InputField";
|
||||||
|
import { getSession, validateSafeInput } from "../../../Services/Others";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { Messages } from "../../../Components/Notifications/Messages";
|
||||||
|
import { DatePic } from '../../../Components/Forms/DatePicker.jsx';
|
||||||
|
import { getAdmin as getTax } from "../../../Features/Tax/Tax.js";
|
||||||
|
import { getAdmin, postTax } from "../../../Features/ProductPage/ProductPage.js";
|
||||||
|
const AddTaxModal = forwardRef((
|
||||||
|
{
|
||||||
|
open = false,
|
||||||
|
close = () => { },
|
||||||
|
prodTaxData = [],
|
||||||
|
flag = false,
|
||||||
|
}, ref) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
console.log(prodTaxData, 'prodTaxData in modal');
|
||||||
|
const AppId = getSession('AppId');
|
||||||
|
const CompId = getSession('CompId');
|
||||||
|
const UserId = getSession('UserId');
|
||||||
|
|
||||||
|
const [messageType, setMessageType] = useState(null);
|
||||||
|
const [messageData, setMessageData] = useState(null);
|
||||||
|
const [selectedTaxNameId, setSelectedTaxNameId] = useState(null);
|
||||||
|
|
||||||
|
const handleTaxNameDropDownChange = async (ConfigId) => {
|
||||||
|
ref.current?.setFieldsValue({ TaxName: ConfigId });
|
||||||
|
await setSelectedTaxNameId(ConfigId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTaxModalClose = () => {
|
||||||
|
close(false);
|
||||||
|
setSelectedTaxNameId(null);
|
||||||
|
ref.current?.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmitTax = async () => {
|
||||||
|
try {
|
||||||
|
const subTaxData = await ref?.current?.validateFields();
|
||||||
|
const effectiveDate = new Date(subTaxData.EffectiveFrom);
|
||||||
|
const formattedDate = effectiveDate.toLocaleDateString('en-CA');
|
||||||
|
const addTaxData = {
|
||||||
|
CompId: CompId,
|
||||||
|
AppId: AppId,
|
||||||
|
TaxName: subTaxData?.TaxName,
|
||||||
|
TaxPercentage: subTaxData?.TaxPercentage,
|
||||||
|
EffectiveFrom: formattedDate,
|
||||||
|
Reference: subTaxData.Reference,
|
||||||
|
CreatedBy: UserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await dispatch(postTax(addTaxData)).unwrap();
|
||||||
|
if (response?.data?.statusCode == 1) {
|
||||||
|
setMessageType('success');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
close(false);
|
||||||
|
if (flag) {
|
||||||
|
await dispatch(getTax({ CompId: CompId, AppId: AppId }));
|
||||||
|
} else {
|
||||||
|
await dispatch(getAdmin({ CompId: CompId, AppId: AppId }));
|
||||||
|
}
|
||||||
|
ref?.current?.resetFields();
|
||||||
|
setSelectedTaxNameId(null);
|
||||||
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData(response?.data?.response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error:', error?.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onComplete = useCallback(() => {
|
||||||
|
setMessageType(null);
|
||||||
|
setMessageData(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Messages messageData={messageData} messageType={messageType} onComplete={onComplete} />
|
||||||
|
<DefaultModal
|
||||||
|
title="Add Tax"
|
||||||
|
open={open}
|
||||||
|
footer={true}
|
||||||
|
buttonText="Submit"
|
||||||
|
children={
|
||||||
|
<Form ref={ref} className="formDivAnt">
|
||||||
|
<div className="ProSubRowFlex">
|
||||||
|
<Form.Item name="TaxName">
|
||||||
|
<DropDowns
|
||||||
|
options={prodTaxData?.map((option) => ({
|
||||||
|
value: option.ConfigId,
|
||||||
|
label: option.ConfigName,
|
||||||
|
}))}
|
||||||
|
label="Tax Name"
|
||||||
|
className="field-DropDown"
|
||||||
|
onChangeFunction={handleTaxNameDropDownChange}
|
||||||
|
valueData={selectedTaxNameId}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="TaxPercentage"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
pattern: /^(?:100(?:\.0+)?|\d{1,2}(?:\.\d+)?)$/,
|
||||||
|
message: 'Please Enter Valid Percentage',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: async (_, value) => {
|
||||||
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
autoComplete="off"
|
||||||
|
label="Tax Percentage"
|
||||||
|
inputMode="decimal"
|
||||||
|
onInput={(e) => {
|
||||||
|
let cleanedValue = e.target.value.replace(
|
||||||
|
/[^0-9.]/g,
|
||||||
|
''
|
||||||
|
); // Remove invalid characters
|
||||||
|
const parts = cleanedValue.split('.');
|
||||||
|
|
||||||
|
if (cleanedValue.startsWith('.')) {
|
||||||
|
cleanedValue = '0' + cleanedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.value =
|
||||||
|
parts.length > 2
|
||||||
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
||||||
|
: cleanedValue;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="Reference"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
pattern: /^(?!\s*$).+/,
|
||||||
|
message: 'Please Enter Reference',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: async (_, value) => {
|
||||||
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputField label="Reference No" autoComplete="off" />
|
||||||
|
</Form.Item>
|
||||||
|
<div>
|
||||||
|
<label className="required">Effective From :</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="EffectiveFrom"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please Enter Effective From',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<DatePic
|
||||||
|
field="EffectiveFrom"
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
max={100}
|
||||||
|
fieldState={true}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
handleSubmit={handleSubmitTax}
|
||||||
|
handleCancel={handleTaxModalClose}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AddTaxModal;
|
||||||
|
|
@ -2,12 +2,19 @@ import { memo, useState, useEffect } from "react";
|
||||||
import { DropDowns } from "../../../Components/Forms/DropDown";
|
import { DropDowns } from "../../../Components/Forms/DropDown";
|
||||||
import { Checkbox, Popover } from "antd";
|
import { Checkbox, Popover } from "antd";
|
||||||
import { Settings, X } from "lucide-react";
|
import { Settings, X } from "lucide-react";
|
||||||
|
import { PlusCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Tooltip } from 'antd';
|
||||||
|
import { getActiveProdSubCatData } from "../../../Features/ProductPage/ProductPage";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { getSession } from "../../../Services/Others";
|
||||||
|
|
||||||
const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault, popOverHeading, checkBoxHeading = 'Apply to all existing rows', showField }) => {
|
const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault, popOverHeading, checkBoxHeading = 'Apply to all existing rows', showField, Component = null, triggerModal = () => { }, needAllSubCategories = false }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [selectedValue, setSelectedValue] = useState(currentDefault);
|
const [selectedValue, setSelectedValue] = useState(currentDefault);
|
||||||
const [applyToAll, setApplyToAll] = useState(false);
|
const [applyToAll, setApplyToAll] = useState(false);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
console.log(showField, "showField")
|
const [fetchSubCategoriesData, setFetchSubCategoriesData] = useState(false);
|
||||||
|
console.log(Component, "showField")
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
setSelectedValue(currentDefault);
|
setSelectedValue(currentDefault);
|
||||||
|
|
@ -15,6 +22,17 @@ const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault,
|
||||||
}
|
}
|
||||||
}, [open, currentDefault]);
|
}, [open, currentDefault]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
const fetchAllSubCategories = async () => {
|
||||||
|
await (dispatch(getActiveProdSubCatData({ AppId: getSession('AppId') })))?.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fetchSubCategoriesData) {
|
||||||
|
fetchAllSubCategories();
|
||||||
|
}
|
||||||
|
}, [fetchSubCategoriesData]);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
onSubmit(field, selectedValue, applyToAll);
|
onSubmit(field, selectedValue, applyToAll);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
|
@ -45,15 +63,28 @@ const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault,
|
||||||
}}
|
}}
|
||||||
>{showField}</div>}
|
>{showField}</div>}
|
||||||
|
|
||||||
<div className="popover-section">
|
<div className="popover-section" style={{ display: 'flex', alignItems: 'flex-start', gap: '5px' }}>
|
||||||
<DropDowns
|
<DropDowns
|
||||||
label={`Select default ${getFieldTitle(field).toLowerCase()}`}
|
label={`Select default ${getFieldTitle(field).toLowerCase()}`}
|
||||||
valueData={selectedValue}
|
valueData={selectedValue}
|
||||||
onChangeFunction={setSelectedValue}
|
onChangeFunction={setSelectedValue}
|
||||||
options={options}
|
options={options}
|
||||||
/>
|
/>
|
||||||
|
{Component && (
|
||||||
|
<Tooltip title={`Add ${getFieldTitle(field)}`} placement="top">
|
||||||
|
<PlusCircleOutlined
|
||||||
|
className="product-add-iconMargin"
|
||||||
|
onClick={() => {
|
||||||
|
triggerModal(true);
|
||||||
|
if (needAllSubCategories) {
|
||||||
|
setFetchSubCategoriesData(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{Component}
|
||||||
<div className="popover-checkbox">
|
<div className="popover-checkbox">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={applyToAll}
|
checked={applyToAll}
|
||||||
|
|
@ -76,6 +107,7 @@ const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Popover
|
<Popover
|
||||||
content={content}
|
content={content}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
|
|
@ -86,6 +118,7 @@ const DefaultSettingPopover = memo(({ field, options, onSubmit, currentDefault,
|
||||||
>
|
>
|
||||||
<Settings size={14} className="setting-icon" />
|
<Settings size={14} className="setting-icon" />
|
||||||
</Popover>
|
</Popover>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue