root.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. "use client"
  2. import { useEffect, useLayoutEffect, useRef } from 'react';
  3. import { useCurrentUser, seedCurrentUserFromPageData, isWebAuthReady } from 'app/context/user';
  4. import { storageClear } from 'app/lib/util';
  5. import { clearClientSessionState } from 'app/lib/platform/session-cleanup';
  6. import { useRouter, redirectTo } from 'app/lib/hooks/router'
  7. import Layouts from 'app/components/layouts';
  8. import { useSetScrollDirection, useSetScrollValue } from 'app/context/jotai/layout';
  9. import emitter, { EVENTS } from 'app/context/emitter';
  10. import { Platform } from 'react-native'
  11. import { useWindowScrollNavigationSync } from 'app/lib/navigation/use-window-scroll-navigation-sync';
  12. export function Root(props) {
  13. const { currentUser, setCurrentUser } = useCurrentUser();
  14. const prevUserIdRef = useRef(currentUser?.id);
  15. const router = useRouter();
  16. useWindowScrollNavigationSync();
  17. const data = props?.data;
  18. const redirectUrl = data?.redirect;
  19. // Seed Zustand before paint; must not run setState during render (Subscriber et al. subscribe to the store).
  20. useLayoutEffect(() => {
  21. seedCurrentUserFromPageData(data);
  22. }, [data]);
  23. // ################## CODE FOR NATIVE VERSION
  24. useEffect(() => {
  25. // Skip: first render (prevUserIdRef not set yet)
  26. if (prevUserIdRef.current === undefined) {
  27. prevUserIdRef.current = currentUser?.id;
  28. return;
  29. }
  30. // Skip: value unchanged
  31. if (prevUserIdRef.current === currentUser?.id) return;
  32. prevUserIdRef.current = currentUser?.id;
  33. // Reload only on user change, not on initial load
  34. if (Platform.OS === 'web' && typeof window !== 'undefined') {
  35. window.location.reload();
  36. } else {
  37. emitter.emit(EVENTS.page, { action: 'reload' });
  38. }
  39. }, [currentUser?.id]);
  40. const setScrollDirection = useSetScrollDirection();
  41. const setScrollValue = useSetScrollValue();
  42. useEffect(() => {
  43. // Reset scroll state when page data changes
  44. setScrollDirection(0);
  45. if (Platform.OS === 'web' && typeof window !== 'undefined') {
  46. setScrollValue(window.scrollY || document.documentElement.scrollTop || 0);
  47. } else {
  48. setScrollValue(0);
  49. }
  50. }, [props?.path, props?.data?.url, setScrollDirection, setScrollValue]);
  51. useEffect(() => {
  52. if (data?.user) {
  53. if (currentUser?.id != data.user.id) {
  54. // Login or switch account: never reuse previous session's client caches.
  55. clearClientSessionState();
  56. setCurrentUser(data.user);
  57. storageClear();
  58. }
  59. if (currentUser?.current_context && currentUser?.current_context != data.user.current_context) {
  60. setCurrentUser(data.user);
  61. storageClear();
  62. }
  63. if (currentUser && currentUser?.informer != data.user.informer) {
  64. setCurrentUser({
  65. informer: data.user.informer,
  66. });
  67. }
  68. }
  69. else {
  70. // Session ended (logout / expired): only full-clear when leaving a logged-in user.
  71. if (currentUser?.id) {
  72. clearClientSessionState();
  73. }
  74. setCurrentUser(false);
  75. storageClear();
  76. }
  77. }, [data?.user]);
  78. if (props.code == 404 && !data?.page_status) {
  79. data.page_status = 404
  80. }
  81. useEffect(() => {
  82. if (redirectUrl) {
  83. redirectTo(router, redirectUrl);
  84. }
  85. }, [redirectUrl]);
  86. if (!isWebAuthReady(data, currentUser)) {
  87. return null;
  88. }
  89. if (data.redirect) {
  90. return null;
  91. }
  92. return (
  93. <Layouts path={props?.path} data={data} uri={data?.uri} url={data?.url} />
  94. );
  95. }