Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/ConfirmationDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ConfirmationDialog = ({
handleConfirmation,
documents,
loading,
concentText = 'Share my documents with the provider for processing my application',
consentText = 'Share my documents with the provider for processing my application',
}) => {
// Function to call the parent's function
const sendCloseDialog = () => {
Expand Down Expand Up @@ -73,7 +73,7 @@ const ConfirmationDialog = ({

<Dialog.Content style={styles.dialogContent}>
<Text variant="bodyMedium" style={styles.conformationText}>
{concentText}
{consentText}
</Text>
<ScrollView style={{height: 220}}>
{loading ? (
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/BenefitCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const BenefitCard = ({item, navigation}) => {
{item?.title}
</Text>
<Text numberOfLines={2} style={styles.subTitle}>
{item?.description}
{item?.provider_name}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update PropTypes to match the new provider_name usage.

The component now displays provider_name instead of description, but the PropTypes definition still includes description and lacks provider_name. This could lead to undefined values and PropTypes validation warnings.

Update the PropTypes definition to include the new property:

BenefitCard.propTypes = {
  item: PropTypes.shape({
    date: PropTypes.string,
    title: PropTypes.string,
    subTitle: PropTypes.string,
    benefitAmount: PropTypes.string,
    eligible: PropTypes.arrayOf(PropTypes.string),
-   description: PropTypes.string,
+   provider_name: PropTypes.string,
    address: PropTypes.string,
    imageUrl: PropTypes.string,
  }),
  // ...
};

Committable suggestion skipped: line range outside the PR's diff.

</Text>
{/* <Text numberOfLines={2} style={styles.benefitAmount}>
<Icon source={'currency-inr'} size={16} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/TextInput/Password.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const PasswordInput = ({
secureTextEntry={showPassword}
right={
<TextInput.Icon
icon={showPassword ? 'eye-off' : 'eye'}
icon={showPassword ? 'eye' : 'eye-off'}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Reverse the icon logic to match the password visibility state.

The current implementation shows 'eye' when the password is hidden and 'eye-off' when it's visible, which is counter-intuitive. The icon should represent the current state rather than the action that will occur.

Apply this change to fix the icon logic:

-          icon={showPassword ? 'eye' : 'eye-off'}
+          icon={showPassword ? 'eye-off' : 'eye'}

This way:

  • When password is hidden (showPassword=true) β†’ shows 'eye-off' icon
  • When password is visible (showPassword=false) β†’ shows 'eye' icon
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
icon={showPassword ? 'eye' : 'eye-off'}
icon={showPassword ? 'eye-off' : 'eye'}

onPress={() => setShowPassword(!showPassword)}
/>
}
Expand Down
7 changes: 5 additions & 2 deletions src/components/common/inputs/Searchbar.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import * as React from 'react';
import {StyleSheet, View, TextInput} from 'react-native';
import {IconButton} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialIcons'; // Import the icon library

const Searchbar = ({onSearch}) => {
const Searchbar = ({onSearch, value}) => {
const [searchQuery, setSearchQuery] = React.useState('');

React.useEffect(() => {
setSearchQuery(value);
}, [value]);

return (
<View style={styles.Searchcontainer}>
<View style={styles.searchWrapper}>
Expand Down
8 changes: 6 additions & 2 deletions src/components/common/layout/SearchHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import React from 'react';
import FilterDialog from '../../FilterDialog';
import Searchbar from '../inputs/Searchbar';

const SearchHeader = ({onSearch, inputs, onFilter}) => {
const SearchHeader = ({onSearch, searchValue, inputs, onFilter}) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codebase verification

Missing searchValue prop in parent components

The verification reveals that parent components are not passing the required searchValue prop:

  • src/screens/benefits/List.js: Only passes onSearch and inputs
  • src/screens/benefits/Application.js: Only passes onSearch
πŸ”— Analysis chain

LGTM! Verify prop usage across parent components.

The addition of the searchValue prop is well-structured and follows React conventions for controlled components.

Let's verify that parent components are correctly passing the searchValue prop:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for SearchHeader usage to ensure searchValue prop is properly passed
rg -l "SearchHeader" | xargs rg -A 5 "<SearchHeader"

Length of output: 764

return (
<View style={styles.view}>
<Searchbar style={styles.searchBar} onSearch={onSearch} />
<Searchbar
style={styles.searchBar}
onSearch={onSearch}
value={searchValue}
/>
<FilterDialog style={styles.filter} inputs={inputs} onFilter={onFilter} />
</View>
);
Expand Down
6 changes: 3 additions & 3 deletions src/screens/auth/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Login = () => {
};

if (!username) {
setError('Enter Username ');
setError('Enter Username');
clearError();
return;
}
Expand Down Expand Up @@ -106,7 +106,7 @@ const Login = () => {
/>
<View>
<CustomTextInput
label={'UserName'}
label={'User Name'}
value={username}
onChangeText={setUsername}
marginBottom={25}
Expand Down Expand Up @@ -156,7 +156,7 @@ const Login = () => {
closeDialog={setDialogVisible}
handleConfirmation={handleCofirmation}
documents={documents}
concentText="Please provide your consent to share the following with Fast Pass"
consentText="Please provide your consent to share the following with Fast Pass"
/>
</View>
);
Expand Down
2 changes: 1 addition & 1 deletion src/screens/auth/Splash.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Splash = () => {
getValue={setSelectedLanguage}
/>
<Button
label="Sign In / Sign Up "
label="Sign In / Sign Up With Your E-Wallet"
padding={2}
width="92%"
handleClick={handleLogin}
Expand Down
93 changes: 59 additions & 34 deletions src/screens/benefits/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Layout from '../../components/common/layout/Layout';
import * as benefitServis from '../../service/benefits';
import {Gender, Castes, IncomeRange} from '../../constatnt/Constant';
import BenefitCard from '../../components/common/BenefitCard';
import {Text} from 'react-native-paper';
import {Dialog, Portal, Text} from 'react-native-paper';
import {getTokenData} from '../../service/ayncStorage';
import {getUser} from '../../service/auth';

Expand All @@ -19,54 +19,79 @@ const List = () => {
// const [hasMore] = useState(true);
// const benefits = data.ubi_network_cache; // data from API
const [benefits, setBenefits] = useState([]);
const [error, setError] = useState();

useEffect(() => {
const init = async () => {
const {sub} = await getTokenData(); // Assuming sub is the user identifier
const user = await getUser(sub);
const filters = {
'social-eligibility': user?.userInfo?.caste,
'ann-hh-inc': user?.userInfo?.income,
'gender-eligibility': user?.userInfo?.gender,
};
const newFilter = {};
Object.keys(filters).forEach(key => {
if (filters[key] && filters[key] !== '') {
if (typeof filters[key] === 'string') {
newFilter[key] = filters[key].toLowerCase();
} else {
newFilter[key] = filters[key];
try {
const {sub} = await getTokenData(); // Assuming sub is the user identifier
const user = await getUser(sub);
const filters = {
'social-eligibility': user?.userInfo?.caste,
'ann-hh-inc': user?.userInfo?.income,
'gender-eligibility': user?.userInfo?.gender,
};
const newFilter = {};
Object.keys(filters).forEach(key => {
if (filters[key] && filters[key] !== '') {
if (typeof filters[key] === 'string') {
newFilter[key] = filters[key].toLowerCase();
} else {
newFilter[key] = filters[key];
}
}
}
});
setFilter(newFilter);
setInitState('no');
});
setFilter(newFilter);
setInitState('no');
} catch (e) {
setError(e.message);
setInitState('no');
}
};
init();
}, []);
console.log(loading, initState);

useEffect(() => {
const init = async () => {
if (initState == 'no') {
setLoading(true);
console.log('hello2');
const result = await benefitServis.getAll({
filters: {
...filter,
'ann-hh-inc': filter?.['ann-hh-inc']
? `0-${filter?.['ann-hh-inc']}`
: '',
},
search,
});
console.log(result, 'result');
setBenefits(result?.data?.ubi_network_cache || []);
try {
if (initState == 'no') {
setLoading(true);
const result = await benefitServis.getAll({
filters: {
...filter,
'ann-hh-inc': filter?.['ann-hh-inc']
? `0-${filter?.['ann-hh-inc']}`
: '',
},
search,
});
Comment on lines +59 to +67

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codebase verification

Error handling needs to be improved in List component

The component's error handling is incomplete. While benefitServis properly throws errors with response data or network errors, the List component's try-catch block doesn't handle these errors:

  • Missing error handling in catch block
  • No error state management for failed requests
  • Loading state might get stuck if an error occurs

Suggested improvements:

  • Add error state management (e.g., setError state)
  • Ensure loading state is set to false in catch block
  • Display error message to users when request fails
πŸ”— Analysis chain

Verify error handling in benefitServis integration

The error handling looks good, but we should verify the error responses from the service.


Let me check the error handling in the component to ensure it properly catches these service errors.


Let me try a different pattern to check the error handling in the List component.


Let me try one final search to see the complete context of the benefitServis call.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for error handling in the service layer
rg -A 5 "throw|catch|error" src/service/benefits.js

Length of output: 1079


Script:

#!/bin/bash
# Check error handling in the List component
ast-grep --pattern 'try {
  $$$
  const result = await benefitServis.getAll($$$)
  $$$
} catch ($err) {
  $$$
}'

Length of output: 114


Script:

#!/bin/bash
# Check for try-catch blocks around benefitServis calls in List.js
rg -A 10 "try.*\{.*benefitServis" src/screens/benefits/List.js

Length of output: 64


Script:

#!/bin/bash
# Get the full context around the benefitServis.getAll call
rg -B 5 -A 10 "benefitServis\.getAll" src/screens/benefits/List.js

Length of output: 549

setBenefits(result?.data?.ubi_network_cache);
setLoading(false);
}
} catch (e) {
setError(e.message);
setLoading(false);
}
};
init();
}, [filter, search, initState]);

if (error) {
return (
<Portal>
<Dialog visible={!!error} onDismiss={() => setError('')}>
<Dialog.Title>Error</Dialog.Title>
<Dialog.Content>
<Text>{error}</Text>
</Dialog.Content>
<Dialog.Actions>
<Text onPress={() => setError('')}>Close</Text>
</Dialog.Actions>
</Dialog>
</Portal>
);
}

return (
<Layout
loading={loading}
Expand Down
74 changes: 51 additions & 23 deletions src/screens/benefits/ViewDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CustomButton from '../../components/common/button/Button';
import ConfirmationDialog from '../../components/ConfirmationDialog';
import Layout from '../../components/common/layout/Layout';
import {useNavigation} from '@react-navigation/native';
import {ActivityIndicator, Icon} from 'react-native-paper';
import {ActivityIndicator, Dialog, Icon, Portal} from 'react-native-paper';
import * as benefitServis from '../../service/benefits';
import WebViewFormExample from '../../components/common/webview/Form';
import {getTokenData} from '../../service/ayncStorage';
Expand All @@ -21,6 +21,7 @@ const ViewDetails = ({route}) => {
const navigation = useNavigation();
const [context, setContext] = useState({});
const [isApplied, setIsApplied] = useState(false);
const [error, setError] = useState();
const handleBack = () => {
navigation.navigate('BenefitsListing');
};
Expand Down Expand Up @@ -70,7 +71,7 @@ const ViewDetails = ({route}) => {
}
setLoading(false);
} catch (e) {
console.log('Error:', e.message);
setError('Error:', e.message);
}
};
init();
Expand All @@ -89,32 +90,40 @@ const ViewDetails = ({route}) => {
];
const submitConfirm = async submission_id => {
setLoading(true);
const result = await benefitServis.confirmApplication({
submission_id,
context,
});
const orderId = result?.data?.responses?.[0]?.message?.order?.id;
if (orderId) {
const payload = {
user_id: authUser?.user_id,
benefit_id: id,
benefit_provider_id: context?.bpp_id,
benefit_provider_uri: context?.bap_uri,
external_application_id: orderId,
application_name: item?.descriptor?.name,
status: 'submitted',
application_data: authUser,
};
try {

try {
const result = await benefitServis.confirmApplication({
submission_id,
item_id: id,
context,
});
const orderId = result?.data?.responses?.[0]?.message?.order?.id;
if (orderId) {
const payload = {
user_id: authUser?.user_id,
benefit_id: id,
benefit_provider_id: context?.bpp_id,
benefit_provider_uri: context?.bap_uri,
external_application_id: orderId,
application_name: item?.descriptor?.name,
status: 'submitted',
application_data: authUser,
};
const appResult = await benefitServis.createApplication(payload);
if (appResult) {
setWebFromProp();
setVisibleDialog({orderId, name: item?.descriptor?.name});
setLoading(false);
}
} catch (e) {
console.log(e.message);
} else {
setError(
'Error while creating application. Please try again later. (Status code 500)',
);
setLoading(false);
}
} catch (e) {
setError('Error:', e.message);
setLoading(false);
}
Comment on lines 92 to 127

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Refactor submitConfirm for better error handling and cleanup.

The function has several areas that could be improved:

  1. Multiple setLoading(false) calls could lead to race conditions
  2. No cleanup handling for component unmount during async operations
  3. Deeply nested logic could be simplified

Consider this refactor:

 const submitConfirm = async submission_id => {
+  const controller = new AbortController();
   setLoading(true);
   try {
     const result = await benefitServis.confirmApplication({
       submission_id,
       item_id: id,
       context,
     });
     const orderId = result?.data?.responses?.[0]?.message?.order?.id;
-    if (orderId) {
-      const payload = {
-        user_id: authUser?.user_id,
-        benefit_id: id,
-        benefit_provider_id: context?.bpp_id,
-        benefit_provider_uri: context?.bap_uri,
-        external_application_id: orderId,
-        application_name: item?.descriptor?.name,
-        status: 'submitted',
-        application_data: authUser,
-      };
-      const appResult = await benefitServis.createApplication(payload);
-      if (appResult) {
-        setWebFromProp();
-        setVisibleDialog({orderId, name: item?.descriptor?.name});
-        setLoading(false);
-      }
-    } else {
+    if (!orderId) {
       setError(
         'Error while creating application. Please try again later. (Status code 500)',
       );
-      setLoading(false);
+      return;
     }
+    const payload = {
+      user_id: authUser?.user_id,
+      benefit_id: id,
+      benefit_provider_id: context?.bpp_id,
+      benefit_provider_uri: context?.bap_uri,
+      external_application_id: orderId,
+      application_name: item?.descriptor?.name,
+      status: 'submitted',
+      application_data: authUser,
+    };
+    const appResult = await benefitServis.createApplication(payload);
+    if (appResult) {
+      setWebFromProp();
+      setVisibleDialog({orderId, name: item?.descriptor?.name});
+    }
   } catch (e) {
-    setError('Error:', e.message);
-    setLoading(false);
+    setError(`Error: ${e.message}`);
+  } finally {
+    if (!controller.signal.aborted) {
+      setLoading(false);
+    }
   }
-  setLoading(false);
+  return () => controller.abort();
 };
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setLoading(true);
const result = await benefitServis.confirmApplication({
submission_id,
context,
});
const orderId = result?.data?.responses?.[0]?.message?.order?.id;
if (orderId) {
const payload = {
user_id: authUser?.user_id,
benefit_id: id,
benefit_provider_id: context?.bpp_id,
benefit_provider_uri: context?.bap_uri,
external_application_id: orderId,
application_name: item?.descriptor?.name,
status: 'submitted',
application_data: authUser,
};
try {
try {
const result = await benefitServis.confirmApplication({
submission_id,
item_id: id,
context,
});
const orderId = result?.data?.responses?.[0]?.message?.order?.id;
if (orderId) {
const payload = {
user_id: authUser?.user_id,
benefit_id: id,
benefit_provider_id: context?.bpp_id,
benefit_provider_uri: context?.bap_uri,
external_application_id: orderId,
application_name: item?.descriptor?.name,
status: 'submitted',
application_data: authUser,
};
const appResult = await benefitServis.createApplication(payload);
if (appResult) {
setWebFromProp();
setVisibleDialog({orderId, name: item?.descriptor?.name});
setLoading(false);
}
} catch (e) {
console.log(e.message);
} else {
setError(
'Error while creating application. Please try again later. (Status code 500)',
);
setLoading(false);
}
} catch (e) {
setError('Error:', e.message);
setLoading(false);
}
const submitConfirm = async submission_id => {
const controller = new AbortController();
setLoading(true);
try {
const result = await benefitServis.confirmApplication({
submission_id,
item_id: id,
context,
});
const orderId = result?.data?.responses?.[0]?.message?.order?.id;
if (!orderId) {
setError(
'Error while creating application. Please try again later. (Status code 500)',
);
return;
}
const payload = {
user_id: authUser?.user_id,
benefit_id: id,
benefit_provider_id: context?.bpp_id,
benefit_provider_uri: context?.bap_uri,
external_application_id: orderId,
application_name: item?.descriptor?.name,
status: 'submitted',
application_data: authUser,
};
const appResult = await benefitServis.createApplication(payload);
if (appResult) {
setWebFromProp();
setVisibleDialog({orderId, name: item?.descriptor?.name});
}
} catch (e) {
setError(`Error: ${e.message}`);
} finally {
if (!controller.signal.aborted) {
setLoading(false);
}
}
return () => controller.abort();
};

setLoading(false);
};
Expand All @@ -131,6 +140,23 @@ const ViewDetails = ({route}) => {
</View>
);
}

if (error) {
return (
<Portal>
<Dialog visible={!!error} onDismiss={() => setError('')}>
<Dialog.Title>Error</Dialog.Title>
<Dialog.Content>
<Text>{error}</Text>
</Dialog.Content>
<Dialog.Actions>
<Text onPress={() => setError('')}>Close</Text>
</Dialog.Actions>
</Dialog>
</Portal>
);
}

if (webFromProp?.url) {
return (
<WebViewFormExample {...webFromProp} setPageContent={submitConfirm} />
Expand All @@ -144,7 +170,7 @@ const ViewDetails = ({route}) => {
}}>
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.sidePadding}>
<Text style={styles.title}>{item?.descriptor?.name}</Text>
<Text style={styles.title}>{'Benefit'}</Text>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codebase verification

Static 'Benefit' title appears to be a regression

Based on the codebase analysis, other benefit-related components use dynamic titles (e.g., item?.title), and this component previously used dynamic titles as well. The change to a static 'Benefit' text reduces the clarity and consistency of the UI.

  • Consider reverting back to using a dynamic title that shows the specific benefit name
  • If a static title is required, consider adding a subtitle that shows the specific benefit name for better user context
πŸ”— Analysis chain

Verify if static title is intentional.

The title has been changed from dynamic ${item?.descriptor?.name} to static 'Benefit'. This might reduce the clarity for users viewing different benefits.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if other benefit-related components use dynamic titles
rg -A 2 "descriptor\.name" --type js

Length of output: 38


Script:

#!/bin/bash
# Search for any usage of dynamic titles in benefit-related files
fd "benefit" --type f --exec rg -i "title|header" -A 2 {}

# Also check ViewDetails.js for any other instances of dynamic titles
rg "title" -A 2 "src/screens/benefits/ViewDetails.js"

Length of output: 2484

<View style={styles.benefitAmount}>
<Icon source={'currency-inr'} size={16} color="#484848" />
<View style={{flexDirection: 'row', alignItems: 'center'}}>
Expand Down Expand Up @@ -196,6 +222,7 @@ const ViewDetails = ({route}) => {
scrollEnabled={false}
/>
<CustomButton
marginTop={40}
label={
isApplied
? 'Application Already Submitted'
Expand All @@ -204,7 +231,8 @@ const ViewDetails = ({route}) => {
disabled={isApplied}
width="100%"
mode="contained"
handleClick={() => setVisibleDialog(true)}
// handleClick={() => setVisibleDialog(true)}
handleClick={openCOnfirmDialog}
/>
<ConfirmationDialog
dialogVisible={visibleDialog}
Expand Down
7 changes: 4 additions & 3 deletions src/service/benefits.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const applyApplication = async ({id, context}) => {
}
};

export const confirmApplication = async ({submission_id, context}) => {
export const confirmApplication = async ({submission_id, item_id, context}) => {
const data = {
context: {
...context,
Expand All @@ -112,7 +112,7 @@ export const confirmApplication = async ({submission_id, context}) => {
message: {
order: {
provider: {
id: '79',
id: item_id,
descriptor: {
name: '',
images: [],
Expand All @@ -122,7 +122,7 @@ export const confirmApplication = async ({submission_id, context}) => {
},
items: [
{
id: '79',
id: item_id,
descriptor: {
name: '',
long_desc: '',
Expand Down Expand Up @@ -160,6 +160,7 @@ export const confirmApplication = async ({submission_id, context}) => {
},
},
};

try {
const {token} = await getToken();
const response = await axios.post(`${API_BASE_URL}/confirm`, data, {
Expand Down