|
| 1 | +import {useCallback, useMemo, useState} from 'react'; |
| 2 | +import DateUtils from '@libs/DateUtils'; |
| 3 | +import {isCreatedAction} from '@libs/ReportActionsUtils'; |
| 4 | +import {buildConciergeGreetingReportAction} from '@libs/ReportUtils'; |
| 5 | +import type * as OnyxTypes from '@src/types/onyx'; |
| 6 | + |
| 7 | +type UseConciergeSidePanelReportActionsParams = { |
| 8 | + report: OnyxTypes.Report; |
| 9 | + reportActions: OnyxTypes.ReportAction[]; |
| 10 | + visibleReportActions: OnyxTypes.ReportAction[]; |
| 11 | + isConciergeSidePanel: boolean; |
| 12 | + hasUserSentMessage: boolean; |
| 13 | + hasOlderActions: boolean; |
| 14 | + sessionStartTime: string | null; |
| 15 | + currentUserAccountID: number; |
| 16 | + greetingText: string; |
| 17 | + loadOlderChats: (force?: boolean) => void; |
| 18 | +}; |
| 19 | + |
| 20 | +function useConciergeSidePanelReportActions({ |
| 21 | + report, |
| 22 | + reportActions, |
| 23 | + visibleReportActions, |
| 24 | + isConciergeSidePanel, |
| 25 | + hasUserSentMessage, |
| 26 | + hasOlderActions, |
| 27 | + sessionStartTime, |
| 28 | + currentUserAccountID, |
| 29 | + greetingText, |
| 30 | + loadOlderChats, |
| 31 | +}: UseConciergeSidePanelReportActionsParams) { |
| 32 | + const [showFullHistory, setShowFullHistory] = useState(false); |
| 33 | + const [prevSessionStartTime, setPrevSessionStartTime] = useState(sessionStartTime); |
| 34 | + const [prevHasUserSentMessage, setPrevHasUserSentMessage] = useState(hasUserSentMessage); |
| 35 | + |
| 36 | + if (prevSessionStartTime !== sessionStartTime) { |
| 37 | + setPrevSessionStartTime(sessionStartTime); |
| 38 | + setShowFullHistory(false); |
| 39 | + } else if (prevHasUserSentMessage && !hasUserSentMessage) { |
| 40 | + setPrevHasUserSentMessage(hasUserSentMessage); |
| 41 | + setShowFullHistory(false); |
| 42 | + } else if (prevHasUserSentMessage !== hasUserSentMessage) { |
| 43 | + setPrevHasUserSentMessage(hasUserSentMessage); |
| 44 | + } |
| 45 | + |
| 46 | + // Check if the user had sent any message BEFORE this session started. |
| 47 | + // Uses sessionStartTime as the boundary — any user message created before the |
| 48 | + // panel opened is a pre-session message, regardless of when it was loaded. |
| 49 | + // |
| 50 | + // When no user message is found in the loaded set, hasOlderActions indicates |
| 51 | + // whether there is unloaded history. On a new account all onboarding messages |
| 52 | + // fit in a single page (hasOlderActions=false). On an existing account with |
| 53 | + // prior interactions the history spans multiple pages (hasOlderActions=true). |
| 54 | + // |
| 55 | + const hadUserMessageAtSessionStart = useMemo(() => { |
| 56 | + if (!isConciergeSidePanel || !sessionStartTime) { |
| 57 | + return false; |
| 58 | + } |
| 59 | + const hasUserMessageInLoadedSet = visibleReportActions.some( |
| 60 | + (action) => !isCreatedAction(action) && action.actorAccountID === currentUserAccountID && action.created < sessionStartTime, |
| 61 | + ); |
| 62 | + return hasUserMessageInLoadedSet || hasOlderActions; |
| 63 | + }, [isConciergeSidePanel, visibleReportActions, currentUserAccountID, sessionStartTime, hasOlderActions]); |
| 64 | + |
| 65 | + const hasPreviousMessages = useMemo(() => { |
| 66 | + if (!isConciergeSidePanel || !hadUserMessageAtSessionStart || !sessionStartTime) { |
| 67 | + return false; |
| 68 | + } |
| 69 | + return visibleReportActions.some((action) => !isCreatedAction(action) && action.created < sessionStartTime); |
| 70 | + }, [isConciergeSidePanel, visibleReportActions, sessionStartTime, hadUserMessageAtSessionStart]); |
| 71 | + |
| 72 | + const showConciergeSidePanelWelcome = isConciergeSidePanel && hadUserMessageAtSessionStart && !hasUserSentMessage && !showFullHistory; |
| 73 | + const showConciergeGreeting = isConciergeSidePanel && hadUserMessageAtSessionStart && !showFullHistory; |
| 74 | + |
| 75 | + const conciergeGreetingAction = useMemo(() => { |
| 76 | + if (!showConciergeGreeting) { |
| 77 | + return undefined; |
| 78 | + } |
| 79 | + return buildConciergeGreetingReportAction(report.reportID, greetingText, report.lastReadTime ?? DateUtils.getDBTime()); |
| 80 | + }, [showConciergeGreeting, report.reportID, report.lastReadTime, greetingText]); |
| 81 | + |
| 82 | + const firstUserMessageCreated = useMemo(() => { |
| 83 | + if (showConciergeSidePanelWelcome || !isConciergeSidePanel || !hasUserSentMessage || !sessionStartTime) { |
| 84 | + return undefined; |
| 85 | + } |
| 86 | + return reportActions.reduce<string | undefined>((earliest, action) => { |
| 87 | + if (isCreatedAction(action) || action.created < sessionStartTime || action.actorAccountID !== currentUserAccountID) { |
| 88 | + return earliest; |
| 89 | + } |
| 90 | + return !earliest || action.created < earliest ? action.created : earliest; |
| 91 | + }, undefined); |
| 92 | + }, [showConciergeSidePanelWelcome, isConciergeSidePanel, hasUserSentMessage, sessionStartTime, reportActions, currentUserAccountID]); |
| 93 | + |
| 94 | + const isCurrentSessionAction = useCallback( |
| 95 | + (action: OnyxTypes.ReportAction): boolean => { |
| 96 | + if (!firstUserMessageCreated || !sessionStartTime) { |
| 97 | + return false; |
| 98 | + } |
| 99 | + return isCreatedAction(action) || (action.created >= sessionStartTime && action.created >= firstUserMessageCreated); |
| 100 | + }, |
| 101 | + [firstUserMessageCreated, sessionStartTime], |
| 102 | + ); |
| 103 | + |
| 104 | + const filterActions = useCallback( |
| 105 | + (actions: OnyxTypes.ReportAction[]): OnyxTypes.ReportAction[] => { |
| 106 | + if (showConciergeSidePanelWelcome && conciergeGreetingAction) { |
| 107 | + const createdAction = actions.find(isCreatedAction); |
| 108 | + return createdAction ? [conciergeGreetingAction, createdAction] : [conciergeGreetingAction]; |
| 109 | + } |
| 110 | + if (!isConciergeSidePanel || showFullHistory) { |
| 111 | + return actions; |
| 112 | + } |
| 113 | + if (!sessionStartTime) { |
| 114 | + return actions.filter(isCreatedAction); |
| 115 | + } |
| 116 | + if (!hadUserMessageAtSessionStart) { |
| 117 | + return actions; |
| 118 | + } |
| 119 | + const filtered = actions.filter(isCurrentSessionAction); |
| 120 | + if (filtered.length === 0) { |
| 121 | + return actions; |
| 122 | + } |
| 123 | + if (conciergeGreetingAction) { |
| 124 | + const createdIndex = filtered.findIndex(isCreatedAction); |
| 125 | + filtered.splice(createdIndex === -1 ? filtered.length : createdIndex, 0, conciergeGreetingAction); |
| 126 | + } |
| 127 | + return filtered; |
| 128 | + }, |
| 129 | + [showConciergeSidePanelWelcome, conciergeGreetingAction, isConciergeSidePanel, showFullHistory, sessionStartTime, isCurrentSessionAction, hadUserMessageAtSessionStart], |
| 130 | + ); |
| 131 | + |
| 132 | + const filteredVisibleActions = useMemo(() => filterActions(visibleReportActions), [filterActions, visibleReportActions]); |
| 133 | + const filteredReportActions = useMemo(() => filterActions(reportActions), [filterActions, reportActions]); |
| 134 | + |
| 135 | + const handleShowPreviousMessages = useCallback(() => { |
| 136 | + setShowFullHistory(true); |
| 137 | + loadOlderChats(true); |
| 138 | + }, [loadOlderChats]); |
| 139 | + |
| 140 | + return { |
| 141 | + filteredVisibleActions, |
| 142 | + filteredReportActions, |
| 143 | + showConciergeSidePanelWelcome, |
| 144 | + showFullHistory, |
| 145 | + hasPreviousMessages, |
| 146 | + handleShowPreviousMessages, |
| 147 | + }; |
| 148 | +} |
| 149 | + |
| 150 | +export default useConciergeSidePanelReportActions; |
0 commit comments