Merge pull request 'Fix #5: Support custom fields in Quick Add screen' (#17) from feature/5-quick-add-custom-fields into main
Reviewed-on: Pozomind/pozo-retail-app#17
This commit is contained in:
commit
ee474db911
|
|
@ -6,6 +6,7 @@ import {
|
|||
PlusCircleOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { IoSettingsOutline } from "react-icons/io5";
|
||||
import Buttons from '../../../../Components/Forms/Buttons.jsx';
|
||||
import { InputField } from '../../../../Components/Forms/InputField.jsx';
|
||||
import { Messages } from '../../../../Components/Notifications/Messages';
|
||||
|
|
@ -31,7 +32,9 @@ import {
|
|||
supplierSelector,
|
||||
postProductData,
|
||||
postTax,
|
||||
getHsnData
|
||||
getHsnData,
|
||||
getFieldSetupData,
|
||||
postFieldSetup
|
||||
} from '../../../../Features/ProductPage/ProductPage.js';
|
||||
import {
|
||||
ChangeNewQrProduct,
|
||||
|
|
@ -78,8 +81,12 @@ const ProductForm = ({
|
|||
const productFieldPreferences = appPreferences?.find(
|
||||
(preference) => preference?.PreferredCatName?.toLowerCase() === "product form fields"
|
||||
)?.PreferenceCatDetails;
|
||||
|
||||
|
||||
// const CustomQuickAddField = appPreferences?.find(
|
||||
// (preference) => preference?.PreferredCatName?.toLowerCase() === "quick add custom fields"
|
||||
// )?.PreferenceCatDetails;
|
||||
const categoryId = appPreferences?.find(
|
||||
p => p?.PreferredCatName?.toLowerCase() === "quick add custom fields"
|
||||
)?.PreferredCatId;
|
||||
|
||||
const UomTypePreference = appPreferences?.find((preference) => preference?.PreferredCatName === 'Product Uom')?.PreferenceCatDetails
|
||||
const UomPreference = UomData?.filter((item) => UomTypePreference?.some?.((e) => e?.PreferredSubCatName?.toLowerCase() == item?.ConfigName?.toLowerCase() && e?.PreferredStatus == "Y"))
|
||||
|
|
@ -87,6 +94,7 @@ const ProductForm = ({
|
|||
const filteredFields = productFieldPreferences?.filter(
|
||||
(field) => field?.PreferredStatus === 'Y'
|
||||
);
|
||||
|
||||
const cessField = filteredFields?.find((field) => field?.PreferredSubCatName === 'Cess');
|
||||
const hsnField = filteredFields?.find((field) => field?.PreferredSubCatName === 'HSN');
|
||||
const taxField = filteredFields?.find((field) => field?.PreferredSubCatName === 'Tax');
|
||||
|
|
@ -95,15 +103,21 @@ const ProductForm = ({
|
|||
const [messageType, setMessageType] = useState(null);
|
||||
const [messageData, setMessageData] = useState(null);
|
||||
const [SelectedUom, setSelectedUom] = useState(null);
|
||||
|
||||
const [SelectedTaxId, setSelectedTaxId] = useState(null);
|
||||
const [SelectedTaxNameId, setSelectedTaxNameId] = useState(null);
|
||||
const [OpenTaxModel, setOpenTaxModel] = useState(false);
|
||||
const [OpenAdd, setOpenAdd] = useState(false);
|
||||
// const [OpenAdd, setOpenAdd] = useState(false);
|
||||
const [imageBrandUrl, setBrandImageUrl] = useState('');
|
||||
const [selectedHsn, setSelectedHsn] = useState("");
|
||||
const [HsnDetails, setHsnDetails] = useState([]);
|
||||
|
||||
|
||||
const [selectedAdditionalColumn, setSelectedAdditionalColumn] = useState([]);
|
||||
const [showColumnModal, setShowColumnModal] = useState(false);
|
||||
const [tempSelectedColumns, setTempSelectedColumns] = useState([]);
|
||||
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
|
||||
const [selectedFields, setSelectedFields] = useState([]);
|
||||
console.log(selectedAdditionalColumn, "selectedAdditionalColumn")
|
||||
console.log(tempSelectedColumns, "tempSelectedColumns")
|
||||
const CompId = getSession('CompId');
|
||||
const BranchId = getSession('BranchId');
|
||||
const AppId = getSession('AppId');
|
||||
|
|
@ -149,19 +163,39 @@ const ProductForm = ({
|
|||
setSelectedTaxId(TaxId);
|
||||
}
|
||||
}, [TaxData]);
|
||||
useEffect(() => {
|
||||
getFieldSetup();
|
||||
}, [categoryId])
|
||||
|
||||
const getFieldSetup = async () => {
|
||||
try {
|
||||
const response = await dispatch(getFieldSetupData({ AppId, CompId, BranchId, categoryId, Type: "QA" })).unwrap();
|
||||
if (response?.data?.statusCode === 1) {
|
||||
console.log(response?.data?.data?.[0]?.ConfigDtl, "Field Setup Data");
|
||||
setSelectedFields(response?.data?.data?.[0]?.ConfigDtl?.filter(c => c.ConfigId && c.Access === 'Y')?.map(c => c.ConfigId) || []);
|
||||
setSelectedAdditionalColumn(response?.data?.data?.[0]?.ConfigDtl?.filter(c => c.ConfigId && c.Access === 'Y')?.map(c => c.ConfigName) || [])
|
||||
setTableFieldPreferences(response?.data?.data?.[0]?.ConfigDtl?.map(c => ({
|
||||
value: c.ConfigId,
|
||||
label: c.ConfigName,
|
||||
access: c.Access
|
||||
})) || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching field setup:', error);
|
||||
}
|
||||
};
|
||||
const onComplete = useCallback(() => {
|
||||
setMessageData(null);
|
||||
setMessageType(null);
|
||||
}, []);
|
||||
|
||||
const openAdditionalDetails = () => {
|
||||
if (OpenAdd) {
|
||||
setOpenAdd(false);
|
||||
} else {
|
||||
setOpenAdd(true);
|
||||
}
|
||||
};
|
||||
// const openAdditionalDetails = () => {
|
||||
// if (OpenAdd) {
|
||||
// setOpenAdd(false);
|
||||
// } else {
|
||||
// setOpenAdd(true);
|
||||
// }
|
||||
// };
|
||||
|
||||
const getApplicationPreference = async () => {
|
||||
|
||||
|
|
@ -367,7 +401,7 @@ const ProductForm = ({
|
|||
setSelectedUom(null);
|
||||
setSelectedTaxId(null);
|
||||
handleCancelData();
|
||||
setOpenAdd(false);
|
||||
// setOpenAdd(false);
|
||||
if (ProductSearchType != 'C') {
|
||||
let data = {
|
||||
CompId: CompId,
|
||||
|
|
@ -444,6 +478,36 @@ const ProductForm = ({
|
|||
}
|
||||
|
||||
}
|
||||
const handleFieldSetupSubmit = async () => {
|
||||
|
||||
const postData = {
|
||||
"AppId": AppId,
|
||||
"CompId": CompId,
|
||||
"BranchId": BranchId,
|
||||
"Type": "QA",
|
||||
"FormType": "Quick Add",
|
||||
"TypeId": categoryId,
|
||||
"ConfigDtl": selectedFields?.map((field) => ({
|
||||
"ConfigId": field,
|
||||
"Access": 'Y',
|
||||
})),
|
||||
"CreatedBy": UserId
|
||||
}
|
||||
|
||||
const response = await dispatch(postFieldSetup(postData))?.unwrap();
|
||||
|
||||
if (response?.data?.statusCode === 1) {
|
||||
setSelectedAdditionalColumn([...tempSelectedColumns]);
|
||||
setShowColumnModal(false);
|
||||
setTempSelectedColumns([])
|
||||
setMessageType("success");
|
||||
setMessageData(response?.data?.response);
|
||||
await getFieldSetup();
|
||||
} else {
|
||||
setMessageType("error");
|
||||
setMessageData("Failed to set up fields");
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Messages
|
||||
|
|
@ -455,6 +519,27 @@ const ProductForm = ({
|
|||
<FormHeader title={'Quick Add'} />
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', gap: '10px', justifyContent: "flex-end"
|
||||
, fontFamily: "Poppins", fontWeight: "500", textDecoration: "underline", cursor: "Pointer", width: "100%"
|
||||
}}
|
||||
onClick={() => {
|
||||
setTempSelectedColumns([...selectedAdditionalColumn]);
|
||||
setShowColumnModal(true);
|
||||
}}>
|
||||
<Tooltip title="Add Fields" placement="left">
|
||||
{/* <span>Additional Fields</span> */}
|
||||
<IoSettingsOutline
|
||||
onClick={() => {
|
||||
setTempSelectedColumns([...selectedAdditionalColumn]);
|
||||
setShowColumnModal(true);
|
||||
}}
|
||||
style={{ cursor: 'pointer', fontSize: '20px' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Form ref={formRef} className="formDivAnt" onFinish={onFinish}>
|
||||
<div>
|
||||
<div className="productinputForm">
|
||||
|
|
@ -667,30 +752,35 @@ const ProductForm = ({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{OpenAdd && (
|
||||
{true && (
|
||||
<>
|
||||
{taxField && <Form.Item name="TaxId">
|
||||
<DropDowns
|
||||
options={TaxData?.map((option) => ({
|
||||
value: option.TaxId,
|
||||
label: getOptionLabel(
|
||||
option,
|
||||
SelectedTaxId === option.TaxId
|
||||
),
|
||||
// label: option.TaxIdName + ' - ' + option.TaxPercentage + ' % ',
|
||||
}))}
|
||||
label="Tax"
|
||||
className="field-DropDown"
|
||||
isOnchanges={SelectedTaxId ? true : false}
|
||||
onChangeFunction={handleTaxDropDownChange}
|
||||
valueData={SelectedTaxId}
|
||||
/>
|
||||
<Tooltip title="Add Tax" placement="top">
|
||||
<PlusCircleOutlined onClick={addTax} />
|
||||
</Tooltip>
|
||||
</Form.Item>}
|
||||
{(taxField && selectedAdditionalColumn?.includes('Tax')) &&
|
||||
<Form.Item name="TaxId">
|
||||
<DropDowns
|
||||
options={TaxData?.map((option) => ({
|
||||
value: option.TaxId,
|
||||
label: getOptionLabel(
|
||||
option,
|
||||
SelectedTaxId === option.TaxId
|
||||
),
|
||||
// label: option.TaxIdName + ' - ' + option.TaxPercentage + ' % ',
|
||||
}))}
|
||||
label="Tax"
|
||||
className="field-DropDown"
|
||||
isOnchanges={SelectedTaxId ? true : false}
|
||||
onChangeFunction={handleTaxDropDownChange}
|
||||
valueData={SelectedTaxId}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
{(taxField && selectedAdditionalColumn?.includes('Tax')) &&
|
||||
<Form.Item name="TaxId">
|
||||
<Tooltip title="Add Tax" placement="top">
|
||||
<PlusCircleOutlined onClick={addTax} />
|
||||
</Tooltip>
|
||||
</Form.Item>}
|
||||
|
||||
{cessField && <Form.Item
|
||||
{(cessField && selectedAdditionalColumn?.includes('Cess')) && <Form.Item
|
||||
name="Cess"
|
||||
rules={[
|
||||
{
|
||||
|
|
@ -708,13 +798,13 @@ const ProductForm = ({
|
|||
<InputField autoComplete="off" label="Cess" />
|
||||
</Form.Item>}
|
||||
|
||||
{hsnField &&
|
||||
<Form.Item
|
||||
name="HSNCode"
|
||||
rules={[
|
||||
{
|
||||
{(hsnField && selectedAdditionalColumn?.includes('Hsn Code')) &&
|
||||
<Form.Item
|
||||
name="HSNCode"
|
||||
rules={[
|
||||
{
|
||||
message: 'Please enter HSN',
|
||||
},
|
||||
},
|
||||
|
||||
]}
|
||||
>
|
||||
|
|
@ -779,32 +869,34 @@ const ProductForm = ({
|
|||
}
|
||||
|
||||
|
||||
<Form.Item
|
||||
name="WhSalePrice"
|
||||
rules={[
|
||||
{
|
||||
pattern: /^[0-9]\d*(\.\d+)?$/,
|
||||
message: 'Please Enter WholeSale',
|
||||
},
|
||||
{
|
||||
validator: async (_, value) => {
|
||||
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
||||
return Promise.resolve();
|
||||
{selectedAdditionalColumn?.includes('WholeSale') &&
|
||||
<Form.Item
|
||||
name="WhSalePrice"
|
||||
rules={[
|
||||
{
|
||||
pattern: /^[0-9]\d*(\.\d+)?$/,
|
||||
message: 'Please Enter WholeSale',
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputField
|
||||
autoComplete="off"
|
||||
label={<label>WholeSale</label>}
|
||||
/>
|
||||
</Form.Item>
|
||||
{
|
||||
validator: async (_, value) => {
|
||||
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputField
|
||||
autoComplete="off"
|
||||
label={<label>WholeSale</label>}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="prodAddDetails" onClick={openAdditionalDetails}>
|
||||
{/* <div className="prodAddDetails" onClick={openAdditionalDetails}>
|
||||
Additional Details
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
|
|
@ -823,6 +915,7 @@ const ProductForm = ({
|
|||
open={OpenTaxModel}
|
||||
footer={true}
|
||||
buttonText="Submit"
|
||||
destroyOnClose={true}
|
||||
children={
|
||||
<Form ref={formTaxRef} className="formDivAnt">
|
||||
<div className="subRowFlex">
|
||||
|
|
@ -901,6 +994,51 @@ const ProductForm = ({
|
|||
handleSubmit={submitTax}
|
||||
handleCancel={handleTax}
|
||||
></DefaultModal>
|
||||
|
||||
<DefaultModal
|
||||
title="Select Additional Fields"
|
||||
open={showColumnModal}
|
||||
footer={true}
|
||||
buttonText="Apply"
|
||||
destroyOnClose={true}
|
||||
handleSubmit={handleFieldSetupSubmit}
|
||||
handleCancel={() => {
|
||||
setShowColumnModal(false);
|
||||
setSelectedFields([...selectedAdditionalColumn.map(col =>
|
||||
tableFieldPreferences?.find(pref => pref.label === col)?.value
|
||||
).filter(Boolean)]);
|
||||
setTempSelectedColumns([...selectedAdditionalColumn]);
|
||||
}}
|
||||
>
|
||||
<div style={{ padding: '20px' }}>
|
||||
{tableFieldPreferences?.map((option) => (
|
||||
<div key={option.value} className='Customized_QuickAdd'>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedFields?.includes(option.value)}
|
||||
onChange={(e) => {
|
||||
const isChecked = e.target.checked;
|
||||
setSelectedFields(prev =>
|
||||
isChecked
|
||||
? [...prev, option.value]
|
||||
: prev.filter(item => item !== option.value)
|
||||
);
|
||||
setTempSelectedColumns(prev =>
|
||||
isChecked
|
||||
? [...prev, option.label]
|
||||
: prev.filter(item => item !== option.label)
|
||||
);
|
||||
}}
|
||||
style={{ marginRight: '8px' }}
|
||||
/>
|
||||
{option.label}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DefaultModal>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,24 +1,9 @@
|
|||
.cropUploadFieldSmall {
|
||||
:where(
|
||||
.css-dev-only-do-not-override-1v5z42l
|
||||
).ant-upload-wrapper.ant-upload-picture-card-wrapper
|
||||
.ant-upload-list.ant-upload-list-picture-card
|
||||
.ant-upload-list-item-container,
|
||||
:where(
|
||||
.css-dev-only-do-not-override-1v5z42l
|
||||
).ant-upload-wrapper.ant-upload-picture-circle-wrapper
|
||||
.ant-upload-list.ant-upload-list-picture-card
|
||||
.ant-upload-list-item-container,
|
||||
:where(
|
||||
.css-dev-only-do-not-override-1v5z42l
|
||||
).ant-upload-wrapper.ant-upload-picture-card-wrapper
|
||||
.ant-upload-list.ant-upload-list-picture-circle
|
||||
.ant-upload-list-item-container,
|
||||
:where(
|
||||
.css-dev-only-do-not-override-1v5z42l
|
||||
).ant-upload-wrapper.ant-upload-picture-circle-wrapper
|
||||
.ant-upload-list.ant-upload-list-picture-circle
|
||||
.ant-upload-list-item-container {
|
||||
|
||||
:where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container,
|
||||
:where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container,
|
||||
:where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container,
|
||||
:where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container {
|
||||
width: 65px;
|
||||
height: 65px;
|
||||
}
|
||||
|
|
@ -125,6 +110,7 @@
|
|||
.float-label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ant-form-item-explain-error {
|
||||
position: relative;
|
||||
top: 16px;
|
||||
|
|
@ -333,14 +319,14 @@
|
|||
}
|
||||
|
||||
.viewerExcelupload .ant-table-wrapper,
|
||||
.viewerExcelupload .ant-table-tbody > tr.ant-table-row > td {
|
||||
.viewerExcelupload .ant-table-tbody>tr.ant-table-row>td {
|
||||
padding: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.viewerExcelupload .ant-table-wrapper,
|
||||
.viewerExcelupload .ant-table-thead > tr > th {
|
||||
.viewerExcelupload .ant-table-thead>tr>th {
|
||||
padding: 1px 8px !important;
|
||||
}
|
||||
|
||||
|
|
@ -395,7 +381,7 @@
|
|||
}
|
||||
|
||||
.productinputForm {
|
||||
.ant-input-affix-wrapper > input.ant-input {
|
||||
.ant-input-affix-wrapper>input.ant-input {
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -449,7 +435,7 @@
|
|||
}
|
||||
|
||||
.product-Add-HSN {
|
||||
.ant-input-affix-wrapper > input.ant-input {
|
||||
.ant-input-affix-wrapper>input.ant-input {
|
||||
padding: 12px 0 0 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -490,7 +476,15 @@
|
|||
}
|
||||
|
||||
|
||||
.productFormproductImg{
|
||||
.productFormproductImg {
|
||||
width: 350px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.Customized_QuickAdd {
|
||||
margin-bottom: 10px;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
Loading…
Reference in New Issue