-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
Welcome.ts
192 lines (160 loc) · 6.51 KB
/
Welcome.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import type {NavigationState} from '@react-navigation/native';
import type {OnyxCollection} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportUtils from '@libs/ReportUtils';
import type {RootStackParamList} from '@navigation/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import type OnyxPolicy from '@src/types/onyx/Policy';
import type Report from '@src/types/onyx/Report';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import * as Policy from './Policy';
let resolveIsReadyPromise: (value?: Promise<void>) => void | undefined;
let isReadyPromise = new Promise<void>((resolve) => {
resolveIsReadyPromise = resolve;
});
let isFirstTimeNewExpensifyUser: boolean | undefined;
let hasDismissedModal: boolean | undefined;
let hasSelectedChoice: boolean | undefined;
let isLoadingReportData = true;
let currentUserAccountID: number | undefined;
/**
* Check that a few requests have completed so that the welcome action can proceed:
*
* - Whether we are a first time new expensify user
* - Whether we have loaded all policies the server knows about
* - Whether we have loaded all reports the server knows about
*/
function checkOnReady() {
if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData || hasSelectedChoice === undefined || hasDismissedModal === undefined) {
return;
}
resolveIsReadyPromise?.();
}
Onyx.connect({
key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
initWithStoredValues: false,
callback: (value) => {
// If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic
// More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359
isFirstTimeNewExpensifyUser = value ?? undefined;
checkOnReady();
},
});
Onyx.connect({
key: ONYXKEYS.NVP_INTRO_SELECTED,
initWithStoredValues: true,
callback: (value) => {
hasSelectedChoice = !!value;
checkOnReady();
},
});
Onyx.connect({
key: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL,
initWithStoredValues: true,
callback: (value) => {
hasDismissedModal = value ?? false;
checkOnReady();
},
});
Onyx.connect({
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
initWithStoredValues: false,
callback: (value) => {
isLoadingReportData = value ?? false;
checkOnReady();
},
});
const allReports: OnyxCollection<Report> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
initWithStoredValues: false,
callback: (val, key) => {
if (!val || !key) {
return;
}
allReports[key] = {...allReports[key], ...val};
},
});
const allPolicies: OnyxCollection<OnyxPolicy> | EmptyObject = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
if (!key) {
return;
}
if (val === null || val === undefined) {
delete allPolicies[key];
return;
}
allPolicies[key] = {...allPolicies[key], ...val};
},
});
Onyx.connect({
key: ONYXKEYS.SESSION,
callback: (val, key) => {
if (!val || !key) {
return;
}
currentUserAccountID = val.accountID;
},
});
/**
* Shows a welcome action on first login
*/
function show(routes: NavigationState<RootStackParamList>['routes'], showEngagementModal = () => {}) {
isReadyPromise.then(() => {
if (!isFirstTimeNewExpensifyUser) {
return;
}
// If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global
// create menu right now. We should also stay on the workspace page if that is our destination.
const transitionRoute = routes.find(
(route): route is NavigationState<Pick<RootStackParamList, typeof SCREENS.TRANSITION_BETWEEN_APPS>>['routes'][number] => route.name === SCREENS.TRANSITION_BETWEEN_APPS,
);
const isExitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new';
// If we already opened the workspace settings or want the admin room to stay open, do not
// navigate away to the workspace chat report
const shouldNavigateToWorkspaceChat = !isExitingToWorkspaceRoute;
const workspaceChatReport = Object.values(allReports ?? {}).find((report) => {
if (report) {
return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS_NUM.CLOSED;
}
return false;
});
if (workspaceChatReport) {
// This key is only updated when we call ReconnectApp, setting it to false now allows the user to navigate normally instead of always redirecting to the workspace chat
Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false);
}
if (shouldNavigateToWorkspaceChat && workspaceChatReport) {
if (workspaceChatReport.reportID !== null) {
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID));
}
// New user has been redirected to their workspace chat, and we won't show them the engagement modal.
// So we update isFirstTimeNewExpensifyUser to prevent the Welcome logic from running again
isFirstTimeNewExpensifyUser = false;
return;
}
// If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then
// we will show the engagement modal.
if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isExitingToWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) {
showEngagementModal();
}
// Update isFirstTimeNewExpensifyUser so the Welcome logic doesn't run again
isFirstTimeNewExpensifyUser = false;
});
}
function resetReadyCheck() {
isReadyPromise = new Promise((resolve) => {
resolveIsReadyPromise = resolve;
});
isFirstTimeNewExpensifyUser = undefined;
isLoadingReportData = true;
}
function serverDataIsReadyPromise(): Promise<void> {
return isReadyPromise;
}
export {show, serverDataIsReadyPromise, resetReadyCheck};