Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Developing new API which is completely driven by address hierarchy and uses AddressNode psql table to get required nodes data

Expand
titleapi/CustomerPortal/fetchGeneralAddressCode
Code Block
const fetchGeneralAddressCode = async (organisationId, extendedModels, params, options = {}) => {

    const { searchType, queryString } = params;
    if (!searchType) {
        throw helper.wrongInputError('Location Key should be present');
    }

    const metaData = await addressHierarchy.getAddressMetadata(extendedModels, organisationId);
    if (!metaData) {
        throw helper.wrongInputError('Metadata not found');
    }
    const hierarchy = metaData.hierarchy || [];
    const nodeHierarchyMetaData = hierarchy.find(obj => helper.sanitizeStringCode(obj.location_key) === helper.sanitizeStringCode(searchType));
    if (!nodeHierarchyMetaData) {
        throw helper.wrongInputError('Invalid Location Key');
    }
    const parentMetaDataArr = [];
    let searchTypeNodeFound = false;
    if (Array.isArray(hierarchy) && hierarchy.length > 0) {
        for (let i = 0; i < (hierarchy.length - 1); i++) {
            if (searchTypeNodeFound || helper.sanitizeStringCode(hierarchy[i].location_key) === helper.sanitizeStringCode(searchType)) {
                searchTypeNodeFound = true;
                parentMetaDataArr.push(hierarchy[i + 1]);
            }
        }
    }

    const queryParameters = [];
    let heirarchyId = nodeHierarchyMetaData.id;
    let nodeCode = helper.sanitizeStringCode(queryString);

    const toRet = {};
    toRet.data = {};
    queryParameters.push(organisationId);
    queryParameters.push(heirarchyId);
    queryParameters.push(nodeCode);

    const selectPart = 'SELECT addressNode.id as node_id,addressNode.code as node_code,addressNode.name as node_name,addressNode.hierarchy_id as hierarchy_id';
    const fromPart = ' FROM addressNode';
    let extendedSelectPart = '';
    let joinPart = '';
    const wherePart = ' WHERE addressNode.organisation_id = $1 and addressNode.hierarchy_id = $2 and addressNode.code = $3';

    if (parentMetaDataArr.length) {
        extendedSelectPart = ',addressNode.parent_node_id as parent_node_id,parentAddressNode.code as parent_code,parentAddressNode.name as parent_name';
        joinPart = ' JOIN addressNode AS parentAddressNode on addressNode.parent_node_id = parentAddressNode.id';
    }
    const queryToExecute = selectPart + extendedSelectPart + fromPart + joinPart + wherePart;
    const result = await helper.executeQueryAsync(extendedModels.AddressNode, queryToExecute, queryParameters, options);

    if (result[0] && result[0].node_name) {
        toRet.data[searchType] = result[0].node_name;
    } else {
        throw helper.wrongInputError('Data not found for this location key');
    }

    let nextNodesResult = result;
    for (let i = 0; i < parentMetaDataArr.length; i++) {
        try {
            heirarchyId = parentMetaDataArr[i].id;
            nodeCode = nextNodesResult[0].parent_code;
            const locationKey = parentMetaDataArr[i].location_key;

            queryParameters[1] = heirarchyId;
            queryParameters[2] = nodeCode;
            if (i === (parentMetaDataArr.length - 1)) {
                const lastNodeQueryResult = selectPart + fromPart + wherePart;
                nextNodesResult = await helper.executeQueryAsync(extendedModels.AddressNode, lastNodeQueryResult, queryParameters, options);
            } else {
                nextNodesResult = await helper.executeQueryAsync(extendedModels.AddressNode, queryToExecute, queryParameters, options);
            }
            if (nextNodesResult[0] && nextNodesResult[0].node_name) {
                toRet.data[locationKey] = nextNodesResult[0].node_name;
            }
        } catch (err) {
            //do nothing
        }
    }
    return toRet;
};
Code Block
//success response type will be like

...

Code Block
 
{
    "data": {
        "pincode": "DAM",
        "city": "Z1",
        "state": "DAMMAM"
    }
}

...

To make filter also applicable on name and code both while fetching node list at frontend, updating filter logic.

Current filter logic:

Expand
titleCurrent filter logic:
Code Block
const conditions = {
            hierarchy_id: hierarchyId,
            organisation_id: organisationId
        };

        if (isDataSearchApplied) {
            searchQuery = helper.sanitizeStringCode(searchQuery);
            let queryString = `${searchQuery}%`;

			if (sortResult) {
				queryString = `%${queryString}`;
			}

            conditions.code = {ilike: queryString};
			if (shouldSearchByName) {
				conditions.name = {ilike: queryString};
				delete conditions.code;
			}
        }
		
		const heirarchyData = await extendedModels.AddressNode.find({
			where: conditions,
			fields: { code: true, name: true, id: true },
			order: sortResult && 'name ASC',
		});
		

Updated filter logic:

Expand
titleUpdated filter logic:
Code Block
const conditions = {
			and: [
				{hierarchy_id: hierarchyId},
				{organisation_id: organisationId},
			],
		};

		if (isDataSearchApplied) {
            searchQuery = helper.sanitizeStringCode(searchQuery);
            let queryString = `${searchQuery}%`;

			if (sortResult) {
				queryString = `%${queryString}`;
			}

			const orConditions = shouldIncludeNameInSearchFilter
				? [
					{ name: { ilike: queryString } },
					{ code: { ilike: queryString } }
				]
				: 
				[{ code: { ilike: queryString } }];

			conditions.and.push({ or: orConditions });
        }
		
		const heirarchyData = await extendedModels.AddressNode.find({
			where: conditions,
			fields: { code: true, name: true, id: true }
		});
		

Frontend changes:

  1. At frontend side changes are to be done at 3 places

    1. Add Consignment modal (src/components/pages/details/AddDetails.tsx )

    2. Counter Booking → Add Address ( src/components/pages/OpsDashboard/Manage/counterBooking/AddAddress2.tsx )

    3. Customer-Portal → src/components/address/create-address.tsx

  2. List to be populated in dropdown will be fetched after entering atleast 3 characters in the input field for corresponding node( pincode, city, state, country).

  3. Debouncing will be implemented at all places whereever we are fetching list to be populated in the dropdown.

  4. In case allowOverrideHierarchy is false , we will let user only enter values from dropdown only.

  5. In case allowOverrideHierarchy is true: user can either select from dropdown or enter other values too.

  6. Only those fields will be disabled for which data is fetched, only when allow override hierarchy is false

...

Instead of showing only Name of options in dropdown it will now be shown as Name (Code). This will require another update in find query in common/models/customer-portal-parts/address-node-api-helper.jsgetAddressNodeData (mentioned above in backend changes).

Customer Portal changes

Changes in src/components/address/create-address.tsx

General Function to be called whenever any option from rendered dropdown is selected, it make call to api api/CustomerPortal/fetchGeneralAddressCode

Code Block
// this logic will be used to get whether isAddressHierarchyPresent is true or false
 if (Array.isArray(response.data.hierarchy) && response.data.hierarchy.length) {
                 })(setIsAddressHierarchyPresent(true);
                   <Select
                     showSearch
   }
  1. In case isAddressHierarchyPresent is false then we will render only Simple Input text field.

  2. If isAddressHierarchyPresent is true:

  • It fetches data from AddressNode table on basis of address hierarchy setup, and returns data for current and higher nodes to populate.

  • It also handle the logic to either disbale the higher level nodes based on whether their value is fetched and allow_override_hierarchy is false.

  • It also update (auto populate) the value of higher nodes

Expand
titlesaveAddressUsingAddressHierarchy code snippet called on onChange
Code Block
const saveAddressUsingAddressHierarchy = async (nodeValue: string, nodeType: string) => {
        if (!isKeyOfNewAddress(nodeType) || !nodeValue) return;
     
optionFilterProp="children"
   setLoading(true);

        const fetchLocality = await fetchAddressUsingAddressHierarchy({ queryString: nodeValue, searchType: nodeType 
onChange={(value
})
=> this.saveAddressUsingAddressHierarchy(value, 'country', 'sender')}
;

        if (!fetchLocality.isSuccess) {
            setNewAddress({
        
placeholder={t("Country")}
        ...newAddress,
             
disabled={this.state.senderDisableCountry}
   city: '',
                state: '',
   
onSearch={this.loadCountries}
             country: '',
       
allowClear
     });
            setDisableLocality(false);
 
>
       } else {
            
{this.state?.countriesList?.map(opt => <Option key={opt.id} value={opt.code}>{t(opt.name)} ({opt.code})</Option>)}
let nodeFound = false;
            const parentLevelNodes = [];
          
</Select>,
  for (let i = 0; i < hierarchyData?.length; i += 1) {
    
)}
            const curNode 
{this.state.allowOverrideHierarchy && getFieldDecorator('sender_country', {
= hierarchyData[i].location_key.toLowerCase();
                if ((nodeFound || curNode === nodeType.toLocaleLowerCase()) && 
rules: [
curNode in fetchLocality?.data) {
required:
 
false,
 
message:
 
t('cannot_be_empty')
 
}],
                nodeFound 
})(
= true;
                 
<AutoComplete
   parentLevelNodes.push({ key: hierarchyData[i].location_key, value: fetchLocality?.data[curNode] });
            
options={this.state?.countriesList?.map(item
 
=>
 
({
 
label:
 
`${item.name} (${item.code})`, value: item.code }))}
}
            }
            const fetchedAddressFieldsObj 
onSearch
=
{this.loadCountries}
 parentLevelNodes?.reduce((acc, curr) => {
                if 
onSelect={(value
(isKeyOfNewAddress(curr.key)) 
=> this.saveAddressUsingAddressHierarchy(value, 'country', 'sender')}
{
                    
onChange={(value) => this.handleAddressFields('country', value, !this.state.allowOverrideHierarchy, 'sender')}
acc[curr.key] = curr.value || null;
                    if 
disabled={this.state.senderDisableCountry}
(curr.key !== nodeType && (!isAddressMappingAllowed && curr.value)) {
                   
allowClear
     setDisableLocality(true, curr.key);
            
>
        } else {
          
<Input
              setDisableLocality(false, curr.key);
       
allowClear
             }
         
placeholder={t("Country")}
       }
             
/>
   return acc;
            }, 
</AutoComplete>,

Instead of showing only Name of options in dropdown it will now be shown as Name (Code). This will require another update in find query in common/models/customer-portal-parts/address-node-api-helper.jsgetAddressNodeData (mentioned above in backend changes).

Customer Portal changes

Changes in src/components/address/create-address.tsx

General Function to be called whenever any option from rendered dropdown is selected, it make call to api api/CustomerPortal/fetchGeneralAddressCode

  1. It fetches data from AddressNode table on basis of address hierarchy setup, and returns data for current and higher nodes to populate.

  2. It also handle the logic to either disbale the higher level nodes based on whether their value is fetched and allow_override_hierarchy is false.

  3. It also update (auto populate) the value of higher nodes.

Code Block
const saveAddressUsingAddressHierarchy = async (nodeValue: string, nodeType: string) => { if (!isKeyOfNewAddress(nodeType) || !nodeValue) return; setLoading(true);
{} as { [key: string]: string | null });
            setNewAddress({
                ...newAddress,
                ...fetchedAddressFieldsObj,
            });
        }

        setLoading(false);
    };

Function to be called on typing text to be searched in address fields( pincode, city, state country)

Expand
titleSearching function logic called on onSearch
Code Block
const loadPincodes = async (value: any) => {
        if (value?.length < 3) return;
        if (!hierarchyData?.some((node: any) => node.location_key === 'pincode')) return;
        setLoading(true);

        const response = await fetchPincodeList(value);
        if (response && response.isSuccess && Array.isArray(response?.data)) {
            setLocalityPincodesList(response.data || []);
        }
        setLoading(false);
    };

    const loadCitiesList = async (value: any) => {
        if (value?.length < 3) return;
        if (!hierarchyData?.some((node: any) => node.location_key === 'city')) return;
        setLoading(true);

        const response = await fetchCitiesList(value);
        if (response && response.isSuccess && Array.isArray(response?.data)) {
            setLocalityCitiesList(response.data || []);
        }
        setLoading(false);
    };

    const loadStatesList = async (value: any) => {
        if (value?.length < 3) return;
        if (!hierarchyData?.some((node: any) => node.location_key === 'state')) return;
        setLoading(true);

        const response = await fetchStatesList(value);

        if (response && response.isSuccess && Array.isArray(response?.data)) {
            setLocalityStatesList(response.data || []);
        }
        setLoading(false);
    };

    const loadCountriesList = async (value: any) => {
        if (value?.length < 3) return;
        if (!hierarchyData?.some((node: any) => node.location_key === 'country')) return;
        setLoading(true);

        const response = await fetchCountriesList(value);

        if (response && response.isSuccess && Array.isArray(response?.data)) {
            setCountriesList(response.data || []);
        }
        setLoading(false);
    };

Debouncing logic is also applied :

Expand
titleCode snippet
Code Block
 useEffect(() => {
        loadPincodes(newAddress.pincode);
    }, [debouncePincode]);

    useEffect(() => {
        loadCitiesList(newAddress.city);
    }, [debounceCity]);

    useEffect(() => {
        loadStatesList(newAddress.state);
    }, [debounceState]);

    useEffect(() => {
        loadCountriesList(newAddress.country);
    }, [debounceCountry]);

//import { useDebounce } from 'hooks/use-debounce'; using already imported (was being used for w3wCode) useDebounce HoC
//SEARCH_TIMEOUT = 500 -> debounce time is used by default
const debouncePincode = useDebounce(newAddress.pincode);
const debounceCity = useDebounce(newAddress.city);
const debounceState = useDebounce(newAddress.state);
const debounceCountry = useDebounce(newAddress.country);

Following rendering logic is used for all nodes (pincode, state, city, country)

  • It renders only dropdown for case when allow_override_hierarchy is false (user can only select options from dropdown only).

  • When allow_override_hierarchy is true: user can type and search will be done in db, if data found user can select any option from dropdown and on basis of it higher level nodes is auto-populated, and can also enter anything out of option in dropdown for current node and higher nodes too.

  • On clearing a node’s value, all higher node's value will also be cleared.

Expand
titleRendering snippet for address fields
Code Block
  const renderPincodeBox = () => {
        if (isAddressHierarchyPresent && isAddressMappingAllowed) {
            return (
                <AutoComplete
                    value={newAddress.pincode}
                    className={classes.pincodeInput}
                    dropdownClassName={classes.pincodeInputDropdown}
                    options={
                        localityPincodesList.map((pincode: any) => {
                            return {
                                label: `${pincode.name} (${pincode.code})`,
                                value: pincode.code,
                            };
                        })
                    }
                    onSearch={loadPincodes}
                    onSelect={(e) => saveAddressUsingAddressHierarchy(e, 'pincode')}
                    onChange={(value) => updateAddressFieldWithValidations('pincode', value)}
                    style={{ textAlign: 'left' }}
                    allowClear
                >
                    <Input
                        className={classes.autoCompleteInputBox}
                        allowClear
                        placeholder={t('address_pincode')}
                    />
                </AutoComplete>
            );
        } else if (isAddressHierarchyPresent && !isAddressMappingAllowed) {
            return (
          
const
 
fetchLocality
 
=
 
await
 
fetchAddressUsingAddressHierarchy({
 
queryString: nodeValue, searchType: nodeType });
 <Form.Item
            
if
 
(!fetchLocality.isSuccess)
 
{
      className={classes.pincodeWithExtra}
      
setNewAddress({
              name="pincode"
  
...newAddress,
                 
city: '',
 extra={samplePincode ? `Ex. ${samplePincode}` : undefined}
           
state:
 
'',
    >
            
country:
 
'',
       <Select
     
});
             
setDisableLocality(false);
      value={newAddress.pincode}
  
}
 
else
 
{
             
let
 
nodeFound
 
=
 
false;
    dropdownClassName={classes.pincodeInputDropdown}
        
const
 
parentLevelNodes
 
=
 
[];
             
for (let i = 0; i < hierarchyData?.length; i += 1) {
placeholder={t('address_pincode')}
                        onChange={(e) => {
const
 
curNode
 
=
 
hierarchyData[i].location_key.toLowerCase();
                 
if
 
((nodeFound
 
||
 
curNode
 
===
 
nodeType.toLocaleLowerCase())
 
&&
 
curNode in fetchLocality?.data) {
 updateAddressFieldWithValidations('pincode', e);
                       
nodeFound
 
=
 
true;
   const isValid = isValidPincode(e);
              
parentLevelNodes.push({
 
key:
 
hierarchyData[i].location_key,
 
value:
 
fetchLocality?.data[curNode]
 
});
         if (isValid !== validPincode) {
   
}
             
}
             
const
 
fetchedAddressFieldsObj
 
=
 
parentLevelNodes?.reduce((acc, curr) => {
setValidPincode(isValid);
                  
if (isKeyOfNewAddress(curr.key)) {
          }
             
acc[curr.key]
 
=
 
curr.value
 
||
 
null;
       }}
             
if
 
(curr.key
 
!==
 
nodeType
 
&&
 
(!isAddressMappingAllowed
 
&&
 
curr.value))
 
{
   options={
                     
setDisableLocality(true,
 
curr.key);
      localityPincodesList.map((pincode: any) => {
           
}
 
else
 
{
                   return {
    
setDisableLocality(false,
 
curr.key);
                     
}
          label: `${pincode.name} (${pincode.code})`,
    
}
                 
return
 
acc;
             
}, {} as { [key: string]: string | null });
 value: pincode.code,
                
setNewAddress({
                };
...newAddress,
                 
...fetchedAddressFieldsObj,
           
})
;

       
}
          
setLoading(false);
     
};

Function to be called on typing text to be searched in address fields( pincode, city, state country)

Code Block
const loadPincodes = async (value: any) => {
  }
          
if
 
(value?.length
 
<
 
3)
 
return;
         
if
 
(!hierarchyData?.some((node: any
onSelect={(e) => 
node.location_key ===
saveAddressUsingAddressHierarchy(e, 'pincode')
)
}
return;
         
setLoading(true);
          
const
 
response
 
=
 
await
 
fetchPincodeList(value);
 defaultActiveFirstOption={false}
       
if (response && response.isSuccess && Array.isArray(response?.data))
 
{
             
setLocalityPincodesList(response.data
 
||
 
[]);
 filterOption={false}
       
}
         
setLoading(false);
     
};
   onSearch={loadPincodes}
  
const
 
loadCitiesList
 
=
 
async
 
(value:
 
any)
 
=>
 
{
         
if
 
(value?.length
 
<
 
3)
 
return;
  showSearch
      
if
 
(!hierarchyData?.some((node:
 
any)
 
=>
 
node.location_key
 
===
 
'city'))
 
return;
         
setLoading(true);
  allowClear
       
const
 
response
 
=
 
await
 
fetchCitiesList(value);
         
if
 
(response
 
&&
 
response.isSuccess && Array.isArray(response?.data)) {
 style={validPincode ? {} : { borderColor: 'red' }}
            
setLocalityCitiesList(response.data
 
||
 
[]);
      />
  
}
         
setLoading(false);
     
};
</Form.Item>
     
const
 
loadStatesList
 
=
 
async
 
(value:
 
any)
 
=>
 
{
);
        
if
}
(value?.length
 
<
 
3)
 
return;
     else {
  
if
 
(!hierarchyData?.some((node:
 
any)
 
=>
 
node.location_key
 
===
 
'state'))
 
return;
   return (
    
setLoading(true);
          
const
 
response
 
=
<Input
await
 
fetchStatesList(value);
          
if
 
(response
 
&&
 
response.isSuccess
 
&&
 
Array.isArray(response?.data))
 
{
   value={newAddress.pincode}
         
setLocalityStatesList(response.data
 
||
 
[]);
         className={classes.pincodeInput}

       
setLoading(false);
     
};
      
const
 
loadCountriesList
 placeholder=
async (value: any) => {
{t('address_city')}
          
if
 
(value?.length
 
<
 
3)
 
return;
      onChange={(e) => 
if (!hierarchyData?.some((node: any) => node.location_key === 'country')) return;
updateAddressFieldWithValidations('pincodeInput', e.target.value)}
               
setLoading(true);
 />
        
const
 
response
 
=
 
await
 
fetchCountriesList(value
);
        }
if
 
(response
 
&&
 
response.isSuccess && Array.isArray(response?.data)) { setCountriesList(response.data || []); } setLoading(false); };

Debouncing logic is also applied :

Code Block
useEffect(() => { loadPincodes(newAddress.pincode); }, [debouncePincode]); useEffect(() => { loadCitiesList(newAddress.city); }, [debounceCity]); useEffect(() => {
 };

Changes in src/network/pickup.api.ts

Expand
titleChanges in src/network/pickup.api.ts
Code Block
//api to fetch states list
export const FETCH_STATES_LIST = '/api/CustomerPortal/addressManagement/getAddressNodeData?type=State';
//api to fetch nodes value based on address hierarchy (new dev api)
export const FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY = '/api/CustomerPortal/fetchGeneralAddressCode';

export const fetchAddressUsingAddressHierarchy = (params: any) => {
    return POST(`${API_BASE_URL}${FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY}`, params);
};

//exporting functions to fetch nodes' list to be called from create-address.tsx file on entering sompething in inpit fileds (> 3chars)
export const fetchCountriesList = (params: any) => {
    return GET(`${API_BASE_URL}${FETCH_COUNTRIES_NODE_DATA}`,
        { 
loadStatesList(newAddress.state); }, [debounceState]); useEffect((
isDataSearchApplied: true, searchQuery: params, sortResult: true });
};

export const fetchCitiesList = (params: any) => {
    return GET(`${API_BASE_URL}${FETCH_CITIES_LIST}`,
  
loadCountriesList(newAddress.country);
      { isDataSearchApplied: 
}
true, 
[debounceCountry]); //import { useDebounce } from 'hooks/use-debounce'; using already imported (was being used for w3wCode) useDebounce HoC //SEARCH_TIMEOUT = 500 -> debounce time is used by default const debouncePincode = useDebounce(newAddress.pincode); const debounceCity = useDebounce(newAddress.city); const debounceState = useDebounce(newAddress.state); const debounceCountry = useDebounce(newAddress.country);

Following rendering logic is used for all nodes (pincode, state, city, country)

  • It renders only dropdown for case when allow_override_hierarchy is false (user can only select options from dropdown only).

  • When allow_override_hierarchy is true: user can type and search will be done in db, if data found user can select any option from dropdown and on basis of it higher level nodes is auto-populated, and can also enter anything out of option in dropdown for current node and higher nodes too.

  • On clearing a node’s value, all higher node's value will also be cleared.

Code Block
const renderStateBox = () => { if (isAddressMappingAllowed) { return ( <AutoComplete value={newAddress.state} className={classes.stateInput}
searchQuery: params, sortResult: true });
};


export const fetchStatesList = (params: any) => {
    return GET(`${API_BASE_URL}${FETCH_STATES_LIST}`,
        { isDataSearchApplied: true, searchQuery: params, sortResult: true });
};

Changes in src/network/api.constants.ts

Expand
titlechanges in src/network/api.constants.ts
Code Block
export const FETCH_STATES_LIST = '/api/CustomerPortal/addressManagement/getAddressNodeData?type=State';
export const FETCH_COUNTRIES_NODE_DATA = '/api/CustomerPortal/addressManagement/getAddressNodeData?type=Country';
export const FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY = '/api/CustomerPortal/fetchGeneralAddressCode';

CRMDashboard changes:

General Function to be called whenever any option from rendered dropdown is selected, it make call to api api/CustomerPortal/fetchGeneralAddressCode

  1. In case isAddressHierarchyPresent is false then we will render only Simple Input text field.

  2. If isAddressHierarchyPresent is true:

    1. It fetches data from AddressNode table on basis of address hierarchy setup, and returns data for current and higher nodes to populate.

    2. It also handle the logic to either disbale the higher level nodes based on whether their value is fetched and allow_override_hierarchy is false.

    3. It also update (auto populate) the value of higher nodes

Expand
titlesaveAddressUsingAddressHierarchy code snippet called on onChange
Code Block
 const saveAddressUsingAddressHierarchy = async (nodeValue, nodeType) => {
    if (!nodeType) return;

    if (!nodeValue) {
      handleAddressFields(nodeType, null, false);
      return;
    }

    const fetchLocality = await fetchAddressUsingAddressHierarchy({ queryString: nodeValue, searchType: nodeType });

    if (!fetchLocality.isSuccess) {
      form.setFieldsValue({
        cityName: '',
        stateName: '',
      
dropdownClassName={classes.pincodeInputDropdown}
  countryName: '',
      });
      setDisableLocality(false, null);
  
options={
  } else {
      handleAddressFields(nodeType, fetchLocality, false);
    }
  };
Expand
titleSearching function logic called on onSearch for pincode
Code Block

const debouncePincode = 
localityStatesList
lodash.
map
debounce(
(state: any
async (value) => {
    const pincodesListResp = await searchAddressNodeData({ type: 'pincode', isDataSearchApplied: true, searchQuery: value, sortResult: true });
    if (pincodesListResp?.isSuccess 
return
&& Array.isArray(pincodesListResp?.data)) {
      
setPincodesList(pincodesListResp.data || []);
    }
  }, 500);

  const loadPincodes = async 
label: state.name,
(value) => {
    if (value?.length < 3) return;
    if (!hierarchyData?.some((node: any) => node.location_key === 'pincode')) return;
    debouncePincode(value);
  
value: state.code,
};
Expand
titleRendering logic for address fields (pincode) similar for others:
Code Block
<FormItem
              {...formItemLayoutNew}
              className={classes.formCounterBooking}
;

              
})
label={<div>{t("pincode")}</div>}
            >
       
}
       {!allowOverrideHierarchy && isAddressHierarchyPresent && getFieldDecorator('pincode', {
        
onSearch={loadStatesList}
        initialValue: address['pincode'],
           
onSelect={(e)
 
=>
 
saveAddressUsingAddressHierarchy(e, 'state')}
   rules: [
                  
onChange={(value) => updateAddressFieldWithValidations('state', value)}
{ required: false, message: 'Cannot be empty!' },
                ],
   
style={{
 
textAlign:
 
'left'
 
}}
        })(
            
disabled={disableState}
    <Select
                
allowClear
  style={{ textAlign: 'left' }}
           
>
       showSearch
             
<Input
     optionFilterProp="children"
                  onChange={(value) 
className={classes.autoCompleteInputBox
=> saveAddressUsingAddressHierarchy(value, 'pincode')}
                  placeholder={t("pincode_placeholder")}
     
allowClear
             onSearch={loadPincodes}
           
placeholder={t('address_state')}
       allowClear
             
/>
   >
             
</AutoComplete>
     {pincodesList?.map(opt => <Option style={{ textAlign: 'left' }} key={opt.id} 
);
value={opt.code}>{opt.name} ({opt.code})</Option>)}
        
return
 
(
       </Select>,
     
<Select
         )}
       
value={newAddress.state}
       {allowOverrideHierarchy && isAddressHierarchyPresent && getFieldDecorator('pincode', {
    
className={classes.stateInput}
            
dropdownClassName={classes.pincodeInputDropdown}
initialValue: address['pincode'],
                
onChange={(e
rules: 
any)
[
=>
 
updateAddressFieldWithValidations('state',
 
e)}
                
placeholder={t('address_state')}
{ required: false, message: 'Cannot be empty!' },
         
options={
       ],
             
localityStatesList.map((state: any) => {
 })(
                <AutoComplete
         
return
 
{
        options={pincodesList?.map(item => ({ label: `${item.name} (${item.code})`, value: item.code }))}
            
label:
 
state.name,
     onSearch={loadPincodes}
                  
value: state.name,
onSelect={(value) => saveAddressUsingAddressHierarchy(value, 'pincode')}
                  onChange={(value) => handleAddressFields('pincode', value, !allowOverrideHierarchy)}
};
                  style={{ textAlign: 'left' }
)
}
                 
}
 allowClear
               
onSelect={(e)
 
=
>
saveAddressUsingAddressHierarchy(e,
 
'state')}
                 
onSearch={loadStatesList}
<Input
                
disabled={disableState}
    allowClear
            
showSearch
        
placeholder={t("pincode_placeholder")}
     
allowClear
             />
         
);
      
};

Changes in src/network/pickup.api.ts

Code Block
//api to fetch states list export const FETCH_STATES_LIST = '/api/CustomerPortal/addressManagement/getAddressNodeData?type=State'; //api to fetch nodes value based on address hierarchy (new dev api) export const FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY = '/api/CustomerPortal/fetchGeneralAddressCode'; export const fetchAddressUsingAddressHierarchy = (params: any) => {
 </AutoComplete>,
              )}
              {!isAddressHierarchyPresent && getFieldDecorator('pincode', {
        
return
 
POST(`${API_BASE_URL}${FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY}`,
 
params);
 
};
  
//exporting
 
functions
 
to
 
fetch nodes' list to be called from create-address.tsx file on entering sompething in inpit fileds (> 3chars) export const fetchCountriesList = (params: any) => {
initialValue: address['pincode'],
                rules: [
        
return
 
GET(`${API_BASE_URL}${FETCH_COUNTRIES_NODE_DATA}`,
         { 
isDataSearchApplied
required: 
true
false, 
searchQuery
message: 
params, sortResult: true }); }; export const fetchCitiesList = (params: any) => {
'Cannot be empty!' },
               
return GET(`${API_BASE_URL}${FETCH_CITIES_LIST}`
 ],
        
{
 
isDataSearchApplied: true,
 
searchQuery:
 
params,
 
sortResult:
 
true
 })
;
(
 
};
   
export
 
const
 
fetchStatesList
 
=
 
(params:
 
any)
 
=>
 
{
     
return GET(`${API_BASE_URL}${FETCH_STATES_LIST}`
<Input placeholder={t("pincode_placeholder")} />,
       
{
 
isDataSearchApplied:
 
true,
 
searchQuery:
 
params,
 
sortResult:
 
true
 
}
)
;
}
;

changes in src/network/api.constants.ts

Code Block
export

const FETCH_STATES_LIST
 
=
 
'/api/CustomerPortal/addressManagement/getAddressNodeData?type=State';
 
export
 
const
 
FETCH_COUNTRIES_NODE_DATA
 
=
 
'/api/CustomerPortal/addressManagement/getAddressNodeData?type=Country';
 
export
 
const
 
FETCH_ADDRESS_FROM_ADDRESS_HIERARCHY
 
= '/api/CustomerPortal/fetchGeneralAddressCode';

...

 </FormItem>

Above logic is updated in

  1. src/components/pages/OpsDashboard/Manage/counterBooking/AddAddress2.tsx

  2. src/components/pages/details/AddDetails.tsx