react-native-timacare 3.3.41 → 3.3.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/lib/commonjs/components/AlertLoan.js +1 -1
  2. package/lib/commonjs/components/AlertLoan.js.flow +10 -1
  3. package/lib/commonjs/components/AlertLoan.js.map +1 -1
  4. package/lib/commonjs/components/ModalOptionLoan.js +1 -1
  5. package/lib/commonjs/components/ModalOptionLoan.js.flow +12 -1
  6. package/lib/commonjs/components/ModalOptionLoan.js.map +1 -1
  7. package/lib/commonjs/components/ModalOptionLoanDigital.js +1 -1
  8. package/lib/commonjs/components/ModalOptionLoanDigital.js.flow +12 -1
  9. package/lib/commonjs/components/ModalOptionLoanDigital.js.map +1 -1
  10. package/lib/commonjs/screens/home/index.js +1 -1
  11. package/lib/commonjs/screens/home/index.js.flow +187 -80
  12. package/lib/commonjs/screens/home/index.js.map +1 -1
  13. package/lib/commonjs/screens/home/not_found.png +0 -0
  14. package/lib/commonjs/screens/toan-trinh-so/store.js +1 -1
  15. package/lib/commonjs/screens/toan-trinh-so/store.js.flow +1 -1
  16. package/lib/commonjs/screens/toan-trinh-so/store.js.map +1 -1
  17. package/lib/module/components/AlertLoan.js +1 -1
  18. package/lib/module/components/AlertLoan.js.map +1 -1
  19. package/lib/module/components/ModalOptionLoan.js +1 -1
  20. package/lib/module/components/ModalOptionLoan.js.map +1 -1
  21. package/lib/module/components/ModalOptionLoanDigital.js +1 -1
  22. package/lib/module/components/ModalOptionLoanDigital.js.map +1 -1
  23. package/lib/module/screens/home/index.js +1 -1
  24. package/lib/module/screens/home/index.js.map +1 -1
  25. package/lib/module/screens/home/not_found.png +0 -0
  26. package/lib/module/screens/toan-trinh-so/store.js +1 -1
  27. package/lib/module/screens/toan-trinh-so/store.js.map +1 -1
  28. package/lib/typescript/components/AlertLoan.d.ts.map +1 -1
  29. package/lib/typescript/components/ModalOptionLoan.d.ts +2 -1
  30. package/lib/typescript/components/ModalOptionLoan.d.ts.map +1 -1
  31. package/lib/typescript/components/ModalOptionLoanDigital.d.ts +2 -1
  32. package/lib/typescript/components/ModalOptionLoanDigital.d.ts.map +1 -1
  33. package/lib/typescript/screens/home/index.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/AlertLoan.tsx +10 -1
  36. package/src/components/ModalOptionLoan.tsx +12 -1
  37. package/src/components/ModalOptionLoanDigital.tsx +12 -1
  38. package/src/screens/home/index.tsx +187 -80
  39. package/src/screens/home/not_found.png +0 -0
  40. package/src/screens/toan-trinh-so/store.ts +1 -1
@@ -6,6 +6,7 @@ import {
6
6
  Dimensions,
7
7
  Image,
8
8
  ImageBackground,
9
+ InteractionManager,
9
10
  Linking,
10
11
  Platform,
11
12
  RefreshControl,
@@ -116,15 +117,36 @@ const $action: ViewStyle = {
116
117
  };
117
118
 
118
119
  let _unsubscribe;
120
+ // Dữ liệu tham chiếu tĩnh (ngân hàng, nghề nghiệp, tỉnh...) chỉ cần prefetch 1 lần/phiên
121
+ let _didPrefetchRefData = false;
122
+
123
+ // Props an toàn cho react-native-modal:
124
+ // - backdropTransitionOutTiming={0}: tránh lớp backdrop fade-out còn sót lại chặn touch (treo màn hình)
125
+ // - useNativeDriver/useNativeDriverForBackdrop: animation mượt, không rớt animation đóng
126
+ // - hideModalContentWhileAnimating: ẩn nội dung khi đang animate, giảm giật
127
+ const modalSafeProps = {
128
+ useNativeDriver: true,
129
+ useNativeDriverForBackdrop: true,
130
+ hideModalContentWhileAnimating: true,
131
+ backdropTransitionOutTiming: 0,
132
+ };
133
+
134
+ // Tên các modal - dùng 1 state duy nhất để đảm bảo chỉ 1 modal hiển thị tại 1 thời điểm
135
+ const MODAL = {
136
+ CIMB_ERROR: 'CIMB_ERROR', // showModal
137
+ CIMB_APPROVE: 'CIMB_APPROVE', // showModal2
138
+ TTS_APPROVE: 'TTS_APPROVE', // showModal3
139
+ SUGGEST: 'SUGGEST', // showModal4
140
+ ALERT: 'ALERT', // showModal5
141
+ DIGITAL_SUGGEST: 'DIGITAL_SUGGEST', // showModal6
142
+ };
119
143
 
120
144
  export const Home = observer(function Home() {
121
145
  const navigation = useNavigation();
122
- const [showModal, setShowModal] = useState(false);
123
- const [showModal2, setShowModal2] = useState(false);
124
- const [showModal3, setShowModal3] = useState(false);
125
- const [showModal4, setShowModal4] = useState(false);
126
- const [showModal5, setShowModal5] = useState(false);
127
- const [showModal6, setShowModal6] = useState(false);
146
+ // 1 modal tại 1 thời điểm: tránh stack backdrop gây treo màn hình
147
+ const [activeModal, setActiveModal] = useState<string | null>(null);
148
+ // Hành động điều hướng chờ chạy SAU khi modal đóng hẳn (onModalHide)
149
+ const pendingNavRef = React.useRef<(() => void) | null>(null);
128
150
  const [listLoan, setListLoan] = useState<any[]>([]);
129
151
  const [checkEKYC, setCheckEKYC] = useState<any>({});
130
152
  const [isLoading, setIsLoading] = useState(false);
@@ -132,14 +154,21 @@ export const Home = observer(function Home() {
132
154
  const [loan, setLoan] = useState(null);
133
155
  const [dataSuggest, setDataSuggest] = useState<any>();
134
156
  const insets = useSafeAreaInsets();
135
- console.log(
136
- showModal,
137
- showModal2,
138
- showModal3,
139
- showModal4,
140
- showModal5,
141
- showModal6
142
- );
157
+
158
+ // Chỉ mở modal khi chưa có modal nào đang mở -> không bao giờ stack 2 modal
159
+ const openModal = (name: string) =>
160
+ setActiveModal((prev) => prev ?? name);
161
+ const closeModal = () => setActiveModal(null);
162
+ // Đóng modal rồi điều hướng sau khi animation đóng hoàn tất (chống treo màn hình)
163
+ const closeModalThen = (fn?: () => void) => {
164
+ pendingNavRef.current = fn ?? null;
165
+ setActiveModal(null);
166
+ };
167
+ const runPendingNav = () => {
168
+ const fn = pendingNavRef.current;
169
+ pendingNavRef.current = null;
170
+ if (fn) fn();
171
+ };
143
172
 
144
173
  const onRefresh = async () => {
145
174
  homeStore.getListLoan();
@@ -161,8 +190,8 @@ export const Home = observer(function Home() {
161
190
  if (item?.messageErrorCIMB && item.messageErrorCIMB !== '') {
162
191
  setLoanCimb(item);
163
192
  setTimeout(() => {
164
- setShowModal(true);
165
- }, 800);
193
+ openModal(MODAL.CIMB_ERROR);
194
+ }, 300);
166
195
  }
167
196
  if (
168
197
  (item?.typeLoan === 4 || item?.typeLoan === 2) &&
@@ -172,8 +201,8 @@ export const Home = observer(function Home() {
172
201
  if (!checkShow || checkShow !== true) {
173
202
  setLoanCimb(item);
174
203
  setTimeout(() => {
175
- setShowModal2(true);
176
- }, 800);
204
+ openModal(MODAL.CIMB_APPROVE);
205
+ }, 300);
177
206
  }
178
207
  }
179
208
  }
@@ -183,8 +212,8 @@ export const Home = observer(function Home() {
183
212
  ) {
184
213
  setLoan(item);
185
214
  setTimeout(() => {
186
- setShowModal3(true);
187
- }, 800);
215
+ openModal(MODAL.TTS_APPROVE);
216
+ }, 300);
188
217
  }
189
218
  if (
190
219
  (item?.typeLoan === 5 || item?.typeLoan === 6) &&
@@ -200,8 +229,8 @@ export const Home = observer(function Home() {
200
229
  typeLoan: item?.typeLoan,
201
230
  });
202
231
  setTimeout(() => {
203
- setShowModal4(true);
204
- }, 800);
232
+ openModal(MODAL.SUGGEST);
233
+ }, 300);
205
234
  }
206
235
  }
207
236
 
@@ -222,8 +251,8 @@ export const Home = observer(function Home() {
222
251
  typeLoan: item?.typeLoan,
223
252
  });
224
253
  setTimeout(() => {
225
- setShowModal6(true);
226
- }, 800);
254
+ openModal(MODAL.DIGITAL_SUGGEST);
255
+ }, 300);
227
256
  }
228
257
  }
229
258
 
@@ -233,8 +262,8 @@ export const Home = observer(function Home() {
233
262
  (item?.step === 7 || item?.step === 100)
234
263
  ) {
235
264
  setTimeout(() => {
236
- setShowModal5(true);
237
- }, 800);
265
+ openModal(MODAL.ALERT);
266
+ }, 300);
238
267
  }
239
268
  })
240
269
  );
@@ -263,18 +292,34 @@ export const Home = observer(function Home() {
263
292
  }, [navigation]);
264
293
 
265
294
  useEffect(() => {
266
- setTimeout(() => {
267
- FullSubmitStore.getTypeMerried();
268
- FullSubmitStore.getListBank();
269
- FullSubmitStore.getIncomeCIMB();
270
- FullSubmitStore.getPositionCIMB();
271
- FullSubmitStore.getJobStatusCIMB();
272
- QuickSubmitStore.getJobsCIMB();
273
- appStore.getLoanTimeAll();
274
- appStore.getRateTypeAll();
275
- appStore.getInsurenceTimeAll();
276
- ttsStore.getProvinces();
277
- }, 2000);
295
+ if (_didPrefetchRefData) return;
296
+ // Chạy sau khi màn hình render/animation xong (thay cho setTimeout 2000ms cố định)
297
+ const task = InteractionManager.runAfterInteractions(async () => {
298
+ await Promise.all([
299
+ FullSubmitStore.getTypeMerried(),
300
+ FullSubmitStore.getListBank(),
301
+ FullSubmitStore.getIncomeCIMB(),
302
+ FullSubmitStore.getPositionCIMB(),
303
+ FullSubmitStore.getJobStatusCIMB(),
304
+ QuickSubmitStore.getJobsCIMB(),
305
+ appStore.getLoanTimeAll(),
306
+ appStore.getRateTypeAll(),
307
+ appStore.getInsurenceTimeAll(),
308
+ ttsStore.getProvinces(),
309
+ ]);
310
+ // Các hàm store nuốt lỗi (không throw) -> coi là thành công khi dữ liệu
311
+ // tham chiếu thực sự về store. Nếu mất mạng (list rỗng) sẽ thử lại ở lần mount sau.
312
+ const loaded =
313
+ FullSubmitStore.listTypeMerried?.length > 0 &&
314
+ FullSubmitStore.listBanks?.length > 0 &&
315
+ QuickSubmitStore.listJobCimb?.length > 0 &&
316
+ appStore.listLoanTime?.length > 0 &&
317
+ appStore.listRateType?.length > 0 &&
318
+ appStore.listInsurenceTimeAll?.length > 0 &&
319
+ ttsStore.listProvince?.length > 0;
320
+ if (loaded) _didPrefetchRefData = true;
321
+ });
322
+ return () => task.cancel();
278
323
  }, []);
279
324
 
280
325
  const signLoan = (loan) => {
@@ -398,10 +443,7 @@ export const Home = observer(function Home() {
398
443
  setIsLoading(false);
399
444
  if (response.kind === 'ok') {
400
445
  if (response.data?.meta?.errorCode === 200) {
401
- setShowModal3(false);
402
- setTimeout(() => {
403
- onRefresh();
404
- }, 300);
446
+ closeModalThen(() => onRefresh());
405
447
  } else {
406
448
  Alert.alert('Thông báo', response.data?.meta?.errorMessage);
407
449
  }
@@ -423,10 +465,7 @@ export const Home = observer(function Home() {
423
465
  setIsLoading(false);
424
466
  if (response.kind === 'ok') {
425
467
  if (response.data?.meta?.errorCode === 200) {
426
- setShowModal3(false);
427
- setTimeout(() => {
428
- onRefresh();
429
- }, 300);
468
+ closeModalThen(() => onRefresh());
430
469
  } else {
431
470
  Alert.alert('Thông báo', response.data?.meta?.errorMessage);
432
471
  }
@@ -2346,12 +2385,72 @@ export const Home = observer(function Home() {
2346
2385
  </View>
2347
2386
  )}
2348
2387
  </Observer>
2388
+
2389
+ {/* Empty state: không có cả đơn mới lẫn đơn đang vay */}
2390
+ <Observer>
2391
+ {() =>
2392
+ !isLoading &&
2393
+ !homeStore.isLoading &&
2394
+ (listLoan?.length ?? 0) === 0 &&
2395
+ (homeStore?.listLoan?.length ?? 0) === 0 ? (
2396
+ <View
2397
+ style={{
2398
+ alignItems: 'center',
2399
+ justifyContent: 'center',
2400
+ paddingVertical: 48,
2401
+ }}
2402
+ >
2403
+ <Image
2404
+ source={require('./not_found.png')}
2405
+ style={{
2406
+ width: 180,
2407
+ height: 180,
2408
+ resizeMode: 'contain',
2409
+ }}
2410
+ />
2411
+ <MText
2412
+ style={{
2413
+ marginTop: 16,
2414
+ fontSize: 14,
2415
+ color: '#828282',
2416
+ textAlign: 'center',
2417
+ }}
2418
+ >
2419
+ Oops! Bạn chưa có khoản vay nào
2420
+ </MText>
2421
+ <TouchableOpacity
2422
+ onPress={() => onRefresh()}
2423
+ style={{
2424
+ marginTop: 16,
2425
+ borderWidth: 1,
2426
+ borderColor: '#EF592E',
2427
+ borderRadius: 30,
2428
+ paddingHorizontal: 32,
2429
+ height: 40,
2430
+ alignItems: 'center',
2431
+ justifyContent: 'center',
2432
+ }}
2433
+ >
2434
+ <MText style={{ color: '#EF592E', fontSize: 14 }}>
2435
+ Tải lại trang
2436
+ </MText>
2437
+ </TouchableOpacity>
2438
+ </View>
2439
+ ) : (
2440
+ <View />
2441
+ )
2442
+ }
2443
+ </Observer>
2349
2444
  </View>
2350
- <Modal isVisible={showModal}>
2445
+ <Modal
2446
+ isVisible={activeModal === MODAL.CIMB_ERROR}
2447
+ onModalHide={runPendingNav}
2448
+ {...modalSafeProps}
2449
+ >
2351
2450
  <SafeAreaView style={{ backgroundColor: '#FFFFFF', borderRadius: 6 }}>
2352
2451
  <View style={{ flexDirection: 'row-reverse' }}>
2353
2452
  <TouchableOpacity
2354
- onPress={() => setShowModal(false)}
2453
+ onPress={() => closeModal()}
2355
2454
  style={{
2356
2455
  width: 40,
2357
2456
  height: 40,
@@ -2432,7 +2531,11 @@ export const Home = observer(function Home() {
2432
2531
  </View>
2433
2532
  </SafeAreaView>
2434
2533
  </Modal>
2435
- <Modal isVisible={showModal2}>
2534
+ <Modal
2535
+ isVisible={activeModal === MODAL.CIMB_APPROVE}
2536
+ onModalHide={runPendingNav}
2537
+ {...modalSafeProps}
2538
+ >
2436
2539
  <SafeAreaView style={{ backgroundColor: '#FFFFFF', borderRadius: 8 }}>
2437
2540
  <View>
2438
2541
  <Image
@@ -2483,11 +2586,12 @@ export const Home = observer(function Home() {
2483
2586
  paddingVertical: 8,
2484
2587
  }}
2485
2588
  onPress={() => {
2486
- setShowModal2(false);
2487
- navigation.push(ScreenNames.AcceptPolicy, {
2488
- loan: loanCimb,
2489
- isCimb: true,
2490
- });
2589
+ closeModalThen(() =>
2590
+ navigation.push(ScreenNames.AcceptPolicy, {
2591
+ loan: loanCimb,
2592
+ isCimb: true,
2593
+ })
2594
+ );
2491
2595
  }}
2492
2596
  >
2493
2597
  <MText style={{ color: color.primary }}>Xác nhận</MText>
@@ -2515,7 +2619,7 @@ export const Home = observer(function Home() {
2515
2619
  });
2516
2620
  if (response.kind === 'ok') {
2517
2621
  if (response.data.meta.errorCode === 200) {
2518
- setShowModal2(false);
2622
+ closeModal();
2519
2623
  const key = `SHOW_${loanCimb.id}`;
2520
2624
  save(key, true);
2521
2625
  Alert.alert(
@@ -2586,11 +2690,12 @@ export const Home = observer(function Home() {
2586
2690
  paddingVertical: 8,
2587
2691
  }}
2588
2692
  onPress={() => {
2589
- setShowModal2(false);
2590
- navigation.push(ScreenNames.AcceptPolicy, {
2591
- loan: loanCimb,
2592
- isCimb: false,
2593
- });
2693
+ closeModalThen(() =>
2694
+ navigation.push(ScreenNames.AcceptPolicy, {
2695
+ loan: loanCimb,
2696
+ isCimb: false,
2697
+ })
2698
+ );
2594
2699
  }}
2595
2700
  >
2596
2701
  <MText style={{ color: color.primary }}>Tiếp tục</MText>
@@ -2601,7 +2706,11 @@ export const Home = observer(function Home() {
2601
2706
  </View>
2602
2707
  </SafeAreaView>
2603
2708
  </Modal>
2604
- <Modal isVisible={showModal3}>
2709
+ <Modal
2710
+ isVisible={activeModal === MODAL.TTS_APPROVE}
2711
+ onModalHide={runPendingNav}
2712
+ {...modalSafeProps}
2713
+ >
2605
2714
  <SafeAreaView style={{ backgroundColor: '#FFFFFF', borderRadius: 6 }}>
2606
2715
  <Image
2607
2716
  source={require('../../assets/tts/Banner.png')}
@@ -2703,10 +2812,9 @@ export const Home = observer(function Home() {
2703
2812
  >
2704
2813
  <TouchableOpacity
2705
2814
  onPress={() => {
2706
- setShowModal3(false);
2707
- setTimeout(() => {
2708
- navigation.push(ScreenNames.LoanInterestRate, { loan });
2709
- }, 300);
2815
+ closeModalThen(() =>
2816
+ navigation.push(ScreenNames.LoanInterestRate, { loan })
2817
+ );
2710
2818
  }}
2711
2819
  >
2712
2820
  <MText
@@ -2724,41 +2832,40 @@ export const Home = observer(function Home() {
2724
2832
  </Modal>
2725
2833
 
2726
2834
  <ModalOptionLoan
2727
- open={showModal4}
2835
+ open={activeModal === MODAL.SUGGEST}
2728
2836
  loan={dataSuggest}
2729
2837
  callback={() => {
2730
- setShowModal4(false);
2731
- setTimeout(() => {
2732
- // onRefresh();
2838
+ closeModalThen(() =>
2733
2839
  navigation.push(ScreenNames.ReviewLoan, {
2734
2840
  loan: loan,
2735
- });
2736
- }, 300);
2841
+ })
2842
+ );
2737
2843
  }}
2738
2844
  onClose={() => {
2739
- setShowModal4(false);
2845
+ closeModal();
2740
2846
  }}
2847
+ onModalHide={runPendingNav}
2741
2848
  />
2742
2849
  <ModalOptionLoanDigital
2743
- open={showModal6}
2850
+ open={activeModal === MODAL.DIGITAL_SUGGEST}
2744
2851
  loan={dataSuggest}
2745
2852
  callback={() => {
2746
- setShowModal6(false);
2747
- setTimeout(() => {
2853
+ closeModalThen(() =>
2748
2854
  navigation.push(ScreenNames.ReviewLoan, {
2749
2855
  loan: loan,
2750
- });
2751
- }, 300);
2856
+ })
2857
+ );
2752
2858
  }}
2753
2859
  onClose={() => {
2754
- setShowModal6(false);
2860
+ closeModal();
2755
2861
  }}
2862
+ onModalHide={runPendingNav}
2756
2863
  />
2757
2864
 
2758
2865
  <AlertLoan
2759
- open={showModal5}
2866
+ open={activeModal === MODAL.ALERT}
2760
2867
  onClose={() => {
2761
- setShowModal5(false);
2868
+ closeModal();
2762
2869
  }}
2763
2870
  />
2764
2871
  </ScrollView>