Skip to content
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

fix: QA fixes #1078

Merged
merged 6 commits into from
Nov 25, 2024
Merged

Conversation

DhaaraniCIT
Copy link
Contributor

@DhaaraniCIT DhaaraniCIT commented Nov 19, 2024

Description

fix: QA fixes

Clickup

https://app.clickup.com/t/86cwzceku

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new method to retrieve connector settings for enhanced configuration.
    • Added a checkbox button for marking tasks as done in the onboarding process.
    • Enhanced footer components to accept application names for better context.
    • Updated onboarding components to dynamically include branding information and improved navigation options.
    • Added a new help article link related to skipping exports.
  • Bug Fixes

    • Improved loading state management during connection processes.
  • Style

    • Updated visual styling across various components, including padding and border radius adjustments for a more consistent look.
    • Adjusted layout and spacing for onboarding steps and configuration sections.
    • Enhanced clarity of labels and placeholders in forms for better user experience.
  • Documentation

    • Enhanced user interaction with updated event handlers and improved semantic structure in HTML templates.

Copy link
Contributor

coderabbitai bot commented Nov 19, 2024

Walkthrough

The pull request introduces several changes across multiple components related to the QBD integration. Key modifications include the addition of a new method getQBDConnectorSettings() in the QbdDirectConnectorService, updates to various component HTML templates to enhance styling and layout, and the introduction of new properties and methods in several components to improve state management and functionality. Additionally, adjustments in the SCSS files focus on refining visual aspects. Overall, the changes enhance the onboarding experience and component interactions for QBD integration.

Changes

File Change Summary
src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts Added method getQBDConnectorSettings() to retrieve connector settings via API. Existing method postQbdDirectConntion() remains unchanged.
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.html Updated layout with new class !tw-rounded-border-radius-2xs and adjusted padding for inner <div> elements.
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts Added property isConnectionLoading and updated methods to manage loading state and onboarding state more effectively.
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html Adjusted padding and layout for onboarding steps, added dynamic class binding for step items, and included new property binding for AppName.
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.ts Added properties appName and qbdPreRequisiteState for better application context and state management.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html Modified layout and class attributes, added property binding for AppName.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.ts Introduced property appName and removed assignment of this.fieldLength in ngOnInit().
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html Updated styling and layout, changed icon for completed step, and added property binding for AppName.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.scss Adjusted border radius properties for various elements.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.ts Added property appName for application context.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html Updated layout and added checkbox for marking tasks as done, included property binding for AppName.
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.ts Added property appName for application context.
src/app/integrations/qbd-direct/qbd-direct.component.ts Modified storeWorkspaceAndNavigate method to update the logic for importing attributes.
src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html Updated conditional rendering based on appName and modified link to help article.
src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts Introduced WindowService dependency and added redirect() method for navigation.
src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.html Simplified class application and adjusted icon visibility logic based on AppName.
src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.ts Added new input property AppName and initialized class-level variable appName.
src/app/shared/components/input/checkbox-button/checkbox-button.component.html Changed class names and updated event handling for checkbox clicks.
src/app/shared/components/input/checkbox-button/checkbox-button.component.scss Modified styles for checkbox button, including border radius and hover states.
src/app/shared/components/input/checkbox-button/checkbox-button.component.ts Added FormsModule to imports and simplified checkbox click handling logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QbdDirectConnectorService
    participant API
    participant QbdDirectOnboardingConnectorComponent

    User->>QbdDirectOnboardingConnectorComponent: Initiate onboarding
    QbdDirectOnboardingConnectorComponent->>QbdDirectConnectorService: Call getQBDConnectorSettings()
    QbdDirectConnectorService->>API: GET /workspaces/{workspaceId}/connector_settings/
    API-->>QbdDirectConnectorService: Return connector settings
    QbdDirectConnectorService-->>QbdDirectOnboardingConnectorComponent: Provide settings
    QbdDirectOnboardingConnectorComponent-->>User: Display onboarding steps
Loading

Possibly related PRs

Suggested labels

size/M

Suggested reviewers

  • ashwin1111

Poem

In the meadow where rabbits play,
Changes hop in a lively way.
New methods and styles, oh what a sight,
QBD onboarding, shining bright!
With each click and every glance,
A smoother path, a joyful dance! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the size/M Medium PR label Nov 19, 2024
@DhaaraniCIT DhaaraniCIT added the deploy Triggers deployment of active branch to Staging label Nov 19, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🧹 Outside diff range and nitpick comments (28)
src/app/shared/components/input/checkbox-button/checkbox-button.component.ts (1)

29-31: LGTM: Simplified checkbox state management

The refactored implementation is more idiomatic Angular, directly managing state through the component property rather than reading from the DOM event.

Consider adding type safety by explicitly typing the method:

- onCheckBoxClick() {
+ onCheckBoxClick(): void {
src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts (1)

22-22: Remove unnecessary empty object parameter

The empty object parameter in the get() method call is unnecessary as it's not being used.

Apply this diff to simplify the code:

-    return this.apiService.get(`/workspaces/${this.workspaceService.getWorkspaceId()}/connector_settings/`, {});
+    return this.apiService.get(`/workspaces/${this.workspaceService.getWorkspaceId()}/connector_settings/`);
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.ts (2)

26-26: Add type annotation to the appName property.

For better type safety and code clarity, consider adding the TypeScript type annotation.

- appName = AppName;
+ appName: typeof AppName = AppName;

Remove unused property and empty lifecycle hook

The fieldLength property is only declared but never used throughout the component or its template. The empty ngOnInit lifecycle hook serves no purpose.

Remove both:

- fieldLength: number;
- ngOnInit() {
- }
🔗 Analysis chain

Line range hint 35-36: Critical: Address uninitialized fieldLength property and empty lifecycle hook.

  1. The fieldLength property is declared but never initialized after removing the initialization from ngOnInit. This could lead to undefined behavior.
  2. If ngOnInit is not needed, consider removing it as per Angular best practices.

Let's verify if fieldLength is used in the template:

Consider one of these solutions:

# Solution 1: If fieldLength is needed, initialize it
ngOnInit() {
+  this.fieldLength = this.qbdFields?.length;
}

# Solution 2: If fieldLength is not used, remove it
- fieldLength: number;
- ngOnInit() {
- }
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for fieldLength usage in the component's template
rg "fieldLength" src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html

Length of output: 123


Script:

#!/bin/bash
# Let's check if fieldLength is used anywhere in the component file or its template
rg "fieldLength" src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/

# Let's also check the component class implementation to see the property declaration
ast-grep --pattern 'class QbdDirectDataSyncComponent {
  $$$
}'

Length of output: 282

src/app/shared/components/input/checkbox-button/checkbox-button.component.scss (2)

10-10: Consider reducing reliance on !important declarations

While the styling is consistent with the design system, the use of !important flags might indicate specificity issues with PrimeNG's .p-button class. Consider increasing selector specificity or reviewing the component's style encapsulation strategy.

Alternative approach:

:host {
  ::ng-deep {
    .p-button.your-custom-class {
      @apply tw-h-40-px tw-text-text-secondary tw-bg-btn-outline-secondary-bg tw-rounded-border-radius-2xs tw-border tw-border-btn-outline-secondary-border-color;
    }
  }
}

Line range hint 17-33: LGTM! Consider optimizing hover state transitions

The checkbox implementation follows best practices with proper state management and consistent design tokens. The custom styling with SVG icon provides a clean, modern appearance.

Consider adding smooth transitions for hover states:

input[type="checkbox"] {
  @apply tw-relative tw-w-16-px tw-h-16-px tw-appearance-none tw-bg-white tw-border tw-border-checkbox-icon-color tw-mr-10-px tw-rounded-sm tw-cursor-pointer tw-transition-colors tw-duration-200 #{!important};
}
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.ts (1)

38-39: Consider adding type annotation for better type safety.

While the property initialization is correct, adding explicit type annotation would improve code maintainability and type safety.

-  appName = AppName;
+  appName: typeof AppName = AppName;
src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts (1)

Line range hint 13-31: Consider splitting configuration dialogs by app type

The component accepts multiple inputs and handles different app types (QBD, Sage Intacct, etc.) which could lead to maintenance challenges. Consider:

  1. Creating specialized dialog components for each app type
  2. Using a factory pattern to instantiate the appropriate dialog
  3. Moving URL construction logic to a dedicated service

This would improve maintainability and reduce the risk of cross-app issues like the hardcoded Sage Intacct URL.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.ts (2)

Line range hint 56-73: Improve clipboard functionality implementation

The current clipboard implementation has several issues:

  1. Uses deprecated document.execCommand('copy')
  2. Creates and manipulates DOM elements directly
  3. Missing event parameter declaration
  4. Potential security concerns with password handling

Consider using the modern Clipboard API:

- onClipboardCopy() {
-   const selBox = document.createElement('textarea');
-   selBox.value = this.password;
-   document.body.appendChild(selBox);
-   selBox.select();
-   selBox.click();
-   document.execCommand('copy');
+ onClipboardCopy(event?: Event) {
+   navigator.clipboard.writeText(this.password).then(() => {
+     this.messageService.add({
+       severity: 'success',
+       summary: 'Password copied to clipboard'
+     });
+   }).catch(() => {
+     this.messageService.add({
+       severity: 'error',
+       summary: 'Failed to copy password'
+     });
+   });

-   this.messageService.add({
-     severity: 'success',
-     summary: 'Password copied to clipboard'
-   });

-   document.body.removeChild(selBox);
    event?.stopPropagation();
  }

Remove hardcoded password value for security

The hardcoded password '098765' appears to be the only instance in the codebase. Since this is a required @Input() property in an Angular component, there's no need for a default value as it should be provided by the parent component.

  • Remove the hardcoded default value from src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.ts
🔗 Analysis chain

Line range hint 19-19: Consider security implications of hardcoded password

The default password value is hardcoded. While this might be for testing purposes, it's recommended to avoid hardcoding passwords, even default ones.

Remove the hardcoded default value:

- @Input({required: true}) password: string = '098765';
+ @Input({required: true}) password: string;
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of hardcoded passwords
rg -g '*.ts' -g '*.js' "password.*=.*['\"][0-9a-zA-Z]+['\"]"

Length of output: 241

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (1)

17-18: Consider accessibility implications of opacity changes

While the opacity change provides good visual feedback for completed steps, ensure it maintains sufficient contrast for accessibility. Consider:

  1. Testing with screen readers to verify state changes are announced
  2. Adding ARIA attributes to improve accessibility
-    <div class="tw-flex tw-items-center tw-justify-between tw-py-16-px">
-        <div class="tw-flex tw-items-center tw-justify-center" [ngClass]="[step.state === qbdPreRequisiteState.COMPLETE ? 'tw-opacity-60' : 'tw-opacity-100']">
+    <div class="tw-flex tw-items-center tw-justify-between tw-py-16-px" role="listitem">
+        <div class="tw-flex tw-items-center tw-justify-center" 
+             [ngClass]="[step.state === qbdPreRequisiteState.COMPLETE ? 'tw-opacity-60' : 'tw-opacity-100']"
+             [attr.aria-completed]="step.state === qbdPreRequisiteState.COMPLETE">
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html (2)

21-22: Consider adding ARIA attributes for accessibility

The rotating sync icon should have appropriate ARIA attributes to indicate its loading state to screen readers.

-            <div class="spin-icon tw-text-text-tertiary tw-font-400 tw-text-14-px">
-                <app-svg-icon *ngIf="field.count === null" [svgSource]="'arrow-rotate-sync'" [width]="'14px'" [height]="'14px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-tertiary'"></app-svg-icon>
+            <div class="spin-icon tw-text-text-tertiary tw-font-400 tw-text-14-px" role="status" aria-label="Loading data">
+                <app-svg-icon *ngIf="field.count === null" [svgSource]="'arrow-rotate-sync'" [width]="'14px'" [height]="'14px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-tertiary'" aria-hidden="true"></app-svg-icon>

Line range hint 31-33: Consider improving the loading state implementation

  1. The hardcoded height of 400px might not be responsive on different screen sizes
  2. The loading text could be more descriptive about what's being loaded
-<div *ngIf="isLoading && showSection" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px]">
+<div *ngIf="isLoading && showSection" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-min-h-[200px] tw-h-full">
     <app-loader styleClass="spinner-30 tw-top-2-px"></app-loader>
-    <span class="tw-text-14-px tw-font-400 tw-text-text-primary">Loading</span>
+    <span class="tw-text-14-px tw-font-400 tw-text-text-primary">Loading QuickBooks Desktop data...</span>
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.html (2)

15-16: Consider adding visual separators between steps

While the consistent padding (tw-py-8-px) improves content density, consider adding subtle visual separators (e.g., tw-border-b) between steps to maintain clear visual hierarchy and improve step distinction.

Example modification:

-            <div class="tw-pt-24-px tw-pb-8-px">
+            <div class="tw-pt-24-px tw-pb-8-px tw-border-b tw-border-border-tertiary">

Also applies to: 27-27, 38-38


Line range hint 1-60: Enhance template accessibility

Consider adding ARIA attributes to improve accessibility:

  • Add role="progressbar" to the stepper component
  • Include aria-label attributes for interactive elements
  • Add aria-live regions for dynamic content updates

Example improvements:

-    <app-onboarding-steppers [onboardingSteps]="onboardingSteps"></app-onboarding-steppers>
+    <app-onboarding-steppers [onboardingSteps]="onboardingSteps" role="progressbar" aria-label="Onboarding progress"></app-onboarding-steppers>

-    <div *ngIf="isLoading" class="tw-flex tw-justify-center tw-items-center tw-pt-80-px">
+    <div *ngIf="isLoading" class="tw-flex tw-justify-center tw-items-center tw-pt-80-px" aria-live="polite">
src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html (2)

30-32: Consider moving the help article URL to configuration

The hardcoded help article URL should be managed through configuration:

  1. Move the URL to a configuration file or environment variable
  2. Update the template to use the configured URL:
-                        <p class="tw-text-size-10 tw-text-text-disable tw-font-400">
-                            https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector
-                        </p>
+                        <p class="tw-text-size-10 tw-text-text-disable tw-font-400">
+                            {{helpArticleUrl}}
+                        </p>

23-35: Consider using a semantic button element

For better semantics and accessibility, consider using a button element instead of a div:

-            <div *ngIf="appName===AppName.QBD_DIRECT" class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" (click)="redirect()">
+            <button *ngIf="appName===AppName.QBD_DIRECT" 
+                    type="button"
+                    class="tw-w-full tw-text-left tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" 
+                    (click)="redirect()">
                 <p class="tw-text-12-px tw-font-500 tw-text-text-primary">Common QuickBooks Web Connector errors and solutions</p>
                 <div class="tw-flex tw-items-center tw-justify-start">
                     <div class="tw-pr-10-px">
                         <img [src]="brandIcon" width="12px" height="12px">
                     </div>
                     <div>
                         <p class="tw-text-size-10 tw-text-text-disable tw-font-400">{{helpArticleUrl}}</p>
                     </div>
                 </div>
-            </div>
+            </button>
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.ts (2)

Line range hint 44-60: Consider moving URLs to configuration

The URLs in preRequisitesteps are hardcoded and appear to be placeholder values. Consider moving these to the branding configuration for better maintainability and easier updates.

  preRequisitesteps: QBDPrerequisiteObject[] = [
    {
      id: 1,
      label: 'Install QuickBooks Web Connector',
      caption: 'Download and install the QuickBooks Web Connector on the system where QuickBooks Desktop is installed.',
-     externalLink: 'https://qbd.com',
+     externalLink: brandingKbArticles.onboardingArticles.QBD.WEB_CONNECTOR,
      iconName: 'download-medium',
      state: QBDPreRequisiteState.INCOMPLETE
    },
    // ... similar change for the second step
  ];

Line range hint 70-75: Guard against array index out of bounds

The array index calculation status.id-1 could potentially cause an out-of-bounds error if status.id is 0 or negative. Consider adding bounds checking.

  updateConnectorStatus(status: CheckBoxUpdate): void {
+   if (status.id < 1 || status.id > this.preRequisitesteps.length) {
+     console.error('Invalid prerequisite step ID:', status.id);
+     return;
+   }
    this.preRequisitesteps[status.id-1].state = status.value ? QBDPreRequisiteState.COMPLETE : QBDPreRequisiteState.INCOMPLETE;
    if (this.preRequisitesteps[0].state === QBDPreRequisiteState.COMPLETE && this.preRequisitesteps[1].state === QBDPreRequisiteState.COMPLETE) {
      this.isContinueDisabled = false;
    }
  }
src/app/integrations/qbd-direct/qbd-direct.component.ts (3)

Line range hint 15-24: Implement OnDestroy for proper cleanup

The component should implement OnDestroy to properly clean up subscriptions and prevent memory leaks.

-export class QbdDirectComponent implements OnInit {
+export class QbdDirectComponent implements OnInit, OnDestroy {
+  private destroy$: Subject<void> = new Subject<void>();
+
   user: MinimalUser = this.userService.getUserProfile();
   workspace: QbdDirectWorkspace;
   isLoading: boolean = true;
   windowReference: Window;
+
+  ngOnDestroy(): void {
+    this.destroy$.next();
+    this.destroy$.complete();
+  }

Then update service subscriptions to use takeUntil:

this.workspaceService.getWorkspace(this.user.org_id)
  .pipe(takeUntil(this.destroy$))
  .subscribe(...)

Don't forget to import:

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { OnDestroy } from '@angular/core';

Line range hint 74-86: Improve error handling in workspace setup

The workspace setup logic lacks proper error handling and could benefit from better type safety.

 private setupWorkspace(): void {
   this.helperService.setBaseApiURL(AppUrl.QBD_DIRECT);
   this.workspaceService.getWorkspace(this.user.org_id)
+    .pipe(
+      catchError((error) => {
+        console.error('Failed to fetch workspace:', error);
+        this.isLoading = false;
+        // Handle error appropriately (e.g., show error message)
+        return EMPTY;
+      })
+    )
     .subscribe((workspaces: QbdDirectWorkspace[]) => {
       if (workspaces.length) {
         this.storeWorkspaceAndNavigate(workspaces[0]);
       } else {
         this.workspaceService.postWorkspace()
+          .pipe(
+            catchError((error) => {
+              console.error('Failed to create workspace:', error);
+              this.isLoading = false;
+              // Handle error appropriately
+              return EMPTY;
+            })
+          )
           .subscribe((workspace: QbdDirectWorkspace) => {
             this.storeWorkspaceAndNavigate(workspace);
           });
       }
     });
 }

Line range hint 42-63: Refactor navigation logic for better maintainability

The current navigation logic uses a hardcoded path check and a large state-to-route mapping object directly in the method.

Consider extracting the route mapping to a constant and using route constants:

// Create a separate constants file or add to existing one
export const QBD_DIRECT_ROUTES = {
  [QbdDirectOnboardingState.YET_TO_START]: AppRoutes.QBD_DIRECT_LANDING,
  [QbdDirectOnboardingState.CONFIRM_PRE_REQUISITES]: AppRoutes.QBD_DIRECT_PREREQ,
  // ... other mappings
} as const;

// In the component
private navigate(): void {
  if (!this.router.url.startsWith('/integrations/qbd_direct')) {
    return;
  }

  const targetRoute = QBD_DIRECT_ROUTES[this.workspace.onboarding_state];
  if (targetRoute) {
    this.router.navigateByUrl(targetRoute);
  } else {
    console.warn(`No route mapping for state: ${this.workspace.onboarding_state}`);
  }
}
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2)

20-21: Consider enhancing the path format guidance

The description could be more specific about the expected path format to help users avoid errors.

Consider updating the description to include:

-<p class="tw-text-12-px tw-font-400 tw-text-text-muted tw-text-wrap">Enter the file path of your company to generate the integration file. Watch the video for guidance on locating company file path.</p>
+<p class="tw-text-12-px tw-font-400 tw-text-text-muted tw-text-wrap">Enter the complete Windows file path to your QuickBooks company file (e.g., C:\Users\YourName\Documents\QuickBooks\CompanyFile.qbw). Watch the video for guidance on locating the file.</p>

Line range hint 46-47: Consider moving the YouTube URL to component properties

Hardcoding the YouTube URL in the template makes it difficult to update. Consider moving it to the component class.

-<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
+<iframe width="427" height="259" [src]="tutorialVideoUrl | safe" frameborder="0"></iframe>

Add to your component class:

public tutorialVideoUrl = 'https://www.youtube.com/embed/2oYdc8KcQnk';
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (2)

Line range hint 78-80: Enhance iframe security and accessibility

The YouTube video iframe should include additional attributes for better security, accessibility, and performance.

Apply these improvements to the iframe:

-<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
+<iframe
+    width="427"
+    height="259"
+    src="https://www.youtube.com/embed/2oYdc8KcQnk"
+    title="QuickBooks Web Connector Setup Guide"
+    loading="lazy"
+    sandbox="allow-scripts allow-same-origin allow-presentation"
+    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+></iframe>

Line range hint 89-98: Optimize conditional rendering

The condition !isStepCompleted is redundantly checked multiple times.

Consider simplifying the conditions:

-<div *ngIf="!isLoading && !isStepCompleted && connectionStatus === qbdConnectionStatus.SUCCESS && showSection && !isStepCompleted"
+<div *ngIf="!isLoading && connectionStatus === qbdConnectionStatus.SUCCESS && showSection && !isStepCompleted"
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (2)

Line range hint 125-137: Improve error handling in connection polling

The error handling in the polling mechanism needs improvement:

  1. Loading state isn't reset on error
  2. Error is only logged to console without user feedback

Apply this diff to enhance error handling:

 onConnectionDone(event: CheckBoxUpdate) {
   this.isConnectionLoading = true;
   if (event.value) {
     interval(3000).pipe(
       switchMap(() => this.workspaceService.getWorkspace(this.user.org_id)),
       takeWhile((status: any) => !this.isTerminalStatus(status[0].onboarding_state as QbdDirectOnboardingState), true)
     )
     .subscribe(
       (status) => this.handleStatus(status[0]),
-      (error) => console.error('Error polling workspace status:', error)
+      (error) => {
+        console.error('Error polling workspace status:', error);
+        this.isConnectionLoading = false;
+        this.toastService.displayToastMessage(ToastSeverity.ERROR, 'Failed to establish connection. Please try again.');
+      }
     );
   }
 }

155-166: Simplify state handling logic

The state handling logic can be simplified using a switch statement for better readability and maintainability.

Consider this refactor:

 handleStatus(status: QbdDirectWorkspace): void {
   const onboardingState = status.onboarding_state;
-  if (onboardingState === QbdDirectOnboardingState.INCORRECT_COMPANY_PATH) {
-    this.connectionStatus = QBDConnectionStatus.INCORRECT_COMPANY_PATH;
-    this.warningDialogText = 'Incorrect company file path detected. Please check and try again.';
-    this.isDialogVisible = true;
-    this.isConnectionLoading = false;
-  } else if (onboardingState === QbdDirectOnboardingState.INCORRECT_PASSWORD) {
-    this.connectionStatus = QBDConnectionStatus.IN_CORRECT_PASSWORD;
-    this.warningDialogText = 'Incorrect password detected. Please check and try again.';
-    this.isDialogVisible = true;
-    this.isConnectionLoading = false;
-  } else if (onboardingState === QbdDirectOnboardingState.DESTINATION_SYNC_IN_PROGRESS || onboardingState === QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE) {
-    this.connectionStatus = QBDConnectionStatus.SUCCESS;
-    this.isConnectionCTAEnabled = true;
-    this.isConnectionLoading = false;
-  }
+  switch (onboardingState) {
+    case QbdDirectOnboardingState.INCORRECT_COMPANY_PATH:
+      this.connectionStatus = QBDConnectionStatus.INCORRECT_COMPANY_PATH;
+      this.warningDialogText = 'Incorrect company file path detected. Please check and try again.';
+      break;
+    case QbdDirectOnboardingState.INCORRECT_PASSWORD:
+      this.connectionStatus = QBDConnectionStatus.IN_CORRECT_PASSWORD;
+      this.warningDialogText = 'Incorrect password detected. Please check and try again.';
+      break;
+    case QbdDirectOnboardingState.DESTINATION_SYNC_IN_PROGRESS:
+    case QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE:
+      this.connectionStatus = QBDConnectionStatus.SUCCESS;
+      this.isConnectionCTAEnabled = true;
+      break;
+  }
+  this.isDialogVisible = this.connectionStatus !== QBDConnectionStatus.SUCCESS;
+  this.isConnectionLoading = false;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6f3c5f4 and 77b39c7.

⛔ Files ignored due to path filters (2)
  • src/assets/icons/check-small.svg is excluded by !**/*.svg
  • src/assets/sprites/sprite.svg is excluded by !**/*.svg
📒 Files selected for processing (20)
  • src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.html (3 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (4 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.ts (3 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.ts (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (3 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.scss (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.ts (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (5 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.ts (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct.component.ts (1 hunks)
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html (1 hunks)
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts (2 hunks)
  • src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.html (2 hunks)
  • src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.ts (2 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.html (1 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss (1 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.scss
🔇 Additional comments (23)
src/app/shared/components/input/checkbox-button/checkbox-button.component.ts (1)

3-3: LGTM: FormsModule addition aligns with template changes

The addition of FormsModule is appropriate for supporting two-way binding with ngModel in the template.

Also applies to: 11-11

src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts (1)

21-23: Verify method name usage across the codebase

Since this method is used in the onboarding component, ensure the method name change is applied consistently.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.ts (1)

3-3: LGTM! Import statement is correctly added.

src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.ts (2)

3-3: LGTM!

The import statement is correctly placed and properly imports the required enum.


28-28: LGTM!

The class variable follows proper naming conventions and is correctly initialized with the AppName enum.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.ts (1)

5-5: LGTM!

Clean import statement following Angular best practices.

src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts (2)

5-5: LGTM: WindowService import follows Angular conventions


40-42: LGTM: Constructor injection follows Angular DI pattern

src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.html (2)

1-1: LGTM: Simplified border styling logic

The simplified approach of always applying the border classes improves code maintainability while preserving the conditional justification logic.


24-24: Verify the arrow icon visibility change

The condition for showing the right arrow icon has been changed from checking ctaText to checking AppName. While this aligns with QBD-specific requirements, let's verify this change is consistent with the intended UX across different application types.

✅ Verification successful

Let me gather more information about the specific component and its usage to better understand the context of this change.


Based on the gathered information, I can now provide the final response:

Arrow icon visibility change is consistent with the component's design

The change from ctaText to AppName condition for the right arrow icon is correct and intentional. The component already handles QBD-specific UI customizations, and the arrow icon's visibility is part of a broader pattern where:

  • The component uses brandingFeatureConfig.isIconsInsideButtonAllowed as the primary control for all icons
  • QBD Direct specifically requires a simpler UI without directional arrows
  • The left arrow (Back button) and loading spinner follow the same branding configuration pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar icon visibility patterns in other templates
# and verify consistency in QBD-specific UI handling

# Look for other instances where arrow icons are conditionally shown based on app name
rg -l "AppName\s*!==\s*appName\.QBD_DIRECT" --type html

# Check for other QBD-specific UI customizations
rg -l "appName\.QBD_DIRECT" --type html

# Look for similar footer components to verify consistency
fd -e html -e ts "footer.component"

Length of output: 1137


Script:

#!/bin/bash
# Check the component's implementation and usage
cat src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.ts

# Look for previous implementations or changes to understand the context
rg -g "!*.spec.ts" "ctaText" src/app/shared/components/configuration/configuration-step-footer/

# Check for any QBD-specific styling or layout patterns
cat src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.html

Length of output: 4541

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.ts (1)

5-5: LGTM! Clean addition of AppName enum

The import and property addition are well-organized and follow Angular best practices.

Also applies to: 41-42

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2)

15-15: LGTM: Improved vertical spacing

The padding adjustment enhances content readability and visual hierarchy.


22-22: LGTM: Improved icon-text spacing

The increased margin provides better visual separation between the icon and text content.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html (2)

1-1: LGTM! Styling improvements enhance visual consistency

The changes to border radius and margin spacing improve the overall layout and visual hierarchy.

Also applies to: 5-5


37-37: Verify consistent AppName usage across components

The addition of [AppName]="appName.QBD_DIRECT" suggests a standardization of app type handling.

✅ Verification successful

AppName property usage is consistent across QBD Direct components

The verification shows consistent usage of [AppName]="appName.QBD_DIRECT" across QBD Direct components:

  • All QBD Direct components correctly use the AppName property with the QBD_DIRECT enum value
  • The AppName enum is properly defined and referenced in the codebase
  • The property is used consistently for conditional rendering and component configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent AppName usage across components

# Search for AppName property usage
rg -t html "AppName.*QBD_DIRECT" --no-heading

# Search for appName enum/constant definition
rg "QBD_DIRECT" -t ts --no-heading

Length of output: 10752

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.html (1)

7-7: LGTM: Brand-aware styling improvements

The conditional styling based on brand ID enhances visual consistency across different branded versions of the application.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.ts (1)

8-8: LGTM! Clean and consistent changes.

The new imports and properties are well-structured and follow Angular best practices.

Also applies to: 41-41, 62-62

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (3)

1-1: LGTM! Design system improvements

The styling updates to border radius, margins, and icon sizes create a more refined and consistent look.

Also applies to: 5-5, 14-14


38-41: LGTM! Improved vertical spacing

The increased padding creates better visual separation between the input field and action button.


70-70: Verify footer component handles AppName property

The addition of [AppName]="appName.QBD_DIRECT" suggests standardization across different integration types.

✅ Verification successful

Let me gather more information about the footer component implementation since the previous script didn't find the actual component class definition.


AppName property is properly implemented in the footer component

The ConfigurationStepFooterComponent correctly implements the AppName as an @input property and imports the AppName enum from the core models. The property is consistently used across multiple QBD Direct integration components as shown in the earlier results.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the footer component properly handles the AppName property
# and if it's consistently used across other integration types

# Check footer component implementation
ast-grep --pattern 'class ConfigurationStepFooterComponent {
  $$$
  @Input() AppName: $_;
  $$$
}'

# Check usage in other integration components
rg -l "app-configuration-step-footer.*\[AppName\]"

Length of output: 638


Script:

#!/bin/bash
# Search for the configuration step footer component file
fd "configuration-step-footer.component.ts"

# Once found, let's examine its contents and implementation
rg -A 5 "@Input\(\)" --type ts "configuration-step-footer.component.ts"

# Also check for any interfaces or types defining the AppName property
rg "AppName" --type ts "configuration-step-footer.component.ts"

Length of output: 440


Script:

#!/bin/bash
# Now that we have the correct path, let's examine the component implementation
cat src/app/shared/components/configuration/configuration-step-footer/configuration-step-footer.component.ts

# Also check for any interfaces or types that might be related
rg -g "*.ts" "interface.*AppName|type.*AppName" src/app/shared/components/configuration/

Length of output: 1367

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (2)

1-1: LGTM: Styling improvements enhance visual consistency

The changes to border radius, margins, and icon size create better visual harmony and follow the design system more consistently.

Also applies to: 5-5, 14-14


99-99: LGTM: Footer component properly configured

The configuration-step-footer component is correctly implemented with the new AppName property and proper button state management.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (1)

Line range hint 220-225: LGTM! Clear implementation with good user feedback

The implementation correctly updates the onboarding state and provides appropriate user feedback through the toast message.

@@ -1,10 +1,8 @@
<div [ngClass]="isCheckboxSelected ? 'checked-text' : 'unchecked-text'">
<div [ngClass]="isCheckboxSelected ? 'checkedText' : 'unCheckedText'" (click)="onCheckBoxClick()">
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider following HTML/CSS naming conventions and improving click handling

  1. HTML/CSS class names conventionally use kebab-case rather than camelCase:
    • checkedTextchecked-text
    • unCheckedTextunchecked-text
  2. The click handler on the container div might interfere with the checkbox's native click handling.
-<div [ngClass]="isCheckboxSelected ? 'checkedText' : 'unCheckedText'" (click)="onCheckBoxClick()">
+<div [ngClass]="isCheckboxSelected ? 'checked-text' : 'unchecked-text'">
📝 Committable suggestion

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

Suggested change
<div [ngClass]="isCheckboxSelected ? 'checkedText' : 'unCheckedText'" (click)="onCheckBoxClick()">
<div [ngClass]="isCheckboxSelected ? 'checked-text' : 'unchecked-text'">

Comment on lines +4 to 5
<input type="checkbox" [(ngModel)]="isCheckboxSelected"/>
{{ isCheckboxSelected ? checkedText : unCheckedText}}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility with proper labeling

The checkbox lacks an explicit label and proper ARIA attributes, which impacts accessibility.

-                <input type="checkbox" [(ngModel)]="isCheckboxSelected"/>
-                {{ isCheckboxSelected ? checkedText : unCheckedText}}
+                <input 
+                    type="checkbox" 
+                    [(ngModel)]="isCheckboxSelected"
+                    [attr.aria-label]="isCheckboxSelected ? checkedText : unCheckedText"
+                    id="checkbox-button"/>
+                <label for="checkbox-button">{{ isCheckboxSelected ? checkedText : unCheckedText}}</label>
📝 Committable suggestion

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

Suggested change
<input type="checkbox" [(ngModel)]="isCheckboxSelected"/>
{{ isCheckboxSelected ? checkedText : unCheckedText}}
<input
type="checkbox"
[(ngModel)]="isCheckboxSelected"
[attr.aria-label]="isCheckboxSelected ? checkedText : unCheckedText"
id="checkbox-button"/>
<label for="checkbox-button">{{ isCheckboxSelected ? checkedText : unCheckedText}}</label>

@@ -18,6 +18,10 @@ export class QbdDirectConnectorService {
return this.apiService.post(`/workspaces/${this.workspaceService.getWorkspaceId()}/connector_settings/`, payload);
}

getQbdDirectConntion(): Observable<QbdConnectorGet> {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in method name

The method name contains a typo: getQbdDirectConntion should be getQbdDirectConnection.

Apply this diff to fix the typo:

-  getQbdDirectConntion(): Observable<QbdConnectorGet> {
+  getQbdDirectConnection(): Observable<QbdConnectorGet> {
📝 Committable suggestion

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

Suggested change
getQbdDirectConntion(): Observable<QbdConnectorGet> {
getQbdDirectConnection(): Observable<QbdConnectorGet> {

@@ -16,12 +17,16 @@ export class ConfigurationStepFooterComponent implements OnInit {

@Input() showResetButton: boolean;

@Input() AppName: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Follow Angular naming conventions for Input properties

The AppName input property uses PascalCase, which violates Angular's style guide. Input properties should use camelCase naming convention.

Apply this change:

- @Input() AppName: string;
+ @Input() appName: string;

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.

Suggested change
@Input() AppName: string;
@Input() appName: string;

Comment on lines 48 to 50
redirect() {
this.windowService.openInNewTab(`${brandingConfig.helpArticleDomain}/en/articles/8394683-how-to-configure-the-fyle-sage-intacct-integration#h_38e0c9bea6`);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Critical: Incorrect implementation of redirect method

The review comment is correct. The component has several issues with the redirect implementation:

  1. The hardcoded URL ignores the redirectLink input property that's already defined in the component
  2. The URL points to Sage Intacct documentation while the method is specifically used in QBD_DIRECT context (as seen in the template's *ngIf condition)
  3. The template shows a different URL (QuickBooks Web Connector article) than what's being used in the code
- redirect() {
-   this.windowService.openInNewTab(`${brandingConfig.helpArticleDomain}/en/articles/8394683-how-to-configure-the-fyle-sage-intacct-integration#h_38e0c9bea6`);
- }
+ redirect() {
+   try {
+     this.windowService.openInNewTab(this.redirectLink);
+   } catch (error) {
+     console.error('Failed to open help article:', error);
+   }
+ }
🔗 Analysis chain

Critical: Incorrect help article URL and implementation issues

The redirect method has several issues:

  1. The hardcoded URL points to a Sage Intacct help article (#8394683) while this component is being used for QBD integration
  2. The method lacks error handling for the WindowService operation
  3. The method name is too generic and doesn't indicate its specific purpose

Consider applying these improvements:

- redirect() {
-   this.windowService.openInNewTab(`${brandingConfig.helpArticleDomain}/en/articles/8394683-how-to-configure-the-fyle-sage-intacct-integration#h_38e0c9bea6`);
- }
+ openQbdHelpArticle() {
+   try {
+     const qbdHelpUrl = `${brandingConfig.helpArticleDomain}/en/articles/${this.redirectLink}`;
+     this.windowService.openInNewTab(qbdHelpUrl);
+   } catch (error) {
+     console.error('Failed to open help article:', error);
+   }
+ }

Let's verify the correct help article URL:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for QBD-related help article references in the codebase
rg -l "articles.*qbd" --type ts

Length of output: 33


Script:

#!/bin/bash
# Let's first check the component's context and related files
fd configuration-confirmation-dialog

# Then search for any help article URLs in the codebase
rg "helpArticleDomain.*articles" --type ts -A 2

# Also check for any redirectLink references
rg "redirectLink" --type ts -A 2

Length of output: 38849


Script:

#!/bin/bash
# Let's check the component's template to understand how redirectLink is used
cat src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html

# Also check the component's class to understand its context
cat src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts

Length of output: 5024

Comment on lines 23 to 35
<div *ngIf="appName===AppName.QBD_DIRECT" class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" (click)="redirect()">
<p class="tw-text-12-px tw-font-500 tw-text-text-primary">Common QuickBooks Web Connector errors and solutions</p>
<div class="tw-flex tw-items-center tw-justify-start">
<div class="tw-pr-10-px">
<img [src]="brandIcon" width="12px" height="12px">
</div>
<div>
<a class="tw-text-size-10 tw-text-text-disable tw-font-400" href="https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector-errors-and">
<p class="tw-text-size-10 tw-text-text-disable tw-font-400">
https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector
</a>
</p>
</div>
</div>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility and user experience of the clickable container

The clickable div should be made more accessible and user-friendly:

-            <div *ngIf="appName===AppName.QBD_DIRECT" class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" (click)="redirect()">
+            <div *ngIf="appName===AppName.QBD_DIRECT" 
+                 class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" 
+                 (click)="redirect()"
+                 (keydown.enter)="redirect()"
+                 role="button"
+                 tabindex="0"
+                 [attr.aria-label]="'View QuickBooks Web Connector errors and solutions'">
📝 Committable suggestion

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

Suggested change
<div *ngIf="appName===AppName.QBD_DIRECT" class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer" (click)="redirect()">
<p class="tw-text-12-px tw-font-500 tw-text-text-primary">Common QuickBooks Web Connector errors and solutions</p>
<div class="tw-flex tw-items-center tw-justify-start">
<div class="tw-pr-10-px">
<img [src]="brandIcon" width="12px" height="12px">
</div>
<div>
<a class="tw-text-size-10 tw-text-text-disable tw-font-400" href="https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector-errors-and">
<p class="tw-text-size-10 tw-text-text-disable tw-font-400">
https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector
</a>
</p>
</div>
</div>
</div>
<div *ngIf="appName===AppName.QBD_DIRECT"
class="tw-border tw-border-border-tertiary tw-rounded-border-radius-sm tw-bg-white tw-p-12-px tw-cursor-pointer"
(click)="redirect()"
(keydown.enter)="redirect()"
role="button"
tabindex="0"
[attr.aria-label]="'View QuickBooks Web Connector errors and solutions'">
<p class="tw-text-12-px tw-font-500 tw-text-text-primary">Common QuickBooks Web Connector errors and solutions</p>
<div class="tw-flex tw-items-center tw-justify-start">
<div class="tw-pr-10-px">
<img [src]="brandIcon" width="12px" height="12px">
</div>
<div>
<p class="tw-text-size-10 tw-text-text-disable tw-font-400">
https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector
</p>
</div>
</div>
</div>

Comment on lines +67 to +68
this.workspaceService.importFyleAttributes(false).subscribe();
this.qbdDirectHelperService.importQBDAttributes(false).subscribe();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Address potential issues with asynchronous operations

The current implementation has several concerns:

  1. The subscriptions aren't being managed properly, which could lead to memory leaks
  2. There's no error handling for failed attribute imports
  3. Setting isLoading = false and navigating before the imports complete could lead to race conditions

Consider refactoring using one of these approaches:

 private storeWorkspaceAndNavigate(workspace: QbdDirectWorkspace): void {
   this.workspace = workspace;
   this.storageService.set('workspaceId', this.workspace.id);
   this.storageService.set('onboarding-state', this.workspace.onboarding_state);
-  this.workspaceService.importFyleAttributes(false).subscribe();
-  this.qbdDirectHelperService.importQBDAttributes(false).subscribe();
-  this.isLoading = false;
-  this.navigate();
+  // Option 1: Using forkJoin to handle multiple observables
+  forkJoin([
+    this.workspaceService.importFyleAttributes(false),
+    this.qbdDirectHelperService.importQBDAttributes(false)
+  ]).pipe(
+    finalize(() => {
+      this.isLoading = false;
+      this.navigate();
+    })
+  ).subscribe({
+    error: (error) => {
+      console.error('Failed to import attributes:', error);
+      // Handle error appropriately
+    }
+  });

Or using async/await:

private async storeWorkspaceAndNavigate(workspace: QbdDirectWorkspace): Promise<void> {
  try {
    this.workspace = workspace;
    this.storageService.set('workspaceId', this.workspace.id);
    this.storageService.set('onboarding-state', this.workspace.onboarding_state);
    
    await firstValueFrom(this.workspaceService.importFyleAttributes(false));
    await firstValueFrom(this.qbdDirectHelperService.importQBDAttributes(false));
  } catch (error) {
    console.error('Failed to import attributes:', error);
    // Handle error appropriately
  } finally {
    this.isLoading = false;
    this.navigate();
  }
}

Don't forget to import the necessary operators:

import { forkJoin } from 'rxjs';
import { finalize } from 'rxjs/operators';
// Or for async/await approach
import { firstValueFrom } from 'rxjs';

Comment on lines +68 to +74
<app-checkbox-button
[checkedText]="'Done'"
[unCheckedText]="'Mark as done'"
[id]="0"
(checkBoxUpdated)="onDoneClick($event)">
</app-checkbox-button>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add accessibility attributes to the checkbox button

The checkbox button component should include ARIA attributes for better accessibility.

Consider adding these attributes to the checkbox-button component:

 <app-checkbox-button
     [checkedText]="'Done'"
     [unCheckedText]="'Mark as done'"
     [id]="0"
+    role="checkbox"
+    [attr.aria-checked]="isChecked"
+    [attr.aria-label]="'Mark setup as complete'"
     (checkBoxUpdated)="onDoneClick($event)">
 </app-checkbox-button>

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

Comment on lines 231 to 235
this.qbdDirectConnectorService.getQbdDirectConntion().subscribe((qbdConntion: QbdConnectorGet) => {
this.password = qbdConntion.password;
this.isDownloadStepCompleted = true;
this.isDownloadfileLoading = false;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for QBD connection retrieval

The API call to retrieve QBD connection lacks error handling, which could leave the component in an inconsistent state if the request fails.

Add error handling:

 this.qbdDirectConnectorService.getQbdDirectConntion().subscribe(
   (qbdConntion: QbdConnectorGet) => {
     this.password = qbdConntion.password;
     this.isDownloadStepCompleted = true;
     this.isDownloadfileLoading = false;
-  });
+  },
+  (error) => {
+    console.error('Failed to retrieve QBD connection:', error);
+    this.isDownloadfileLoading = false;
+    this.toastService.displayToastMessage(ToastSeverity.ERROR, 'Failed to retrieve connection details. Please try again.');
+  });

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

Comment on lines +199 to +215
if (this.connectionStatus === QBDConnectionStatus.IN_CORRECT_PASSWORD) {
this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: QbdDirectOnboardingState.PENDING_QWC_UPLOAD}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
this.isDialogVisible = false;
this.isConnectionStepCompleted = false;
this.isConnectionLoading = false;
});
} else {
this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: QbdDirectOnboardingState.CONNECTION}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
this.isDialogVisible = false;
this.isConnectionStepCompleted = false;
this.isDownloadStepCompleted = false;
this.showDownloadLink = false;
this.isCompanyPathInvalid = true;
this.isDownloadfileLoading = false;
this.isConnectionLoading = false;
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reduce code duplication in dialog closure handling

The method contains duplicated state reset logic that can be consolidated.

Apply this refactor to improve maintainability:

 closeDialog(event: any) {
+  const resetCommonState = () => {
+    this.isDialogVisible = false;
+    this.isConnectionStepCompleted = false;
+    this.isConnectionLoading = false;
+  };
+
+  const onboardingState = this.connectionStatus === QBDConnectionStatus.IN_CORRECT_PASSWORD
+    ? QbdDirectOnboardingState.PENDING_QWC_UPLOAD
+    : QbdDirectOnboardingState.CONNECTION;
+
   this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: onboardingState}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
-    if (this.connectionStatus === QBDConnectionStatus.IN_CORRECT_PASSWORD) {
-      this.isDialogVisible = false;
-      this.isConnectionStepCompleted = false;
-      this.isConnectionLoading = false;
-    } else {
+    resetCommonState();
+    if (this.connectionStatus !== QBDConnectionStatus.IN_CORRECT_PASSWORD) {
-      this.isDialogVisible = false;
-      this.isConnectionStepCompleted = false;
       this.isDownloadStepCompleted = false;
       this.showDownloadLink = false;
       this.isCompanyPathInvalid = true;
       this.isDownloadfileLoading = false;
-      this.isConnectionLoading = false;
     }
   });
 }
📝 Committable suggestion

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

Suggested change
if (this.connectionStatus === QBDConnectionStatus.IN_CORRECT_PASSWORD) {
this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: QbdDirectOnboardingState.PENDING_QWC_UPLOAD}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
this.isDialogVisible = false;
this.isConnectionStepCompleted = false;
this.isConnectionLoading = false;
});
} else {
this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: QbdDirectOnboardingState.CONNECTION}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
this.isDialogVisible = false;
this.isConnectionStepCompleted = false;
this.isDownloadStepCompleted = false;
this.showDownloadLink = false;
this.isCompanyPathInvalid = true;
this.isDownloadfileLoading = false;
this.isConnectionLoading = false;
});
}
const resetCommonState = () => {
this.isDialogVisible = false;
this.isConnectionStepCompleted = false;
this.isConnectionLoading = false;
};
const onboardingState = this.connectionStatus === QBDConnectionStatus.IN_CORRECT_PASSWORD
? QbdDirectOnboardingState.PENDING_QWC_UPLOAD
: QbdDirectOnboardingState.CONNECTION;
this.workspaceService.updateWorkspaceOnboardingState({onboarding_state: onboardingState}).subscribe((workspaceResponse: QbdDirectWorkspace) => {
resetCommonState();
if (this.connectionStatus !== QBDConnectionStatus.IN_CORRECT_PASSWORD) {
this.isDownloadStepCompleted = false;
this.showDownloadLink = false;
this.isCompanyPathInvalid = true;
this.isDownloadfileLoading = false;
}
});

@github-actions github-actions bot added size/L Large PR and removed size/M Medium PR labels Nov 22, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Outside diff range and nitpick comments (2)
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (1)

17-17: LGTM with accessibility enhancement suggestion

The dynamic styling based on step state is well implemented. However, consider adding ARIA attributes to improve accessibility for completed steps.

Add aria-checked attribute to indicate completion state:

- <div class="tw-flex tw-items-center tw-justify-between tw-py-14-px">
+ <div class="tw-flex tw-items-center tw-justify-between tw-py-14-px" [attr.aria-checked]="step.state === qbdPreRequisiteState.COMPLETE">

Also applies to: 20-20, 22-24

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (1)

64-65: Improve interactive element semantics

The manual download and retry links should be proper buttons for better accessibility.

Consider these changes:

-<span class="tw-text-text-muted tw-text-12-px tw-font-400 tw-pb-20-px">If it didn't start, <a class="tw-underline tw-underline-offset-1 tw-cursor-pointer" (click)="onManualDownload()">download the integration file manually</a>.</span>
-<p class="tw-pt-16-px tw-text-text-muted tw-text-12-px tw-font-400">Not the right file? <a class="tw-underline tw-underline-offset-1 tw-cursor-pointer" (click)="onRetryClick()">Try again.</a></p>
+<span class="tw-text-text-muted tw-text-12-px tw-font-400 tw-pb-20-px">If it didn't start, <button type="button" class="tw-underline tw-underline-offset-1" (click)="onManualDownload()">download the integration file manually</button>.</span>
+<p class="tw-pt-16-px tw-text-text-muted tw-text-12-px tw-font-400">Not the right file? <button type="button" class="tw-underline tw-underline-offset-1" (click)="onRetryClick()">Try again</button>.</p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 77b39c7 and e2f390d.

⛔ Files ignored due to path filters (4)
  • src/assets/icons/check-circle-outline-extra-large.svg is excluded by !**/*.svg
  • src/assets/icons/eye-medium.svg is excluded by !**/*.svg
  • src/assets/icons/eye-slash-medium.svg is excluded by !**/*.svg
  • src/assets/sprites/sprite.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (1 hunks)
  • src/app/shared/components/configuration/configuration-info-label/configuration-info-label.component.scss (1 hunks)
  • src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.html (1 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/shared/components/configuration/configuration-info-label/configuration-info-label.component.scss
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss
🔇 Additional comments (5)
src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.html (1)

9-9: Review the use of forced font weight and consider using CSS variables.

  1. The use of !tw-font-400 forces the font weight, which might override other styles. Consider if this is intentional and aligns with the design system.
  2. For consistent spacing across components, consider using CSS custom properties instead of hardcoded values like tw-pt-2-px and tw-mr-4-px.

Let's check if similar forced styles are used elsewhere:

Consider this alternative approach:

-<h5 class="tw-text-text-tertiary tw-text-14-px !tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">
+<h5 class="tw-text-text-tertiary tw-text-14-px tw-font-normal tw-text-pretty tw-spacing-sm">

And define the spacing in your CSS:

.tw-spacing-sm {
  padding-top: var(--spacing-sm, 0.5rem);
  margin-right: var(--spacing-sm, 0.5rem);
}
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2)

38-38: Previous review comment about Angular property binding convention is still valid

The [AppName] property binding issue mentioned in the previous review hasn't been addressed yet.


15-15: Verify padding consistency with design system

The padding change to tw-py-10-px seems arbitrary. Please ensure this aligns with the design system's spacing guidelines and maintains visual consistency across similar components.

✅ Verification successful

Based on the search results, I can see that tw-py-10-px padding is used consistently across similar components in the codebase, particularly in onboarding and configuration sections. Some examples:

  • src/app/shared/components/helper/onboarding-done/onboarding-done.component.html uses tw-py-10-px
  • src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html uses tw-py-10-px
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (the file in question) uses tw-py-10-px

The padding value aligns with design system patterns

The use of tw-py-10-px appears to be a standard padding value used across similar components in the codebase, particularly in onboarding and configuration sections. The change maintains visual consistency with the established design patterns.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar padding patterns in other onboarding components
rg "tw-py-\d+-px" --type html

Length of output: 26883

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2)

1-1: LGTM! Styling improvements enhance visual consistency

The updated border radius and icon size changes align well with the design system.

Also applies to: 5-5, 14-14


70-70: LGTM! Footer implementation is correct

The addition of the AppName property and button state management is well implemented.

Comment on lines 46 to 47
<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve iframe accessibility and security

The embedded video iframe needs accessibility and security enhancements.

Apply these changes:

-<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
+<iframe 
+    width="427" 
+    height="259" 
+    src="https://www.youtube.com/embed/2oYdc8KcQnk" 
+    title="Guide: How to find QuickBooks company file path" 
+    loading="lazy"
+    sandbox="allow-scripts allow-same-origin allow-presentation"
+    frameborder="0"
+    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+></iframe>
📝 Committable suggestion

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

Suggested change
<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
</div>
<iframe
width="427"
height="259"
src="https://www.youtube.com/embed/2oYdc8KcQnk"
title="Guide: How to find QuickBooks company file path"
loading="lazy"
sandbox="allow-scripts allow-same-origin allow-presentation"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
></iframe>
</div>

Comment on lines 25 to 35
placeholder="Example: C:\Users\[Username]\Documents\QuickBooks"
class="tw-w-full tw-border tw-border-input-default-border tw-rounded-sm tw-px-8-px tw-py-12-px"
class="tw-w-full tw-border tw-border-input-default-border tw-rounded-border-radius-2xs tw-px-8-px tw-py-12-px"
required
#downloadFilePathField="ngModel"
[ngClass]="{
'error-box': (downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid
}">
<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" class="tw-text-alert-toast">
<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" class="tw-text-alert-toast tw-pt-2-px">
<small *ngIf="downloadFilePathField.errors?.required || !isCompanyPathInvalid" class="tw-flex">
<app-svg-icon [svgSource]="'info-circle-fill'" [isTextColorAllowed]="true" [width]="'16px'" [height]="'16px'" [styleClasses]="'tw-text-form-error-help-text-color'"></app-svg-icon>
Enter a valid company file path.</small>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance form accessibility

The form validation UI needs accessibility improvements to ensure it's usable by screen readers.

Apply these changes to improve accessibility:

 <input type="text" pInputText id="downloadFilePath" name="downloadFilePath" [(ngModel)]="downloadFilePath" 
        placeholder="Example: C:\Users\[Username]\Documents\QuickBooks" 
        class="tw-w-full tw-border tw-border-input-default-border tw-rounded-border-radius-2xs tw-px-8-px tw-py-12-px" 
        required
        #downloadFilePathField="ngModel"
+       [attr.aria-invalid]="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid"
+       [attr.aria-describedby]="'downloadFilePath-error'"
        [ngClass]="{
            'error-box': (downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid
        }">
-<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" class="tw-text-alert-toast tw-pt-2-px">
+<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" 
+     id="downloadFilePath-error" 
+     class="tw-text-alert-toast tw-pt-2-px" 
+     role="alert">
📝 Committable suggestion

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

Suggested change
placeholder="Example: C:\Users\[Username]\Documents\QuickBooks"
class="tw-w-full tw-border tw-border-input-default-border tw-rounded-sm tw-px-8-px tw-py-12-px"
class="tw-w-full tw-border tw-border-input-default-border tw-rounded-border-radius-2xs tw-px-8-px tw-py-12-px"
required
#downloadFilePathField="ngModel"
[ngClass]="{
'error-box': (downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid
}">
<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" class="tw-text-alert-toast">
<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid" class="tw-text-alert-toast tw-pt-2-px">
<small *ngIf="downloadFilePathField.errors?.required || !isCompanyPathInvalid" class="tw-flex">
<app-svg-icon [svgSource]="'info-circle-fill'" [isTextColorAllowed]="true" [width]="'16px'" [height]="'16px'" [styleClasses]="'tw-text-form-error-help-text-color'"></app-svg-icon>
Enter a valid company file path.</small>
placeholder="Example: C:\Users\[Username]\Documents\QuickBooks"
class="tw-w-full tw-border tw-border-input-default-border tw-rounded-border-radius-2xs tw-px-8-px tw-py-12-px"
required
#downloadFilePathField="ngModel"
[attr.aria-invalid]="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid"
[attr.aria-describedby]="'downloadFilePath-error'"
[ngClass]="{
'error-box': (downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid
}">
<div *ngIf="(downloadFilePathField.invalid && downloadFilePathField.touched) || !isCompanyPathInvalid"
id="downloadFilePath-error"
class="tw-text-alert-toast tw-pt-2-px"
role="alert">
<small *ngIf="downloadFilePathField.errors?.required || !isCompanyPathInvalid" class="tw-flex">
<app-svg-icon [svgSource]="'info-circle-fill'" [isTextColorAllowed]="true" [width]="'16px'" [height]="'16px'" [styleClasses]="'tw-text-form-error-help-text-color'"></app-svg-icon>
Enter a valid company file path.</small>

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Outside diff range and nitpick comments (2)
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2)

20-21: Consider improving cross-platform support and error messages

  1. The example path uses Windows format (C:\Users\[Username]\Documents\QuickBooks). Consider showing platform-specific examples based on the user's OS.
  2. The error message "Enter a valid company file path" could be more specific about the expected format and common issues.

Consider updating the placeholder and error message:

-placeholder="Example: C:\Users\[Username]\Documents\QuickBooks"
+placeholder="Example: {{getOSSpecificPathExample()}}"
-Enter a valid company file path.</small>
+Enter a valid company file path (e.g., folder containing the .QBW file).</small>

Also applies to: 25-32


Line range hint 1-71: Enhance accessibility implementation

Consider adding the following accessibility improvements:

  1. ARIA labels for interactive elements
  2. Role attributes where appropriate
  3. Keyboard navigation support

Example improvements:

-<button pButton pRipple label="Download" class="downloadBtn" (click)="onDownloadClick()"></button>
+<button
+  pButton
+  pRipple
+  label="Download"
+  class="downloadBtn"
+  (click)="onDownloadClick()"
+  aria-label="Download integration file"
+  [attr.aria-disabled]="isLoading"
+></button>

-<input type="text" pInputText id="downloadFilePath"
+<input
+  type="text"
+  pInputText
+  id="downloadFilePath"
+  aria-label="Company file path input"
+  aria-describedby="path-help-text"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 77b39c7 and e2f390d.

⛔ Files ignored due to path filters (4)
  • src/assets/icons/check-circle-outline-extra-large.svg is excluded by !**/*.svg
  • src/assets/icons/eye-medium.svg is excluded by !**/*.svg
  • src/assets/icons/eye-slash-medium.svg is excluded by !**/*.svg
  • src/assets/sprites/sprite.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (1 hunks)
  • src/app/shared/components/configuration/configuration-info-label/configuration-info-label.component.scss (1 hunks)
  • src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.html (1 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/shared/components/configuration/configuration-info-label/configuration-info-label.component.scss
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-data-sync/qbd-direct-data-sync.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss
🔇 Additional comments (4)
src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.html (1)

Line range hint 9-18: LGTM on styling updates

The changes to text color, padding, and text rendering classes align with the QA fixes objective and improve visual consistency:

  • tw-text-text-tertiary provides better semantic meaning than the previous tw-text-muted
  • tw-text-pretty improves text rendering
  • Adjusted padding and margin enhance spacing
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (3)

1-1: LGTM! Styling updates align with design system

The adjustments to border radius, margins, and icon sizes create a more consistent and polished appearance.

Also applies to: 5-5, 8-8, 14-14


60-64: LGTM! Good UX implementation

The success state provides:

  • Clear visual feedback with the check icon
  • Automatic download with manual fallback
  • Easy retry option

70-70: Verify AppName enum consistency

The addition of [AppName]="appName.QBD_DIRECT" aligns with standardization efforts.

✅ Verification successful

Let me check the actual usage context of AppName in these files to ensure consistent implementation.


Let me check the component class files to verify the AppName enum import and usage.


AppName enum usage is consistent across QBD Direct components

The verification shows that the AppName enum is properly imported and consistently used across all QBD Direct components:

  • All components import AppName from the same path 'src/app/core/models/enum/enum.model'
  • The enum is correctly declared as a class property and used in the template bindings
  • The value QBD_DIRECT is consistently used across all components
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify consistent usage of AppName enum across QBD components
rg -l "appName\.QBD_DIRECT" src/app/integrations/qbd-direct/

Length of output: 528


Script:

#!/bin/bash
# Check the actual usage context of AppName in the QBD components
rg "appName\.QBD_DIRECT" src/app/integrations/qbd-direct/ -A 2 -B 2

Length of output: 4385


Script:

#!/bin/bash
# Check AppName enum import and usage in component files
rg "AppName" src/app/integrations/qbd-direct/ --type ts -A 2 -B 2

Length of output: 26717

@@ -6,7 +6,7 @@
[ngClass]="{'tw-text-18-px': brandingConfig.brandId === 'co'}">
{{ headerText }}
</h3>
<h5 class="tw-text-text-muted tw-text-14-px !tw-font-400 tw-text-pretty tw-pt-8-px tw-mr-4-px">
<h5 class="tw-text-text-tertiary tw-text-14-px !tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using !important in Tailwind classes

The !tw-font-400 class uses the !important flag which can lead to specificity issues and make styles harder to maintain. Consider resolving the specificity conflict by:

  1. Adjusting the CSS cascade
  2. Using more specific selectors
  3. Modifying the conflicting styles at their source
-      <h5 class="tw-text-text-tertiary tw-text-14-px !tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">
+      <h5 class="tw-text-text-tertiary tw-text-14-px tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">
📝 Committable suggestion

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

Suggested change
<h5 class="tw-text-text-tertiary tw-text-14-px !tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">
<h5 class="tw-text-text-tertiary tw-text-14-px tw-font-400 tw-text-pretty tw-pt-2-px tw-mr-4-px">

Comment on lines +44 to +48
<div class="tw-shadow-md tw-rounded-border-radius-2xl">
<div class="tw-flex tw-justify-center">
<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
</div>
<div class="tw-w-[427px] tw-p-16-px">
<div class="tw-p-16-px">
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance video embedding implementation

The current implementation has several areas for improvement:

  1. Hardcoded dimensions may not be responsive
  2. Missing loading/error states for the iframe
  3. YouTube URL should be configurable

Consider implementing these improvements:

-<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
+<iframe
+  [src]="safeVideoUrl"
+  class="tw-w-full tw-aspect-video"
+  [class.tw-hidden]="isVideoLoading"
+  (load)="onVideoLoad()"
+  loading="lazy"
+  title="Company file path tutorial"
+  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+></iframe>
+<app-loader *ngIf="isVideoLoading"></app-loader>

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

DhaaraniCIT and others added 3 commits November 22, 2024 14:14
#1082)

* qbd direct export settings onboarding changes and content changes

* fix: qbd direct import settings onboarding changes and content changes (#1083)

* qbd direct import settings onboarding changes and content changes

* qbd direct advanced settings onboarding changes and content changes (#1084)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (20)
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.html (1)

3-3: Consider adding input/output bindings to the export settings component.

The app-qbd-direct-export-settings component might benefit from:

  • Input bindings for initial configuration
  • Output bindings for error handling
  • Two-way bindings for form state management

Example enhancement:

-    <app-qbd-direct-export-settings></app-qbd-direct-export-settings>
+    <app-qbd-direct-export-settings
+        [initialConfig]="exportConfig"
+        [isLoading]="isConfigLoading"
+        (configChanged)="handleConfigChange($event)"
+        (error)="handleError($event)">
+    </app-qbd-direct-export-settings>
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.html (1)

1-1: Consider using Tailwind's standard spacing scale

The custom padding value tw-pb-48-px appears to use a specific pixel value. Consider using Tailwind's standard spacing scale (e.g., pb-12 for 48px) for better consistency across the application.

-<div class="tw-pb-48-px">
+<div class="pb-12">
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.html (1)

5-7: Consider adding configuration options to import settings component.

The app-qbd-direct-import-settings component might benefit from configuration inputs to make it more flexible and reusable.

Consider adding relevant inputs like:

-<app-qbd-direct-import-settings></app-qbd-direct-import-settings>
+<app-qbd-direct-import-settings
+  [configuration]="importConfiguration"
+  (settingsChange)="onImportSettingsChange($event)">
+</app-qbd-direct-import-settings>
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.ts (1)

27-28: Remove empty lifecycle hook.

The component implements OnInit but the ngOnInit method is empty. Either remove the empty method and the interface implementation if not needed, or implement the required initialization logic.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.ts (3)

4-5: Remove unnecessary imports

  • CommonModule is redundant as it's typically included in SharedModule
  • QbdOnboardingModule is imported but not used in the component's imports array
-import { CommonModule } from '@angular/common';
-import { QbdOnboardingModule } from 'src/app/integrations/qbd/qbd-onboarding/qbd-onboarding.module';

14-14: Remove CommonModule from imports array

Since CommonModule is already included via SharedModule, it should be removed from the imports array.

-  imports: [QbdDirectExportSettingsComponent, SharedModule, CommonModule],
+  imports: [QbdDirectExportSettingsComponent, SharedModule],

28-29: Remove empty lifecycle hook

The ngOnInit method is empty and should be removed if not needed.

-  ngOnInit(): void {
-  }
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.ts (2)

28-29: Remove empty lifecycle hook

The ngOnInit method is empty and can be removed along with the OnInit interface implementation if no initialization logic is needed.

-export class QbdDirectOnboardingAdvancedSettingsComponent implements OnInit {
+export class QbdDirectOnboardingAdvancedSettingsComponent {

-  ngOnInit(): void {
-  }

20-20: Consider lazy loading branding content

The brandingContent is directly imported and initialized, which could impact initial bundle size. Consider lazy loading this configuration if it's large.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (2)

1-17: Enhance accessibility of the header section.

Consider the following improvements for better accessibility:

  • Add proper heading levels for document outline
  • Make the step number semantically meaningful
 <div class="tw-border tw-rounded-border-radius-2xs tw-border-border-info-lighter" [ngClass]="{'tw-bg-border-info-lighter': !showSection}">
     <div class="tw-p-24-px">
-        <div class="tw-flex tw-items-center tw-justify-between">
+        <div class="tw-flex tw-items-center tw-justify-between" role="region" aria-label="Setup Connection Step">
             <div class="tw-flex tw-items-center tw-justify-start">
-                <div class="tw-w-20-px tw-h-20-px tw-rounded-border-radius-2xs tw-bg-bg-secondary tw-text-white tw-text-14-px tw-font-500 tw-text-center tw-mr-12-px">
+                <div class="tw-w-20-px tw-h-20-px tw-rounded-border-radius-2xs tw-bg-bg-secondary tw-text-white tw-text-14-px tw-font-500 tw-text-center tw-mr-12-px" role="text" aria-label="Step 2">
                     2
                 </div>
-                <div class="tw-text-14-px tw-font-500">
+                <h2 class="tw-text-14-px tw-font-500">
                     <span>Set up Quickbooks web connector</span>
-                </div>
+                </h2>
             </div>

83-93: Add ARIA attributes for loading and success states.

Enhance accessibility for dynamic content states.

-        <div *ngIf="isLoading" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px]">
+        <div *ngIf="isLoading" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px]" role="alert" aria-busy="true">
             <app-loader styleClass="spinner-30 tw-top-2-px"></app-loader>
             <span class="tw-text-14-px tw-font-400 tw-text-text-primary tw-pt-8-px">Connecting to QuickBooks Desktop...</span>
         </div>
-        <div *ngIf="!isLoading && !isStepCompleted && connectionStatus === qbdConnectionStatus.SUCCESS" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px] tw-text-center">
+        <div *ngIf="!isLoading && !isStepCompleted && connectionStatus === qbdConnectionStatus.SUCCESS" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px] tw-text-center" role="alert" aria-live="polite">
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-advanced-settings/qbd-direct-advanced-settings.component.html (2)

57-57: Consider moving concatenated strings to component/content file.

While the dynamic label construction works correctly, having long string concatenations in the template can make maintenance challenging. Consider moving these to the component class or a dedicated content file.

Example approach:

// In component class or content file
getReimbursableEntityLabel(mapping: string): string {
  const formattedMapping = this.formatMapping(mapping); // Apply pipes here
  return `${this.brandingContent.autoCreateReimbursableEnitityLabel}${formattedMapping}s in QuickBooks Desktop`;
}

Then in template:

-[label]="brandingContent.autoCreateReimbursableEnitityLabel + (employeeMapping | snakeCaseToSpaceCase | lowercase) + 's in QuickBooks Desktop'"
+[label]="getReimbursableEntityLabel(employeeMapping)"

Also applies to: 59-59


131-131: Consider simplifying template logic.

The template contains complex conditional logic that could be moved to the component class for better maintainability and testability.

Consider moving the complex logic to computed properties in the component:

// In component class
get ctaButtonText(): string {
  if (this.saveInProgress) {
    return ConfigurationCtaText.SAVING;
  }
  return this.isOnboarding ? ConfigurationCtaText.SAVE_AND_CONTINUE : ConfigurationCtaText.SAVE;
}

get isFormValid(): boolean {
  return this.advancedSettingsForm.valid && !this.saveInProgress && this.skipExportForm.valid;
}

Then simplify the template:

-<app-configuration-step-footer [ctaText]="!saveInProgress ? (isOnboarding ? ConfigurationCtaText.SAVE_AND_CONTINUE : ConfigurationCtaText.SAVE) : ConfigurationCtaText.SAVING" [isButtonDisabled]="!advancedSettingsForm.valid || saveInProgress || !skipExportForm.valid"
+<app-configuration-step-footer [ctaText]="ctaButtonText" [isButtonDisabled]="!isFormValid"
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-advanced-settings/qbd-direct-advanced-settings.component.ts (1)

140-142: Consider improving navigation path management and type safety.

While the navigation logic is straightforward, consider these improvements:

  1. Extract the route path to a constant or routing configuration to avoid hardcoding
  2. Consider preserving form state when navigating back, especially if users might want to return to this step
+private readonly IMPORT_SETTINGS_ROUTE = '/integrations/qbd_direct/onboarding/import_settings';
+
 navigateToPreviousStep() {
-  this.router.navigate([`/integrations/qbd_direct/onboarding/import_settings`]);
+  // Optionally store form state before navigation
+  this.router.navigate([this.IMPORT_SETTINGS_ROUTE]);
 }
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component.html (1)

68-69: Improve sub-label formatting and readability

The sub-labels contain formatting issues and could be more concise:

  1. Remove the extra space before the comma in " ,while"
  2. Consider breaking down the long sub-label text into multiple lines or a more concise format

Apply these changes to improve readability:

- [subLabel]="brandingContent.reimbursable.defaultReimbursableAccountPayableSubLabel + (exportSettingsForm.get('reimbursableExportType')?.value | snakeCaseToSpaceCase | titlecase) + ' ,while debit lines will reflect the category chosen by the employee for each respective expense'"
+ [subLabel]="brandingContent.reimbursable.defaultReimbursableAccountPayableSubLabel + (exportSettingsForm.get('reimbursableExportType')?.value | snakeCaseToSpaceCase | titlecase) + ', while debit lines will reflect the category chosen by the employee for each respective expense'"

- [subLabel]="brandingContent.corporateCard.defaultCCCAccountPayableSubLabel + (exportSettingsForm.get('creditCardExportType')?.value | snakeCaseToSpaceCase | titlecase) + ' ,while debit lines will reflect the category chosen by the employee for each respective expense'"
+ [subLabel]="brandingContent.corporateCard.defaultCCCAccountPayableSubLabel + (exportSettingsForm.get('creditCardExportType')?.value | snakeCaseToSpaceCase | titlecase) + ', while debit lines will reflect the category chosen by the employee for each respective expense'"

Also applies to: 190-191

src/app/branding/fyle-contents-config.ts (5)

9-9: Improve string concatenation using template literals

Replace string concatenation with template literals for better readability and maintainability.

Example refactor:

-            contentText: 'Import data from QuickBooks Desktop to ' + brandingConfig.brandName + ' and export expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop',
+            contentText: `Import data from QuickBooks Desktop to ${brandingConfig.brandName} and export expenses from ${brandingConfig.brandName} to QuickBooks Desktop`,

Also applies to: 27-27, 34-34, 40-40, 41-41, 42-42


88-91: Standardize quotation marks in strings

There's inconsistent usage of apostrophes in the strings. Standardize to using straight quotes consistently.

-                topLevelMemoStructureLabel: 'Customize the Top-Level Memo Field',
-                topLevelMemoStructureSubLabel: 'Select the datapoints you\'d like to export to QuickBooks Desktop's top-level memo field when exporting expenses from Fyle.',
+                topLevelMemoStructureLabel: 'Customize the Top-Level Memo Field',
+                topLevelMemoStructureSubLabel: 'Select the datapoints you\'d like to export to QuickBooks Desktop\'s top-level memo field when exporting expenses from Fyle.',

97-100: Remove trailing spaces in strings

Some strings contain trailing spaces which should be removed for consistency.

-                skipExportLabel: 'Skip Export of Specific Expenses from Fyle to QuickBooks Desktop ',
+                skipExportLabel: 'Skip Export of Specific Expenses from Fyle to QuickBooks Desktop',
-                autoCreateReimbursableEnitityLabel: 'Auto-create fyle employees as ',
+                autoCreateReimbursableEnitityLabel: 'Auto-create fyle employees as',

Line range hint 273-274: Fix typo in chartOfAccountsLabel

There's a missing space before the brand name variable.

-                chartOfAccountsLabel: 'Select the accounts from Xero to import as categories in' + brandingConfig.brandName,
+                chartOfAccountsLabel: 'Select the accounts from Xero to import as categories in ' + brandingConfig.brandName,

Line range hint 401-403: Standardize text casing in labels

The casing style is inconsistent across labels. Consider standardizing to Title Case for all labels.

-                scheduleAutoExport: 'Schedule automatic export',
-                email: 'Send error notification to',
-                paymentSyncLabel: 'Auto-sync payment status for reimbursable expenses',
+                scheduleAutoExport: 'Schedule Automatic Export',
+                email: 'Send Error Notification to',
+                paymentSyncLabel: 'Auto-sync Payment Status for Reimbursable Expenses',
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9640a93 and a5eaa57.

📒 Files selected for processing (18)
  • src/app/branding/fyle-contents-config.ts (2 hunks)
  • src/app/core/models/common/advanced-settings.model.ts (1 hunks)
  • src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-advanced-settings.model.ts (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.html (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.html (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.html (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-advanced-settings/qbd-direct-advanced-settings.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-advanced-settings/qbd-direct-advanced-settings.component.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component.html (9 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-shared.module.ts (2 hunks)
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/core/models/common/advanced-settings.model.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-pre-requisite/qbd-direct-onboarding-pre-requisite.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html
  • src/app/shared/components/input/checkbox-button/checkbox-button.component.scss
🔇 Additional comments (15)
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.html (1)

1-2: LGTM! Well-structured container with proper stepper integration.

The container provides appropriate spacing, and the stepper component is correctly integrated with the required input binding.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.html (1)

2-3: LGTM! Component structure follows best practices

The component structure is well-organized with:

  • Proper use of Angular property binding for onboardingSteps
  • Clear component naming that follows Angular conventions
  • Logical component hierarchy for the onboarding flow
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.html (2)

1-8: LGTM! Clean and well-structured template.

The template structure is clear and follows good component organization practices.


2-4: Verify onboardingSteps initialization.

The onboardingSteps input binding suggests this component is part of a multi-step flow. Ensure this property is properly initialized in the component class.

✅ Verification successful

Property is properly initialized with OnboardingStepper array

The onboardingSteps property is correctly initialized in the component class using the QbdDirectOnboardingModel().getOnboardingSteps() method, with proper dependency injection of WorkspaceService to get the onboarding state.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the component class implementation for onboardingSteps initialization
# Expected: Find the component class file and verify onboardingSteps property

# Find and display the component class file content
rg -l "QbdDirectOnboardingImportSettingsComponent" | xargs cat

# Check for onboardingSteps property initialization
ast-grep --pattern 'class QbdDirectOnboardingImportSettingsComponent {
  $$$
  onboardingSteps$_
  $$$
}'

Length of output: 4432

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-shared.module.ts (1)

Line range hint 12-20: Critical: Components must be declared in the declarations array

The new components QbdDirectExportSettingsComponent and QbdDirectImportSettingsComponent (along with other components) are incorrectly configured in the module. In Angular:

  • Components must be declared in the declarations array of their owning module
  • Components should be in imports only if they are standalone components
  • Components can only be declared once in any module

Apply this fix to properly configure the module:

@NgModule({
-  declarations: [],
+  declarations: [
+    QbdDirectDownloadFileComponent,
+    QbdDirectSetupConnectionComponent,
+    QbdDirectDataSyncComponent,
+    QbdDirectExportSettingsComponent,
+    QbdDirectImportSettingsComponent
+  ],
  imports: [
    CommonModule,
    SharedModule,
-    QbdDirectDownloadFileComponent,
-    QbdDirectSetupConnectionComponent,
-    QbdDirectDataSyncComponent,
-    QbdDirectExportSettingsComponent,
-    QbdDirectImportSettingsComponent
  ],
  exports: [
    QbdDirectDownloadFileComponent,
    QbdDirectSetupConnectionComponent,
    QbdDirectDataSyncComponent,
    QbdDirectExportSettingsComponent,
    QbdDirectImportSettingsComponent
  ]
})

Note: If these components are standalone components (using the standalone: true property), they should be removed from the declarations array and kept in the imports array. Please verify the component configuration and adjust accordingly.

Let's verify if these are standalone components:

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-import-settings/qbd-direct-onboarding-import-settings.component.ts (2)

1-8: LGTM! Imports are well-organized and necessary.

The imports follow a logical organization pattern and all appear to be utilized within the component.


12-16: LGTM! Component decorator follows Angular best practices.

The component is properly configured as standalone with necessary module imports and follows Angular's recommended file organization pattern.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-advanced-settings/qbd-direct-onboarding-advanced-settings.component.ts (1)

1-17: LGTM! Proper standalone component setup

The component is correctly set up as a standalone component with all necessary imports and dependencies properly declared.

src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-advanced-settings.model.ts (1)

29-29: LGTM! Good separation of concerns between UI and API.

The change improves user experience by showing a more readable "Expense/Report ID" label while maintaining the API contract with "expense_key". This is a good example of separating presentation from data contract.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html (1)

68-68: LGTM! The updated text provides better clarity.

The modified text clearly explains the vendor import functionality, making it more intuitive for users to understand how QuickBooks vendors map to Fyle merchants.

Let's verify consistency of vendor-related messaging across the codebase:

✅ Verification successful

The vendor/merchant terminology is consistent across the codebase

The updated text in QBD Direct Import Settings aligns well with the vendor/merchant terminology used throughout the application. The search results show consistent messaging across different integrations (QBO, NetSuite, Sage300, Xero, etc.) where:

  • Vendors/Suppliers from the accounting system are consistently imported as Merchants in Fyle
  • The messaging clearly explains the mapping relationship and the purpose (available for selection during expense coding)
  • Similar phrasing patterns are used across all integration modules
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in vendor/merchant terminology across templates

# Search for vendor/merchant related text in template files
rg -t html "vendor.*merchant|merchant.*vendor" --glob "src/app/**/*.html"

Length of output: 378


Script:

#!/bin/bash
# Let's check for more variations of vendor/merchant terminology
# to ensure we have a complete picture

# Search for "vendor" or "merchant" related text in template files
rg -t html "(?i)(vendor|merchant).{0,50}(import|map|match|correspond)" --glob "src/app/**/*.html" -A 2 -B 2

# Also check component files for any related logic or constants
rg -t ts "(?i)(vendor|merchant).{0,50}(import|map|match|correspond)" --glob "src/app/**/*.ts" -A 2 -B 2

Length of output: 67185

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (1)

96-97: LGTM!

The footer section is well-structured with proper component binding and properties.

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-advanced-settings/qbd-direct-advanced-settings.component.html (1)

Line range hint 1-134: Consider adding error handling for async operations.

While the form structure and validation are well implemented, there's no visible error handling for async operations like save. Consider adding error handling and user feedback mechanisms.

Let's check if error handling exists in the component:

Consider implementing:

  1. Error toast/notification for failed operations
  2. Error state in the save button
  3. Form error summary section for API errors
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component.html (3)

35-35: LGTM! Consistent placeholder text improvements

The placeholder text changes across select fields improve consistency and provide clearer guidance to users.

Also applies to: 111-111, 138-138, 255-255


240-242: LGTM! Conditional field disabling

The export group field is appropriately disabled when credit card export type is CREDIT_CARD_PURCHASE, with clear indication through isDisableTextRequired.


264-264: Verify navigation flow with disabled back button

The back button has been disabled in the configuration step footer. Please ensure this aligns with the intended user navigation flow and doesn't create a dead-end for users.

✅ Verification successful

Let me generate additional scripts to better understand the navigation flow and component structure.

The first search will help identify where this component is used, the second will show the full template context, and the third will reveal navigation methods in the component. This will help understand if disabling the back button is appropriate in this context.


Based on the gathered information, I can now provide a final response:

Back button can be safely disabled in this context

The component is used in both onboarding and configuration flows, and the back navigation is only relevant in the onboarding context. Since isOnboarding is properly handled in the component (determined by checking if URL includes 'onboarding'), and alternative navigation options exist through the header and main navigation, disabling the back button in the configuration step footer is appropriate.

  • The component has proper navigation handling through Router for both onboarding and configuration contexts
  • Header includes app-configuration-step-header with redirectLink for navigation
  • The form is part of a larger configuration interface with multiple navigation options
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if this is the first step in the flow or if there are alternative navigation options

# Search for related component files to understand the navigation flow
fd -e ts -e html "qbd-direct.*component" | xargs rg -l "navigateToPreviousStep|showBackButton"

# Look for router configuration to understand available navigation paths
rg "RouterModule.forChild|path.*qbd-direct" -A 5

Length of output: 30402


Script:

#!/bin/bash
# Check the component structure and navigation flow

# Look for the parent component that includes this export settings component
rg -l "qbd-direct-export-settings" --type ts

# Check the template content of the export settings component to understand the navigation context
cat src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component.html

# Look for navigation methods in the component
rg "navigate|router" src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component.ts

Length of output: 21449


brandingContent = brandingContent.configuration.importSetting;

onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor complex property initialization.

The current initialization of onboardingSteps is doing too much in a single line and occurs before the constructor completes. This could lead to potential issues if any of the service calls fail.

Consider moving this initialization to ngOnInit:

-  onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
+  onboardingSteps: OnboardingStepper[] = [];
+
+  ngOnInit(): void {
+    try {
+      const onboardingModel = new QbdDirectOnboardingModel();
+      const onboardingState = this.workspaceService.getOnboardingState();
+      this.onboardingSteps = onboardingModel.getOnboardingSteps(
+        this.brandingContent.stepName,
+        onboardingState
+      );
+    } catch (error) {
+      console.error('Failed to initialize onboarding steps:', error);
+      // Handle error appropriately
+    }
+  }
📝 Committable suggestion

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

Suggested change
onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
onboardingSteps: OnboardingStepper[] = [];
ngOnInit(): void {
try {
const onboardingModel = new QbdDirectOnboardingModel();
const onboardingState = this.workspaceService.getOnboardingState();
this.onboardingSteps = onboardingModel.getOnboardingSteps(
this.brandingContent.stepName,
onboardingState
);
} catch (error) {
console.error('Failed to initialize onboarding steps:', error);
// Handle error appropriately
}
}

Comment on lines +1 to 30
import { Component, OnInit } from '@angular/core';
import { QbdDirectExportSettingsComponent } from "../../qbd-direct-shared/qbd-direct-export-settings/qbd-direct-export-settings.component";
import { SharedModule } from 'src/app/shared/shared.module';
import { CommonModule } from '@angular/common';
import { QbdOnboardingModule } from 'src/app/integrations/qbd/qbd-onboarding/qbd-onboarding.module';
import { QbdDirectOnboardingModel } from 'src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-onboarding.model';
import { brandingContent } from 'src/app/branding/branding-config';
import { OnboardingStepper } from 'src/app/core/models/misc/onboarding-stepper.model';
import { WorkspaceService } from 'src/app/core/services/common/workspace.service';

@Component({
selector: 'app-qbd-direct-onboarding-export-settings',
standalone: true,
imports: [],
imports: [QbdDirectExportSettingsComponent, SharedModule, CommonModule],
templateUrl: './qbd-direct-onboarding-export-settings.component.html',
styleUrl: './qbd-direct-onboarding-export-settings.component.scss'
})
export class QbdDirectOnboardingExportSettingsComponent {
export class QbdDirectOnboardingExportSettingsComponent implements OnInit {

brandingContent = brandingContent.configuration.exportSetting;

onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());

constructor(
private workspaceService: WorkspaceService
) { }

ngOnInit(): void {
}

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Test suite is disabled and lacks proper coverage

The test file exists but:

  • The test suite is disabled (using xdescribe)
  • Only contains a basic component creation test
  • Missing coverage for critical onboarding flow functionality:
    • No tests for onboardingSteps initialization
    • No tests for workspace service integration
    • No tests for branding content integration
🔗 Analysis chain

Verify test coverage for onboarding flow

Since this component is part of the critical onboarding flow, please ensure adequate test coverage exists.


Let me check the content of the test file to verify the test coverage.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for corresponding test file
fd -e spec.ts qbd-direct-onboarding-export-settings.component

# Look for test cases covering the onboarding flow
rg -l "describe.*QbdDirectOnboardingExportSettingsComponent" -g "*.spec.ts"

Length of output: 437


Script:

#!/bin/bash
# Check the content of the test file
cat src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-export-settings/qbd-direct-onboarding-export-settings.component.spec.ts

Length of output: 939


brandingContent = brandingContent.configuration.exportSetting;

onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor onboardingSteps initialization

The current initialization has several issues:

  1. Creating a new instance of QbdDirectOnboardingModel directly is not ideal - consider injecting it
  2. Calling multiple methods in the property initialization can lead to timing issues
  3. Using workspaceService before it's fully initialized could cause problems

Consider refactoring like this:

-  onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
+  onboardingSteps: OnboardingStepper[] = [];
+
+  constructor(
+    private workspaceService: WorkspaceService,
+    private qbdDirectOnboardingModel: QbdDirectOnboardingModel
+  ) { }
+
+  ngOnInit(): void {
+    this.initializeOnboardingSteps();
+  }
+
+  private initializeOnboardingSteps(): void {
+    const onboardingState = this.workspaceService.getOnboardingState();
+    this.onboardingSteps = this.qbdDirectOnboardingModel.getOnboardingSteps(
+      this.brandingContent.stepName,
+      onboardingState
+    );
+  }
📝 Committable suggestion

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

Suggested change
onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
onboardingSteps: OnboardingStepper[] = [];
constructor(
private workspaceService: WorkspaceService,
private qbdDirectOnboardingModel: QbdDirectOnboardingModel
) { }
ngOnInit(): void {
this.initializeOnboardingSteps();
}
private initializeOnboardingSteps(): void {
const onboardingState = this.workspaceService.getOnboardingState();
this.onboardingSteps = this.qbdDirectOnboardingModel.getOnboardingSteps(
this.brandingContent.stepName,
onboardingState
);
}


brandingContent = brandingContent.configuration.advancedSettings;

onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor property initialization

The onboardingSteps property is initialized directly in the declaration using an injected service, which is not a recommended practice as it can lead to potential initialization issues and makes testing more difficult.

Consider moving the initialization to the constructor or ngOnInit:

-  onboardingSteps: OnboardingStepper[] = new QbdDirectOnboardingModel().getOnboardingSteps(this.brandingContent.stepName, this.workspaceService.getOnboardingState());
+  onboardingSteps: OnboardingStepper[];
+
+  constructor(private workspaceService: WorkspaceService) {
+    try {
+      const onboardingState = this.workspaceService.getOnboardingState();
+      this.onboardingSteps = new QbdDirectOnboardingModel().getOnboardingSteps(
+        this.brandingContent.stepName,
+        onboardingState
+      );
+    } catch (error) {
+      console.error('Failed to initialize onboarding steps:', error);
+      this.onboardingSteps = [];
+    }
+  }

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

Comment on lines +61 to +63
const index = topMemo.indexOf('Expense/Report ID');
topMemo[index] = 'expense_key';

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and use a more maintainable approach for field mapping.

The current implementation has potential issues:

  1. No error handling if "Expense/Report ID" is not found (indexOf returns -1)
  2. Direct array manipulation could be risky
  3. The mapping is hardcoded and scattered across methods

Consider this more robust approach:

+ private static readonly MEMO_FIELD_MAPPING = {
+   'Expense/Report ID': 'expense_key'
+ } as const;

  static constructPayload(advancedSettingForm: FormGroup, adminEmails: EmailOption[]): QbdDirectAdvancedSettingsPost {
    const topMemo: string[] = advancedSettingForm.controls.topMemoStructure.value;
-   const index = topMemo.indexOf('Expense/Report ID');
-   topMemo[index] = 'expense_key';
+   const mappedMemo = topMemo.map(field => 
+     QbdDirectAdvancedSettingsModel.MEMO_FIELD_MAPPING[field] || field
+   );

This approach:

  1. Centralizes UI-to-API field mappings
  2. Uses immutable operations
  3. Gracefully handles missing mappings
  4. Makes it easier to add new field mappings in the future

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

Comment on lines +77 to +79
<div class="tw-flex tw-justify-center tw-shadow-sm">
<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance iframe accessibility and security.

The YouTube video iframe needs proper title, controls, and security attributes.

-                    <iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
+                    <iframe 
+                        width="427" 
+                        height="259" 
+                        src="https://www.youtube.com/embed/2oYdc8KcQnk" 
+                        title="QuickBooks Web Connector Setup Guide"
+                        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+                        loading="lazy"
+                        frameborder="0">
+                    </iframe>
📝 Committable suggestion

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

Suggested change
<div class="tw-flex tw-justify-center tw-shadow-sm">
<iframe width="427" height="259" src="https://www.youtube.com/embed/2oYdc8KcQnk" frameborder="0"></iframe>
</div>
<div class="tw-flex tw-justify-center tw-shadow-sm">
<iframe
width="427"
height="259"
src="https://www.youtube.com/embed/2oYdc8KcQnk"
title="QuickBooks Web Connector Setup Guide"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
loading="lazy"
frameborder="0">
</iframe>
</div>

Comment on lines +40 to +41
<p *ngIf="!isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">****{{password.slice(4)}}</p>
<p *ngIf="isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">{{password}}</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance password security in the DOM.

The password is currently stored in plain text in the DOM, even when masked. Consider using a more secure approach.

-                    <p *ngIf="!isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">****{{password.slice(4)}}</p>
-                    <p *ngIf="isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">{{password}}</p>
+                    <p class="tw-text-16-px tw-text-text-muted tw-font-400">{{isPasswordShown ? password : '••••' + password.slice(-4)}}</p>
📝 Committable suggestion

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

Suggested change
<p *ngIf="!isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">****{{password.slice(4)}}</p>
<p *ngIf="isPasswordShown" class="tw-text-16-px tw-text-text-muted tw-font-400">{{password}}</p>
<p class="tw-text-16-px tw-text-text-muted tw-font-400">{{isPasswordShown ? password : '••••' + password.slice(-4)}}</p>

Comment on lines +44 to +49
<div class="tw-pr-6-px">
<app-svg-icon *ngIf="!isPasswordShown" [svgSource]="'eye-slash-medium'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="showPassword(true)"></app-svg-icon>
<app-svg-icon *ngIf="isPasswordShown" [svgSource]="'eye-medium'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="showPassword(false)"></app-svg-icon>
</div>
<div>
<app-svg-icon [svgSource]="'duplicate'" [width]="'22px'" [height]="'22px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="onClipboardCopy()"></app-svg-icon>
<app-svg-icon [svgSource]="'duplicate'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="onClipboardCopy()"></app-svg-icon>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add accessibility attributes and feedback for interactive elements.

The password visibility toggle and copy buttons need proper ARIA labels and user feedback.

-                    <div class="tw-pr-6-px">
+                    <div class="tw-pr-6-px" role="group" aria-label="Password controls">
                         <app-svg-icon *ngIf="!isPasswordShown" 
                             [svgSource]="'eye-slash-medium'" 
                             [width]="'18px'" 
                             [height]="'18px'" 
                             [isTextColorAllowed]="true" 
                             [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
+                            role="button"
+                            aria-label="Show password"
                             (iconClick)="showPassword(true)">
                         </app-svg-icon>
                         <app-svg-icon *ngIf="isPasswordShown" 
                             [svgSource]="'eye-medium'" 
                             [width]="'18px'" 
                             [height]="'18px'" 
                             [isTextColorAllowed]="true" 
                             [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
+                            role="button"
+                            aria-label="Hide password"
                             (iconClick)="showPassword(false)">
                         </app-svg-icon>
                     </div>
                     <div>
                         <app-svg-icon 
                             [svgSource]="'duplicate'" 
                             [width]="'18px'" 
                             [height]="'18px'" 
                             [isTextColorAllowed]="true" 
                             [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
+                            role="button"
+                            aria-label="Copy password to clipboard"
                             (iconClick)="onClipboardCopy()">
                         </app-svg-icon>
                     </div>
📝 Committable suggestion

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

Suggested change
<div class="tw-pr-6-px">
<app-svg-icon *ngIf="!isPasswordShown" [svgSource]="'eye-slash-medium'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="showPassword(true)"></app-svg-icon>
<app-svg-icon *ngIf="isPasswordShown" [svgSource]="'eye-medium'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="showPassword(false)"></app-svg-icon>
</div>
<div>
<app-svg-icon [svgSource]="'duplicate'" [width]="'22px'" [height]="'22px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="onClipboardCopy()"></app-svg-icon>
<app-svg-icon [svgSource]="'duplicate'" [width]="'18px'" [height]="'18px'" [isTextColorAllowed]="true" [styleClasses]="'tw-text-icon-muted tw-cursor-pointer'" (iconClick)="onClipboardCopy()"></app-svg-icon>
<div class="tw-pr-6-px" role="group" aria-label="Password controls">
<app-svg-icon *ngIf="!isPasswordShown"
[svgSource]="'eye-slash-medium'"
[width]="'18px'"
[height]="'18px'"
[isTextColorAllowed]="true"
[styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
role="button"
aria-label="Show password"
(iconClick)="showPassword(true)">
</app-svg-icon>
<app-svg-icon *ngIf="isPasswordShown"
[svgSource]="'eye-medium'"
[width]="'18px'"
[height]="'18px'"
[isTextColorAllowed]="true"
[styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
role="button"
aria-label="Hide password"
(iconClick)="showPassword(false)">
</app-svg-icon>
</div>
<div>
<app-svg-icon
[svgSource]="'duplicate'"
[width]="'18px'"
[height]="'18px'"
[isTextColorAllowed]="true"
[styleClasses]="'tw-text-icon-muted tw-cursor-pointer'"
role="button"
aria-label="Copy password to clipboard"
(iconClick)="onClipboardCopy()">
</app-svg-icon>
</div>

@@ -18,6 +18,10 @@ export class QbdDirectConnectorService {
return this.apiService.post(`/workspaces/${this.workspaceService.getWorkspaceId()}/connector_settings/`, payload);
}

getQbdDirectConntion(): Observable<QbdConnectorGet> {
Copy link
Contributor

Choose a reason for hiding this comment

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

getQBDConnectorSettings

} else if (onboardingState === QbdDirectOnboardingState.DESTINATION_SYNC_IN_PROGRESS || onboardingState === QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE) {
// Set success status, enable connection CTA, and stop polling
this.connectionStatus = QBDConnectionStatus.SUCCESS;
this.isConnectionCTAEnabled = true;
this.isConnectionLoading = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

move this outside if else

<p class="tw-text-12-px tw-font-500 tw-text-text-primary">Common QuickBooks Web Connector errors and solutions</p>
<div class="tw-flex tw-items-center tw-justify-start">
<div class="tw-pr-10-px">
<img [src]="brandIcon" width="12px" height="12px">
</div>
<div>
<a class="tw-text-size-10 tw-text-text-disable tw-font-400" href="https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector-errors-and">
<p class="tw-text-size-10 tw-text-text-disable tw-font-400">
https://help.fylehq.com/en/articles/71773-common-quickbooks-web-connector
Copy link
Contributor

Choose a reason for hiding this comment

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

link should come from KbArticle file


acceptWarning(isWarningAccepted: boolean) {
this.warningAccepted.emit({hasAccepted: isWarningAccepted, event: this.event});
}

redirect() {
this.windowService.openInNewTab(`${brandingConfig.helpArticleDomain}/en/articles/8394683-how-to-configure-the-fyle-sage-intacct-integration#h_38e0c9bea6`);
Copy link
Contributor

Choose a reason for hiding this comment

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

get from file

* QBD direct bug fixes

* QBD direct bug fixes

* QBD direct bug fixes
Copy link

Unit Test Coverage % values
Statements 34.83% ( 4246 / 12188 )
Branches 28.8% ( 1232 / 4277 )
Functions 27.45% ( 938 / 3417 )
Lines 34.98% ( 4176 / 11938 )

@DhaaraniCIT DhaaraniCIT merged commit 6e6de2c into qbd-direct-onboarding-phase-1 Nov 25, 2024
4 checks passed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (10)
src/app/shared/components/core/svg-icon/svg-icon.component.ts (1)

Line range hint 3-89: Consider enhancing type safety.

The component could benefit from stronger TypeScript types to prevent runtime errors and improve maintainability.

Consider applying these type safety improvements:

// Define icon name literals
type IconName = 'check-circle-outline-extra-large' | 'arrow-down' | /* ... other icons ... */;
type IconValue = 'grv-checkmark-encircled-extra-large' | 'grv-chevron-down' | /* ... other values ... */;

// Type the mapping object
const ICON_MAPPING: Record<IconName, IconValue> = {
  'check-circle-outline-extra-large': 'grv-checkmark-encircled-extra-large',
  // ... other mappings ...
};

export class SvgIconComponent implements OnInit {
  @Input() svgSource: IconName;
  @Input() c1SvgSource: IconValue;
  // ... rest of the component ...
}

This would:

  1. Prevent typos in icon names
  2. Enable autocomplete for icon names
  3. Remove the need for @ts-ignore
src/app/core/services/common/dashboard.service.ts (1)

61-61: Consider improving readability with a mapping object

The ternary expression is becoming complex with multiple conditions. Consider refactoring to use a mapping object for better maintainability.

-      const expenseKey = appName === AppName.INTACCT ? 'expense_group_ids' : appName === AppName.QBD_DIRECT ? 'export_log__id' : 'expense_group_id__in';
+      const expenseKeyMap = {
+        [AppName.INTACCT]: 'expense_group_ids',
+        [AppName.QBD_DIRECT]: 'export_log__id'
+      };
+      const expenseKey = expenseKeyMap[appName] || 'expense_group_id__in';
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (3)

20-30: Enhance semantic structure of setup steps

Consider wrapping the setup steps in an ordered list for better semantic structure and accessibility.

-<div>
+<ol class="tw-list-none">
-    <div>
+    <li>
         <div class="tw-flex tw-items-center tw-justify-start">
             <!-- Step 1 content -->
         </div>
-    </div>
+    </li>
-    <div class="tw-pt-40-px">
+    <li class="tw-pt-40-px">
         <div class="tw-flex tw-items-center tw-justify-start">
             <!-- Step 2 content -->
         </div>
-    </div>
+    </li>
-    <div class="tw-pt-40-px">
+    <li class="tw-pt-40-px">
         <div class="tw-flex tw-items-center tw-justify-start">
             <!-- Step 3 content -->
         </div>
-    </div>
+    </li>
-</div>
+</ol>

Also applies to: 31-55, 56-66


86-94: Add ARIA live region for success message

Consider adding an ARIA live region to announce the success state to screen readers.

-<div *ngIf="!isLoading && !isStepCompleted && connectionStatus === qbdConnectionStatus.SUCCESS && showSection && !isStepCompleted" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px] tw-text-center">
+<div *ngIf="!isLoading && !isStepCompleted && connectionStatus === qbdConnectionStatus.SUCCESS && showSection && !isStepCompleted" class="tw-flex tw-flex-col tw-justify-center tw-items-center tw-h-[400px] tw-text-center" role="status" aria-live="polite">

96-98: Remove redundant condition in ngIf

The condition !isStepCompleted appears twice in the ngIf directive.

-<div *ngIf="!isStepCompleted && showSection && !isStepCompleted">
+<div *ngIf="!isStepCompleted && showSection">
src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-dashboard/qbd-direct-dashboard.component.ts (2)

146-146: LGTM! Note about array index dependency

The update to responses[4] correctly aligns with the getQbdExportSettings response in the forkJoin array. However, be cautious about relying on array indices as they can be fragile if the order of API calls changes.

Consider destructuring the forkJoin response for better maintainability:

- this.destinationFieldMap = {
-   EMPLOYEE: responses[4].employee_field_mapping,
-   CATEGORY: 'ACCOUNT'
- };
+ const [
+   exportErrors,
+   accountingSummary,
+   tasks,
+   exportableIds,
+   qbdSettings,
+   importSettings
+ ] = responses;
+ this.destinationFieldMap = {
+   EMPLOYEE: qbdSettings.employee_field_mapping,
+   CATEGORY: 'ACCOUNT'
+ };

Line range hint 139-171: Enhance error handling and subscription management

The setupPage method handles multiple async operations but could benefit from improved error handling and subscription cleanup.

Consider these improvements:

  1. Add error handling for all forkJoin observables:
 forkJoin([
   this.getExportErrors$,
   this.getAccountingExportSummary$.pipe(catchError(() => of(null))),
   this.dashboardService.getAllTasks(...).pipe(catchError(() => of({ results: [] }))),
   this.dashboardService.getExportableAccountingExportIds('v2').pipe(catchError(() => of({ exportable_export_log_ids: [] }))),
   this.QbdDirectExportSettingsService.getQbdExportSettings().pipe(catchError(() => of({}))),
   this.importSettingService.getImportSettings().pipe(catchError(() => of({})))
 ]).pipe(
+  finalize(() => {
+    this.isLoading = false;
+  })
 ).subscribe(...)
  1. Implement proper cleanup in ngOnDestroy:
private destroy$ = new Subject<void>();

ngOnInit(): void {
  this.setupPage();
}

ngOnDestroy(): void {
  this.destroy$.next();
  this.destroy$.complete();
}
  1. Use takeUntil for subscription management:
 interval(3000).pipe(
+  takeUntil(this.destroy$),
   switchMap(() => ...)
 )
src/app/branding/c1-branding-config.ts (2)

Line range hint 126-126: Address TODO comments for demo video links

There are unaddressed TODO comments regarding demo video links:

  • "TODO" comment for XERO section
  • "TODO: Update link for MS Dynamics" for Business Central

Both sections currently use placeholder or potentially outdated video links.

Would you like me to create GitHub issues to track these TODOs?

Also applies to: 142-143


Line range hint 126-148: Standardize URL format for consistency

Most URLs use template literals with brandingConfig.helpArticleDomain, but TravelPerk URLs are hardcoded. This inconsistency could make future domain updates more difficult.

Consider updating TravelPerk URLs to use the template literal format:

 TRAVELPERK: {
-    PAYMENT_PROFILE_SETTINGS: 'https://help.fylehq.com/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration#h_0f8ebdfa10',
-    ADVANCED_SETTING: 'https://help.fylehq.com/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration#h_281acb3026',
-    LANDING: 'https://help.fylehq.com/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration'
+    PAYMENT_PROFILE_SETTINGS: `${brandingConfig.helpArticleDomain}/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration#h_0f8ebdfa10`,
+    ADVANCED_SETTING: `${brandingConfig.helpArticleDomain}/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration#h_281acb3026`,
+    LANDING: `${brandingConfig.helpArticleDomain}/en/articles/7193187-how-to-set-up-the-fyle-travelperk-integration`
 }
src/app/branding/fyle-branding-config.ts (1)

Line range hint 73-73: Consider tracking TODO comments

There are TODO comments for Sage 300 and Xero sections that might need tracking for future updates.

Would you like me to create GitHub issues to track these TODOs?

Also applies to: 156-156

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a5eaa57 and a561310.

⛔ Files ignored due to path filters (4)
  • src/assets/icons/check-circle-outline-extra-large.svg is excluded by !**/*.svg
  • src/assets/icons/co/grv-checkmark-encircled-extra-large.svg is excluded by !**/*.svg
  • src/assets/icons/eye-medium.svg is excluded by !**/*.svg
  • src/assets/sprites/sprite.svg is excluded by !**/*.svg
📒 Files selected for processing (15)
  • src/app/branding/c1-branding-config.ts (1 hunks)
  • src/app/branding/fyle-branding-config.ts (1 hunks)
  • src/app/core/models/branding/kb-article.model.ts (1 hunks)
  • src/app/core/models/db/task-log.model.ts (1 hunks)
  • src/app/core/models/enum/enum.model.ts (1 hunks)
  • src/app/core/services/common/dashboard.service.ts (1 hunks)
  • src/app/core/services/common/export-log.service.ts (2 hunks)
  • src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts (1 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-dashboard/qbd-direct-dashboard.component.ts (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (4 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html (2 hunks)
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (1 hunks)
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html (1 hunks)
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts (2 hunks)
  • src/app/shared/components/core/svg-icon/svg-icon.component.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-connector.service.ts
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-download-file/qbd-direct-download-file.component.html
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.html
  • src/app/shared/components/configuration/configuration-confirmation-dialog/configuration-confirmation-dialog.component.ts
🔇 Additional comments (13)
src/app/core/models/db/task-log.model.ts (1)

26-26: ⚠️ Potential issue

Resolve naming convention inconsistency with type definition

The property name export_log__id suggests a single ID relationship, but the type number[] indicates an array of IDs. This creates confusion about the intended usage. If this is meant to filter by multiple export log IDs, consider keeping the __in suffix (i.e., export_log_id__in). If it's meant for a single ID, the type should be number.

Let's verify the API contract and usage:

src/app/core/models/branding/kb-article.model.ts (1)

23-23: LGTM! Verify the implementation across components.

The addition of HELPER_ARTICLE maintains type safety and follows the established pattern for documentation links.

Let's verify its implementation:

✅ Verification successful

LGTM! The property is properly implemented across the codebase

The verification confirms:

  • The HELPER_ARTICLE property is correctly initialized in both branding configs (fyle and c1)
  • It's being used in the configuration-confirmation-dialog component as intended
  • The property follows the same pattern as other helper articles in the QBD_DIRECT section
  • The implementation is consistent with the type definition
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of HELPER_ARTICLE property across components and configs

# Check the property usage in templates
echo "Checking template usage:"
rg -A 2 "HELPER_ARTICLE" --type html

# Check the property initialization in branding configs
echo "Checking branding configs:"
rg "HELPER_ARTICLE.*=" src/app/branding/

Length of output: 722


Script:

#!/bin/bash
# Let's check the branding configs with a broader pattern to ensure we don't miss any initialization
echo "Checking branding configs with broader pattern:"
rg -A 2 "QBD_DIRECT.*=.*{" src/app/branding/

# Let's also check if there are any other references to this property
echo "Checking all references to QBD_DIRECT and HELPER_ARTICLE:"
rg -A 2 "QBD_DIRECT|HELPER_ARTICLE" --type ts

Length of output: 18710

src/app/core/services/common/export-log.service.ts (2)

6-6: LGTM!

The addition of AccountingExportStatus to the imports is appropriate and necessary for the new status handling logic.


88-91: Verify the impact of status replacement across the system

While the change from FAILED to ERROR status for QBD_DIRECT appears intentional, we should ensure this doesn't cause issues in downstream processing.

Let's verify the usage of these statuses:

Consider enhancing the status replacement logic

The current implementation assumes a single status value. Consider handling multiple statuses more explicitly:

-      if (params.status__in?.includes(AccountingExportStatus.FAILED)) {
-        params.status__in = AccountingExportStatus.ERROR;
+      if (Array.isArray(params.status__in)) {
+        params.status__in = params.status__in.map(status => 
+          status === AccountingExportStatus.FAILED ? AccountingExportStatus.ERROR : status
+        );
+      } else if (params.status__in === AccountingExportStatus.FAILED) {
+        params.status__in = AccountingExportStatus.ERROR;
+      }
src/app/shared/components/core/svg-icon/svg-icon.component.ts (1)

23-23: LGTM! Verify the new icon usage.

The new icon mapping follows the existing naming convention and size progression pattern.

Let's verify the usage of this new icon size:

✅ Verification successful

Icon mapping is correctly used in QBD integration templates

The new icon mapping is actively used in two QBD Direct integration components, with consistent styling and dimensions:

  • qbd-direct-setup-connection.component.html
  • qbd-direct-download-file.component.html
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of the new icon in template files
rg "check-circle-outline-extra-large" --type html

Length of output: 675

src/app/core/services/common/dashboard.service.ts (1)

61-61: Verify API contract for QBD_DIRECT export_log__id parameter

The parameter name change from 'expense_group_id__in' to 'export_log__id' for QBD_DIRECT looks correct based on the AI summary. However, let's verify the API contract.

✅ Verification successful

API contract change for QBD_DIRECT is correctly implemented

The verification confirms that the parameter change is consistent with the API contract:

  • The TaskLogGetParams type in src/app/core/models/db/task-log.model.ts explicitly includes export_log__id?: number[] as a valid parameter
  • This aligns with the conditional logic in dashboard.service.ts that sets expenseKey to 'export_log__id' for QBD_DIRECT
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the API contract for QBD_DIRECT export logs endpoint

# Search for API route definitions and parameter handling
rg -t ts "export_log__id|export_log_id__in" --no-heading

# Look for related test files to confirm parameter expectations
fd -e spec.ts -e test.ts | xargs rg "export_log__id|export_log_id__in" --no-heading

Length of output: 417


Script:

#!/bin/bash
# Let's search for QBD_DIRECT related API interfaces and task parameters
rg -t ts "interface.*TaskLogGetParams|type.*TaskLogGetParams" -A 10

# Also search for QBD_DIRECT task-related code to understand the parameter usage
rg -t ts "QBD_DIRECT.*task" -B 2 -A 2

# Look for any QBD export log related models or interfaces
ast-grep --pattern 'interface $_ {
  $$$
  export_log?: $_
  $$$
}'

Length of output: 830

src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-setup-connection/qbd-direct-setup-connection.component.html (2)

83-85: LGTM! Clear loading state feedback

The loading state provides clear visual and textual feedback about the connection process.


14-14: Verify icon size change impact

The icon size was changed from 'check-medium' to 'check-small'. Ensure this change maintains visual consistency with other completion indicators across the application.

✅ Verification successful

Icon size change is consistent with existing usage

The icon size change to 'check-small' with dimensions of 20x20px is consistent with other completion indicators in the codebase. The search results show that:

  • The same 'check-small' icon with identical dimensions (20x20px) is used in qbd-direct-download-file.component.html
  • Larger 'check-circle-outline-extra-large' icons (40x40px) are used in different contexts for success states
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other completion indicator icon sizes
rg -A 1 "svgSource=\"check-" --glob "*.html"

Length of output: 1812

src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-dashboard/qbd-direct-dashboard.component.ts (1)

118-118: Verify the implementation of parseAPIResponseToAccountingSummaryForQbdDirect

The method name change suggests QBD-specific parsing logic. Let's ensure the method exists and is properly implemented.

✅ Verification successful

Let me gather more information about the implementation details of both methods to ensure the QBD-specific method is properly implemented.


Let me try a different approach to get the method implementations.


Method implementation is correct and properly used

The QBD-specific method parseAPIResponseToAccountingSummaryForQbdDirect is correctly implemented in the AccountingExportSummaryModel class. The key difference is in the field mapping:

  • Regular method uses: total_expense_groups_count, successful_expense_groups_count, failed_expense_groups_count
  • QBD method uses: total_export_log_count, successful_export_log_count, failed_export_log_count

The usage is consistent across the codebase with QBD components using the QBD-specific method and other integrations using the standard method.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the method implementation
ast-grep --pattern 'parseAPIResponseToAccountingSummaryForQbdDirect($_) {
  $$$
}'

# Search for any other usages to ensure consistent adoption
rg "parseAPIResponseToAccountingSummary[A-Za-z]*" --type ts

Length of output: 3198


Script:

#!/bin/bash
# Get the implementation of both methods from the model file
ast-grep --pattern 'static parseAPIResponseToAccountingSummary(response: any): AccountingExportSummary {
  $$$
}'

ast-grep --pattern 'static parseAPIResponseToAccountingSummaryForQbdDirect(response: any): AccountingExportSummary {
  $$$
}'

Length of output: 243


Script:

#!/bin/bash
# Get the content of the model file with context
rg -A 20 "static parseAPIResponseToAccountingSummary.*" src/app/core/models/db/accounting-export-summary.model.ts

Length of output: 1504

src/app/branding/c1-branding-config.ts (1)

133-134: Verify URL accessibility

Let's verify that all help article URLs are accessible.

src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (2)

165-165: LGTM!

Proper reset of loading state after status handling is complete.


197-213: Refer to existing review comment

The code duplication issue in this method was previously identified. Please refer to the existing review comment that provides a solution for consolidating the state reset logic.

src/app/core/models/enum/enum.model.ts (1)

625-626: Verify the distinction between similar status values.

The newly added status values appear to overlap with existing ones:

  • EXPORT_QUEUED vs ENQUEUED
  • ERROR vs FAILED vs FATAL

Please clarify the specific use cases for each status to ensure they serve distinct purposes.

Consider adding code comments to document the specific scenarios where each status should be used, for example:

export enum AccountingExportStatus {
  // Used when the export is ready to be processed
  READY = 'READY',
  // Used when the export fails due to a recoverable error
  FAILED = 'FAILED',
  // Used when the export fails due to an unrecoverable error
  FATAL = 'FATAL',
  // Used when the export is successfully completed
  COMPLETE = 'COMPLETE',
  // Used when the export is currently being processed
  IN_PROGRESS = 'IN_PROGRESS',
  // Used when the export is queued for processing
  ENQUEUED = 'ENQUEUED',
  // Used when the export is queued specifically for the export phase
  EXPORT_QUEUED = 'EXPORT_QUEUED',
  // Used when the export encounters a validation or business logic error
  ERROR = 'ERROR'
}
✅ Verification successful

Based on the search results, I can now generate the final response as I have sufficient evidence to understand the distinction between the status values.

The status values serve distinct purposes in the export workflow

The code shows clear differentiation in how these statuses are used:

  • EXPORT_QUEUED is specifically used alongside ENQUEUED and IN_PROGRESS to track different queuing stages in the export process, as seen in the dashboard components
  • ERROR is treated differently from FAILED/FATAL in the export log service, where it's used as a separate status for filtering export logs

The distinction is particularly evident in these patterns:

  • Dashboard components track progress using all three queue-related statuses: ENQUEUED, IN_PROGRESS, and EXPORT_QUEUED
  • Error handling distinguishes between ERROR (used in export logs) vs FAILED/FATAL (used for accounting exports)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of these status values to understand their distinct purposes
echo "Searching for EXPORT_QUEUED usage..."
rg "EXPORT_QUEUED" -A 5

echo "Searching for ERROR, FAILED, and FATAL usage in export-related code..."
rg "AccountingExportStatus\.(ERROR|FAILED|FATAL)" -A 5

Length of output: 21920

Comment on lines +133 to +134
SKIP_EXPORT: `${brandingConfig.helpArticleDomain}/en/articles/9082146-configure-the-capital-one-sage-intacct-integration`,
HELPER_ARTICLE: `${brandingConfig.helpArticleDomain}/en/articles/7882821-how-to-skip-exporting-specific-expenses-from-fyle-to-sage-intacct`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect help article URL for QBD_DIRECT

The HELPER_ARTICLE URL points to a Sage Intacct article ("how-to-skip-exporting-specific-expenses-from-fyle-to-sage-intacct") instead of a QuickBooks Desktop article. This could mislead users by providing incorrect documentation.

Please update the URL to point to the correct QBD documentation.

Comment on lines +134 to +135
SKIP_EXPORT: `${brandingConfig.helpArticleDomain}/en/articles/7882821-how-to-skip-exporting-specific-expenses-from-fyle-to-sage-intacct`,
HELPER_ARTICLE: `${brandingConfig.helpArticleDomain}/en/articles/7882821-how-to-skip-exporting-specific-expenses-from-fyle-to-sage-intacct`
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

All help article URLs in QBD_DIRECT section are incorrectly pointing to Sage Intacct documentation

The entire QBD_DIRECT section in the branding config is using Sage Intacct documentation URLs for all its properties:

  • IMPORT_SETTING
  • EXPORT_SETTING
  • ADVANCED_SETTING
  • LANDING
  • CONNECTOR
  • SKIP_EXPORT
  • HELPER_ARTICLE

This appears to be a copy-paste error where the entire Sage Intacct section was duplicated for QBD_DIRECT without updating the URLs to point to the correct QuickBooks Desktop documentation.

🔗 Analysis chain

Incorrect documentation URLs for QuickBooks Desktop

The SKIP_EXPORT and HELPER_ARTICLE URLs under QBD_DIRECT are currently pointing to Sage Intacct documentation. This needs to be updated with the correct QuickBooks Desktop documentation URLs.

Let's verify if similar URL mismatches exist in other sections:


Let me verify the URLs in the QBD_DIRECT section by checking the branding config file:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential documentation URL mismatches
# Look for URLs that contain product names in sections for different products

echo "Checking for potential URL mismatches..."
rg -n "intacct" | grep -i "qbd\|quickbooks"
rg -n "sage" | grep -i "qbd\|quickbooks"

Length of output: 10043


Script:

#!/bin/bash
# Check the QBD_DIRECT section in the branding config
rg -A 10 "QBD_DIRECT" src/app/branding/fyle-branding-config.ts

Length of output: 2282

@@ -122,6 +122,7 @@ export class QbdDirectOnboardingConnectorComponent implements OnInit {
}

onConnectionDone(event: CheckBoxUpdate) {
this.isConnectionLoading = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling in connection polling

While setting the loading state is good, the error handling in the subscription could be improved to provide better user feedback.

Consider enhancing the error handling:

 onConnectionDone(event: CheckBoxUpdate) {
   this.isConnectionLoading = true;
   if (event.value) {
     interval(3000).pipe(
       switchMap(() => this.workspaceService.getWorkspace(this.user.org_id)),
       takeWhile((status: any) => !this.isTerminalStatus(status[0].onboarding_state as QbdDirectOnboardingState), true)
     )
     .subscribe(
       (status) => this.handleStatus(status[0]),
-      (error) => console.error('Error polling workspace status:', error)
+      (error) => {
+        console.error('Error polling workspace status:', error);
+        this.isConnectionLoading = false;
+        this.toastService.displayToastMessage(
+          ToastSeverity.ERROR,
+          'Failed to check connection status. Please try again.'
+        );
+      }
     );
   }
 }

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

Comment on lines +230 to +234
this.qbdDirectConnectorService.getQBDConnectorSettings().subscribe((qbdConntion: QbdConnectorGet) => {
this.password = qbdConntion.password;
this.isDownloadStepCompleted = true;
this.isDownloadfileLoading = false;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for QBD connector settings retrieval

The API call lacks error handling, which could leave the component in an inconsistent state if the request fails.

Add error handling:

 this.qbdDirectConnectorService.getQBDConnectorSettings().subscribe(
   (qbdConntion: QbdConnectorGet) => {
     this.password = qbdConntion.password;
     this.isDownloadStepCompleted = true;
     this.isDownloadfileLoading = false;
-  });
+  },
+  (error) => {
+    console.error('Failed to retrieve QBD connector settings:', error);
+    this.isDownloadStepCompleted = false;
+    this.isDownloadfileLoading = false;
+    this.isLoading = false;
+    this.toastService.displayToastMessage(
+      ToastSeverity.ERROR,
+      'Failed to retrieve connection settings. Please refresh the page.'
+    );
+  });
📝 Committable suggestion

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

Suggested change
this.qbdDirectConnectorService.getQBDConnectorSettings().subscribe((qbdConntion: QbdConnectorGet) => {
this.password = qbdConntion.password;
this.isDownloadStepCompleted = true;
this.isDownloadfileLoading = false;
});
this.qbdDirectConnectorService.getQBDConnectorSettings().subscribe(
(qbdConntion: QbdConnectorGet) => {
this.password = qbdConntion.password;
this.isDownloadStepCompleted = true;
this.isDownloadfileLoading = false;
},
(error) => {
console.error('Failed to retrieve QBD connector settings:', error);
this.isDownloadStepCompleted = false;
this.isDownloadfileLoading = false;
this.isLoading = false;
this.toastService.displayToastMessage(
ToastSeverity.ERROR,
'Failed to retrieve connection settings. Please refresh the page.'
);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deploy Triggers deployment of active branch to Staging size/L Large PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants