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

feat: qbd direct onboarding landing page #1056

Merged
merged 8 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/app/branding/c1-contents-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const brandingConfig: BrandingConfiguration = config as BrandingConfigura
export const c1Contents = {
qbd_direct: {
landing: {
contentText: 'Import chart of accounts and projects from NetSuite and export expenses from your Expense Management account.',
contentText: 'Import data from QuickBooks Desktop to ' + brandingConfig.brandName + ' and export expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop',
guideHeaderText: 'How to setup your integration'
},
configuration: {
Expand All @@ -16,9 +16,9 @@ export const c1Contents = {
configurationSubHeaderText: 'Begin your QuickBooks integration by completing the following steps.'
},
connector: {
configurationHeaderText: 'Connect to NetSuite subsidary',
configurationSubHeaderText: 'Expenses will be posted to the NetSuite subsidary selected here. You can\'t change the subsidary once they\'re configured.',
stepName: 'Connect to NetSuite',
configurationHeaderText: 'Connect to QuickBooks Desktop',
configurationSubHeaderText: 'Connect to QuickBooks desktop by completing the following steps.',
stepName: 'Connect to QuickBooks Desktop',
subLabel: 'Provide your credentials to establish a secure connection between your Expense Management and NetSuite account'
},
exportSetting: {
Expand Down Expand Up @@ -78,7 +78,7 @@ export const c1Contents = {
stepName: 'Advanced settings',
contentText: 'Customize the integration based on your accounting requirements.',
customizeSectionLabel: 'Customization',
customizeSectionSubLabel: 'In this section, you can customize the data that you\'d like to export from Fyle to QuickBooks Desktop You can choose what data points need to be exported and what shouldn\'t be.',
customizeSectionSubLabel: 'In this section, you can customize the data that you\'d like to export from ' + brandingConfig.brandName + ' to QuickBooks Desktop You can choose what data points need to be exported and what shouldn\'t be.',
automationLabel: 'Automation',
automationSubLabel: 'You can automate the export and sync of your data in this section.',
scheduleAutoExportLabel: 'Schedule automatic export',
Expand All @@ -93,7 +93,7 @@ export const c1Contents = {
otherPreferencesLabel: 'Other preferences',
otherPreferencesSubLabel: 'Based on your preference, you can choose whether you want to create any new records in QuickBooks Desktop from ' + brandingConfig.brandName + '.',
autoCreateMerchantsAsVendorsLabel: 'Auto-create merchants as vendors',
autoCreateMerchantsAsVendorsSubLabel: 'Fyle will auto-create a new vendor in QuickBooks Desktop if a merchant added by an employee does not have a corresponding match in QuickBooks Desktop. ',
autoCreateMerchantsAsVendorsSubLabel: '' + brandingConfig.brandName + ' will auto-create a new vendor in QuickBooks Desktop if a merchant added by an employee does not have a corresponding match in QuickBooks Desktop. ',
skipExportLabel: 'Skip export of specific expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop',
skipExportSubLabel: 'You could choose to skip expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop by setting up a conditional rule. ',
autoCreateReimbursableEnitityLabel: 'Auto create reimbursable enitity',
Expand Down
8 changes: 4 additions & 4 deletions src/app/branding/fyle-contents-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const brandingConfig: BrandingConfiguration = config as BrandingConfigura
export const fyleContents = {
qbd_direct: {
landing: {
contentText: 'Import data from NetSuite to ' + brandingConfig.brandName + ' and export expenses from ' + brandingConfig.brandName + ' to NetSuite. ',
contentText: 'Import data from QuickBooks Desktop to Fyle and export expenses from Fyle to QuickBooks Desktop',
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

Maintain consistency by using dynamic branding

The content text should use dynamic branding (brandingConfig.brandName) to maintain consistency with other integration sections.

Apply this change:

-            contentText: 'Import data from QuickBooks Desktop to Fyle and export expenses from Fyle to QuickBooks Desktop',
+            contentText: 'Import data from QuickBooks Desktop to ' + brandingConfig.brandName + ' and export expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop',
📝 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
contentText: 'Import data from QuickBooks Desktop to Fyle and export expenses from Fyle to QuickBooks Desktop',
contentText: 'Import data from QuickBooks Desktop to ' + brandingConfig.brandName + ' and export expenses from ' + brandingConfig.brandName + ' to QuickBooks Desktop',

guideHeaderText: 'Guide to setup your integrations'
},
configuration: {
Expand All @@ -16,9 +16,9 @@ export const fyleContents = {
configurationSubHeaderText: 'Begin your QuickBooks integration by completing the following steps.'
},
connector: {
configurationHeaderText: 'Connect to NetSuite Tenant',
configurationSubHeaderText: 'Connect to the NetSuite Tenant from which you would like to import and export data. The ' + brandingConfig.brandName + ' org and NetSuite Tenant cannot be changed once the configuration steps are complete.',
stepName: 'Connect to NetSuite',
configurationHeaderText: 'Connect to QuickBooks desktop',
configurationSubHeaderText: 'Connect to QuickBooks desktop by completing the following steps.',
stepName: 'Connect to QuickBooks Desktop',
subLabel: 'Expenses will be posted to the NetSuite Tenant Mapping selected here. Once configured, you can not change ' + brandingConfig.brandName + ' organization or Tenant Mapping.'
},
exportSetting: {
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/models/common/helper.model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FormGroup, Validators } from "@angular/forms";

export type checkBoxEvent = {
export type CheckBoxUpdate = {
id: number;
value: boolean;
}
Expand Down
4 changes: 4 additions & 0 deletions src/app/core/models/db/workspaces.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export type Workspace = {
created_at: Date;
updated_at: Date;
}

export type WorkspaceOnboardingState = {
onboarding_state: string;
}
Comment on lines +11 to +13
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 using string literal union type for better type safety

The onboarding_state property would benefit from being more strictly typed to prevent invalid states. Consider using a string literal union type to explicitly define all possible onboarding states.

Here's a suggested improvement:

+/**
+ * Represents the onboarding state of a workspace in QBD direct integration
+ */
 export type WorkspaceOnboardingState = {
-  onboarding_state: string;
+  onboarding_state: 'LANDING_PAGE' | 'IN_PROGRESS' | 'COMPLETE';  // Add all valid states
 }

This change will:

  • Provide better type safety by restricting possible values
  • Make the code more self-documenting
  • Help catch potential errors at compile time

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

16 changes: 14 additions & 2 deletions src/app/core/models/enum/enum.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export enum QbdDirectOnboardingState {
CONFIRM_PRE_REQUISITES = 'CONFIRM_PRE_REQUISITES',
PENDING_QWC_UPLOAD = 'PENDING_QWC_UPLOAD',
INCORRECT_COMPANY_PATH = 'INCORRECT_COMPANY_PATH',
IN_CORRECT_PASSWORD = 'IN_CORRECT_PASSWORD',
INCORRECT_PASSWORD = 'INCORRECT_PASSWORD',
DESTINATION_SYNC_IN_PROGRESS = 'DESTINATION_SYNC_IN_PROGRESS',
DESTINATION_SYNC_COMPLETE = 'DESTINATION_SYNC_COMPLETE',
}
Expand All @@ -348,7 +348,8 @@ export enum ConfigurationCta {
CONTINUE = 'Continue',
SAVING = 'Saving',
SYNCING = 'Syncing',
UPDATE = 'Update connection'
UPDATE = 'Update connection',
NEXT = 'Next'
}

export enum QBDReimbursableExpensesObject {
Expand Down Expand Up @@ -883,3 +884,14 @@ export enum ThemeOption {
LIGHT = 'light',
DARK = 'dark'
}

export enum QBDPreRequisiteState {
COMPLETE = 'COMPLETE',
INCOMPLETE = 'INCOMPLETE'
}

export enum QBDConnectionStatus {
SUCCESS = 'SUCCESS',
INCORRECT_COMPANY_PATH = 'INCORRECT_COMPANY_PATH',
IN_CORRECT_PASSWORD = 'IN_CORRECT_PASSWORD'
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { QBDPreRequisiteState } from "../../enum/enum.model";

export type QbdConnectorPost = {
file_location: string;
}
Expand All @@ -12,4 +14,18 @@ export type QbdConnectorGet = {
qwc: string,
created_at: Date,
updated_at: Date
}
}

export type QBDPrerequisiteObject = {
id: number,
label: string,
caption: string,
externalLink?: string,
iconName: string,
state: QBDPreRequisiteState
}

export type SyncDataType = {
attribute_type: string;
count: null | number
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type QbdOnboardingStepperMap = {
[QbdDirectOnboardingState.CONNECTION]: number;
[QbdDirectOnboardingState.PENDING_QWC_UPLOAD]: number;
[QbdDirectOnboardingState.INCORRECT_COMPANY_PATH]: number;
[QbdDirectOnboardingState.IN_CORRECT_PASSWORD]: number;
[QbdDirectOnboardingState.INCORRECT_PASSWORD]: number;
[QbdDirectOnboardingState.DESTINATION_SYNC_IN_PROGRESS]: number;
[QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE]: number;
[QbdDirectOnboardingState.EXPORT_SETTINGS]: number;
Expand All @@ -17,25 +17,25 @@ type QbdOnboardingStepperMap = {
[QbdDirectOnboardingState.COMPLETE]: number;
}

export class QbdOnboardingModel {
export class QbdDirectOnboardingModel {
brandingContent = brandingContent.qbd_direct.configuration;

private onboardingSteps: OnboardingStepper[] = [
{
active: false,
completed: false,
step: this.brandingContent.preRequisite.stepName,
icon: 'link-vertical-medium',
icon: 'arrow-tail-up-medium',
route: '/integrations/qbo/onboarding/pre_requisite',
styleClasses: ['step-name-connector--text']
styleClasses: ['step-name-pre-requisite--text']
},
{
active: false,
completed: false,
step: this.brandingContent.connector.stepName,
icon: 'link-vertical-medium',
route: '/integrations/qbo/onboarding/connector',
styleClasses: ['step-name-connector--text']
styleClasses: ['step-name-connector--text !tw-left-[-70px]']
},
{
active: false,
Expand Down Expand Up @@ -69,7 +69,7 @@ export class QbdOnboardingModel {
[QbdDirectOnboardingState.CONNECTION]: 2,
[QbdDirectOnboardingState.PENDING_QWC_UPLOAD]: 2,
[QbdDirectOnboardingState.INCORRECT_COMPANY_PATH]: 2,
[QbdDirectOnboardingState.IN_CORRECT_PASSWORD]: 2,
[QbdDirectOnboardingState.INCORRECT_PASSWORD]: 2,
[QbdDirectOnboardingState.DESTINATION_SYNC_IN_PROGRESS]: 2,
[QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE]: 2,
[QbdDirectOnboardingState.EXPORT_SETTINGS]: 3,
Expand Down
8 changes: 6 additions & 2 deletions src/app/core/services/common/workspace.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { AppUrl, BusinessCentralOnboardingState, IntacctOnboardingState, Netsuit
import { ApiService } from './api.service';
import { HelperService } from './helper.service';
import { AppUrlMap } from '../../models/integrations/integrations.model';
import { Workspace } from '../../models/db/workspaces.model';
import { XeroWorkspace } from '../../models/xero/db/xero-workspace.model';
import { WorkspaceOnboardingState } from '../../models/db/workspaces.model';
import { QbdDirectWorkspace } from '../../models/qbd-direct/db/qbd-direct-workspaces.model';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -74,4 +74,8 @@ export class WorkspaceService {
getWorkspaceGeneralSettings(): Observable<any> {
return this.apiService.get(`/workspaces/${this.getWorkspaceId()}/settings/general/`, {});
}

updateWorkspaceOnboardingState(payload: WorkspaceOnboardingState): Observable<QbdDirectWorkspace> {
return this.apiService.patch(`/workspaces/${this.getWorkspaceId()}/onboarding_state/`, payload);
}
Comment on lines +78 to +80
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

Inconsistency found between onboarding state enums

The verification reveals a mismatch between the onboarding states. The code uses QbdDirectOnboardingState enum in the actual implementation, which has different states (CONNECTION, EXPORT_SETTINGS, IMPORT_SETTINGS, ADVANCED_SETTINGS, COMPLETE) compared to QBDOnboardingState (CONNECTION, EXPORT_SETTINGS, FIELD_MAPPINGS, ADVANCED_SETTINGS, COMPLETE).

  • The workspace service is using WorkspaceOnboardingState type which accepts any string, potentially leading to inconsistencies
  • The component is using QbdDirectOnboardingState while the stepper is using QBDOnboardingState
  • These enums have different states: QbdDirectOnboardingState has IMPORT_SETTINGS while QBDOnboardingState has FIELD_MAPPINGS
🔗 Analysis chain

Verify onboarding state values consistency

Ensure that the WorkspaceOnboardingState values align with QBDOnboardingState enum values used in the service.


Let me gather more information about the QBD onboarding states to verify the consistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for QBDOnboardingState enum definition and WorkspaceOnboardingState usage
echo "Searching for QBDOnboardingState enum definition:"
rg -A 5 "QBDOnboardingState\s*=" src/

echo "\nSearching for WorkspaceOnboardingState usage:"
rg -A 2 "WorkspaceOnboardingState" src/

Length of output: 2763


Script:

#!/bin/bash
# Search for QBD onboarding state enums and their values
echo "Searching for QBD onboarding state enum definitions:"
rg -B2 -A5 "enum.*OnboardingState" src/

# Search for actual usage of onboarding states in the codebase
echo "\nSearching for onboarding state assignments:"
rg "onboarding_state.*=.*" src/

Length of output: 6119

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { QbdDirectConnectorService } from './qbd-direct-connector.service';

describe('QbdDirectConnectorService', () => {
xdescribe('QbdDirectConnectorService', () => {
let service: QbdDirectConnectorService;

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import { Injectable } from '@angular/core';
import { ApiService } from '../../common/api.service';
import { WorkspaceService } from '../../common/workspace.service';
import { Observable } from 'rxjs';
import { QbdConnectorPost, QbdConnectorGet, SyncDataType } from 'src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-connector.model';

@Injectable({
providedIn: 'root'
})
export class QbdDirectConnectorService {

constructor() { }
constructor(
private apiService: ApiService,
private workspaceService: WorkspaceService
) { }

postQbdDirectConntion(payload: QbdConnectorPost): Observable<QbdConnectorGet> {
return this.apiService.post(`/workspaces/${this.workspaceService.getWorkspaceId()}/connector_settings/`, payload);
}

syncAttribuites(): Observable<SyncDataType[]> {
return this.apiService.get(`/workspaces/${this.workspaceService.getWorkspaceId()}/qbd/attribute_stats/`, {});
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1 +1,61 @@
<p>qbd-direct-onboarding-connector works!</p>
<div class="tw-pb-48-px">
<app-onboarding-steppers [onboardingSteps]="onboardingSteps"></app-onboarding-steppers>
<div>
<div *ngIf="isLoading" class="tw-flex tw-justify-center tw-items-center tw-pt-80-px">
<app-loader></app-loader>
</div>
<div *ngIf="!isLoading" class="configuration--contents tw-border-border-tertiary tw-mt-24-px" [ngClass]="{'tw-mx-120-px tw-shadow-app-card': brandingConfig.brandId === 'fyle', 'tw-mx-60-px tw-shadow-shadow-level-1': brandingConfig.brandId === 'co'}">
<div>
<app-configuration-step-header
[headerText]="brandingContent.configurationHeaderText"
[contentText]="brandingContent.configurationSubHeaderText"
[redirectLink]="redirectLink">
</app-configuration-step-header>
</div>
<div class="tw-px-24-px">
<div class="tw-py-24-px">
<app-qbd-direct-download-file
[isLoading]="isDownloadfileLoading"
[showDownloadLink]="showDownloadLink"
[isStepCompleted]="isDownloadStepCompleted"
[isCompanyPathInvalid]="isCompanyPathInvalid"
(nextStep)="proceedToConnection()"
(downloadClick)="triggerDownload($event)"
(retryClick)="retry()"
(manualDownload)="triggerManualDownload()"></app-qbd-direct-download-file>
</div>
<div class="tw-py-24-px">
<app-qbd-direct-setup-connection
[showSection]="isDownloadStepCompleted"
[password]="password"
[isLoading]="isConnectionLoading"
[connectionStatus]="connectionStatus"
[isStepCompleted]="isConnectionStepCompleted"
[isCTAEnabled]="isConnectionCTAEnabled"
(doneClick)="onConnectionDone($event)"
(nextClick)="proceedToSyncData()"></app-qbd-direct-setup-connection>
</div>
<div class="tw-py-24-px">
<app-qbd-direct-data-sync
[isLoading]="isDataSyncLoading"
[qbdFields]="qbdFields"
[isCTAEnabled]="isDataSyncCTADisabled"
[showSection]="isConnectionStepCompleted"
(continueClick)="proceedToExportSetting()"></app-qbd-direct-data-sync>
</div>
</div>
</div>
</div>
</div>

<div *ngIf="isDialogVisible">
<app-configuration-confirmation-dialog
(warningAccepted)="closeDialog($event)"
[isWarningVisible]="isDialogVisible"
[headerText]="'Connection failed'"
[contextText]="warningDialogText"
[confirmBtnText]="'Got it'"
[appName]="appName"
[showSecondaryCTA]="false">
</app-configuration-confirmation-dialog>
</div>
Loading
Loading