-
Notifications
You must be signed in to change notification settings - Fork 15
feat: Auto scanning of receipts #3850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
WalkthroughThe app now wields the mighty MLKit Document Scanner service for capturing receipts, replacing the old camera preview method. The Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DashboardPage
participant CaptureReceiptComponent
participant MLKitDocumentScannerService
participant MLKit Plugin
User->>DashboardPage: Clicks "Auto capture expenses" button
DashboardPage->>CaptureReceiptComponent: Navigate with auto_capture_expenses=true
CaptureReceiptComponent->>CaptureReceiptComponent: Check URL param on init
CaptureReceiptComponent->>MLKitDocumentScannerService: scanDocument(isBulkMode?)
MLKitDocumentScannerService->>MLKit Plugin: Start document scan
MLKit Plugin-->>MLKitDocumentScannerService: Return scanned file URL(s)
MLKitDocumentScannerService->>MLKitDocumentScannerService: Convert file URL to base64
MLKitDocumentScannerService-->>CaptureReceiptComponent: Observable emits base64 image(s)
CaptureReceiptComponent->>CaptureReceiptComponent: Navigate to expense form or list with scanned images
CaptureReceiptComponent-->>User: Show scanned receipts or form
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
package.json(1 hunks)src/app/core/services/mlkit-document-scanner.service.ts(1 hunks)src/app/shared/components/capture-receipt/capture-receipt.component.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
**/*.component.{ts,html}: Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Do not translate strings that are already translation keys, tracking/analytics strings, strings with only special characters, comments, non-user-visible text, or variable bindings and expressions.
One object per component or feature in i18n translation files; avoid deep nesting and avoid prefixes like 'ui*' or 'feature*' in object names.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
src/**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
**/*.{service,pipe,directive}.ts
📄 CodeRabbit Inference Engine (.cursor/rules/atomics-i18n-key-pattern.mdc)
**/*.{service,pipe,directive}.ts: i18n keys for services, pipes, and directives must use the schema: services.., pipes.., directives..
Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Use only the three roots: services, pipes, directives for i18n key grouping
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Files:
src/app/core/services/mlkit-document-scanner.service.ts
🧠 Learnings (4)
📚 Learning: in angular code, prefer using the `tap` operator to set state variables within observable streams fo...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3306
File: src/app/auth/pending-verification/pending-verification.page.ts:45-45
Timestamp: 2024-12-06T10:17:48.921Z
Learning: In Angular code, prefer using the `tap` operator to set state variables within observable streams for better readability, as seen in `pending-verification.page.ts`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isvisartfen...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:293-354
Timestamp: 2024-10-23T11:45:16.974Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isVisaRTFEnabled$', 'isMastercardRTFEnabled$', and 'isYodleeEnabled$' do not have rapidly changing values, so tests for rapid changes in these flags are unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in this codebase, properties used in angular templates are not explicitly declared as 'public', sinc...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.html:14-14
Timestamp: 2024-10-23T09:23:56.684Z
Learning: In this codebase, properties used in Angular templates are not explicitly declared as 'public', since they are public by default in TypeScript.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isad...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:200-200
Timestamp: 2024-10-23T08:40:59.542Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isAddCorporateCardVisible$ = of(true);' to the top-level beforeEach block causes tests to fail, so mock values need to be set in individual tests.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
🧬 Code Graph Analysis (1)
src/app/shared/components/capture-receipt/capture-receipt.component.ts (1)
src/app/constants.ts (1)
DEVICE_PLATFORM(6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-app
- GitHub Check: build
🔇 Additional comments (3)
package.json (1)
46-46: Style! The dependency addition is perfect, machan!The MLKit document scanner package is added with proper version specification, maintaining consistency with other Capacitor packages.
src/app/shared/components/capture-receipt/capture-receipt.component.ts (2)
70-106: Superb! The dependency injection style is like my signature moves - modern and powerful!The refactoring to use Angular's
inject()function is clean and follows modern Angular practices.
541-549: Style warning! The camera flow has changed dramatically like my action sequences!The method now immediately triggers document scanning instead of setting up a camera preview. This is a significant UX change where users won't see a camera preview before scanning starts.
Please verify if this immediate scanner launch is the intended behavior for the auto-scanning feature. If users need to see a preview first, consider adding a conditional check or user interaction before calling
onCaptureReceipt().
| // MLKit returns file URLs, so we need to convert them to base64 | ||
| return from(this.convertFileToBase64(result.scannedImages[0])); | ||
| } | ||
| throw new Error('No document scanned'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kabali da! The error messages need translation power!
Per coding guidelines, services must use i18n keys. Error messages should follow the schema services.mlkitDocumentScanner.<messageKey>.
Consider injecting TranslocoService and using translation keys:
- Line 17:
services.mlkitDocumentScanner.noDocumentScanned - Line 32:
services.mlkitDocumentScanner.fileConversionFailed - Line 36:
services.mlkitDocumentScanner.fileConversionFailed
Also applies to: 32-32, 36-36
🤖 Prompt for AI Agents
In src/app/core/services/mlkit-document-scanner.service.ts at lines 17, 32, and
36, replace the hardcoded error messages with translation keys following the
pattern services.mlkitDocumentScanner.<messageKey>. Inject TranslocoService into
the service and use it to throw errors with translated messages for keys
services.mlkitDocumentScanner.noDocumentScanned and
services.mlkitDocumentScanner.fileConversionFailed accordingly.
| } catch { | ||
| throw new Error('Failed to convert file to base64'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind it! The error details are vanishing like a villain in my movies!
The generic catch block swallows the original error information, making debugging difficult. Preserve the error details for better troubleshooting.
- } catch {
- throw new Error('Failed to convert file to base64');
+ } catch (error) {
+ throw new Error(`Failed to convert file to base64: ${error.message || 'Unknown error'}`);📝 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.
| } catch { | |
| throw new Error('Failed to convert file to base64'); | |
| } | |
| } catch (error) { | |
| throw new Error(`Failed to convert file to base64: ${error.message || 'Unknown error'}`); | |
| } |
🤖 Prompt for AI Agents
In src/app/core/services/mlkit-document-scanner.service.ts around lines 35 to
37, the catch block throws a new error without preserving the original error
details, which hinders debugging. Modify the catch block to capture the caught
error object and include its message or stack trace when throwing the new error,
so the original error information is preserved and visible for troubleshooting.
| this.mlkitScanner.scanDocument().subscribe({ | ||
| next: (base64PictureData) => { | ||
| this.lastCapturedReceipt = base64PictureData; | ||
| if (!this.isBulkMode) { | ||
| this.stopCamera(); | ||
| this.base64ImagesWithSource.push({ | ||
| source: 'MOBILE_DASHCAM_SINGLE', | ||
| base64Image: base64PictureData, | ||
| }); | ||
| this.onSingleCapture(); | ||
| } else { | ||
| this.base64ImagesWithSource.push({ | ||
| source: 'MOBILE_DASHCAM_BULK', | ||
| base64Image: base64PictureData, | ||
| }); | ||
| this.onBulkCapture(); | ||
| } | ||
| }, | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| error: (error) => { | ||
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: 'Camera not available', | ||
| }), | ||
| }); | ||
| this.onBulkCapture(); | ||
| } | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Rajini's rule: Always have a backup plan, like I have multiple entry styles!
Consider adding a check for MLKit scanner availability before use, with fallback to the previous camera preview method if unavailable.
Add a method to check scanner availability:
private async isScannerAvailable(): Promise<boolean> {
try {
// Check if MLKit scanner is available on the platform
return await DocumentScanner.isSupported();
} catch {
return false;
}
}Then use it in onCaptureReceipt() with a fallback mechanism.
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts
between lines 404 and 430, the code uses mlkitScanner.scanDocument() without
verifying if the scanner is available, risking runtime errors. Add a private
async method isScannerAvailable() that returns a boolean indicating scanner
support by calling DocumentScanner.isSupported() with error handling. Then, in
the onCaptureReceipt() method, call isScannerAvailable() before scanning; if the
scanner is unavailable, fallback to the previous camera preview method to ensure
functionality continuity.
| error: (error) => { | ||
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: 'Camera not available', | ||
| }), | ||
| }); | ||
| this.onBulkCapture(); | ||
| } | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thalaiva says: Don't waste the error information, use it wisely!
The error parameter should be utilized for logging to help with debugging. Also, the error message should use i18n keys.
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- error: (error) => {
+ error: (error) => {
+ console.error('Document scanning failed:', error);
this.matSnackBar.openFromComponent(ToastMessageComponent, {
...this.snackbarProperties.setSnackbarProperties('failure', {
- message: 'Camera not available',
+ message: this.translocoService.translate('captureReceipt.scanningFailed'),
}),
});
},🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts around
lines 422 to 429, the error parameter is currently unused and the error message
is hardcoded. Modify the error callback to log the error parameter for debugging
purposes and replace the hardcoded message with an i18n key to support
internationalization.
| stopCamera(): void { | ||
| this.cameraPreview.stopCamera(); | ||
| // MLKit scanner handles its own camera lifecycle | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Mind it! Empty methods need explanation, like my punch dialogues need context!
While MLKit handles camera lifecycle, consider documenting why this method is kept empty or remove it entirely if no longer needed.
stopCamera(): void {
- // MLKit scanner handles its own camera lifecycle
+ // MLKit scanner handles its own camera lifecycle
+ // Method retained for compatibility with existing call sites
+ // Can be removed after refactoring all references
}📝 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.
| stopCamera(): void { | |
| this.cameraPreview.stopCamera(); | |
| // MLKit scanner handles its own camera lifecycle | |
| } | |
| stopCamera(): void { | |
| // MLKit scanner handles its own camera lifecycle | |
| // Method retained for compatibility with existing call sites | |
| // Can be removed after refactoring all references | |
| } |
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts around
lines 551 to 553, the stopCamera method is empty without explanation. Add a
comment inside the method explaining that it is intentionally left empty because
MLKit manages the camera lifecycle, or if the method is no longer required,
remove it entirely to keep the code clean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
src/app/core/services/mlkit-document-scanner.service.ts(1 hunks)src/app/fyle/dashboard/dashboard.page.ts(2 hunks)src/app/shared/components/capture-receipt/capture-receipt.component.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
**/*.component.{ts,html}: Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Do not translate strings that are already translation keys, tracking/analytics strings, strings with only special characters, comments, non-user-visible text, or variable bindings and expressions.
One object per component or feature in i18n translation files; avoid deep nesting and avoid prefixes like 'ui*' or 'feature*' in object names.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
src/**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
**/*.{service,pipe,directive}.ts
📄 CodeRabbit Inference Engine (.cursor/rules/atomics-i18n-key-pattern.mdc)
**/*.{service,pipe,directive}.ts: i18n keys for services, pipes, and directives must use the schema: services.., pipes.., directives..
Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Use only the three roots: services, pipes, directives for i18n key grouping
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Files:
src/app/core/services/mlkit-document-scanner.service.ts
🧠 Learnings (27)
📚 Learning: in `src/app/fyle/my-expenses/my-expenses.page.spec.ts`, when testing private methods like `filterdei...
Learnt from: arjunaj5
PR: fylein/fyle-mobile-app#3242
File: src/app/fyle/my-expenses/my-expenses.page.spec.ts:967-968
Timestamp: 2024-11-04T13:10:36.868Z
Learning: In `src/app/fyle/my-expenses/my-expenses.page.spec.ts`, when testing private methods like `filterDEIncompleteExpenses`, it's acceptable to use `//ts-ignore` to spy on them in unit tests.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isvisartfen...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:293-354
Timestamp: 2024-10-23T11:45:16.974Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isVisaRTFEnabled$', 'isMastercardRTFEnabled$', and 'isYodleeEnabled$' do not have rapidly changing values, so tests for rapid changes in these flags are unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/fyle/dashboard/dashboard.page.ts
📚 Learning: in 'personalcardsservice', move the launchdarkly feature flag subscription inside the service method...
Learnt from: Dimple16
PR: fylein/fyle-mobile-app#3259
File: src/app/core/services/personal-cards.service.ts:35-42
Timestamp: 2024-11-13T06:25:08.957Z
Learning: In 'PersonalCardsService', move the LaunchDarkly feature flag subscription inside the service methods instead of the constructor to prevent issues during first-time login.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/fyle/add-edit-expense/add-edit-expense.page.ts`, the `unmatchexpense` method is used for...
Learnt from: sumrender
PR: fylein/fyle-mobile-app#3265
File: src/app/fyle/personal-cards-matched-expenses/expense-preview/expense-preview.component.spec.ts:35-37
Timestamp: 2024-11-18T06:55:17.972Z
Learning: In `src/app/fyle/add-edit-expense/add-edit-expense.page.ts`, the `unmatchExpense` method is used for corporate card expenses, not for personal card expenses.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/fyle/dashboard/dashboard.page.ts
📚 Learning: in angular code, prefer using the `tap` operator to set state variables within observable streams fo...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3306
File: src/app/auth/pending-verification/pending-verification.page.ts:45-45
Timestamp: 2024-12-06T10:17:48.921Z
Learning: In Angular code, prefer using the `tap` operator to set state variables within observable streams for better readability, as seen in `pending-verification.page.ts`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `h...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3284
File: src/app/auth/verify/verify.page.ts:0-0
Timestamp: 2024-11-27T07:03:32.242Z
Learning: In `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `handleError` method without adding user messages via `ToastController`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in `src/app/auth/reset-password/reset-password.page.ts`, within the `resetpasswordpage` component, w...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3304
File: src/app/auth/reset-password/reset-password.page.ts:67-74
Timestamp: 2024-12-06T07:12:22.732Z
Learning: In `src/app/auth/reset-password/reset-password.page.ts`, within the `ResetPasswordPage` component, we should use only the generic error message 'Something went wrong. Please try after some time.' in the `handleError` method, rather than specific error messages based on error types.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: the team prefers to retain existing error messages in `newpasswordpage` component (`src/app/auth/new...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3309
File: src/app/auth/new-password/new-password.page.ts:79-99
Timestamp: 2024-12-09T06:37:55.768Z
Learning: The team prefers to retain existing error messages in `NewPasswordPage` component (`src/app/auth/new-password/new-password.page.ts`) unless there's a compelling reason to change them.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : use meaningful, semantic, and context-aware key names ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in 'src/app/post-verification/invited-user/invited-user.page.ts', the 'password' and 'fullname' obta...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3289
File: src/app/post-verification/invited-user/invited-user.page.ts:97-98
Timestamp: 2024-12-04T05:23:21.200Z
Learning: In 'src/app/post-verification/invited-user/invited-user.page.ts', the 'password' and 'fullName' obtained from 'this.fg.controls.password.value' and 'this.fg.controls.fullName.value' will always be strings, so additional error handling for type checking is unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in the `passwordcriteria` interface located at `src/app/shared/components/password-check-tooltip/pas...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3281
File: src/app/shared/components/password-check-tooltip/password-criteria.model.ts:1-4
Timestamp: 2024-12-03T05:19:33.839Z
Learning: In the `PasswordCriteria` interface located at `src/app/shared/components/password-check-tooltip/password-criteria.model.ts`, the `message` property is required and should not be optional.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/verify/verify.page.html`, error handling is performed by redirecting the user to a ...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3284
File: src/app/auth/verify/verify.page.html:2-7
Timestamp: 2024-11-27T06:26:04.313Z
Learning: In `src/app/auth/verify/verify.page.html`, error handling is performed by redirecting the user to a different page, so displaying error messages on this page is unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/sign-in/error/error.component.scss`, the team prefers to maintain the current bem n...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3346
File: src/app/auth/sign-in/error/error.component.scss:13-19
Timestamp: 2024-12-13T07:47:50.883Z
Learning: In `src/app/auth/sign-in/error/error.component.scss`, the team prefers to maintain the current BEM naming structure, even if it involves nested elements with double underscores like `error-internal__header__header-text`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: applies to src/**/*.component.{ts,html} : translation keys for angular components and templates loca...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to src/**/*.component.{ts,html} : Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : use meaningful, semantic, and context-aware key names for i18n...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: jsdoc documentation is not needed for the 'passwordchecks' interface in 'src/app/shared/components/p...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3281
File: src/app/shared/components/password-check-tooltip/password-checks.model.ts:1-1
Timestamp: 2024-11-25T08:30:23.873Z
Learning: JSDoc documentation is not needed for the 'PasswordChecks' interface in 'src/app/shared/components/password-check-tooltip/password-checks.model.ts'.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: do not suggest adding smooth transitions to the `&--receipt-container` class in `expenses-card.compo...
Learnt from: SahilK-027
PR: fylein/fyle-mobile-app#3311
File: src/app/shared/components/expenses-card-v2/expenses-card.component.scss:115-118
Timestamp: 2024-12-09T06:28:38.240Z
Learning: Do not suggest adding smooth transitions to the `&--receipt-container` class in `expenses-card.component.scss`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html`, the conditional s...
Learnt from: SahilK-027
PR: fylein/fyle-mobile-app#3312
File: src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html:19-22
Timestamp: 2024-12-09T07:08:28.540Z
Learning: In `src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html`, the conditional size logic for `[attr.size]` will be removed after the new design changes are applied across the entire mobile app, so refactoring is unnecessary at this time.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in this codebase, properties used in angular templates are not explicitly declared as 'public', sinc...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.html:14-14
Timestamp: 2024-10-23T09:23:56.684Z
Learning: In this codebase, properties used in Angular templates are not explicitly declared as 'public', since they are public by default in TypeScript.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isad...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:200-200
Timestamp: 2024-10-23T08:40:59.542Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isAddCorporateCardVisible$ = of(true);' to the top-level beforeEach block causes tests to fail, so mock values need to be set in individual tests.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: user sumrender prefers explicit, readable code structure over concise rxjs operator chains. they val...
Learnt from: sumrender
PR: fylein/fyle-mobile-app#3721
File: src/app/fyle/my-profile/my-profile.page.ts:137-153
Timestamp: 2025-06-18T06:14:36.495Z
Learning: User sumrender prefers explicit, readable code structure over concise RxJS operator chains. They value clarity and straightforward logic flow in navigation handling rather than consolidated functional programming approaches.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in angular components, interval timers created with setinterval() should always be cleared using cle...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3410
File: src/app/fyle/spender-onboarding/spender-onboarding.page.ts:144-150
Timestamp: 2025-01-20T05:15:40.653Z
Learning: In Angular components, interval timers created with setInterval() should always be cleared using clearInterval() to prevent memory leaks, especially before navigation.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in angular applications, navigation patterns should be consistent throughout the codebase. if skiplo...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3410
File: src/app/fyle/spender-onboarding/spender-onboarding.page.ts:144-150
Timestamp: 2025-01-20T05:15:40.653Z
Learning: In Angular applications, navigation patterns should be consistent throughout the codebase. If skipLocationChange is needed, prefer using router.navigate() with the skipLocationChange option instead of using both navigateByUrl() and navigate().
Applied to files:
src/app/fyle/dashboard/dashboard.page.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use the schema: services.<serviceName>.<messageKey>, pipes.<pipeName>.<messageKey>, directives.<directiveName>.<messageKey>
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : convert kebab-case file names to camelcase and remove ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : top-level object in i18n translation files must be the compone...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : keys inside the top-level object in i18n translation files mus...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
🧬 Code Graph Analysis (1)
src/app/shared/components/capture-receipt/capture-receipt.component.ts (1)
src/app/constants.ts (1)
DEVICE_PLATFORM(6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-app
- GitHub Check: build
🔇 Additional comments (2)
src/app/fyle/dashboard/dashboard.page.ts (1)
707-713: Kabali da! The navigation logic flows smoothly like my punch dialogues!The conditional parameter addition for auto capture expenses is well implemented and maintains backward compatibility.
src/app/shared/components/capture-receipt/capture-receipt.component.ts (1)
70-108: Thalaiva approves! The dependency injection transformation is powerful!Excellent refactoring to use Angular's modern
inject()function. This makes the component more tree-shakable and follows current best practices.
| if (result.scannedImages && result.scannedImages.length > 0) { | ||
| // In bulk mode, we still return one image at a time to maintain compatibility | ||
| return from(this.convertFileToBase64(result.scannedImages[0])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind it! The bulk mode logic is like a villain's incomplete plan!
When isBulkMode is true and multiple images are scanned, you're only returning the first image. This defeats the purpose of bulk scanning where users expect all scanned images.
Consider returning all images or handling them differently for bulk mode.
🤖 Prompt for AI Agents
In src/app/core/services/mlkit-document-scanner.service.ts around lines 20 to
22, the current code only returns the first scanned image even when isBulkMode
is true, which breaks the bulk scanning functionality. Modify the logic to check
if isBulkMode is true, and if so, convert all scanned images to base64 and
return them as a collection instead of just the first image. This ensures all
scanned images are processed and returned properly in bulk mode.
| { | ||
| text: 'Auto capture expenses', | ||
| icon: 'assets/svg/camera.svg', | ||
| cssClass: 'capture-receipt', | ||
| handler: this.actionSheetButtonsHandler('Auto capture expenses', 'camera_overlay'), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Style matters, even in code! Same icon for different actions is like wearing the same costume in every scene!
Both "Capture receipt" and "Auto capture expenses" buttons use the same icon 'assets/svg/camera.svg'. Users might get confused between the two actions.
Consider using a different icon for the auto capture feature, perhaps one that indicates automation or bulk scanning.
🤖 Prompt for AI Agents
In src/app/fyle/dashboard/dashboard.page.ts around lines 734 to 739, the "Auto
capture expenses" button uses the same camera.svg icon as the "Capture receipt"
button, which can confuse users. Change the icon for the "Auto capture expenses"
button to a different SVG that visually represents automation or bulk scanning
to clearly differentiate the two actions.
| // Check if the URL contains auto_capture_expenses=true | ||
| const autoCaptureParam = this.route.snapshot.params?.['auto_capture_expenses'] as string | undefined; | ||
| if (autoCaptureParam === 'true') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dei! The parameter reading is like looking for keys in the wrong pocket!
You're reading auto_capture_expenses from route params using this.route.snapshot.params, but the dashboard sends it as a query parameter. This will always be undefined.
- const autoCaptureParam = this.route.snapshot.params?.['auto_capture_expenses'] as string | undefined;
+ const autoCaptureParam = this.route.snapshot.queryParams?.['auto_capture_expenses'] as string | undefined;📝 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.
| // Check if the URL contains auto_capture_expenses=true | |
| const autoCaptureParam = this.route.snapshot.params?.['auto_capture_expenses'] as string | undefined; | |
| if (autoCaptureParam === 'true') { | |
| // Check if the URL contains auto_capture_expenses=true | |
| const autoCaptureParam = this.route.snapshot.queryParams?.['auto_capture_expenses'] as string | undefined; | |
| if (autoCaptureParam === 'true') { |
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts around
lines 539 to 541, the code incorrectly reads the 'auto_capture_expenses' value
from route params instead of query parameters. Change the code to read
'auto_capture_expenses' from this.route.snapshot.queryParams instead of
this.route.snapshot.params to correctly capture the query parameter sent by the
dashboard.
| this.mlkitScanner.scanDocument(false).subscribe({ | ||
| next: (base64PictureData) => { | ||
| // Navigate directly to expense form with the scanned image | ||
| const isInstafyleEnabled$ = this.platformEmployeeSettingsService | ||
| .get() | ||
| .pipe( | ||
| map( | ||
| (employeeSettings) => | ||
| employeeSettings.insta_fyle_settings.allowed && employeeSettings.insta_fyle_settings.enabled, | ||
| ), | ||
| ); | ||
|
|
||
| isInstafyleEnabled$.subscribe((isInstafyleEnabled) => { | ||
| this.router.navigate([ | ||
| '/', | ||
| 'enterprise', | ||
| 'add_edit_expense', | ||
| { | ||
| dataUrl: base64PictureData, | ||
| canExtractData: isInstafyleEnabled, | ||
| }, | ||
| ]); | ||
| }); | ||
| }, | ||
| error: () => { | ||
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: 'failed', | ||
| }), | ||
| }); | ||
| }, | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Mind it! Code duplication is like a remake without improvements!
The logic for navigating to expense form with InstaFyle check is duplicated between startDirectDocumentScan() (lines 562-581) and navigateToExpenseForm() (lines 204-224).
Extract the common logic and reuse:
startDirectDocumentScan(): void {
this.mlkitScanner.scanDocument(false).subscribe({
next: (base64PictureData) => {
- // Navigate directly to expense form with the scanned image
- const isInstafyleEnabled$ = this.platformEmployeeSettingsService
- .get()
- .pipe(
- map(
- (employeeSettings) =>
- employeeSettings.insta_fyle_settings.allowed && employeeSettings.insta_fyle_settings.enabled,
- ),
- );
-
- isInstafyleEnabled$.subscribe((isInstafyleEnabled) => {
- this.router.navigate([
- '/',
- 'enterprise',
- 'add_edit_expense',
- {
- dataUrl: base64PictureData,
- canExtractData: isInstafyleEnabled,
- },
- ]);
- });
+ this.base64ImagesWithSource = [{
+ source: 'MOBILE_DASHCAM_SINGLE',
+ base64Image: base64PictureData,
+ }];
+ this.navigateToExpenseForm();
},Also applies to: 204-224
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts
between lines 558-591 and 204-224, the logic for navigating to the expense form
with the InstaFyle check is duplicated. Extract this common logic into a new
reusable private method that accepts the base64PictureData and handles the
InstaFyle settings check and navigation. Replace the duplicated code in both
startDirectDocumentScan() and navigateToExpenseForm() by calling this new method
with the appropriate data.
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: 'failed', | ||
| }), | ||
| }); | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style is important, but so is clarity in error messages!
The error message 'failed' is too generic and not internationalized. Users deserve proper feedback.
- message: 'failed',
+ message: this.translocoService.translate('captureReceipt.documentScanFailed'),📝 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.
| error: () => { | |
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | |
| ...this.snackbarProperties.setSnackbarProperties('failure', { | |
| message: 'failed', | |
| }), | |
| }); | |
| }, | |
| error: () => { | |
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | |
| ...this.snackbarProperties.setSnackbarProperties('failure', { | |
| message: this.translocoService.translate('captureReceipt.documentScanFailed'), | |
| }), | |
| }); | |
| }, |
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts around
lines 583 to 589, the error message shown in the snackbar is too generic and not
internationalized. Replace the hardcoded 'failed' message with a clear,
user-friendly message that is internationalized using the app's translation
service or i18n framework to provide proper feedback to users in their language.
| if (this.noOfReceipts >= 20) { | ||
| this.trackingService.receiptLimitReached(); | ||
| this.showLimitReachedPopover().subscribe(noop); | ||
| return; | ||
| } | ||
|
|
||
| this.mlkitScanner.scanDocument(true).subscribe({ | ||
| next: (base64PictureData) => { | ||
| this.base64ImagesWithSource.push({ | ||
| source: 'MOBILE_DASHCAM_BULK', | ||
| base64Image: base64PictureData, | ||
| }); | ||
| this.noOfReceipts += 1; | ||
|
|
||
| // Add to queue and navigate to my expenses | ||
| this.loaderService.showLoader(this.translocoService.translate('captureReceipt.pleaseWait'), 10000); | ||
| this.addMultipleExpensesToQueue(this.base64ImagesWithSource) | ||
| .pipe(finalize(() => this.loaderService.hideLoader())) | ||
| .subscribe(() => { | ||
| this.router.navigate(['/', 'enterprise', 'my_expenses']); | ||
| }); | ||
| }, | ||
| error: () => { | ||
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: this.translocoService.translate('captureReceipt.documentScanFailed'), | ||
| }), | ||
| }); | ||
| }, | ||
| }); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kabali says: Incomplete implementation is worse than no implementation!
The startDirectBulkDocumentScan() method doesn't actually enable bulk mode in the scanner - it calls scanDocument(true) but immediately processes and navigates after the first scan, defeating the bulk purpose.
The method should either:
- Loop to capture multiple documents, or
- Pass the correct bulk flag to actually scan multiple pages at once
Currently, it's misleading as it behaves like single capture with extra steps.
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts around
lines 593 to 624, the startDirectBulkDocumentScan() method calls
scanDocument(true) but processes only one scanned image before navigating away,
so it does not actually perform bulk scanning. To fix this, modify the method to
either loop and accumulate multiple scans before processing or ensure the
scanner is invoked in a mode that captures multiple pages in one call, then
process all images together before navigating. This will align the method
behavior with its intended bulk scanning purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (5)
src/app/core/services/mlkit-document-scanner.service.ts (3)
10-27: Mind it! The bulk scanning is like my incomplete stunts - looks powerful but doesn't deliver!When
isBulkModeis true and multiple pages are scanned, you're still returning only the first image. This defeats the purpose of bulk scanning where users expect all scanned documents.Consider modifying the logic to handle all scanned images in bulk mode:
- // In bulk mode, we still return one image at a time to maintain compatibility - return from(this.convertFileToBase64(result.scannedImages[0])); + if (isBulkMode) { + // Convert all scanned images and emit them as an array or individually + const conversions$ = result.scannedImages.map(imageUrl => + from(this.convertFileToBase64(imageUrl)) + ); + return forkJoin(conversions$); // Returns Observable<string[]> + } else { + return from(this.convertFileToBase64(result.scannedImages[0])); + }
20-22: Kabali da! Error messages without translation are like dialogues without punch!Per coding guidelines, services must use i18n keys. The error message should follow the schema
services.mlkitDocumentScanner.<messageKey>.Inject TranslocoService and use translation key:
+ constructor(private translocoService: TranslocoService) {} + scanDocument(isBulkMode = false): Observable<string> { // ... existing code ... if (!result || !result.scannedImages || result.scannedImages.length === 0) { - throw new Error('No document scanned or scan was cancelled'); + throw new Error(this.translocoService.translate('services.mlkitDocumentScanner.noDocumentScanned')); }
29-45: Style matters, but preserving error details matters more - like my signature sunglasses flip!The error handling needs two improvements:
- Preserve original error details for debugging
- Use i18n translation keys for error messages
private async convertFileToBase64(fileUrl: string): Promise<string> { try { const response = await fetch(fileUrl); const blob = await response.blob(); return new Promise<string>((resolve, reject): void => { const reader = new FileReader(); reader.onloadend = (): void => { const base64data = reader.result as string; resolve(base64data); }; - reader.onerror = (): void => reject(new Error('Failed to convert file to base64')); + reader.onerror = (error): void => reject(new Error( + this.translocoService.translate('services.mlkitDocumentScanner.fileConversionFailed') + + `: ${error?.type || 'Unknown error'}` + )); reader.readAsDataURL(blob); }); - } catch { - throw new Error('Failed to convert file to base64'); + } catch (error) { + throw new Error( + this.translocoService.translate('services.mlkitDocumentScanner.fileConversionFailed') + + `: ${error?.message || 'Unknown error'}` + ); } }src/app/shared/components/capture-receipt/capture-receipt.component.ts (2)
538-544: Thalaiva says: You're searching in the wrong pocket, like a villain looking for my weakness!You're reading
auto_capture_expensesfrom route params, but the dashboard sends it as a query parameter. This will always be undefined.- const autoCaptureParam = this.route.snapshot.params?.['auto_capture_expenses'] as string | undefined; + const autoCaptureParam = this.route.snapshot.queryParams?.['auto_capture_expenses'] as string | undefined;
597-628: Mind it! Your bulk scanning is like my movie without action - disappointing the fans!The
startDirectBulkDocumentScanmethod doesn't implement actual bulk scanning. It captures one document and navigates away immediately, defeating the purpose of bulk mode.Consider implementing proper bulk flow:
- Allow multiple scans in a loop
- Show preview after each scan with option to continue
- Process all images together before navigation
startDirectBulkDocumentScan(): void { if (this.noOfReceipts >= 20) { this.trackingService.receiptLimitReached(); this.showLimitReachedPopover().subscribe(noop); return; } this.mlkitScanner.scanDocument(true).subscribe({ next: (base64PictureData) => { this.base64ImagesWithSource.push({ source: 'MOBILE_DASHCAM_BULK', base64Image: base64PictureData, }); this.noOfReceipts += 1; + + // Show preview and ask if user wants to continue scanning + this.showReceiptPreview().subscribe((decision) => { + if (decision.continueCaptureReceipt) { + this.startDirectBulkDocumentScan(); // Recursive call for next scan + } else { + // Process all images and navigate + this.loaderService.showLoader(this.translocoService.translate('captureReceipt.pleaseWait'), 10000); + this.addMultipleExpensesToQueue(this.base64ImagesWithSource) + .pipe(finalize(() => this.loaderService.hideLoader())) + .subscribe(() => { + this.router.navigate(['/', 'enterprise', 'my_expenses']); + }); + } + }); - - // Add to queue and navigate to my expenses - this.loaderService.showLoader(this.translocoService.translate('captureReceipt.pleaseWait'), 10000); - this.addMultipleExpensesToQueue(this.base64ImagesWithSource) - .pipe(finalize(() => this.loaderService.hideLoader())) - .subscribe(() => { - this.router.navigate(['/', 'enterprise', 'my_expenses']); - }); },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/app/core/services/mlkit-document-scanner.service.ts(1 hunks)src/app/shared/components/capture-receipt/capture-receipt.component.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
**/*.component.{ts,html}: Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Do not translate strings that are already translation keys, tracking/analytics strings, strings with only special characters, comments, non-user-visible text, or variable bindings and expressions.
One object per component or feature in i18n translation files; avoid deep nesting and avoid prefixes like 'ui*' or 'feature*' in object names.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
src/**/*.component.{ts,html}
📄 CodeRabbit Inference Engine (.cursor/rules/component-i18n-key-naming.mdc)
Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
**/*.{service,pipe,directive}.ts
📄 CodeRabbit Inference Engine (.cursor/rules/atomics-i18n-key-pattern.mdc)
**/*.{service,pipe,directive}.ts: i18n keys for services, pipes, and directives must use the schema: services.., pipes.., directives..
Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Use only the three roots: services, pipes, directives for i18n key grouping
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Files:
src/app/core/services/mlkit-document-scanner.service.ts
🧠 Learnings (31)
📚 Learning: in `src/app/fyle/my-expenses/my-expenses.page.spec.ts`, when testing private methods like `filterdei...
Learnt from: arjunaj5
PR: fylein/fyle-mobile-app#3242
File: src/app/fyle/my-expenses/my-expenses.page.spec.ts:967-968
Timestamp: 2024-11-04T13:10:36.868Z
Learning: In `src/app/fyle/my-expenses/my-expenses.page.spec.ts`, when testing private methods like `filterDEIncompleteExpenses`, it's acceptable to use `//ts-ignore` to spy on them in unit tests.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isvisartfen...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:293-354
Timestamp: 2024-10-23T11:45:16.974Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', the flags 'isVisaRTFEnabled$', 'isMastercardRTFEnabled$', and 'isYodleeEnabled$' do not have rapidly changing values, so tests for rapid changes in these flags are unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/fyle/add-edit-expense/add-edit-expense.page.ts`, the `unmatchexpense` method is used for...
Learnt from: sumrender
PR: fylein/fyle-mobile-app#3265
File: src/app/fyle/personal-cards-matched-expenses/expense-preview/expense-preview.component.spec.ts:35-37
Timestamp: 2024-11-18T06:55:17.972Z
Learning: In `src/app/fyle/add-edit-expense/add-edit-expense.page.ts`, the `unmatchExpense` method is used for corporate card expenses, not for personal card expenses.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'personalcardsservice', move the launchdarkly feature flag subscription inside the service method...
Learnt from: Dimple16
PR: fylein/fyle-mobile-app#3259
File: src/app/core/services/personal-cards.service.ts:35-42
Timestamp: 2024-11-13T06:25:08.957Z
Learning: In 'PersonalCardsService', move the LaunchDarkly feature flag subscription inside the service methods instead of the constructor to prevent issues during first-time login.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `h...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3284
File: src/app/auth/verify/verify.page.ts:0-0
Timestamp: 2024-11-27T07:03:32.242Z
Learning: In `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `handleError` method without adding user messages via `ToastController`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in angular code, prefer using the `tap` operator to set state variables within observable streams fo...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3306
File: src/app/auth/pending-verification/pending-verification.page.ts:45-45
Timestamp: 2024-12-06T10:17:48.921Z
Learning: In Angular code, prefer using the `tap` operator to set state variables within observable streams for better readability, as seen in `pending-verification.page.ts`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/reset-password/reset-password.page.ts`, within the `resetpasswordpage` component, w...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3304
File: src/app/auth/reset-password/reset-password.page.ts:67-74
Timestamp: 2024-12-06T07:12:22.732Z
Learning: In `src/app/auth/reset-password/reset-password.page.ts`, within the `ResetPasswordPage` component, we should use only the generic error message 'Something went wrong. Please try after some time.' in the `handleError` method, rather than specific error messages based on error types.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: the team prefers to retain existing error messages in `newpasswordpage` component (`src/app/auth/new...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3309
File: src/app/auth/new-password/new-password.page.ts:79-99
Timestamp: 2024-12-09T06:37:55.768Z
Learning: The team prefers to retain existing error messages in `NewPasswordPage` component (`src/app/auth/new-password/new-password.page.ts`) unless there's a compelling reason to change them.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : use meaningful, semantic, and context-aware key names ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in 'src/app/post-verification/invited-user/invited-user.page.ts', the 'password' and 'fullname' obta...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3289
File: src/app/post-verification/invited-user/invited-user.page.ts:97-98
Timestamp: 2024-12-04T05:23:21.200Z
Learning: In 'src/app/post-verification/invited-user/invited-user.page.ts', the 'password' and 'fullName' obtained from 'this.fg.controls.password.value' and 'this.fg.controls.fullName.value' will always be strings, so additional error handling for type checking is unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in the `passwordcriteria` interface located at `src/app/shared/components/password-check-tooltip/pas...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3281
File: src/app/shared/components/password-check-tooltip/password-criteria.model.ts:1-4
Timestamp: 2024-12-03T05:19:33.839Z
Learning: In the `PasswordCriteria` interface located at `src/app/shared/components/password-check-tooltip/password-criteria.model.ts`, the `message` property is required and should not be optional.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/verify/verify.page.html`, error handling is performed by redirecting the user to a ...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3284
File: src/app/auth/verify/verify.page.html:2-7
Timestamp: 2024-11-27T06:26:04.313Z
Learning: In `src/app/auth/verify/verify.page.html`, error handling is performed by redirecting the user to a different page, so displaying error messages on this page is unnecessary.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/auth/sign-in/error/error.component.scss`, the team prefers to maintain the current bem n...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3346
File: src/app/auth/sign-in/error/error.component.scss:13-19
Timestamp: 2024-12-13T07:47:50.883Z
Learning: In `src/app/auth/sign-in/error/error.component.scss`, the team prefers to maintain the current BEM naming structure, even if it involves nested elements with double underscores like `error-internal__header__header-text`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: applies to src/**/*.component.{ts,html} : translation keys for angular components and templates loca...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to src/**/*.component.{ts,html} : Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : use meaningful, semantic, and context-aware key names for i18n...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: jsdoc documentation is not needed for the 'passwordchecks' interface in 'src/app/shared/components/p...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3281
File: src/app/shared/components/password-check-tooltip/password-checks.model.ts:1-1
Timestamp: 2024-11-25T08:30:23.873Z
Learning: JSDoc documentation is not needed for the 'PasswordChecks' interface in 'src/app/shared/components/password-check-tooltip/password-checks.model.ts'.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: do not suggest adding smooth transitions to the `&--receipt-container` class in `expenses-card.compo...
Learnt from: SahilK-027
PR: fylein/fyle-mobile-app#3311
File: src/app/shared/components/expenses-card-v2/expenses-card.component.scss:115-118
Timestamp: 2024-12-09T06:28:38.240Z
Learning: Do not suggest adding smooth transitions to the `&--receipt-container` class in `expenses-card.component.scss`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in `src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html`, the conditional s...
Learnt from: SahilK-027
PR: fylein/fyle-mobile-app#3312
File: src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html:19-22
Timestamp: 2024-12-09T07:08:28.540Z
Learning: In `src/app/shared/components/fy-loading-screen/fy-loading-screen.component.html`, the conditional size logic for `[attr.size]` will be removed after the new design changes are applied across the entire mobile app, so refactoring is unnecessary at this time.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in the sidemenucomponent, use optional chaining (`?.`) for safer property access when checking neste...
Learnt from: arjunaj5
PR: fylein/fyle-mobile-app#3632
File: src/app/shared/components/sidemenu/sidemenu.component.ts:207-207
Timestamp: 2025-03-25T11:23:24.170Z
Learning: In the SidemenuComponent, use optional chaining (`?.`) for safer property access when checking nested object properties like `allowedReportsActions.approve` and `allowedAdvancesActions.approve`.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in the fyle mobile app, the migration from orgusersettingsservice to platformemployeesettingsservice...
Learnt from: Dimple16
PR: fylein/fyle-mobile-app#3714
File: src/app/core/services/mileage.service.ts:23-25
Timestamp: 2025-06-17T05:15:26.587Z
Learning: In the Fyle mobile app, the migration from OrgUserSettingsService to PlatformEmployeeSettingsService introduced a potential breaking change where mileage_settings could be null or undefined. Test cases in add-edit-mileage-2.spec.ts and add-edit-mileage-5.spec.ts explicitly test scenarios where getOrgUserMileageSettings returns null or undefined, indicating this is a real-world scenario that needs defensive handling.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in angular applications, navigation patterns should be consistent throughout the codebase. if skiplo...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3410
File: src/app/fyle/spender-onboarding/spender-onboarding.page.ts:144-150
Timestamp: 2025-01-20T05:15:40.653Z
Learning: In Angular applications, navigation patterns should be consistent throughout the codebase. If skipLocationChange is needed, prefer using router.navigate() with the skipLocationChange option instead of using both navigateByUrl() and navigate().
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in the fyle mobile app's spender onboarding flow, the team prefers to keep the loader implementation...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3423
File: src/app/fyle/spender-onboarding/spender-onboarding.page.html:0-0
Timestamp: 2025-01-20T02:26:35.101Z
Learning: In the Fyle mobile app's spender onboarding flow, the team prefers to keep the loader implementation within the spender-onboarding.page.html component rather than extracting it into a separate reusable component.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: when optimizing angular templates with repeated code blocks, consider moving conditions and messages...
Learnt from: arjunaj5
PR: fylein/fyle-mobile-app#3281
File: src/app/shared/components/password-check-tooltip/password-check-tooltip.component.html:6-70
Timestamp: 2024-11-26T05:41:37.044Z
Learning: When optimizing Angular templates with repeated code blocks, consider moving conditions and messages into a configuration array and loop over them with *ngFor for better maintainability.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use the schema: services.<serviceName>.<messageKey>, pipes.<pipeName>.<messageKey>, directives.<directiveName>.<messageKey>
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : top-level object in i18n translation files must be the compone...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.tssrc/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in this codebase, properties used in angular templates are not explicitly declared as 'public', sinc...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.html:14-14
Timestamp: 2024-10-23T09:23:56.684Z
Learning: In this codebase, properties used in Angular templates are not explicitly declared as 'public', since they are public by default in TypeScript.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isad...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3240
File: src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts:200-200
Timestamp: 2024-10-23T08:40:59.542Z
Learning: In 'src/app/fyle/manage-corporate-cards/manage-corporate-cards.page.spec.ts', moving 'component.isAddCorporateCardVisible$ = of(true);' to the top-level beforeEach block causes tests to fail, so mock values need to be set in individual tests.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: user sumrender prefers explicit, readable code structure over concise rxjs operator chains. they val...
Learnt from: sumrender
PR: fylein/fyle-mobile-app#3721
File: src/app/fyle/my-profile/my-profile.page.ts:137-153
Timestamp: 2025-06-18T06:14:36.495Z
Learning: User sumrender prefers explicit, readable code structure over concise RxJS operator chains. They value clarity and straightforward logic flow in navigation handling rather than consolidated functional programming approaches.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: in angular components, interval timers created with setinterval() should always be cleared using cle...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3410
File: src/app/fyle/spender-onboarding/spender-onboarding.page.ts:144-150
Timestamp: 2025-01-20T05:15:40.653Z
Learning: In Angular components, interval timers created with setInterval() should always be cleared using clearInterval() to prevent memory leaks, especially before navigation.
Applied to files:
src/app/shared/components/capture-receipt/capture-receipt.component.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : convert kebab-case file names to camelcase and remove ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : keys inside the top-level object in i18n translation files mus...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
🧬 Code Graph Analysis (1)
src/app/shared/components/capture-receipt/capture-receipt.component.ts (1)
src/app/constants.ts (1)
DEVICE_PLATFORM(6-6)
🪛 GitHub Check: Run linters
src/app/shared/components/capture-receipt/capture-receipt.component.ts
[failure] 586-586:
Unexpected console statement. Only these console methods are allowed: .
🪛 GitHub Actions: Lint
src/app/shared/components/capture-receipt/capture-receipt.component.ts
[error] 586-586: ESLint: Unexpected console statement. Only these console methods are allowed. (no-console)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-app
- GitHub Check: build
🔇 Additional comments (1)
src/app/shared/components/capture-receipt/capture-receipt.component.ts (1)
70-108: Superstar style! The inject() pattern is like my signature moves - modern and powerful!The refactoring from constructor injection to Angular's
inject()function is well done. This modern approach reduces boilerplate and improves code readability.
| startDirectDocumentScan(): void { | ||
| this.mlkitScanner.scanDocument(false).subscribe({ | ||
| next: (base64PictureData) => { | ||
| // Navigate directly to expense form with the scanned image | ||
| const isInstafyleEnabled$ = this.platformEmployeeSettingsService | ||
| .get() | ||
| .pipe( | ||
| map( | ||
| (employeeSettings) => | ||
| employeeSettings.insta_fyle_settings.allowed && employeeSettings.insta_fyle_settings.enabled, | ||
| ), | ||
| ); | ||
|
|
||
| isInstafyleEnabled$.subscribe((isInstafyleEnabled) => { | ||
| this.router.navigate([ | ||
| '/', | ||
| 'enterprise', | ||
| 'add_edit_expense', | ||
| { | ||
| dataUrl: base64PictureData, | ||
| canExtractData: isInstafyleEnabled, | ||
| }, | ||
| ]); | ||
| }); | ||
| }, | ||
| error: (error: Error) => { | ||
| // Only show error if it's not a user cancellation | ||
| if (error?.message !== 'No document scanned or scan was cancelled') { | ||
| console.log('error', error); | ||
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | ||
| ...this.snackbarProperties.setSnackbarProperties('failure', { | ||
| message: 'Document scanning failed. Please try again.' + error.message, | ||
| }), | ||
| }); | ||
| } | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Style matters! Code duplication is like repeating my punch dialogues - powerful once, boring twice!
The navigation logic (lines 562-581) duplicates the navigateToExpenseForm method. Also, there's a console statement that violates linting rules.
Refactor to reuse existing method and fix the console statement:
startDirectDocumentScan(): void {
this.mlkitScanner.scanDocument(false).subscribe({
next: (base64PictureData) => {
- // Navigate directly to expense form with the scanned image
- const isInstafyleEnabled$ = this.platformEmployeeSettingsService
- .get()
- .pipe(
- map(
- (employeeSettings) =>
- employeeSettings.insta_fyle_settings.allowed && employeeSettings.insta_fyle_settings.enabled,
- ),
- );
-
- isInstafyleEnabled$.subscribe((isInstafyleEnabled) => {
- this.router.navigate([
- '/',
- 'enterprise',
- 'add_edit_expense',
- {
- dataUrl: base64PictureData,
- canExtractData: isInstafyleEnabled,
- },
- ]);
- });
+ this.base64ImagesWithSource = [{
+ source: 'MOBILE_DASHCAM_SINGLE',
+ base64Image: base64PictureData,
+ }];
+ this.navigateToExpenseForm();
},
error: (error: Error) => {
// Only show error if it's not a user cancellation
if (error?.message !== 'No document scanned or scan was cancelled') {
- console.log('error', error);
this.matSnackBar.openFromComponent(ToastMessageComponent, {
...this.snackbarProperties.setSnackbarProperties('failure', {
- message: 'Document scanning failed. Please try again.' + error.message,
+ message: this.translocoService.translate('captureReceipt.documentScanFailed'),
}),
});
}
},
});
}📝 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.
| startDirectDocumentScan(): void { | |
| this.mlkitScanner.scanDocument(false).subscribe({ | |
| next: (base64PictureData) => { | |
| // Navigate directly to expense form with the scanned image | |
| const isInstafyleEnabled$ = this.platformEmployeeSettingsService | |
| .get() | |
| .pipe( | |
| map( | |
| (employeeSettings) => | |
| employeeSettings.insta_fyle_settings.allowed && employeeSettings.insta_fyle_settings.enabled, | |
| ), | |
| ); | |
| isInstafyleEnabled$.subscribe((isInstafyleEnabled) => { | |
| this.router.navigate([ | |
| '/', | |
| 'enterprise', | |
| 'add_edit_expense', | |
| { | |
| dataUrl: base64PictureData, | |
| canExtractData: isInstafyleEnabled, | |
| }, | |
| ]); | |
| }); | |
| }, | |
| error: (error: Error) => { | |
| // Only show error if it's not a user cancellation | |
| if (error?.message !== 'No document scanned or scan was cancelled') { | |
| console.log('error', error); | |
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | |
| ...this.snackbarProperties.setSnackbarProperties('failure', { | |
| message: 'Document scanning failed. Please try again.' + error.message, | |
| }), | |
| }); | |
| } | |
| }, | |
| }); | |
| } | |
| startDirectDocumentScan(): void { | |
| this.mlkitScanner.scanDocument(false).subscribe({ | |
| next: (base64PictureData) => { | |
| this.base64ImagesWithSource = [{ | |
| source: 'MOBILE_DASHCAM_SINGLE', | |
| base64Image: base64PictureData, | |
| }]; | |
| this.navigateToExpenseForm(); | |
| }, | |
| error: (error: Error) => { | |
| // Only show error if it's not a user cancellation | |
| if (error?.message !== 'No document scanned or scan was cancelled') { | |
| this.matSnackBar.openFromComponent(ToastMessageComponent, { | |
| ...this.snackbarProperties.setSnackbarProperties('failure', { | |
| message: this.translocoService.translate('captureReceipt.documentScanFailed'), | |
| }), | |
| }); | |
| } | |
| }, | |
| }); | |
| } |
🧰 Tools
🪛 GitHub Check: Run linters
[failure] 586-586:
Unexpected console statement. Only these console methods are allowed: .
🪛 GitHub Actions: Lint
[error] 586-586: ESLint: Unexpected console statement. Only these console methods are allowed. (no-console)
🤖 Prompt for AI Agents
In src/app/shared/components/capture-receipt/capture-receipt.component.ts
between lines 558 and 595, the navigation logic inside startDirectDocumentScan
duplicates the existing navigateToExpenseForm method and includes a console.log
statement which violates linting rules. Refactor by replacing the duplicated
navigation code with a call to navigateToExpenseForm, passing the necessary
parameters, and remove or replace the console.log with proper error handling or
logging consistent with the project's standards.
🔁 Code Duplication Report - Angular
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
src/app/core/services/mlkit-document-scanner.service.ts (3)
22-22: The error messages need translation power like my punch dialogues!Per coding guidelines, services must use i18n keys. Error messages should follow the schema
services.mlkitDocumentScanner.<messageKey>.Also applies to: 44-44
43-45: The error details are vanishing like a villain in my movies!The generic catch block swallows the original error information, making debugging difficult for my technical team.
24-25: The bulk mode logic is like a villain's incomplete plan!When
isBulkModeis true and multiple images are scanned, you're only returning the first image. This defeats the purpose of bulk scanning where users expect all scanned images.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
package.json(1 hunks)src/app/core/services/mlkit-document-scanner.service.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{service,pipe,directive}.ts
📄 CodeRabbit Inference Engine (.cursor/rules/atomics-i18n-key-pattern.mdc)
**/*.{service,pipe,directive}.ts: i18n keys for services, pipes, and directives must use the schema: services.., pipes.., directives..
Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Use only the three roots: services, pipes, directives for i18n key grouping
Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Files:
src/app/core/services/mlkit-document-scanner.service.ts
🧠 Learnings (10)
📚 Learning: applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : i18n keys for services, pipes, and directives must use the schema: services.<serviceName>.<messageKey>, pipes.<pipeName>.<messageKey>, directives.<directiveName>.<messageKey>
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : use meaningful, semantic, and context-aware key names ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like message1, text1, error1
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to src/**/*.component.{ts,html} : translation keys for angular components and templates loca...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to src/**/*.component.{ts,html} : Translation keys for Angular components and templates located in 'src/**' must be placed in 'src/assets/i18n/{lang}.json' for every supported language.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: the team prefers to retain existing error messages in `newpasswordpage` component (`src/app/auth/new...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3309
File: src/app/auth/new-password/new-password.page.ts:79-99
Timestamp: 2024-12-09T06:37:55.768Z
Learning: The team prefers to retain existing error messages in `NewPasswordPage` component (`src/app/auth/new-password/new-password.page.ts`) unless there's a compelling reason to change them.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `h...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3284
File: src/app/auth/verify/verify.page.ts:0-0
Timestamp: 2024-11-27T07:03:32.242Z
Learning: In `src/app/auth/verify/verify.page.ts`, prefer to retain the existing error handling flow in the `handleError` method without adding user messages via `ToastController`.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: in `src/app/auth/reset-password/reset-password.page.ts`, within the `resetpasswordpage` component, w...
Learnt from: bistaastha
PR: fylein/fyle-mobile-app#3304
File: src/app/auth/reset-password/reset-password.page.ts:67-74
Timestamp: 2024-12-06T07:12:22.732Z
Learning: In `src/app/auth/reset-password/reset-password.page.ts`, within the `ResetPasswordPage` component, we should use only the generic error message 'Something went wrong. Please try after some time.' in the `handleError` method, rather than specific error messages based on error types.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.{service,pipe,directive}.ts : convert kebab-case file names to camelcase and remove ...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/atomics-i18n-key-pattern.mdc:0-0
Timestamp: 2025-07-28T05:57:50.701Z
Learning: Applies to **/*.{service,pipe,directive}.ts : Convert kebab-case file names to camelCase and remove the suffix (Service, Pipe, Directive) when generating i18n keys for services, pipes, and directives
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : use meaningful, semantic, and context-aware key names for i18n...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Use meaningful, semantic, and context-aware key names for i18n keys; avoid generic names like 'label1', 'text1', or 'message1'.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : top-level object in i18n translation files must be the compone...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Top-level object in i18n translation files must be the component or feature folder name, derived from the file name by converting kebab-case to camelCase and removing the first matching prefix from: 'feature', 'ui', 'component'.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
📚 Learning: applies to **/*.component.{ts,html} : keys inside the top-level object in i18n translation files mus...
Learnt from: CR
PR: fylein/fyle-mobile-app#0
File: .cursor/rules/component-i18n-key-naming.mdc:0-0
Timestamp: 2025-07-28T05:57:57.796Z
Learning: Applies to **/*.component.{ts,html} : Keys inside the top-level object in i18n translation files must be free-form, not prefixed, and there must be no nested objects beyond the first level.
Applied to files:
src/app/core/services/mlkit-document-scanner.service.ts
🪛 GitHub Actions: Lint
src/app/core/services/mlkit-document-scanner.service.ts
[warning] 33-33: ESLint warning: Unused eslint-disable directive (no problems were reported from '@typescript-eslint/no-unsafe-assignment', '@typescript-eslint/no-unsafe-call', or '@typescript-eslint/no-unsafe-member-access').
[warning] 36-36: ESLint warning: Unused eslint-disable directive (no problems were reported from '@typescript-eslint/no-unsafe-assignment' or '@typescript-eslint/no-unsafe-member-access').
[warning] 41-41: ESLint warning: Unused eslint-disable directive (no problems were reported from '@typescript-eslint/no-unsafe-member-access').
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-app
- GitHub Check: build
| "@awesome-cordova-plugins/smartlook": "^6.14.0", | ||
| "@awesome-cordova-plugins/spinner-dialog": "^6.2.0", | ||
| "@capacitor-community/camera-preview": "^7.0.0", | ||
| "@capacitor-mlkit/document-scanner": "^7.3.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Mind it! These new packages need my blessing for security!
The new dependencies look stylish, but let me verify they're the latest and safest versions for my fans to use.
Also applies to: 54-54
🌐 Web query:
What are the latest versions of @capacitor-mlkit/document-scanner and @capacitor/filesystem packages on npm?
💡 Result:
As of August 7, 2025, the latest versions of the specified npm packages are:
-
@capacitor-mlkit/document-scanner: The most recent version is
7.2.1, released on April 7, 2025. (classic.yarnpkg.com) -
@capacitor/filesystem: The latest stable version is
7.0.1, published 18 days ago. (npmjs.com)
Please note that @capacitor/filesystem has a nightly build version 7.0.2-nightly-20250527T150614.0, released 19 days ago. (npmjs.com)
For the most current information, you can visit the npm package pages:
-
@capacitor-mlkit/document-scanner: (classic.yarnpkg.com)
-
@capacitor/filesystem: (npmjs.com)
Citations:
- 1: https://classic.yarnpkg.com/en/package/%40capacitor-mlkit/barcode-scanning?utm_source=openai
- 2: https://www.npmjs.com/package/%40capacitor/filesystem?activeTab=versions&utm_source=openai
- 3: https://www.npmjs.com/package/%40capacitor/filesystem/v/7.0.2-nightly-20250527T150614.0?utm_source=openai
- 4: https://classic.yarnpkg.com/en/package/%40capacitor-mlkit/barcode-scanning?utm_source=openai
- 5: https://www.npmjs.com/package/%40capacitor/filesystem?activeTab=versions&utm_source=openai
I will verify the version of @capacitor/filesystem in package.json now, mighty developer!
🏁 Script executed:
#!/bin/bash
rg "@capacitor/filesystem" -n package.jsonLength of output: 84
Double-check published versions of new dependencies, Superstar!
I see two package versions that leap beyond the latest npm releases:
- package.json:46 – “@capacitor-mlkit/document-scanner”: “^7.3.0”
• Latest published is 7.2.1 (yarnpkg.com) - package.json:54 – “@capacitor/filesystem”: “^7.1.4”
• Latest stable is 7.0.1 (npmjs.com)
Please confirm these versions actually exist on npm or adjust them down to the current stable releases. Rajini says: get this right at once!
🤖 Prompt for AI Agents
In package.json at line 46, the version "^7.3.0" for
"@capacitor-mlkit/document-scanner" is higher than the latest published version
7.2.1 on npm. Verify the actual published version on npm and if "^7.3.0" does
not exist, change it to "^7.2.1" or the latest stable version available.
Similarly, check the version for "@capacitor/filesystem" at line 54 and adjust
it to "^7.0.1" if "^7.1.4" is not published. Ensure all dependency versions
match the latest stable releases on npm before updating package.json.
| private async convertFileToBase64(fileUri: string): Promise<string> { | ||
| try { | ||
| // Read the file content using Filesystem API | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused ESLint directives are like unnecessary action sequences in my movies!
The pipeline is complaining about unused ESLint disable directives. These safety measures aren't needed here.
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
const result = await Filesystem.readFile({
path: fileUri,
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
encoding: Encoding.UTF8,
});
// file.data will be base64 string
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return 'data:image/jpeg;base64,' + result.data;Also applies to: 36-36, 41-41
🧰 Tools
🪛 GitHub Actions: Lint
[warning] 33-33: ESLint warning: Unused eslint-disable directive (no problems were reported from '@typescript-eslint/no-unsafe-assignment', '@typescript-eslint/no-unsafe-call', or '@typescript-eslint/no-unsafe-member-access').
🤖 Prompt for AI Agents
In src/app/core/services/mlkit-document-scanner.service.ts at lines 33, 36, and
41, remove the unused ESLint disable directives as they are unnecessary and
cause warnings. Simply delete the comments that disable ESLint rules on these
lines to clean up the code.
Clickup
https://app.clickup.com/
Code Coverage
Please add code coverage here
UI Preview
Please add screenshots for UI changes
Summary by CodeRabbit
New Features
Refactor
Chores