From b7a9a4fb56e464a943fc2b82fda9d2b56a3c4422 Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Thu, 24 Oct 2024 14:10:45 -0700 Subject: [PATCH 01/66] Conditionally add nvp_onboarding when not invited --- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Report.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 497f43f93317..531f8176021a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7604,7 +7604,7 @@ function completePaymentOnboarding(paymentSelected: ValueOf, full = true) { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index dce8f2d19559..45fd68df1be7 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3329,6 +3329,7 @@ function completeOnboarding( paymentSelected?: string, companySize?: OnboardingCompanySizeType, userReportedIntegration?: OnboardingAccountingType, + wasInvited = false, ) { const actorAccountID = CONST.ACCOUNT_ID.CONCIERGE; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); @@ -3574,12 +3575,14 @@ function completeOnboarding( key: ONYXKEYS.NVP_INTRO_SELECTED, value: {choice: engagementChoice}, }, - { + ); + if (!wasInvited) { + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_ONBOARDING, value: {hasCompletedGuidedSetupFlow: true}, - }, - ); + }); + } const successData: OnyxUpdate[] = [...tasksForSuccessData]; successData.push({ From 791649a506ef26c28ce729be918f762468ef350c Mon Sep 17 00:00:00 2001 From: truph01 Date: Fri, 25 Oct 2024 06:14:34 +0700 Subject: [PATCH 02/66] fix: incorrect message displayed when deleting workspace --- src/pages/workspace/WorkspacesListPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 82503134b09e..f3cbdd388e21 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -124,7 +124,11 @@ function WorkspacesListPage() { const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyIDToDelete ?? '-1'); const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`); - const hasCardFeedOrExpensifyCard = !isEmptyObject(cardFeeds) || !isEmptyObject(cardsList); + const hasCardFeedOrExpensifyCard = + !isEmptyObject(cardFeeds) || + !isEmptyObject(cardsList) || + ((PolicyUtils.getPolicy(policyIDToDelete)?.areExpensifyCardsEnabled || PolicyUtils.getPolicy(policyIDToDelete)?.areCompanyCardsEnabled) && + PolicyUtils.getPolicy(policyIDToDelete)?.workspaceAccountID); const confirmDeleteAndHideModal = () => { if (!policyIDToDelete || !policyNameToDelete) { From 45e8f104b299128b7a565da3fbb6bff70a81fb9c Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Thu, 24 Oct 2024 16:15:57 -0700 Subject: [PATCH 03/66] Add undefined params to get pamentSeleted in right place; wasinvited too --- src/libs/actions/IOU.ts | 13 ++++++++++++- src/libs/actions/Report.ts | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 531f8176021a..7d0281a43b21 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7604,7 +7604,18 @@ function completePaymentOnboarding(paymentSelected: ValueOf, full = true) { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 45fd68df1be7..6e5ecf7f53a6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3329,7 +3329,7 @@ function completeOnboarding( paymentSelected?: string, companySize?: OnboardingCompanySizeType, userReportedIntegration?: OnboardingAccountingType, - wasInvited = false, + wasInvited?: boolean, ) { const actorAccountID = CONST.ACCOUNT_ID.CONCIERGE; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); From 9935cc3d8449f8a71c80522eff09a0defceedcd7 Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Thu, 24 Oct 2024 16:27:47 -0700 Subject: [PATCH 04/66] Apply same reasoning to failure data --- src/libs/actions/Report.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6e5ecf7f53a6..84b438d4a2fa 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3637,6 +3637,9 @@ function completeOnboarding( key: ONYXKEYS.NVP_INTRO_SELECTED, value: {choice: null}, }, + ); + + if (!wasInvited) failureData.push( { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_ONBOARDING, From 38d75c4255ff953f1188061704251bf18fe69749 Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Thu, 24 Oct 2024 17:17:21 -0700 Subject: [PATCH 05/66] Fix bad syntax --- src/libs/actions/Report.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 84b438d4a2fa..91eec9df1d77 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3639,13 +3639,13 @@ function completeOnboarding( }, ); - if (!wasInvited) failureData.push( - { + if (!wasInvited) { + failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_ONBOARDING, value: {hasCompletedGuidedSetupFlow: false}, - }, - ); + }); + } if (userReportedIntegration) { optimisticData.push({ From 8206ad0092a999dfd633f5874ec073d042059380 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 30 Oct 2024 17:35:14 +0700 Subject: [PATCH 06/66] fix: sound plays before paying held expense report --- src/components/ProcessMoneyReportHoldMenu.tsx | 2 ++ src/components/SettlementButton/index.tsx | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/ProcessMoneyReportHoldMenu.tsx b/src/components/ProcessMoneyReportHoldMenu.tsx index 3d6ad9006dc5..f1a72cc7fb8e 100644 --- a/src/components/ProcessMoneyReportHoldMenu.tsx +++ b/src/components/ProcessMoneyReportHoldMenu.tsx @@ -4,6 +4,7 @@ import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import Navigation from '@libs/Navigation/Navigation'; import {isLinkedTransactionHeld} from '@libs/ReportActionsUtils'; +import playSound, {SOUNDS} from '@libs/Sound'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -74,6 +75,7 @@ function ProcessMoneyReportHoldMenu({ if (startAnimation) { startAnimation(); } + playSound(SOUNDS.SUCCESS); IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport, full); } onClose(); diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 53b09bfcbf31..f98415a5f11a 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -208,7 +208,9 @@ function SettlementButton({ return; } - playSound(SOUNDS.SUCCESS); + if (!ReportUtils.hasHeldExpenses(iouReport?.reportID)) { + playSound(SOUNDS.SUCCESS); + } onPress(iouPaymentType); }; From 936b5bd45d821e34eecbf852f9627c1cef0f7d45 Mon Sep 17 00:00:00 2001 From: jaydamani Date: Sat, 2 Nov 2024 13:23:30 +0100 Subject: [PATCH 07/66] feature(onboarding): combine category and tag setup task for connections --- src/CONST.ts | 9 +++++++++ src/libs/actions/Report.ts | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 437ee4e7fd42..b79c831264eb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4891,6 +4891,15 @@ const CONST = { '\n' + `Chat with the specialist in your [#admins room](${adminsRoomLink}).`, }, + { + type: 'addAccountingIntegration', + autoCompleted: false, + title: 'Set up categories and tags', + description: ({workspaceCategoriesLink, workspaceAccountingLink}) => + '*Set up categories and tags* so your team can code expenses for easy reporting.\n' + + '\n' + + `Import them automatically by [connecting your accounting software](${workspaceAccountingLink}), or set them up manually in your [workspace settings](${workspaceCategoriesLink}).`, + }, { type: 'setupCategories', autoCompleted: false, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3eac21cd1b18..0333577fff8d 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3439,7 +3439,11 @@ function completeOnboarding( const tasksData = data.tasks .filter((task) => { - if (task.type === 'addAccountingIntegration' && !userReportedIntegration) { + if (['setupCategories', 'setupTags'].includes(task.type) && userReportedIntegration) { + return false; + } + + if (['addAccountingIntegration', 'setupCategoriesAndTags'].includes(task.type) && !userReportedIntegration) { return false; } return true; From 3c8de6dbc3ff0c764b6d4973d664ea7c386c0f16 Mon Sep 17 00:00:00 2001 From: jaydamani Date: Sat, 2 Nov 2024 13:32:05 +0100 Subject: [PATCH 08/66] update task type --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index b79c831264eb..1ce3b14acc53 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4892,7 +4892,7 @@ const CONST = { `Chat with the specialist in your [#admins room](${adminsRoomLink}).`, }, { - type: 'addAccountingIntegration', + type: 'setupCategoriesAndTags', autoCompleted: false, title: 'Set up categories and tags', description: ({workspaceCategoriesLink, workspaceAccountingLink}) => From 766e05bca88f1fa039404b0e0d6b92cce7452560 Mon Sep 17 00:00:00 2001 From: jaydamani Date: Tue, 5 Nov 2024 19:55:41 +0100 Subject: [PATCH 09/66] update link in setupCategoriesAndTags --- src/CONST.ts | 5 +++-- src/libs/actions/Report.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 1ce3b14acc53..97b8ac45acc7 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -264,6 +264,7 @@ type OnboardingTaskType = { workspaceMembersLink: string; integrationName: string; workspaceAccountingLink: string; + workspaceSettingsLink: string; }>, ) => string); }; @@ -4895,10 +4896,10 @@ const CONST = { type: 'setupCategoriesAndTags', autoCompleted: false, title: 'Set up categories and tags', - description: ({workspaceCategoriesLink, workspaceAccountingLink}) => + description: ({workspaceSettingsLink, workspaceAccountingLink}) => '*Set up categories and tags* so your team can code expenses for easy reporting.\n' + '\n' + - `Import them automatically by [connecting your accounting software](${workspaceAccountingLink}), or set them up manually in your [workspace settings](${workspaceCategoriesLink}).`, + `Import them automatically by [connecting your accounting software](${workspaceAccountingLink}), or set them up manually in your [workspace settings](${workspaceSettingsLink}).`, }, { type: 'setupCategories', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0333577fff8d..b560dc244d89 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3458,6 +3458,7 @@ function completeOnboarding( workspaceMoreFeaturesLink: `${environmentURL}/${ROUTES.WORKSPACE_MORE_FEATURES.getRoute(onboardingPolicyID ?? '-1')}`, integrationName, workspaceAccountingLink: `${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(onboardingPolicyID ?? '-1')}`, + workspaceSettingsLink: `${environmentURL}/${ROUTES.WORKSPACE_INITIAL.getRoute(onboardingPolicyID ?? '01')}`, }) : task.description; const taskTitle = From 7888a0d87cc23b53bb95621125322709ab438940 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 7 Nov 2024 14:38:09 +0700 Subject: [PATCH 10/66] fix: Not found page appear briefly after updating the first approver --- .../approvals/WorkspaceWorkflowsApprovalsEditPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx index d67dd564057c..b4f1164c8102 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx @@ -50,8 +50,10 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true // We need to remove members and approvers that are no longer in the updated workflow const membersToRemove = initialApprovalWorkflow.members.filter((initialMember) => !approvalWorkflow.members.some((member) => member.email === initialMember.email)); const approversToRemove = initialApprovalWorkflow.approvers.filter((initialApprover) => !approvalWorkflow.approvers.some((approver) => approver.email === initialApprover.email)); - Workflow.updateApprovalWorkflow(route.params.policyID, approvalWorkflow, membersToRemove, approversToRemove); Navigation.dismissModal(); + InteractionManager.runAfterInteractions(() => { + Workflow.updateApprovalWorkflow(route.params.policyID, approvalWorkflow, membersToRemove, approversToRemove); + }); }, [approvalWorkflow, initialApprovalWorkflow, route.params.policyID]); const removeApprovalWorkflow = useCallback(() => { From 49f2a49db137054a54ed8c42c6daaa587172d4b2 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Thu, 7 Nov 2024 16:17:23 +0100 Subject: [PATCH 11/66] remove isPolicyExpenseChat from Report --- src/libs/DebugUtils.ts | 1 - src/libs/OptionsListUtils.ts | 7 ++++++- src/libs/ReportUtils.ts | 6 +++--- src/libs/actions/IOU.ts | 4 ++-- src/pages/ProfilePage.tsx | 1 - src/pages/home/ReportScreen.tsx | 1 - src/types/onyx/Report.ts | 3 --- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index d63758761c3c..110a7c604618 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -59,7 +59,6 @@ const REPORT_BOOLEAN_PROPERTIES: Array = [ 'hasOutstandingChildRequest', 'hasOutstandingChildTask', 'isOwnPolicyExpenseChat', - 'isPolicyExpenseChat', 'isPinned', 'hasParentAccess', 'isDeletedParentAction', diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 1296a64e571d..939d2a0704ad 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -833,7 +833,7 @@ function getReportOption(participant: Participant): ReportUtils.OptionData { * Get the option for a policy expense report. */ function getPolicyExpenseReportOption(participant: Participant | ReportUtils.OptionData): ReportUtils.OptionData { - const expenseReport = ReportUtils.isPolicyExpenseChat(participant) ? ReportUtils.getReportOrDraftReport(participant.reportID) : null; + const expenseReport = isOptionPolicyExpenseChat(participant) ? ReportUtils.getReportOrDraftReport(participant.reportID) : null; const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) .filter(([, reportParticipant]) => reportParticipant && reportParticipant.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) @@ -2612,6 +2612,10 @@ function shouldUseBoldText(report: ReportUtils.OptionData): boolean { return report.isUnread === true && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; } +function isOptionPolicyExpenseChat(option: ReportUtils.OptionData | Participant): boolean { + return option?.isPolicyExpenseChat ?? false; +} + export { getAvatarsForAccountIDs, isCurrentUser, @@ -2658,6 +2662,7 @@ export { getAttendeeOptions, getAlternateText, hasReportErrors, + isOptionPolicyExpenseChat, }; export type {MemberForList, CategorySection, CategoryTreeSection, Options, OptionList, SearchOption, PayeePersonalDetails, Category, Tax, TaxRatesOption, Option, OptionTree}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a62716975c01..53358b090ae9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -488,7 +488,7 @@ type OptionData = { searchText?: string; isIOUReportOwner?: boolean | null; shouldShowSubscript?: boolean | null; - isPolicyExpenseChat?: boolean | null; + isPolicyExpenseChat?: boolean; isMoneyRequestReport?: boolean | null; isInvoiceReport?: boolean; isExpenseRequest?: boolean | null; @@ -1040,8 +1040,8 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxInputOrEntry | Participant): boolean { - return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); +function isPolicyExpenseChat(report: OnyxInputOrEntry): boolean { + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; } function isInvoiceRoom(report: OnyxEntry): boolean { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1db2555f3393..e060c3e71a1d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4224,7 +4224,7 @@ function createSplitsAndOnyxData( const hasMultipleParticipants = participants.length > 1; participants.forEach((participant) => { // In a case when a participant is a workspace, even when a current user is not an owner of the workspace - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); + const isPolicyExpenseChat = OptionsListUtils.isOptionPolicyExpenseChat(participant); const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, false); const splitTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, false); @@ -4844,7 +4844,7 @@ function startSplitBill({ }); participants.forEach((participant) => { - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); + const isPolicyExpenseChat = OptionsListUtils.isOptionPolicyExpenseChat(participant); if (!isPolicyExpenseChat) { return; } diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index e99fb0118d4e..b9746126135d 100755 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -73,7 +73,6 @@ const chatReportSelector = (report: OnyxEntry): OnyxEntry => parentReportActionID: report.parentReportActionID, type: report.type, chatType: report.chatType, - isPolicyExpenseChat: report.isPolicyExpenseChat, }; function ProfilePage({route}: ProfilePageProps) { diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 4c3ed5c705a5..4c86e66322ef 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -179,7 +179,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro writeCapability: reportOnyx.writeCapability, type: reportOnyx.type, errorFields: reportOnyx.errorFields, - isPolicyExpenseChat: reportOnyx.isPolicyExpenseChat, parentReportID: reportOnyx.parentReportID, parentReportActionID: reportOnyx.parentReportActionID, chatType: reportOnyx.chatType, diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 43c82cfdc227..fff12e60c5cd 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -89,9 +89,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** Whether the user is not an admin of policyExpenseChat chat */ isOwnPolicyExpenseChat?: boolean; - /** Whether the report is policyExpenseChat */ - isPolicyExpenseChat?: boolean; - /** Indicates if the report is pinned to the LHN or not */ isPinned?: boolean; From 0543b85da007aad44d2af129f82157879970823a Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Fri, 8 Nov 2024 15:58:24 +0100 Subject: [PATCH 12/66] use typeguard in isPolicyExpenseChat --- src/libs/OptionsListUtils.ts | 7 +------ src/libs/ReportUtils.ts | 4 ++-- src/libs/actions/IOU.ts | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 939d2a0704ad..1296a64e571d 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -833,7 +833,7 @@ function getReportOption(participant: Participant): ReportUtils.OptionData { * Get the option for a policy expense report. */ function getPolicyExpenseReportOption(participant: Participant | ReportUtils.OptionData): ReportUtils.OptionData { - const expenseReport = isOptionPolicyExpenseChat(participant) ? ReportUtils.getReportOrDraftReport(participant.reportID) : null; + const expenseReport = ReportUtils.isPolicyExpenseChat(participant) ? ReportUtils.getReportOrDraftReport(participant.reportID) : null; const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) .filter(([, reportParticipant]) => reportParticipant && reportParticipant.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) @@ -2612,10 +2612,6 @@ function shouldUseBoldText(report: ReportUtils.OptionData): boolean { return report.isUnread === true && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; } -function isOptionPolicyExpenseChat(option: ReportUtils.OptionData | Participant): boolean { - return option?.isPolicyExpenseChat ?? false; -} - export { getAvatarsForAccountIDs, isCurrentUser, @@ -2662,7 +2658,6 @@ export { getAttendeeOptions, getAlternateText, hasReportErrors, - isOptionPolicyExpenseChat, }; export type {MemberForList, CategorySection, CategoryTreeSection, Options, OptionList, SearchOption, PayeePersonalDetails, Category, Tax, TaxRatesOption, Option, OptionTree}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 53358b090ae9..d836bed329f2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1040,8 +1040,8 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxInputOrEntry): boolean { - return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; +function isPolicyExpenseChat(option: OnyxInputOrEntry | OptionData | Participant): boolean { + return getChatType(option) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT ?? (option && 'isPolicyExpenseChat' in option && option.isPolicyExpenseChat) ?? false; } function isInvoiceRoom(report: OnyxEntry): boolean { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e060c3e71a1d..1db2555f3393 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4224,7 +4224,7 @@ function createSplitsAndOnyxData( const hasMultipleParticipants = participants.length > 1; participants.forEach((participant) => { // In a case when a participant is a workspace, even when a current user is not an owner of the workspace - const isPolicyExpenseChat = OptionsListUtils.isOptionPolicyExpenseChat(participant); + const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, false); const splitTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, false); @@ -4844,7 +4844,7 @@ function startSplitBill({ }); participants.forEach((participant) => { - const isPolicyExpenseChat = OptionsListUtils.isOptionPolicyExpenseChat(participant); + const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); if (!isPolicyExpenseChat) { return; } From dd9ad232726742bf81c2b12970e7cfa6aca32d3b Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Mon, 11 Nov 2024 17:13:15 +0700 Subject: [PATCH 13/66] Fix search icon is unresponsive --- src/libs/actions/IOU.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 69c5badbc83f..bb3ed1c7078e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3960,6 +3960,10 @@ function trackExpense( Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); if (action === CONST.IOU.ACTION.SHARE) { + if (isSearchTopmostCentralPane() && activeReportID) { + Navigation.goBack(); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(activeReportID)); + } Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(activeReportID ?? '-1', CONST.IOU.SHARE.ROLE.ACCOUNTANT))); } From 34325c28fae8608deeb7e0b37d9bb2d7a5233487 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 12 Nov 2024 14:14:36 +0800 Subject: [PATCH 14/66] make the playback options scrollable --- src/components/VideoPopoverMenu/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/VideoPopoverMenu/index.tsx b/src/components/VideoPopoverMenu/index.tsx index 23f3447cf495..f4f3092df109 100644 --- a/src/components/VideoPopoverMenu/index.tsx +++ b/src/components/VideoPopoverMenu/index.tsx @@ -35,6 +35,7 @@ function VideoPopoverMenu({ anchorPosition={anchorPosition} menuItems={menuItems} anchorRef={videoPlayerMenuRef} + shouldUseScrollView /> ); } From 5a08343a4448658a8d2ccfaf8317ab109a6cc757 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Tue, 12 Nov 2024 14:46:05 +0100 Subject: [PATCH 15/66] move displayName to OptionData --- .../HTMLRenderers/MentionReportRenderer/index.tsx | 2 +- src/libs/ReportConnection.ts | 2 +- src/libs/ReportUtils.ts | 1 + src/types/onyx/Report.ts | 3 --- tests/utils/collections/reports.ts | 1 - 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 94a46d861dde..89a9fb21d48f 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -34,7 +34,7 @@ const getMentionDetails = (htmlAttributeReportID: string, currentReport: OnyxEnt if (!isEmpty(htmlAttributeReportID)) { const report = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${htmlAttributeReportID}`]; reportID = report?.reportID ?? htmlAttributeReportID; - mentionDisplayText = removeLeadingLTRAndHash(report?.reportName ?? report?.displayName ?? htmlAttributeReportID); + mentionDisplayText = removeLeadingLTRAndHash(report?.reportName ?? htmlAttributeReportID); // Get mention details from name inside tnode } else if ('data' in tnode && !isEmptyObject(tnode.data)) { mentionDisplayText = removeLeadingLTRAndHash(tnode.data); diff --git a/src/libs/ReportConnection.ts b/src/libs/ReportConnection.ts index a390a5cea2a9..d1abef352f13 100644 --- a/src/libs/ReportConnection.ts +++ b/src/libs/ReportConnection.ts @@ -28,7 +28,7 @@ Onyx.connect({ if (!report) { return; } - reportIDToNameMap[report.reportID] = report.reportName ?? report.displayName ?? report.reportID; + reportIDToNameMap[report.reportID] = report.reportName ?? report.reportID; ReportHelperActions.handleReportChanged(report); }); }, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 73721d094ebe..5956c954a841 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -523,6 +523,7 @@ type OptionData = { lastIOUCreationDate?: string; icons?: Icon[]; iouReportAmount?: number; + displayName?: string; } & Report; type OnyxDataTaskAssigneeChat = { diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 86cf9e71ca73..32f883d489c3 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -179,9 +179,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** When was the last visible action last modified */ lastVisibleActionLastModified?: string; - /** Display name of the report, shown in options and mentions */ - displayName?: string; - /** HTML content of the last message in the report */ lastMessageHtml?: string; diff --git a/tests/utils/collections/reports.ts b/tests/utils/collections/reports.ts index cf8e85893996..51ec8fbf90b5 100644 --- a/tests/utils/collections/reports.ts +++ b/tests/utils/collections/reports.ts @@ -7,7 +7,6 @@ export default function createRandomReport(index: number): Report { reportID: index.toString(), chatType: rand(Object.values(CONST.REPORT.CHAT_TYPE)), currency: randCurrencyCode(), - displayName: randWord(), ownerAccountID: index, isPinned: randBoolean(), isOptimisticReport: randBoolean(), From 06400a0888b0fa764495b0ca854aa5ab2bff5818 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Tue, 12 Nov 2024 15:02:05 +0100 Subject: [PATCH 16/66] remove unused errors property from Report --- src/libs/ReportUtils.ts | 2 -- src/types/onyx/Report.ts | 3 --- tests/unit/DebugUtilsTest.ts | 10 +--------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5956c954a841..6f3892b46aad 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6473,13 +6473,11 @@ function getAllReportActionsErrorsAndReportActionThatRequiresAttention(report: O * Get an object of error messages keyed by microtime by combining all error objects related to the report. */ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry): Errors { - const reportErrors = report?.errors ?? {}; const reportErrorFields = report?.errorFields ?? {}; const {errors: reportActionErrors} = getAllReportActionsErrorsAndReportActionThatRequiresAttention(report, reportActions); // All error objects related to the report. Each object in the sources contains error messages keyed by microtime const errorSources = { - reportErrors, ...reportErrorFields, ...reportActionErrors, }; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 32f883d489c3..382bb4647d99 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -206,9 +206,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback< /** For expense reports, this is the currency of the expense */ currency?: string; - /** Collection of errors to be shown to the user */ - errors?: OnyxCommon.Errors; - /** Collection of errors that exist in report fields */ errorFields?: OnyxCommon.ErrorFields; diff --git a/tests/unit/DebugUtilsTest.ts b/tests/unit/DebugUtilsTest.ts index c5d84341deee..120e5f3622f6 100644 --- a/tests/unit/DebugUtilsTest.ts +++ b/tests/unit/DebugUtilsTest.ts @@ -900,15 +900,7 @@ describe('DebugUtils', () => { expect(reason).toBe('debug.reasonVisibleInLHN.hasRBR'); }); it('returns correct reason when report has errors', () => { - const reason = DebugUtils.getReasonForShowingRowInLHN( - { - ...baseReport, - errors: { - error: 'Something went wrong', - }, - }, - true, - ); + const reason = DebugUtils.getReasonForShowingRowInLHN(baseReport, true); expect(reason).toBe('debug.reasonVisibleInLHN.hasRBR'); }); }); From 6f8b04ef0ed83c2cd86e154c5328c20ef801d80b Mon Sep 17 00:00:00 2001 From: truph01 Date: Tue, 12 Nov 2024 22:22:27 +0700 Subject: [PATCH 17/66] fix: lint --- src/pages/workspace/WorkspacesListPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 43b22da41aaf..7ca31874643a 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -127,6 +127,7 @@ function WorkspacesListPage() { const hasCardFeedOrExpensifyCard = !isEmptyObject(cardFeeds) || !isEmptyObject(cardsList) || + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing ((PolicyUtils.getPolicy(policyIDToDelete)?.areExpensifyCardsEnabled || PolicyUtils.getPolicy(policyIDToDelete)?.areCompanyCardsEnabled) && PolicyUtils.getPolicy(policyIDToDelete)?.workspaceAccountID); From 5c5dcf22e4ad3d639bfe95404b672e76b5a6c5b9 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Tue, 12 Nov 2024 22:44:10 +0700 Subject: [PATCH 18/66] display not found page for invalid magic code --- src/components/ValidateCode/ValidateCodeModal.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx index 1e42773c2dc2..6ff8d6c0d05d 100644 --- a/src/components/ValidateCode/ValidateCodeModal.tsx +++ b/src/components/ValidateCode/ValidateCodeModal.tsx @@ -10,6 +10,9 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ValidationUtils from '@libs/ValidationUtils'; +import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import variables from '@styles/variables'; import * as Session from '@userActions/Session'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -33,6 +36,18 @@ function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalPro const signInHere = useCallback(() => Session.signInWithValidateCode(accountID, code), [accountID, code]); const {translate} = useLocalize(); + const isInvalidValidateCode = !ValidationUtils.isValidValidateCode(code); + + if (isInvalidValidateCode) { + return ( + { + Navigation.goBack(); + }} + /> + ); + } return ( From 90e4e00508561db6f8aa18136300ec204351187e Mon Sep 17 00:00:00 2001 From: truph01 Date: Wed, 13 Nov 2024 15:19:47 +0700 Subject: [PATCH 19/66] fix: create policyToDelete --- src/pages/workspace/WorkspacesListPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 7ca31874643a..891a3d370085 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -124,12 +124,12 @@ function WorkspacesListPage() { const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyIDToDelete ?? '-1'); const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`); + const policyToDelete = PolicyUtils.getPolicy(policyIDToDelete); const hasCardFeedOrExpensifyCard = !isEmptyObject(cardFeeds) || !isEmptyObject(cardsList) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - ((PolicyUtils.getPolicy(policyIDToDelete)?.areExpensifyCardsEnabled || PolicyUtils.getPolicy(policyIDToDelete)?.areCompanyCardsEnabled) && - PolicyUtils.getPolicy(policyIDToDelete)?.workspaceAccountID); + ((policyToDelete?.areExpensifyCardsEnabled || policyToDelete?.areCompanyCardsEnabled) && policyToDelete?.workspaceAccountID); const confirmDeleteAndHideModal = () => { if (!policyIDToDelete || !policyNameToDelete) { From 5e10872d8170a8340fcad04de46d2095dc934910 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 13 Nov 2024 16:38:03 +0200 Subject: [PATCH 20/66] Fix distance amount changes after submitting track distance expense with description --- .../parameters/CategorizeTrackedExpenseParams.ts | 2 ++ .../API/parameters/ShareTrackedExpenseParams.ts | 2 ++ src/libs/actions/IOU.ts | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts b/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts index 78eb0adecc5e..5d7e5a131262 100644 --- a/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts +++ b/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts @@ -11,6 +11,7 @@ type CategorizeTrackedExpenseParams = { moneyRequestPreviewReportActionID: string; moneyRequestReportID: string; moneyRequestCreatedReportActionID: string; + customUnitRateID: string; actionableWhisperReportActionID: string; modifiedExpenseReportActionID: string; reportPreviewReportActionID: string; @@ -20,6 +21,7 @@ type CategorizeTrackedExpenseParams = { taxCode: string; taxAmount: number; billable?: boolean; + waypoints?: string; }; export default CategorizeTrackedExpenseParams; diff --git a/src/libs/API/parameters/ShareTrackedExpenseParams.ts b/src/libs/API/parameters/ShareTrackedExpenseParams.ts index cee4bc40d9ac..c5cd380a7ad9 100644 --- a/src/libs/API/parameters/ShareTrackedExpenseParams.ts +++ b/src/libs/API/parameters/ShareTrackedExpenseParams.ts @@ -20,6 +20,8 @@ type ShareTrackedExpenseParams = { taxCode: string; taxAmount: number; billable?: boolean; + customUnitRateID: string; + waypoints?: string; }; export default ShareTrackedExpenseParams; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5ec2e81b8c01..70ad2400d74f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3405,6 +3405,8 @@ function categorizeTrackedExpense( billable?: boolean, receipt?: Receipt, createdWorkspaceParams?: CreateWorkspaceParams, + waypoints?: string, + customUnitRateID?: string, ) { const {optimisticData, successData, failureData} = onyxData ?? {}; @@ -3451,6 +3453,8 @@ function categorizeTrackedExpense( policyExpenseCreatedReportActionID: createdWorkspaceParams?.expenseCreatedReportActionID, adminsChatReportID: createdWorkspaceParams?.adminsChatReportID, adminsCreatedReportActionID: createdWorkspaceParams?.adminsCreatedReportActionID, + waypoints, + customUnitRateID, }; API.write(WRITE_COMMANDS.CATEGORIZE_TRACKED_EXPENSE, parameters, {optimisticData, successData, failureData}); @@ -3486,6 +3490,8 @@ function shareTrackedExpense( billable?: boolean, receipt?: Receipt, createdWorkspaceParams?: CreateWorkspaceParams, + waypoints?: string, + customUnitRateID?: string, ) { const {optimisticData, successData, failureData} = onyxData ?? {}; @@ -3532,6 +3538,8 @@ function shareTrackedExpense( policyExpenseCreatedReportActionID: createdWorkspaceParams?.expenseCreatedReportActionID, adminsChatReportID: createdWorkspaceParams?.adminsChatReportID, adminsCreatedReportActionID: createdWorkspaceParams?.adminsCreatedReportActionID, + waypoints, + customUnitRateID, }; API.write(WRITE_COMMANDS.SHARE_TRACKED_EXPENSE, parameters, {optimisticData, successData, failureData}); @@ -3833,6 +3841,8 @@ function trackExpense( value: recentServerValidatedWaypoints, }); + const waypoints = validWaypoints ? JSON.stringify(sanitizeRecentWaypoints(validWaypoints)) : undefined; + switch (action) { case CONST.IOU.ACTION.CATEGORIZE: { if (!linkedTrackedExpenseReportAction || !actionableWhisperReportActionID || !linkedTrackedExpenseReportID) { @@ -3863,6 +3873,8 @@ function trackExpense( billable, trackedReceipt, createdWorkspaceParams, + waypoints, + customUnitRateID, ); break; } @@ -3894,6 +3906,8 @@ function trackExpense( billable, trackedReceipt, createdWorkspaceParams, + waypoints, + customUnitRateID, ); break; } @@ -3922,7 +3936,7 @@ function trackExpense( receiptGpsPoints: gpsPoints ? JSON.stringify(gpsPoints) : undefined, transactionThreadReportID: transactionThreadReportID ?? '-1', createdReportActionIDForThread: createdReportActionIDForThread ?? '-1', - waypoints: validWaypoints ? JSON.stringify(sanitizeRecentWaypoints(validWaypoints)) : undefined, + waypoints, customUnitRateID, }; if (actionableWhisperReportActionIDParam) { From 76de333cba6f60b9f90014b58e77374d4a45f186 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 13 Nov 2024 16:49:51 +0200 Subject: [PATCH 21/66] reorder --- src/libs/API/parameters/CategorizeTrackedExpenseParams.ts | 2 +- src/libs/API/parameters/ShareTrackedExpenseParams.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts b/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts index 5d7e5a131262..d999f96fb505 100644 --- a/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts +++ b/src/libs/API/parameters/CategorizeTrackedExpenseParams.ts @@ -11,7 +11,6 @@ type CategorizeTrackedExpenseParams = { moneyRequestPreviewReportActionID: string; moneyRequestReportID: string; moneyRequestCreatedReportActionID: string; - customUnitRateID: string; actionableWhisperReportActionID: string; modifiedExpenseReportActionID: string; reportPreviewReportActionID: string; @@ -22,6 +21,7 @@ type CategorizeTrackedExpenseParams = { taxAmount: number; billable?: boolean; waypoints?: string; + customUnitRateID?: string; }; export default CategorizeTrackedExpenseParams; diff --git a/src/libs/API/parameters/ShareTrackedExpenseParams.ts b/src/libs/API/parameters/ShareTrackedExpenseParams.ts index c5cd380a7ad9..c89c0d400e72 100644 --- a/src/libs/API/parameters/ShareTrackedExpenseParams.ts +++ b/src/libs/API/parameters/ShareTrackedExpenseParams.ts @@ -20,7 +20,7 @@ type ShareTrackedExpenseParams = { taxCode: string; taxAmount: number; billable?: boolean; - customUnitRateID: string; + customUnitRateID?: string; waypoints?: string; }; From b29da7baeaa97bd8e0c445d5d584262054e070e4 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 13 Nov 2024 23:15:25 +0700 Subject: [PATCH 22/66] remove withOnyx --- .../ValidateCode/ValidateCodeModal.tsx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx index 6ff8d6c0d05d..3216a443d183 100644 --- a/src/components/ValidateCode/ValidateCodeModal.tsx +++ b/src/components/ValidateCode/ValidateCodeModal.tsx @@ -1,7 +1,6 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; @@ -16,23 +15,18 @@ import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import variables from '@styles/variables'; import * as Session from '@userActions/Session'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Session as SessionType} from '@src/types/onyx'; -type ValidateCodeModalOnyxProps = { - /** Session of currently logged in user */ - session: OnyxEntry; -}; - -type ValidateCodeModalProps = ValidateCodeModalOnyxProps & { +type ValidateCodeModalProps = { /** Code to display. */ code: string; /** The ID of the account to which the code belongs. */ accountID: number; }; -function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalProps) { +function ValidateCodeModal({code, accountID}: ValidateCodeModalProps) { const theme = useTheme(); const styles = useThemeStyles(); + const [session] = useOnyx(ONYXKEYS.SESSION); const signInHere = useCallback(() => Session.signInWithValidateCode(accountID, code), [accountID, code]); const {translate} = useLocalize(); @@ -88,6 +82,4 @@ function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalPro ValidateCodeModal.displayName = 'ValidateCodeModal'; -export default withOnyx({ - session: {key: ONYXKEYS.SESSION}, -})(ValidateCodeModal); +export default ValidateCodeModal; From 635ffc58bab75a4fa74c9260fcc72aab2f3fcd6a Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Wed, 13 Nov 2024 11:23:05 -0800 Subject: [PATCH 23/66] Resolve bad merge conflict --- src/libs/actions/Report.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 63c5959a22ee..7bae11fe06e9 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3896,6 +3896,7 @@ function completeOnboarding( paymentSelected?: string, companySize?: OnboardingCompanySize, userReportedIntegration?: OnboardingAccounting, + wasInvited?: boolean, ) { const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData( engagementChoice, @@ -3903,6 +3904,7 @@ function completeOnboarding( adminsChatReportID, onboardingPolicyID, userReportedIntegration, + wasInvited, ); const parameters: CompleteGuidedSetupParams = { From 3d9c90af74221f7d0c874548f2278b3641706fa1 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 14 Nov 2024 15:24:13 +0700 Subject: [PATCH 24/66] Improve switch to Expensify Classic flow --- src/CONST.ts | 6 ++ src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + src/languages/en.ts | 12 +++ src/languages/es.ts | 12 +++ .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 3 + src/libs/Navigation/types.ts | 1 + .../ExitSurvey/ExitSurveyBookCall.tsx | 83 +++++++++++++++++++ .../ExitSurvey/ExitSurveyConfirmPage.tsx | 12 ++- src/pages/settings/InitialSettingsPage.tsx | 12 ++- src/styles/index.ts | 8 ++ 12 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 src/pages/settings/ExitSurvey/ExitSurveyBookCall.tsx diff --git a/src/CONST.ts b/src/CONST.ts index 4b2b66ab5a2d..5eeba1d6a546 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5848,6 +5848,12 @@ const CONST = { DONT_UNDERSTAND: 'dontUnderstand', PREFER_CLASSIC: 'preferClassic', }, + BENEFIT: { + CHATTING_DIRECTLY: 'chattingDirectly', + EVERYTHING_MOBILE: 'everythingMobile', + TRAVEL_EXPENSE: 'travelExpense', + }, + BOOK_MEETING_LINK: 'https://calendly.com/d/cqsm-2gm-fxr/expensify-product-team', }, SESSION_STORAGE_KEYS: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 103c4b2c3125..82b2d075bd69 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -257,6 +257,7 @@ const ROUTES = { }, SETTINGS_EXIT_SURVEY_REASON: 'settings/exit-survey/reason', + SETTINGS_EXIT_SURVERY_BOOK_CALL: 'settings/exit-survey/book-call', SETTINGS_EXIT_SURVEY_RESPONSE: { route: 'settings/exit-survey/response', getRoute: (reason?: ValueOf, backTo?: string) => diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 9b8fe54111cf..1d0d4be0cfee 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -116,6 +116,7 @@ const SCREENS = { }, EXIT_SURVEY: { + BOOK_CALL: 'Settings_ExitSurvey_Book_Call', REASON: 'Settings_ExitSurvey_Reason', RESPONSE: 'Settings_ExitSurvey_Response', CONFIRM: 'Settings_ExitSurvey_Confirm', diff --git a/src/languages/en.ts b/src/languages/en.ts index d13cf61957ea..4a44320e4720 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4928,6 +4928,18 @@ const translations = { offlineTitle: "Looks like you're stuck here...", offline: "You appear to be offline. Unfortunately, Expensify Classic doesn't work offline, but New Expensify does. If you prefer to use Expensify Classic, try again when you have an internet connection.", + quickTip: 'Quick tip...', + quickTipSubTitle: 'You can go straight to Expensify Classic by visiting expensify.com. Bookmark it for an easy shortcut!', + bookACall: 'Book a call', + noThanks: 'No thanks', + bookACallTitle: 'Would you like to speak to a product manager?', + benefits: { + [CONST.EXIT_SURVEY.BENEFIT.CHATTING_DIRECTLY]: 'Chatting directly on expenses and reports', + [CONST.EXIT_SURVEY.BENEFIT.EVERYTHING_MOBILE]: 'Ability to do everything on mobile', + [CONST.EXIT_SURVEY.BENEFIT.TRAVEL_EXPENSE]: 'Travel and expense at the speed of chat', + }, + bookACallTextTop: 'By switching to Expensify Classic, you will miss out on:', + bookACallTextBottom: 'We’d be excited to get on a call with you to understand why. You can book a call with one of our senior product managers to discuss your needs.', }, listBoundary: { errorMessage: 'An error occurred while loading more messages.', diff --git a/src/languages/es.ts b/src/languages/es.ts index d0ca8bc173bd..c04406f07ac7 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -5442,6 +5442,18 @@ const translations = { offlineTitle: 'Parece que estás atrapado aquí...', offline: 'Parece que estás desconectado. Desafortunadamente, Expensify Classic no funciona sin conexión, pero New Expensify sí. Si prefieres utilizar Expensify Classic, inténtalo de nuevo cuando tengas conexión a internet.', + quickTip: 'Consejo rápido...', + quickTipSubTitle: 'Puedes ir directamente a Expensify Classic visitando expensify.com. Márcalo como favorito para tener un acceso directo fácil.', + bookACall: 'Reservar una llamada', + noThanks: 'No, gracias', + bookACallTitle: '¿Desea hablar con un responsable de producto?', + benefits: { + [CONST.EXIT_SURVEY.BENEFIT.CHATTING_DIRECTLY]: 'Charla directa sobre gastos e informes', + [CONST.EXIT_SURVEY.BENEFIT.EVERYTHING_MOBILE]: 'Posibilidad de hacerlo todo desde el móvil', + [CONST.EXIT_SURVEY.BENEFIT.TRAVEL_EXPENSE]: 'Viajes y gastos a la velocidad del chat', + }, + bookACallTextTop: 'Al cambiar a Expensify Classic, se perderá:', + bookACallTextBottom: 'Nos encantaría hablar con usted para entender por qué. Puede concertar una llamada con uno de nuestros jefes de producto para hablar de sus necesidades.', }, listBoundary: { errorMessage: 'Se ha producido un error al cargar más mensajes.', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 8a64424c8f7d..9f19c01fcdf8 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -373,6 +373,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Wallet/ReportCardLostPage').default, [SCREENS.KEYBOARD_SHORTCUTS]: () => require('../../../../pages/KeyboardShortcutsPage').default, [SCREENS.SETTINGS.EXIT_SURVEY.REASON]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyReasonPage').default, + [SCREENS.SETTINGS.EXIT_SURVEY.BOOK_CALL]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyBookCall').default, [SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyResponsePage').default, [SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyConfirmPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT]: () => require('../../../../pages/workspace/accounting/qbo/import/QuickbooksImportPage').default, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 7a5b31489764..72cc4bca036e 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -878,6 +878,9 @@ const config: LinkingOptions['config'] = { [SCREENS.SETTINGS.EXIT_SURVEY.REASON]: { path: ROUTES.SETTINGS_EXIT_SURVEY_REASON, }, + [SCREENS.SETTINGS.EXIT_SURVEY.BOOK_CALL]: { + path: ROUTES.SETTINGS_EXIT_SURVERY_BOOK_CALL, + }, [SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE]: { path: ROUTES.SETTINGS_EXIT_SURVEY_RESPONSE.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index fc9601424080..32f9003c777d 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -777,6 +777,7 @@ type SettingsNavigatorParamList = { }; [SCREENS.KEYBOARD_SHORTCUTS]: undefined; [SCREENS.SETTINGS.EXIT_SURVEY.REASON]: undefined; + [SCREENS.SETTINGS.EXIT_SURVEY.BOOK_CALL]: undefined; [SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE]: { [EXIT_SURVEY_REASON_FORM_INPUT_IDS.REASON]: ValueOf; backTo: Routes; diff --git a/src/pages/settings/ExitSurvey/ExitSurveyBookCall.tsx b/src/pages/settings/ExitSurvey/ExitSurveyBookCall.tsx new file mode 100644 index 000000000000..e268e53c87eb --- /dev/null +++ b/src/pages/settings/ExitSurvey/ExitSurveyBookCall.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import {View} from 'react-native'; +import Button from '@components/Button'; +import FixedFooter from '@components/FixedFooter'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@navigation/Navigation'; +import * as Link from '@userActions/Link'; +import * as Expensicons from '@src/components/Icon/Expensicons'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import ExitSurveyOffline from './ExitSurveyOffline'; + +function ExitSurveyBookCallPage() { + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); + const styles = useThemeStyles(); + + return ( + + Navigation.goBack()} + /> + + {isOffline && } + {!isOffline && ( + <> + {translate('exitSurvey.bookACallTitle')} + {translate('exitSurvey.bookACallTextTop')} + + {Object.values(CONST.EXIT_SURVEY.BENEFIT).map((value) => { + return ( + + + {translate(`exitSurvey.benefits.${value}`)} + + ); + })} + + {translate('exitSurvey.bookACallTextBottom')} + + )} + + + + + + + + + + + + @@ -402,6 +524,7 @@

Get Started

+ - + \ No newline at end of file From 5cb6da7957462823a46876e8cc9524bace9986b4 Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 13:16:50 -0800 Subject: [PATCH 57/66] Split up files --- help/_layouts/default.html | 668 +------------------------------------ help/default.css | 373 +++++++++++++++++++++ help/default.js | 289 ++++++++++++++++ 3 files changed, 664 insertions(+), 666 deletions(-) create mode 100644 help/default.css create mode 100644 help/default.js diff --git a/help/_layouts/default.html b/help/_layouts/default.html index 0dc3a3b5f9c0..906dacd9f2b4 100644 --- a/help/_layouts/default.html +++ b/help/_layouts/default.html @@ -5,381 +5,7 @@ {{ page.title }} - + @@ -525,297 +151,7 @@

Get Started

- + \ No newline at end of file diff --git a/help/default.css b/help/default.css new file mode 100644 index 000000000000..c71cbafcab75 --- /dev/null +++ b/help/default.css @@ -0,0 +1,373 @@ +body { + margin: 0; + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", sans-serif; + background-color: #f9fafb; + color: #333; +} + +/* Header styling */ +.header { + display: flex; + align-items: center; + justify-content: space-between; + background-color: #fff; + padding: 15px 0px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: fixed; + top: 0; + width: 100%; + z-index: 1000; +} + +.logo { + display: flex; + align-items: center; + font-size: 24px; + font-weight: bold; + color: #0366d6; + margin-left: 20px; +} + +.logo a { + text-decoration: none; + color: inherit; +} + +/* Dropdown styling */ +.dropdown { + position: relative; + display: inline-block; + font-size: 24px; /* Match the logo font size */ + font-weight: normal; + text-decoration: underline; + color: #0366d6; + cursor: pointer; +} + +.dropdown-content { + display: none; + position: absolute; + background-color: #fff; + min-width: 160px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); + z-index: 1; + padding: 12px 16px; +} + +.dropdown:hover .dropdown-content { + display: block; +} + +.dropdown a { + text-decoration: none; + color: #0366d6; + padding: 8px 0; + display: block; +} + +.dropdown a.active { + font-weight: bold; + background-color: #eaf5ff; +} + +/* Sidebar navigation for TOC */ +.toc-sidebar { + width: 250px; + position: fixed; + top: 60px; + bottom: 0; + left: 0; + background-color: #fff; + padding: 20px; + overflow-y: auto; + border-right: 1px solid #eaecef; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); + transform: translateY(0); + transition: transform 0.3s ease-in-out; + z-index: 999; +} + +.toc-sidebar.open { + transform: translateY(0); +} + +.toc-link::before { + display: none; +} + +.toc-sidebar ul { + list-style: none; + padding-left: 0; + line-height: 1.0; + font-size: 15px; +} + +.toc-sidebar li { + margin-left: 0; + padding-left: 0; +} + +.js-toc > a { + font-weight: bold; + font-size: 18px; + +} + +.js-toc > ul > li { + margin-top: 25px; +} + +.js-toc > ul > li > a { + font-weight: bold; +} + +.js-toc > ul > li > ul > li > ul > li { + padding-left: 10px; +} + +.toc-sidebar a { + word-wrap: break-word; + display: block; + padding: 1px 10px; + margin-bottom: 5px; + text-decoration: none; + color: #0366d6; + border-radius: 6px; +} + +.toc-sidebar a:hover { + background-color: #f1f8ff; + text-decoration: none; +} + +.toc-sidebar .is-active-link { + background-color: #eaf5ff; + color: #0366d6; + border-radius: 6px; +} + +/* Main content area */ +main { + margin-left: 300px; + padding: 20px; + flex-grow: 1; + max-width: 900px; +} + +main h1 { + display: none; +} + +main h2 { + font-size: 28px; + margin-bottom: 16px; +} + +main h3 { + font-size: 24px; + margin-bottom: 12px; +} + +main h4 { + font-size: 20px; + margin-bottom: 12px; +} + +main p { + font-size: 16px; + line-height: 1.6; + margin-bottom: 20px; +} + +.is-active-link { + font-weight: normal; +} + +.scroll-spacer { + height: 300px; +} + +/* Footer */ +footer { + margin-left: 300px; + color: #0366d6; + background-color: #f9fafb; + padding: 40px 20px; + font-size: 14px; + max-width: 900px; +} + +footer h3 { + color: #0366d6; +} + +footer ul { + list-style: none; + padding: 0; +} + +footer ul li a { + color: #0366d6; + text-decoration: none; +} + +footer ul li a:hover { + text-decoration: underline; +} + +footer .social-icons a img { + width: 20px; + margin-right: 10px; +} + +.footer-container { + display: flex; + justify-content: center; + max-width: 1200px; + margin: 0 auto; +} + +.footer-column { + flex: 1; + max-width: 300px; /* Set a max-width for each column */ + padding: 0 20px; /* Add padding for some space between the columns */ +} + +/* Mobile Styles */ +.hamburger { + display: none; + cursor: pointer; + flex-direction: column; + justify-content: space-between; + width: 24px; + height: 18px; +} + +.bar { + height: 3px; + width: 100%; + background-color: #0366d6; + border-radius: 10px; +} + +@media (max-width: 768px) { + + .hamburger { + display: flex; + margin-right: 20px; + } + + .toc-sidebar { + transform: translateY(-100%); + width: 100%; + } + + main { + margin-left: 0; + padding: 20px; + max-width: 100%; + } + + footer { + display: none; + } +} + +/* Modal background */ +#search-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + z-index: 1000; + display: flex; + justify-content: center; + align-items: flex-start; +} + +/* Modal content */ +#modal-content { + top: 20%; + background: white; + padding: 20px; + width: 60%; + max-width: 600px; + position: relative; + border-radius: 6px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); +} + +/* Search input with magnifying glass */ +.search-icon-wrapper { + display: flex; + align-items: center; + width: 100%; + padding: 8px; + border: 1px solid #eaecef; + border-radius: 6px; + box-sizing: border-box; +} + +.search-icon { + font-size: 18px; + margin-right: 8px; +} + +/* Updated input style */ +#search-input { + width: 100%; + border: none; + outline: none; + font-size: 20px; +} + +/* Search results */ +#search-results { + margin-top: 20px; + max-height: 300px; + overflow-y: auto; + border-top: 1px solid #eaecef; + padding-top: 10px; + outline: none; /* Disable the strong outline */ +} + +.search-result { + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 1px solid #eaecef; +} + +.search-result-title { + font-weight: bold; + margin-bottom: 5px; + color: #0366d6; + text-decoration: none; +} + +.search-result-title:hover { + text-decoration: underline; +} + +.search-result-context { + font-size: 14px; + color: #586069; +} + +/* Highlighted search result */ +.highlight { + background-color: #eaecef; +} + +/* Softer focus style for search results */ +#search-results:focus { + border: 2px solid #ddd; /* Softer border on focus */ + outline: none; +} + +/* Soft yellow highlight for selected section */ +.highlight-section { + background-color: #fffbcc; + transition: background-color 0.3s ease; +} \ No newline at end of file diff --git a/help/default.js b/help/default.js new file mode 100644 index 000000000000..b92433e121ac --- /dev/null +++ b/help/default.js @@ -0,0 +1,289 @@ +function updateURLHashOnScroll() { + const activeLink = document.querySelector('.toc-sidebar .is-active-link'); + if (activeLink) { + const hash = activeLink.getAttribute('href'); + if (history.pushState) { + history.pushState(null, null, hash); + } else { + window.location.hash = hash; + } + } +} + +function scrollActiveLinkIntoView() { + const activeLink = document.querySelector('.toc-sidebar .is-active-link'); + if (activeLink) { + activeLink.scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } +} + +tocbot.init({ + tocSelector: '.js-toc', + contentSelector: '.js-toc-content', + headingSelector: 'h1, h2, h3, h4, h5, h6', + collapseDepth: 4, + orderedList: false, + scrollSmooth: true, + scrollToActive: true, + enableUrlHashUpdateOnScroll: false, + headingsOffset: 80, + scrollSmoothOffset: -80, + tocScrollingWrapper: document.querySelector('.toc-sidebar'), + tocScrollOffset: 80, + headingObjectCallback: function(obj, element) { + const tocTitle = element.getAttribute('data-toc-title'); + if (tocTitle) { + obj.textContent = tocTitle; + } + return obj; + }, + onClick: function(e) { + setTimeout(scrollActiveLinkIntoView, 300); + document.getElementById('toc-sidebar').classList.remove('open'); // Close TOC after clicking + }, + scrollEndCallback: function() { + updateURLHashOnScroll(); + scrollActiveLinkIntoView(); + } +}); + +function adjustAnchorOnLoad() { + if (window.location.hash) { + const element = document.querySelector(window.location.hash); + if (element) { + window.scrollTo({ + top: element.getBoundingClientRect().top + window.pageYOffset - 80, + behavior: 'smooth' + }); + } + } +} + +window.addEventListener('load', adjustAnchorOnLoad); + +// Toggle sidebar on hamburger click +document.getElementById('hamburger').addEventListener('click', function() { + var sidebar = document.getElementById('toc-sidebar'); + sidebar.classList.toggle('open'); +}); + +// Keep track of the search results +let g_searchResultsArray = []; +let g_currentSelectionIndex = -1; +let g_highlightedSection = null; + +// Declare the index variable globally so it can be reused +let g_index = null; + +// Look up some commonly used elements once +const g_searchIcon = document.getElementById('search-icon'); +const g_searchModal = document.getElementById('search-modal'); +const g_searchResults = document.getElementById('search-results'); +const g_searchInput = document.getElementById('search-input'); + +// Show and initialize the search modal +function showSearchModal() { + g_searchModal.style.display = 'flex'; + if (g_searchResultsArray.length > 0) { + g_searchResults.style.display = 'block'; + g_searchResults.focus(); // Focus on search results if they exist + } else { + g_searchInput.focus(); + } +} + +// Open modal when search icon is clicked +g_searchIcon.addEventListener('click', showSearchModal); + +// Open modal when Cmd+K is pressed +document.addEventListener('keydown', function(event) { + if (event.metaKey && event.key === 'k') { + event.preventDefault(); + showSearchModal(); + } +}); + +// Close modal when pressing "Escape" +document.addEventListener('keydown', function(event) { + if (event.key === 'Escape' && g_searchModal.style.display === 'flex') { + g_searchModal.style.display = 'none'; + } +}); + +// Close modal when clicking outside of modal content +window.addEventListener('click', function(event) { + if (event.target == g_searchModal) { + g_searchModal.style.display = 'none'; + } +}); + +// Handle keyboard navigation (arrow keys and enter) +g_searchResults.addEventListener('keydown', function(event) { + // If the modal is being shown and has active search results, capture keydown + if (g_searchModal.style.display === 'flex' && g_searchResultsArray.length > 0) { + if (event.key === 'ArrowDown') { + event.preventDefault(); + selectNextResult(); + } else if (event.key === 'ArrowUp') { + event.preventDefault(); + selectPreviousResult(); + } else if (event.key === 'Enter' && g_currentSelectionIndex >= 0) { + event.preventDefault(); + navigateToSelectedResult(); + } else if (!['Tab', 'Shift'].includes(event.key)) { + g_searchInput.focus(); // Focus back on input if typing occurs + } + } +}); + +function selectNextResult() { + if (g_currentSelectionIndex < g_searchResultsArray.length - 1) { + g_currentSelectionIndex++; + updateSelectedResult(); + } +} + +function selectPreviousResult() { + if (g_currentSelectionIndex > 0) { + g_currentSelectionIndex--; + updateSelectedResult(); + } +} + +function updateSelectedResult() { + g_searchResultsArray.forEach((result, index) => { + if (index === g_currentSelectionIndex) { + result.classList.add('highlight'); + result.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } else { + result.classList.remove('highlight'); + } + }); +} + +function navigateToSelectedResult() { + const selectedResult = g_searchResultsArray[g_currentSelectionIndex]; + const link = selectedResult.querySelector('a'); + if (link) { + link.click(); + } +} + +// Execute search when pressing "Enter" in the input field +g_searchInput.addEventListener('keydown', function(event) { + if (event.key === 'Enter') { + event.preventDefault(); + g_searchSubmit.click(); + } +}); + +// Perform search when search button is clicked +const g_searchSubmit = document.getElementById('search-submit'); + +// Handle submitting the search query +g_searchSubmit.addEventListener('click', async function() { + const query = g_searchInput.value.trim().toLowerCase(); + g_searchResults.innerHTML = ''; + g_currentSelectionIndex = -1; + + if (query.length === 0) { + g_searchResults.style.display = 'none'; + return; + } + + // Load the JSON search index file, if not already defined + if (g_index === null) { + console.log('Loading search index from:', '/searchIndex.json'); + const response = await fetch('/searchIndex.json'); + const indexData = await response.json(); + g_index = new FlexSearch.Document({ + document: { + id: 'id', + index: ['content'], // Index on the content field + store: ['title', 'url', 'content'], // Store title, URL, and content + } + }); + + // Import the index + for (const [key, data] of Object.entries(indexData)) { + await g_index.import(key, data); + } + } else { + console.log('Reusing existing search index'); + } + + // Perform search + const results = await g_index.search({ + query, + field: 'content' + }); + + if (results.length > 0) { + g_searchResultsArray = []; + results.forEach(result => { + result.result.forEach(docId => { + const doc = g_index.store[docId]; + if (doc && doc.content) { + const searchTermIndex = doc.content.toLowerCase().indexOf(query); + const contextBefore = doc.content.substring(Math.max(0, searchTermIndex - 30), searchTermIndex); + const contextAfter = doc.content.substring(searchTermIndex + query.length, Math.min(doc.content.length, searchTermIndex + query.length + 30)); + const searchResultHtml = ` +
+ ${doc.title} +
...${contextBefore}${query}${contextAfter}...
+
+ `; + const resultElement = document.createElement('div'); + resultElement.innerHTML = searchResultHtml; + g_searchResults.appendChild(resultElement); + g_searchResultsArray.push(resultElement); + + // Automatically select the first result + if (g_searchResultsArray.length === 1) { + g_currentSelectionIndex = 0; + updateSelectedResult(); + } + } + }); + }); + g_searchResults.style.display = 'block'; + g_searchResults.focus(); // Focus on search results whenever there are results + } else { + g_searchResults.style.display = 'none'; + } +}); + +// Trigger the TOC link click to use TocBot's smooth scrolling behavior +function scrollToTOC(url) { + const elementId = url.split('#')[1]; + const tocLink = document.querySelector(`.toc-sidebar a[href="#${elementId}"]`); + + if (tocLink) { + tocLink.click(); // Simulate a click on the TOC link for smooth scroll + highlightSelectedSection(elementId); // Highlight the section in yellow + closeModalAfterClick(); + } +} + +// Highlight the selected section +function highlightSelectedSection(sectionId) { + // Remove the previous highlight, if any + if (g_highlightedSection) { + g_highlightedSection.classList.remove('highlight-section'); + } + + // Highlight the new section + const sectionElement = document.getElementById(sectionId); + if (sectionElement) { + sectionElement.classList.add('highlight-section'); + g_highlightedSection = sectionElement; + } +} + +// Close modal after clicking a search result +function closeModalAfterClick() { + g_searchModal.style.display = 'none'; +} \ No newline at end of file From efdebefab9c4a6b1d4a75d567c352ca3a9cd100c Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 14:23:21 -0800 Subject: [PATCH 58/66] Prettified the JS --- help/default.js | 86 ++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/help/default.js b/help/default.js index b92433e121ac..0884de48bab2 100644 --- a/help/default.js +++ b/help/default.js @@ -15,39 +15,39 @@ function scrollActiveLinkIntoView() { if (activeLink) { activeLink.scrollIntoView({ behavior: 'smooth', - block: 'nearest' + block: 'nearest', }); } } tocbot.init({ - tocSelector: '.js-toc', - contentSelector: '.js-toc-content', - headingSelector: 'h1, h2, h3, h4, h5, h6', - collapseDepth: 4, - orderedList: false, - scrollSmooth: true, - scrollToActive: true, - enableUrlHashUpdateOnScroll: false, - headingsOffset: 80, - scrollSmoothOffset: -80, - tocScrollingWrapper: document.querySelector('.toc-sidebar'), - tocScrollOffset: 80, - headingObjectCallback: function(obj, element) { - const tocTitle = element.getAttribute('data-toc-title'); - if (tocTitle) { - obj.textContent = tocTitle; - } - return obj; - }, - onClick: function(e) { - setTimeout(scrollActiveLinkIntoView, 300); - document.getElementById('toc-sidebar').classList.remove('open'); // Close TOC after clicking - }, - scrollEndCallback: function() { - updateURLHashOnScroll(); - scrollActiveLinkIntoView(); - } + tocSelector: '.js-toc', + contentSelector: '.js-toc-content', + headingSelector: 'h1, h2, h3, h4, h5, h6', + collapseDepth: 4, + orderedList: false, + scrollSmooth: true, + scrollToActive: true, + enableUrlHashUpdateOnScroll: false, + headingsOffset: 80, + scrollSmoothOffset: -80, + tocScrollingWrapper: document.querySelector('.toc-sidebar'), + tocScrollOffset: 80, + headingObjectCallback: function (obj, element) { + const tocTitle = element.getAttribute('data-toc-title'); + if (tocTitle) { + obj.textContent = tocTitle; + } + return obj; + }, + onClick: function (e) { + setTimeout(scrollActiveLinkIntoView, 300); + document.getElementById('toc-sidebar').classList.remove('open'); // Close TOC after clicking + }, + scrollEndCallback: function () { + updateURLHashOnScroll(); + scrollActiveLinkIntoView(); + }, }); function adjustAnchorOnLoad() { @@ -56,7 +56,7 @@ function adjustAnchorOnLoad() { if (element) { window.scrollTo({ top: element.getBoundingClientRect().top + window.pageYOffset - 80, - behavior: 'smooth' + behavior: 'smooth', }); } } @@ -65,7 +65,7 @@ function adjustAnchorOnLoad() { window.addEventListener('load', adjustAnchorOnLoad); // Toggle sidebar on hamburger click -document.getElementById('hamburger').addEventListener('click', function() { +document.getElementById('hamburger').addEventListener('click', function () { var sidebar = document.getElementById('toc-sidebar'); sidebar.classList.toggle('open'); }); @@ -99,7 +99,7 @@ function showSearchModal() { g_searchIcon.addEventListener('click', showSearchModal); // Open modal when Cmd+K is pressed -document.addEventListener('keydown', function(event) { +document.addEventListener('keydown', function (event) { if (event.metaKey && event.key === 'k') { event.preventDefault(); showSearchModal(); @@ -107,21 +107,21 @@ document.addEventListener('keydown', function(event) { }); // Close modal when pressing "Escape" -document.addEventListener('keydown', function(event) { +document.addEventListener('keydown', function (event) { if (event.key === 'Escape' && g_searchModal.style.display === 'flex') { g_searchModal.style.display = 'none'; } }); // Close modal when clicking outside of modal content -window.addEventListener('click', function(event) { +window.addEventListener('click', function (event) { if (event.target == g_searchModal) { g_searchModal.style.display = 'none'; } }); // Handle keyboard navigation (arrow keys and enter) -g_searchResults.addEventListener('keydown', function(event) { +g_searchResults.addEventListener('keydown', function (event) { // If the modal is being shown and has active search results, capture keydown if (g_searchModal.style.display === 'flex' && g_searchResultsArray.length > 0) { if (event.key === 'ArrowDown') { @@ -157,7 +157,7 @@ function updateSelectedResult() { g_searchResultsArray.forEach((result, index) => { if (index === g_currentSelectionIndex) { result.classList.add('highlight'); - result.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + result.scrollIntoView({behavior: 'smooth', block: 'nearest'}); } else { result.classList.remove('highlight'); } @@ -173,7 +173,7 @@ function navigateToSelectedResult() { } // Execute search when pressing "Enter" in the input field -g_searchInput.addEventListener('keydown', function(event) { +g_searchInput.addEventListener('keydown', function (event) { if (event.key === 'Enter') { event.preventDefault(); g_searchSubmit.click(); @@ -184,7 +184,7 @@ g_searchInput.addEventListener('keydown', function(event) { const g_searchSubmit = document.getElementById('search-submit'); // Handle submitting the search query -g_searchSubmit.addEventListener('click', async function() { +g_searchSubmit.addEventListener('click', async function () { const query = g_searchInput.value.trim().toLowerCase(); g_searchResults.innerHTML = ''; g_currentSelectionIndex = -1; @@ -204,7 +204,7 @@ g_searchSubmit.addEventListener('click', async function() { id: 'id', index: ['content'], // Index on the content field store: ['title', 'url', 'content'], // Store title, URL, and content - } + }, }); // Import the index @@ -218,13 +218,13 @@ g_searchSubmit.addEventListener('click', async function() { // Perform search const results = await g_index.search({ query, - field: 'content' + field: 'content', }); if (results.length > 0) { g_searchResultsArray = []; - results.forEach(result => { - result.result.forEach(docId => { + results.forEach((result) => { + result.result.forEach((docId) => { const doc = g_index.store[docId]; if (doc && doc.content) { const searchTermIndex = doc.content.toLowerCase().indexOf(query); @@ -250,7 +250,7 @@ g_searchSubmit.addEventListener('click', async function() { }); }); g_searchResults.style.display = 'block'; - g_searchResults.focus(); // Focus on search results whenever there are results + g_searchResults.focus(); // Focus on search results whenever there are results } else { g_searchResults.style.display = 'none'; } @@ -286,4 +286,4 @@ function highlightSelectedSection(sectionId) { // Close modal after clicking a search result function closeModalAfterClick() { g_searchModal.style.display = 'none'; -} \ No newline at end of file +} From cdb71f320b46b1ce68fd7c04ab2731dcd08f1b16 Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 14:48:11 -0800 Subject: [PATCH 59/66] Fixed a lot of lint errors --- help/default.js | 123 ++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 68 deletions(-) diff --git a/help/default.js b/help/default.js index 0884de48bab2..ba85a8306680 100644 --- a/help/default.js +++ b/help/default.js @@ -1,12 +1,11 @@ function updateURLHashOnScroll() { const activeLink = document.querySelector('.toc-sidebar .is-active-link'); - if (activeLink) { - const hash = activeLink.getAttribute('href'); - if (history.pushState) { - history.pushState(null, null, hash); - } else { - window.location.hash = hash; - } + if (!activeLink) return; + const hash = activeLink.getAttribute('href'); + if (window.history.pushState) { + window.history.pushState(null, null, hash); + } else { + window.location.hash = hash; } } @@ -20,7 +19,8 @@ function scrollActiveLinkIntoView() { } } -tocbot.init({ +// Assuming tocbot is globally defined +window.tocbot.init({ tocSelector: '.js-toc', contentSelector: '.js-toc-content', headingSelector: 'h1, h2, h3, h4, h5, h6', @@ -33,32 +33,33 @@ tocbot.init({ scrollSmoothOffset: -80, tocScrollingWrapper: document.querySelector('.toc-sidebar'), tocScrollOffset: 80, - headingObjectCallback: function (obj, element) { + headingObjectCallback(obj, element) { const tocTitle = element.getAttribute('data-toc-title'); if (tocTitle) { - obj.textContent = tocTitle; + const newObj = { ...obj }; + newObj.textContent = tocTitle; + return newObj; } return obj; }, - onClick: function (e) { + onClick() { setTimeout(scrollActiveLinkIntoView, 300); - document.getElementById('toc-sidebar').classList.remove('open'); // Close TOC after clicking + document.getElementById('toc-sidebar').classList.remove('open'); }, - scrollEndCallback: function () { + scrollEndCallback() { updateURLHashOnScroll(); scrollActiveLinkIntoView(); }, }); function adjustAnchorOnLoad() { - if (window.location.hash) { - const element = document.querySelector(window.location.hash); - if (element) { - window.scrollTo({ - top: element.getBoundingClientRect().top + window.pageYOffset - 80, - behavior: 'smooth', - }); - } + if (!window.location.hash) return; + const element = document.querySelector(window.location.hash); + if (element) { + window.scrollTo({ + top: element.getBoundingClientRect().top + window.pageYOffset - 80, + behavior: 'smooth', + }); } } @@ -66,7 +67,7 @@ window.addEventListener('load', adjustAnchorOnLoad); // Toggle sidebar on hamburger click document.getElementById('hamburger').addEventListener('click', function () { - var sidebar = document.getElementById('toc-sidebar'); + let sidebar = document.getElementById('toc-sidebar'); sidebar.classList.toggle('open'); }); @@ -89,7 +90,7 @@ function showSearchModal() { g_searchModal.style.display = 'flex'; if (g_searchResultsArray.length > 0) { g_searchResults.style.display = 'block'; - g_searchResults.focus(); // Focus on search results if they exist + g_searchResults.focus(); } else { g_searchInput.focus(); } @@ -115,42 +116,38 @@ document.addEventListener('keydown', function (event) { // Close modal when clicking outside of modal content window.addEventListener('click', function (event) { - if (event.target == g_searchModal) { + if (event.target === g_searchModal) { g_searchModal.style.display = 'none'; } }); // Handle keyboard navigation (arrow keys and enter) g_searchResults.addEventListener('keydown', function (event) { - // If the modal is being shown and has active search results, capture keydown - if (g_searchModal.style.display === 'flex' && g_searchResultsArray.length > 0) { - if (event.key === 'ArrowDown') { - event.preventDefault(); - selectNextResult(); - } else if (event.key === 'ArrowUp') { - event.preventDefault(); - selectPreviousResult(); - } else if (event.key === 'Enter' && g_currentSelectionIndex >= 0) { - event.preventDefault(); - navigateToSelectedResult(); - } else if (!['Tab', 'Shift'].includes(event.key)) { - g_searchInput.focus(); // Focus back on input if typing occurs - } + if (g_searchModal.style.display !== 'flex' || g_searchResultsArray.length === 0) return; + if (event.key === 'ArrowDown') { + event.preventDefault(); + selectNextResult(); + } else if (event.key === 'ArrowUp') { + event.preventDefault(); + selectPreviousResult(); + } else if (event.key === 'Enter' && g_currentSelectionIndex >= 0) { + event.preventDefault(); + navigateToSelectedResult(); + } else if (!['Tab', 'Shift'].includes(event.key)) { + g_searchInput.focus(); } }); function selectNextResult() { - if (g_currentSelectionIndex < g_searchResultsArray.length - 1) { - g_currentSelectionIndex++; - updateSelectedResult(); - } + if (g_currentSelectionIndex >= g_searchResultsArray.length - 1) return; + g_currentSelectionIndex++; + updateSelectedResult(); } function selectPreviousResult() { - if (g_currentSelectionIndex > 0) { - g_currentSelectionIndex--; - updateSelectedResult(); - } + if (g_currentSelectionIndex <= 0) return; + g_currentSelectionIndex--; + updateSelectedResult(); } function updateSelectedResult() { @@ -176,15 +173,13 @@ function navigateToSelectedResult() { g_searchInput.addEventListener('keydown', function (event) { if (event.key === 'Enter') { event.preventDefault(); - g_searchSubmit.click(); + document.getElementById('search-submit').click(); } }); // Perform search when search button is clicked -const g_searchSubmit = document.getElementById('search-submit'); - -// Handle submitting the search query -g_searchSubmit.addEventListener('click', async function () { +// Assuming search-submit is defined +document.getElementById('search-submit').addEventListener('click', async function () { const query = g_searchInput.value.trim().toLowerCase(); g_searchResults.innerHTML = ''; g_currentSelectionIndex = -1; @@ -194,28 +189,23 @@ g_searchSubmit.addEventListener('click', async function () { return; } - // Load the JSON search index file, if not already defined if (g_index === null) { - console.log('Loading search index from:', '/searchIndex.json'); + // Assuming the fetch works correctly without console.log const response = await fetch('/searchIndex.json'); const indexData = await response.json(); - g_index = new FlexSearch.Document({ + g_index = new window.FlexSearch.Document({ document: { id: 'id', - index: ['content'], // Index on the content field - store: ['title', 'url', 'content'], // Store title, URL, and content + index: ['content'], + store: ['title', 'url', 'content'], }, }); - // Import the index for (const [key, data] of Object.entries(indexData)) { - await g_index.import(key, data); + g_index.import(key, data); } - } else { - console.log('Reusing existing search index'); } - // Perform search const results = await g_index.search({ query, field: 'content', @@ -241,7 +231,6 @@ g_searchSubmit.addEventListener('click', async function () { g_searchResults.appendChild(resultElement); g_searchResultsArray.push(resultElement); - // Automatically select the first result if (g_searchResultsArray.length === 1) { g_currentSelectionIndex = 0; updateSelectedResult(); @@ -250,7 +239,7 @@ g_searchSubmit.addEventListener('click', async function () { }); }); g_searchResults.style.display = 'block'; - g_searchResults.focus(); // Focus on search results whenever there are results + g_searchResults.focus(); } else { g_searchResults.style.display = 'none'; } @@ -262,20 +251,18 @@ function scrollToTOC(url) { const tocLink = document.querySelector(`.toc-sidebar a[href="#${elementId}"]`); if (tocLink) { - tocLink.click(); // Simulate a click on the TOC link for smooth scroll - highlightSelectedSection(elementId); // Highlight the section in yellow + tocLink.click(); + highlightSelectedSection(elementId); closeModalAfterClick(); } } // Highlight the selected section function highlightSelectedSection(sectionId) { - // Remove the previous highlight, if any if (g_highlightedSection) { g_highlightedSection.classList.remove('highlight-section'); } - // Highlight the new section const sectionElement = document.getElementById(sectionId); if (sectionElement) { sectionElement.classList.add('highlight-section'); @@ -286,4 +273,4 @@ function highlightSelectedSection(sectionId) { // Close modal after clicking a search result function closeModalAfterClick() { g_searchModal.style.display = 'none'; -} +} \ No newline at end of file From 7b4eebf90465c5f4425ccbd0ed05c7b2aeb7871e Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 14:52:18 -0800 Subject: [PATCH 60/66] Prettied the code --- help/default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/help/default.js b/help/default.js index ba85a8306680..d8e75413597a 100644 --- a/help/default.js +++ b/help/default.js @@ -36,7 +36,7 @@ window.tocbot.init({ headingObjectCallback(obj, element) { const tocTitle = element.getAttribute('data-toc-title'); if (tocTitle) { - const newObj = { ...obj }; + const newObj = {...obj}; newObj.textContent = tocTitle; return newObj; } @@ -273,4 +273,4 @@ function highlightSelectedSection(sectionId) { // Close modal after clicking a search result function closeModalAfterClick() { g_searchModal.style.display = 'none'; -} \ No newline at end of file +} From e8e3ce21848519e0737163c390b503d498578e48 Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 15:35:38 -0800 Subject: [PATCH 61/66] fixing more lint/pretty issues --- help/default.js | 80 ++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/help/default.js b/help/default.js index d8e75413597a..84a8991ac9f2 100644 --- a/help/default.js +++ b/help/default.js @@ -1,6 +1,8 @@ function updateURLHashOnScroll() { const activeLink = document.querySelector('.toc-sidebar .is-active-link'); - if (!activeLink) return; + if (!activeLink) { + return; + } const hash = activeLink.getAttribute('href'); if (window.history.pushState) { window.history.pushState(null, null, hash); @@ -53,7 +55,9 @@ window.tocbot.init({ }); function adjustAnchorOnLoad() { - if (!window.location.hash) return; + if (!window.location.hash) { + return; + } const element = document.querySelector(window.location.hash); if (element) { window.scrollTo({ @@ -67,7 +71,7 @@ window.addEventListener('load', adjustAnchorOnLoad); // Toggle sidebar on hamburger click document.getElementById('hamburger').addEventListener('click', function () { - let sidebar = document.getElementById('toc-sidebar'); + const sidebar = document.getElementById('toc-sidebar'); sidebar.classList.toggle('open'); }); @@ -123,7 +127,9 @@ window.addEventListener('click', function (event) { // Handle keyboard navigation (arrow keys and enter) g_searchResults.addEventListener('keydown', function (event) { - if (g_searchModal.style.display !== 'flex' || g_searchResultsArray.length === 0) return; + if (g_searchModal.style.display !== 'flex' || g_searchResultsArray.length === 0) { + return; + } if (event.key === 'ArrowDown') { event.preventDefault(); selectNextResult(); @@ -139,13 +145,17 @@ g_searchResults.addEventListener('keydown', function (event) { }); function selectNextResult() { - if (g_currentSelectionIndex >= g_searchResultsArray.length - 1) return; + if (g_currentSelectionIndex >= g_searchResultsArray.length - 1) { + return; + } g_currentSelectionIndex++; updateSelectedResult(); } function selectPreviousResult() { - if (g_currentSelectionIndex <= 0) return; + if (g_currentSelectionIndex <= 0) { + return; + } g_currentSelectionIndex--; updateSelectedResult(); } @@ -179,7 +189,7 @@ g_searchInput.addEventListener('keydown', function (event) { // Perform search when search button is clicked // Assuming search-submit is defined -document.getElementById('search-submit').addEventListener('click', async function () { +document.getElementById('search-submit').addEventListener('click', function () { const query = g_searchInput.value.trim().toLowerCase(); g_searchResults.innerHTML = ''; g_currentSelectionIndex = -1; @@ -191,27 +201,35 @@ document.getElementById('search-submit').addEventListener('click', async functio if (g_index === null) { // Assuming the fetch works correctly without console.log - const response = await fetch('/searchIndex.json'); - const indexData = await response.json(); - g_index = new window.FlexSearch.Document({ - document: { - id: 'id', - index: ['content'], - store: ['title', 'url', 'content'], - }, - }); + fetch('/searchIndex.json') + .then((response) => response.json()) + .then((indexData) => { + g_index = new window.FlexSearch.Document({ + document: { + id: 'id', + index: ['content'], + store: ['title', 'url', 'content'], + }, + }); - for (const [key, data] of Object.entries(indexData)) { - g_index.import(key, data); - } + for (const [key, data] of Object.entries(indexData)) { + g_index.import(key, data); + } + + performSearch(query); + }); + } else { + performSearch(query); } +}); - const results = await g_index.search({ +function performSearch(query) { + const results = g_index.search({ query, field: 'content', }); - if (results.length > 0) { + if (results && results.length > 0) { g_searchResultsArray = []; results.forEach((result) => { result.result.forEach((docId) => { @@ -221,10 +239,10 @@ document.getElementById('search-submit').addEventListener('click', async functio const contextBefore = doc.content.substring(Math.max(0, searchTermIndex - 30), searchTermIndex); const contextAfter = doc.content.substring(searchTermIndex + query.length, Math.min(doc.content.length, searchTermIndex + query.length + 30)); const searchResultHtml = ` -
- ${doc.title} -
...${contextBefore}${query}${contextAfter}...
-
+
+ ${doc.title} +
...${contextBefore}${query}${contextAfter}...
+
`; const resultElement = document.createElement('div'); resultElement.innerHTML = searchResultHtml; @@ -243,18 +261,6 @@ document.getElementById('search-submit').addEventListener('click', async functio } else { g_searchResults.style.display = 'none'; } -}); - -// Trigger the TOC link click to use TocBot's smooth scrolling behavior -function scrollToTOC(url) { - const elementId = url.split('#')[1]; - const tocLink = document.querySelector(`.toc-sidebar a[href="#${elementId}"]`); - - if (tocLink) { - tocLink.click(); - highlightSelectedSection(elementId); - closeModalAfterClick(); - } } // Highlight the selected section From 6bce953fe5d67d76705b32eb534a168cbca29968 Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 16:14:30 -0800 Subject: [PATCH 62/66] More lint fixes --- help/default.js | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/help/default.js b/help/default.js index 84a8991ac9f2..3ebb4a37de5b 100644 --- a/help/default.js +++ b/help/default.js @@ -105,24 +105,27 @@ g_searchIcon.addEventListener('click', showSearchModal); // Open modal when Cmd+K is pressed document.addEventListener('keydown', function (event) { - if (event.metaKey && event.key === 'k') { - event.preventDefault(); - showSearchModal(); + if (!(event.metaKey && event.key === 'k')) { + return; } + event.preventDefault(); + showSearchModal(); }); // Close modal when pressing "Escape" document.addEventListener('keydown', function (event) { - if (event.key === 'Escape' && g_searchModal.style.display === 'flex') { - g_searchModal.style.display = 'none'; + if (!(event.key === 'Escape' && g_searchModal.style.display === 'flex')) { + return; } + g_searchModal.style.display = 'none'; }); // Close modal when clicking outside of modal content window.addEventListener('click', function (event) { - if (event.target === g_searchModal) { - g_searchModal.style.display = 'none'; + if (!(event.target === g_searchModal)) { + return; } + g_searchModal.style.display = 'none'; }); // Handle keyboard navigation (arrow keys and enter) @@ -181,10 +184,11 @@ function navigateToSelectedResult() { // Execute search when pressing "Enter" in the input field g_searchInput.addEventListener('keydown', function (event) { - if (event.key === 'Enter') { - event.preventDefault(); - document.getElementById('search-submit').click(); + if (!(event.key === 'Enter')) { + return; } + event.preventDefault(); + document.getElementById('search-submit').click(); }); // Perform search when search button is clicked @@ -262,21 +266,3 @@ function performSearch(query) { g_searchResults.style.display = 'none'; } } - -// Highlight the selected section -function highlightSelectedSection(sectionId) { - if (g_highlightedSection) { - g_highlightedSection.classList.remove('highlight-section'); - } - - const sectionElement = document.getElementById(sectionId); - if (sectionElement) { - sectionElement.classList.add('highlight-section'); - g_highlightedSection = sectionElement; - } -} - -// Close modal after clicking a search result -function closeModalAfterClick() { - g_searchModal.style.display = 'none'; -} From 4715f2e54208a2d37f38a9ebbfdab3a6bdef33d1 Mon Sep 17 00:00:00 2001 From: David Barrett Date: Sun, 17 Nov 2024 16:25:49 -0800 Subject: [PATCH 63/66] Even more lint fixes --- help/default.js | 1 - 1 file changed, 1 deletion(-) diff --git a/help/default.js b/help/default.js index 3ebb4a37de5b..1c27ade6c9e1 100644 --- a/help/default.js +++ b/help/default.js @@ -78,7 +78,6 @@ document.getElementById('hamburger').addEventListener('click', function () { // Keep track of the search results let g_searchResultsArray = []; let g_currentSelectionIndex = -1; -let g_highlightedSection = null; // Declare the index variable globally so it can be reused let g_index = null; From 697fd4585973bb477d06ab273a865628ba84bf78 Mon Sep 17 00:00:00 2001 From: Tom Rhys Jones Date: Mon, 18 Nov 2024 11:33:04 +0000 Subject: [PATCH 64/66] casing fix.ts Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 728954acd7f7..726b2dc186f1 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -134,7 +134,7 @@ const onboardingEmployerOrSubmitMessage: OnboardingMessage = { '\n' + 'Here’s how to set up your bank account:\n' + '\n' + - '1. Click the Settings tab.\n' + + '1. Click the settings tab.\n' + '2. Click *Wallet* > *Bank accounts* > *+ Add bank account*.\n' + '3. Connect your bank account.\n' + '\n' + From f3ddea633accba7bb733cacf9dbcaabb790932e1 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 18 Nov 2024 15:53:29 +0100 Subject: [PATCH 65/66] update whitelisted report keys --- src/types/utils/whitelistedReportKeys.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/utils/whitelistedReportKeys.ts b/src/types/utils/whitelistedReportKeys.ts index 3c566c987526..3b06872147e4 100644 --- a/src/types/utils/whitelistedReportKeys.ts +++ b/src/types/utils/whitelistedReportKeys.ts @@ -12,7 +12,6 @@ type WhitelistedReport = OnyxCommon.OnyxValueWithOfflineFeedback< hasOutstandingChildRequest: unknown; hasOutstandingChildTask: unknown; isOwnPolicyExpenseChat: unknown; - isPolicyExpenseChat: unknown; isPinned: unknown; lastMessageText: unknown; lastVisibleActionCreated: unknown; From a8ee09fbeed5fbe98fbeb9cce5647b4a505510e7 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 18 Nov 2024 15:55:32 +0100 Subject: [PATCH 66/66] update whitelisted report keys --- src/types/utils/whitelistedReportKeys.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/types/utils/whitelistedReportKeys.ts b/src/types/utils/whitelistedReportKeys.ts index 3c566c987526..c74c86aaa4fa 100644 --- a/src/types/utils/whitelistedReportKeys.ts +++ b/src/types/utils/whitelistedReportKeys.ts @@ -43,7 +43,6 @@ type WhitelistedReport = OnyxCommon.OnyxValueWithOfflineFeedback< isOptimisticReport: unknown; managerID: unknown; lastVisibleActionLastModified: unknown; - displayName: unknown; lastMessageHtml: unknown; lastActorAccountID: unknown; lastActionType: unknown; @@ -52,7 +51,6 @@ type WhitelistedReport = OnyxCommon.OnyxValueWithOfflineFeedback< total: unknown; unheldTotal: unknown; currency: unknown; - errors: unknown; errorFields: unknown; isWaitingOnBankAccount: unknown; isCancelledIOU: unknown;