diff --git a/native/ios/Podfile.lock b/native/ios/Podfile.lock index c5d3d9863..a97805277 100644 --- a/native/ios/Podfile.lock +++ b/native/ios/Podfile.lock @@ -1,784 +1,784 @@ PODS: - boost-for-react-native (1.63.0) - CocoaAsyncSocket (7.6.4) - CocoaLibEvent (1.0.0) - DoubleConversion (1.1.6) - DVAssetLoaderDelegate (0.3.3) - EXConstants (9.0.0): - UMConstantsInterface - UMCore - EXFileSystem (8.1.0): - UMCore - UMFileSystemInterface - EXImageLoader (1.0.1): - React-Core - UMCore - UMImageLoaderInterface - EXImageManipulator (8.4.0): - UMCore - UMFileSystemInterface - UMImageLoaderInterface - EXMediaLibrary (10.0.0): - React-Core - UMCore - UMFileSystemInterface - UMPermissionsInterface - EXPermissions (8.1.0): - UMCore - UMPermissionsInterface - EXSplashScreen (0.3.1): - UMCore - FBLazyVector (0.63.4) - FBReactNativeSpec (0.63.4): - Folly (= 2020.01.13.00) - RCTRequired (= 0.63.4) - RCTTypeSafety (= 0.63.4) - React-Core (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - Flipper (0.54.0): - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - Flipper-Folly (2.2.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - OpenSSL-Universal (= 1.0.2.19) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): - Flipper-Folly (~> 2.2) - FlipperKit (0.54.0): - FlipperKit/Core (= 0.54.0) - FlipperKit/Core (0.54.0): - Flipper (~> 0.54.0) - FlipperKit/CppBridge - FlipperKit/FBCxxFollyDynamicConvert - FlipperKit/FBDefines - FlipperKit/FKPortForwarding - FlipperKit/CppBridge (0.54.0): - Flipper (~> 0.54.0) - FlipperKit/FBCxxFollyDynamicConvert (0.54.0): - Flipper-Folly (~> 2.2) - FlipperKit/FBDefines (0.54.0) - FlipperKit/FKPortForwarding (0.54.0): - CocoaAsyncSocket (~> 7.6) - Flipper-PeerTalk (~> 0.0.4) - FlipperKit/FlipperKitHighlightOverlay (0.54.0) - FlipperKit/FlipperKitLayoutPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitHighlightOverlay - FlipperKit/FlipperKitLayoutTextSearchable - YogaKit (~> 1.18) - FlipperKit/FlipperKitLayoutTextSearchable (0.54.0) - FlipperKit/FlipperKitNetworkPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitReactPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0): - FlipperKit/Core - FlipperKit/SKIOSNetworkPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitNetworkPlugin - Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion - Folly/Default (= 2020.01.13.00) - glog - Folly/Default (2020.01.13.00): - boost-for-react-native - DoubleConversion - glog - glog (0.3.5) - libwebp (1.1.0): - libwebp/demux (= 1.1.0) - libwebp/mux (= 1.1.0) - libwebp/webp (= 1.1.0) - libwebp/demux (1.1.0): - libwebp/webp - libwebp/mux (1.1.0): - libwebp/demux - libwebp/webp (1.1.0) - lottie-ios (3.1.3) - lottie-react-native (3.2.1): - lottie-ios (~> 3.1.3) - React - mobile-ffmpeg-min (4.3.1.LTS) - OpenSSL-Universal (1.0.2.19): - OpenSSL-Universal/Static (= 1.0.2.19) - OpenSSL-Universal/Static (1.0.2.19) - RCTRequired (0.63.4) - RCTTypeSafety (0.63.4): - FBLazyVector (= 0.63.4) - Folly (= 2020.01.13.00) - RCTRequired (= 0.63.4) - React-Core (= 0.63.4) - React (0.63.4): - React-Core (= 0.63.4) - React-Core/DevSupport (= 0.63.4) - React-Core/RCTWebSocket (= 0.63.4) - React-RCTActionSheet (= 0.63.4) - React-RCTAnimation (= 0.63.4) - React-RCTBlob (= 0.63.4) - React-RCTImage (= 0.63.4) - React-RCTLinking (= 0.63.4) - React-RCTNetwork (= 0.63.4) - React-RCTSettings (= 0.63.4) - React-RCTText (= 0.63.4) - React-RCTVibration (= 0.63.4) - React-callinvoker (0.63.4) - React-Core (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default (= 0.63.4) - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/CoreModulesHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/Default (0.63.4): - Folly (= 2020.01.13.00) - glog - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/DevSupport (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default (= 0.63.4) - React-Core/RCTWebSocket (= 0.63.4) - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - React-jsinspector (= 0.63.4) - Yoga - React-Core/RCTActionSheetHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTAnimationHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTBlobHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTImageHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTLinkingHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTNetworkHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTSettingsHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTTextHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTVibrationHeaders (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-Core/RCTWebSocket (0.63.4): - Folly (= 2020.01.13.00) - glog - React-Core/Default (= 0.63.4) - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsiexecutor (= 0.63.4) - Yoga - React-CoreModules (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - RCTTypeSafety (= 0.63.4) - React-Core/CoreModulesHeaders (= 0.63.4) - React-jsi (= 0.63.4) - React-RCTImage (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-cxxreact (0.63.4): - boost-for-react-native (= 1.63.0) - DoubleConversion - Folly (= 2020.01.13.00) - glog - React-callinvoker (= 0.63.4) - React-jsinspector (= 0.63.4) - React-jsi (0.63.4): - boost-for-react-native (= 1.63.0) - DoubleConversion - Folly (= 2020.01.13.00) - glog - React-jsi/Default (= 0.63.4) - React-jsi/Default (0.63.4): - boost-for-react-native (= 1.63.0) - DoubleConversion - Folly (= 2020.01.13.00) - glog - React-jsiexecutor (0.63.4): - DoubleConversion - Folly (= 2020.01.13.00) - glog - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsinspector (0.63.4) - react-native-background-upload (5.6.0): - React - react-native-camera (3.31.0): - React - react-native-camera/RCT (= 3.31.0) - react-native-camera/RN (= 3.31.0) - react-native-camera/RCT (3.31.0): - React - react-native-camera/RN (3.31.0): - React - react-native-ffmpeg/min-lts (0.4.4): - mobile-ffmpeg-min (= 4.3.1.LTS) - React - react-native-in-app-message (1.0.2): - React - react-native-netinfo (4.4.0): - React - react-native-notifications (1.1.19): - React - react-native-orientation-locker (1.1.6): - React - react-native-safe-area-context (3.1.9): - React-Core - react-native-video/Video (5.0.2): - React - react-native-video/VideoCaching (5.0.2): - DVAssetLoaderDelegate (~> 0.3.1) - React - react-native-video/Video - SPTPersistentCache (~> 1.1.0) - React-RCTActionSheet (0.63.4): - React-Core/RCTActionSheetHeaders (= 0.63.4) - React-RCTAnimation (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - RCTTypeSafety (= 0.63.4) - React-Core/RCTAnimationHeaders (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTBlob (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - React-Core/RCTBlobHeaders (= 0.63.4) - React-Core/RCTWebSocket (= 0.63.4) - React-jsi (= 0.63.4) - React-RCTNetwork (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTImage (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - RCTTypeSafety (= 0.63.4) - React-Core/RCTImageHeaders (= 0.63.4) - React-jsi (= 0.63.4) - React-RCTNetwork (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTLinking (0.63.4): - FBReactNativeSpec (= 0.63.4) - React-Core/RCTLinkingHeaders (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTNetwork (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - RCTTypeSafety (= 0.63.4) - React-Core/RCTNetworkHeaders (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTSettings (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - RCTTypeSafety (= 0.63.4) - React-Core/RCTSettingsHeaders (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - React-RCTText (0.63.4): - React-Core/RCTTextHeaders (= 0.63.4) - React-RCTVibration (0.63.4): - FBReactNativeSpec (= 0.63.4) - Folly (= 2020.01.13.00) - React-Core/RCTVibrationHeaders (= 0.63.4) - React-jsi (= 0.63.4) - ReactCommon/turbomodule/core (= 0.63.4) - ReactCommon/turbomodule/core (0.63.4): - DoubleConversion - Folly (= 2020.01.13.00) - glog - React-callinvoker (= 0.63.4) - React-Core (= 0.63.4) - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - ReactNativeART (1.2.0): - React - ReactNativeDarkMode (0.2.0-rc.1): - React - ReactNativeKeyboardInput (6.0.1): - React - ReactNativeKeyboardTrackingView (5.7.0): - React - RNCAsyncStorage (1.6.2): - React - RNCClipboard (1.5.1): - React-Core - RNCMaskedView (0.1.10): - React - RNExitApp (1.1.0): - React - RNFastImage (7.0.2): - React - SDWebImage (~> 5.0) - SDWebImageWebPCoder (~> 0.2.3) - RNFS (2.15.2): - React - RNGestureHandler (1.8.0): - React - RNKeychain (4.0.1): - React - RNReanimated (1.13.1): - React - RNScreens (2.14.0): - React-Core - RNVectorIcons (6.6.0): - React - SDWebImage (5.9.1): - SDWebImage/Core (= 5.9.1) - SDWebImage/Core (5.9.1) - SDWebImageWebPCoder (0.2.5): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.0) - SPTPersistentCache (1.1.0) - UMAppLoader (1.0.1) - UMBarCodeScannerInterface (5.1.0) - UMCameraInterface (5.1.0) - UMConstantsInterface (5.1.0) - UMCore (5.1.0) - UMFaceDetectorInterface (5.1.0) - UMFileSystemInterface (5.1.0) - UMFontInterface (5.1.0) - UMImageLoaderInterface (5.1.0) - UMPermissionsInterface (5.1.0): - UMCore - UMReactNativeAdapter (5.2.0): - React-Core - UMCore - UMFontInterface - UMSensorsInterface (5.1.0) - UMTaskManagerInterface (5.1.0) - Yoga (1.14.0) - YogaKit (1.18.1): - Yoga (~> 1.14) DEPENDENCIES: - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EXConstants (from `../../node_modules/expo-constants/ios`) - EXFileSystem (from `../../node_modules/expo-file-system/ios`) - EXImageLoader (from `../../node_modules/expo-image-loader/ios`) - EXImageManipulator (from `../../node_modules/expo-image-manipulator/ios`) - EXMediaLibrary (from `../../node_modules/expo-media-library/ios`) - EXPermissions (from `../../node_modules/expo-permissions/ios`) - EXSplashScreen (from `../../node_modules/expo-splash-screen/ios`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) - Flipper (~> 0.54.0) - Flipper-DoubleConversion (= 1.1.7) - Flipper-Folly (~> 2.2) - Flipper-Glog (= 0.3.6) - Flipper-PeerTalk (~> 0.0.4) - Flipper-RSocket (~> 1.1) - FlipperKit (~> 0.54.0) - FlipperKit/Core (~> 0.54.0) - FlipperKit/CppBridge (~> 0.54.0) - FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0) - FlipperKit/FBDefines (~> 0.54.0) - FlipperKit/FKPortForwarding (~> 0.54.0) - FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0) - FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0) - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0) - FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0) - FlipperKit/FlipperKitReactPlugin (~> 0.54.0) - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0) - FlipperKit/SKIOSNetworkPlugin (~> 0.54.0) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - lottie-ios (from `../../node_modules/lottie-ios`) - lottie-react-native (from `../../node_modules/lottie-react-native`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - React (from `../node_modules/react-native/`) - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Core (from `../node_modules/react-native/`) - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - react-native-background-upload (from `../../node_modules/react-native-background-upload`) - react-native-camera (from `../../node_modules/react-native-camera`) - react-native-ffmpeg/min-lts (from `../../node_modules/react-native-ffmpeg/react-native-ffmpeg.podspec`) - react-native-in-app-message (from `../../node_modules/react-native-in-app-message`) - "react-native-netinfo (from `../../node_modules/@react-native-community/netinfo`)" - react-native-notifications (from `../../node_modules/react-native-notifications`) - react-native-orientation-locker (from `../../node_modules/react-native-orientation-locker`) - react-native-safe-area-context (from `../../node_modules/react-native-safe-area-context`) - react-native-video/VideoCaching (from `../../node_modules/react-native-video/react-native-video.podspec`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - "ReactNativeART (from `../../node_modules/@react-native-community/art`)" - ReactNativeDarkMode (from `../../node_modules/react-native-dark-mode`) - ReactNativeKeyboardInput (from `../../node_modules/react-native-keyboard-input`) - ReactNativeKeyboardTrackingView (from `../../node_modules/react-native-keyboard-tracking-view`) - "RNCAsyncStorage (from `../../node_modules/@react-native-community/async-storage`)" - "RNCClipboard (from `../../node_modules/@react-native-community/clipboard`)" - "RNCMaskedView (from `../../node_modules/@react-native-community/masked-view`)" - RNExitApp (from `../../node_modules/react-native-exit-app`) - RNFastImage (from `../../node_modules/react-native-fast-image`) - RNFS (from `../../node_modules/react-native-fs`) - RNGestureHandler (from `../../node_modules/react-native-gesture-handler`) - RNKeychain (from `../../node_modules/react-native-keychain`) - RNReanimated (from `../../node_modules/react-native-reanimated`) - RNScreens (from `../../node_modules/react-native-screens`) - RNVectorIcons (from `../../node_modules/react-native-vector-icons`) - UMAppLoader (from `../../node_modules/unimodules-app-loader/ios`) - UMBarCodeScannerInterface (from `../../node_modules/unimodules-barcode-scanner-interface/ios`) - UMCameraInterface (from `../../node_modules/unimodules-camera-interface/ios`) - UMConstantsInterface (from `../../node_modules/unimodules-constants-interface/ios`) - "UMCore (from `../../node_modules/@unimodules/core/ios`)" - UMFaceDetectorInterface (from `../../node_modules/unimodules-face-detector-interface/ios`) - UMFileSystemInterface (from `../../node_modules/unimodules-file-system-interface/ios`) - UMFontInterface (from `../../node_modules/unimodules-font-interface/ios`) - UMImageLoaderInterface (from `../../node_modules/unimodules-image-loader-interface/ios`) - UMPermissionsInterface (from `../../node_modules/unimodules-permissions-interface/ios`) - "UMReactNativeAdapter (from `../../node_modules/@unimodules/react-native-adapter/ios`)" - UMSensorsInterface (from `../../node_modules/unimodules-sensors-interface/ios`) - UMTaskManagerInterface (from `../../node_modules/unimodules-task-manager-interface/ios`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: - boost-for-react-native - CocoaAsyncSocket - CocoaLibEvent - DVAssetLoaderDelegate - Flipper - Flipper-DoubleConversion - Flipper-Folly - Flipper-Glog - Flipper-PeerTalk - Flipper-RSocket - FlipperKit - libwebp - mobile-ffmpeg-min - OpenSSL-Universal - SDWebImage - SDWebImageWebPCoder - SPTPersistentCache - YogaKit EXTERNAL SOURCES: DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" EXConstants: :path: "../../node_modules/expo-constants/ios" EXFileSystem: :path: "../../node_modules/expo-file-system/ios" EXImageLoader: :path: "../../node_modules/expo-image-loader/ios" EXImageManipulator: :path: "../../node_modules/expo-image-manipulator/ios" EXMediaLibrary: :path: "../../node_modules/expo-media-library/ios" EXPermissions: :path: "../../node_modules/expo-permissions/ios" EXSplashScreen: :path: "../../node_modules/expo-splash-screen/ios" FBLazyVector: :path: "../node_modules/react-native/Libraries/FBLazyVector" FBReactNativeSpec: :path: "../node_modules/react-native/Libraries/FBReactNativeSpec" Folly: :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" lottie-ios: :path: "../../node_modules/lottie-ios" lottie-react-native: :path: "../../node_modules/lottie-react-native" RCTRequired: :path: "../node_modules/react-native/Libraries/RCTRequired" RCTTypeSafety: :path: "../node_modules/react-native/Libraries/TypeSafety" React: :path: "../node_modules/react-native/" React-callinvoker: :path: "../node_modules/react-native/ReactCommon/callinvoker" React-Core: :path: "../node_modules/react-native/" React-CoreModules: :path: "../node_modules/react-native/React/CoreModules" React-cxxreact: :path: "../node_modules/react-native/ReactCommon/cxxreact" React-jsi: :path: "../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: :path: "../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: :path: "../node_modules/react-native/ReactCommon/jsinspector" react-native-background-upload: :path: "../../node_modules/react-native-background-upload" react-native-camera: :path: "../../node_modules/react-native-camera" react-native-ffmpeg: :podspec: "../../node_modules/react-native-ffmpeg/react-native-ffmpeg.podspec" react-native-in-app-message: :path: "../../node_modules/react-native-in-app-message" react-native-netinfo: :path: "../../node_modules/@react-native-community/netinfo" react-native-notifications: :path: "../../node_modules/react-native-notifications" react-native-orientation-locker: :path: "../../node_modules/react-native-orientation-locker" react-native-safe-area-context: :path: "../../node_modules/react-native-safe-area-context" react-native-video: :podspec: "../../node_modules/react-native-video/react-native-video.podspec" React-RCTActionSheet: :path: "../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: :path: "../node_modules/react-native/Libraries/NativeAnimation" React-RCTBlob: :path: "../node_modules/react-native/Libraries/Blob" React-RCTImage: :path: "../node_modules/react-native/Libraries/Image" React-RCTLinking: :path: "../node_modules/react-native/Libraries/LinkingIOS" React-RCTNetwork: :path: "../node_modules/react-native/Libraries/Network" React-RCTSettings: :path: "../node_modules/react-native/Libraries/Settings" React-RCTText: :path: "../node_modules/react-native/Libraries/Text" React-RCTVibration: :path: "../node_modules/react-native/Libraries/Vibration" ReactCommon: :path: "../node_modules/react-native/ReactCommon" ReactNativeART: :path: "../../node_modules/@react-native-community/art" ReactNativeDarkMode: :path: "../../node_modules/react-native-dark-mode" ReactNativeKeyboardInput: :path: "../../node_modules/react-native-keyboard-input" ReactNativeKeyboardTrackingView: :path: "../../node_modules/react-native-keyboard-tracking-view" RNCAsyncStorage: :path: "../../node_modules/@react-native-community/async-storage" RNCClipboard: :path: "../../node_modules/@react-native-community/clipboard" RNCMaskedView: :path: "../../node_modules/@react-native-community/masked-view" RNExitApp: :path: "../../node_modules/react-native-exit-app" RNFastImage: :path: "../../node_modules/react-native-fast-image" RNFS: :path: "../../node_modules/react-native-fs" RNGestureHandler: :path: "../../node_modules/react-native-gesture-handler" RNKeychain: :path: "../../node_modules/react-native-keychain" RNReanimated: :path: "../../node_modules/react-native-reanimated" RNScreens: :path: "../../node_modules/react-native-screens" RNVectorIcons: :path: "../../node_modules/react-native-vector-icons" UMAppLoader: :path: "../../node_modules/unimodules-app-loader/ios" UMBarCodeScannerInterface: :path: "../../node_modules/unimodules-barcode-scanner-interface/ios" UMCameraInterface: :path: "../../node_modules/unimodules-camera-interface/ios" UMConstantsInterface: :path: "../../node_modules/unimodules-constants-interface/ios" UMCore: :path: "../../node_modules/@unimodules/core/ios" UMFaceDetectorInterface: :path: "../../node_modules/unimodules-face-detector-interface/ios" UMFileSystemInterface: :path: "../../node_modules/unimodules-file-system-interface/ios" UMFontInterface: :path: "../../node_modules/unimodules-font-interface/ios" UMImageLoaderInterface: :path: "../../node_modules/unimodules-image-loader-interface/ios" UMPermissionsInterface: :path: "../../node_modules/unimodules-permissions-interface/ios" UMReactNativeAdapter: :path: "../../node_modules/@unimodules/react-native-adapter/ios" UMSensorsInterface: :path: "../../node_modules/unimodules-sensors-interface/ios" UMTaskManagerInterface: :path: "../../node_modules/unimodules-task-manager-interface/ios" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: cde416483dac037923206447da6e1454df403714 DVAssetLoaderDelegate: 0caec20e4e08b8560b691131539e9180024d4bce EXConstants: 5304709b1bea70a4828f48ba4c7fc3ec3b2d9b17 EXFileSystem: cf4232ba7c62dc49b78c2d36005f97b6fddf0b01 EXImageLoader: 5ad6896fa1ef2ee814b551873cbf7a7baccc694a EXImageManipulator: 77756def08b3f2bc2a0470c657fbd0d94f381fa4 EXMediaLibrary: 580c097a85f9253deaaf7aaa75a8a2e692e9d8b9 EXPermissions: 24b97f734ce9172d245a5be38ad9ccfcb6135964 EXSplashScreen: c4ed5d39cd5dbc1329f8dec720e280276bafa28b FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d Folly: b73c3869541e86821df3c387eb0af5f65addfab4 glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3 lottie-ios: 496ac5cea1bbf1a7bd1f1f472f3232eb1b8d744b lottie-react-native: b123a79529cc732201091f585c62c89bb4747252 mobile-ffmpeg-min: d5d22dcef5c8ec56f771258f1f5be245d914f193 OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b React: b0a957a2c44da4113b0c4c9853d8387f8e64e615 React-callinvoker: c3f44dd3cb195b6aa46621fff95ded79d59043fe React-Core: d3b2a1ac9a2c13c3bcde712d9281fc1c8a5b315b React-CoreModules: 0581ff36cb797da0943d424f69e7098e43e9be60 React-cxxreact: c1480d4fda5720086c90df537ee7d285d4c57ac3 React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31 React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949 React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a react-native-background-upload: 6e8ba7f41a6308231306bddc88f11da3b74c9de4 react-native-camera: b5c8c7a71feecfdd5b39f0dbbf6b64b957ed55f2 react-native-ffmpeg: f9a60452aaa5d478aac205b248224994f3bde416 react-native-in-app-message: f91de5009620af01456531118264c93e249b83ec react-native-netinfo: 6bb847e64f45a2d69c6173741111cfd95c669301 react-native-notifications: bb042206ac7eab9323d528c780b3d6fe796c1f5e react-native-orientation-locker: 23918c400376a7043e752c639c122fcf6bce8f1c react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94 react-native-video: d01ed7ff1e38fa7dcc6c15c94cf505e661b7bfd0 React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0 React-RCTImage: c1b1f2d3f43a4a528c8946d6092384b5c880d2f0 React-RCTLinking: 35ae4ab9dc0410d1fcbdce4d7623194a27214fb2 React-RCTNetwork: 29ec2696f8d8cfff7331fac83d3e893c95ef43ae React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab ReactNativeDarkMode: 88317ff05ba95fd063dd347ad32f8c4cefd3166c ReactNativeKeyboardInput: 266ba27a2e9921f5bdc0b4cc30289b2a2f46b157 ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306 RNCAsyncStorage: 60a80e72d95bf02a01cace55d3697d9724f0d77f RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495 RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3 RNFastImage: 9b0c22643872bb7494c8d87bbbb66cc4c0d9e7a2 RNFS: 54da03c2b7d862c42ea3ca8c7f86f892760a535a RNGestureHandler: 7a5833d0f788dbd107fbb913e09aa0c1ff333c39 RNKeychain: 45dbd50d1ac4bd42c3740f76ffb135abf05746d0 RNReanimated: dd8c286ab5dd4ba36d3a7fef8bff7e08711b5476 RNScreens: 2e278a90eb15092ed261d4f2271e3fc9b60d08d4 RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4 SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5 SDWebImageWebPCoder: 947093edd1349d820c40afbd9f42acb6cdecd987 SPTPersistentCache: df36ea46762d7cf026502bbb86a8b79d0080dff4 UMAppLoader: 90273a65f9b1d789214e0c913dfcabc7a1b1590e UMBarCodeScannerInterface: 9dc692b87e5f20fe277fa57aa47f45d418c3cc6c UMCameraInterface: 625878bbf2ba188a8548675e1d1d2e438a653e6d UMConstantsInterface: 64060cf86587bcd90b1dbd804cceb6d377a308c1 UMCore: d6117852f32c74cde466b863cfdeaa0960186249 UMFaceDetectorInterface: d6677d6ddc9ab95a0ca857aa7f8ba76656cc770f UMFileSystemInterface: c70ea7147198b9807080f3597f26236be49b0165 UMFontInterface: d9d3b27af698c5389ae9e20b99ef56a083f491fb UMImageLoaderInterface: 14dd2c46c67167491effc9e91250e9510f12709e UMPermissionsInterface: 5e83a9167c177e4a0f0a3539345983cc749efb3e UMReactNativeAdapter: 126da3486c1a1f11945b649d557d6c2ebb9407b2 UMSensorsInterface: 48941f70175e2975af1a9386c6d6cb16d8126805 UMTaskManagerInterface: cb890c79c63885504ddc0efd7a7d01481760aca2 Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 9e67a7c3373805d3742a6685b308d920d73ed027 -COCOAPODS: 1.10.0 +COCOAPODS: 1.10.1 diff --git a/server/src/responders/website-responders.js b/server/src/responders/website-responders.js index 9ec97cab6..9dfcaa8c1 100644 --- a/server/src/responders/website-responders.js +++ b/server/src/responders/website-responders.js @@ -1,330 +1,331 @@ // @flow import html from 'common-tags/lib/html'; import type { $Response, $Request } from 'express'; import fs from 'fs'; import _keyBy from 'lodash/fp/keyBy'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import { Provider } from 'react-redux'; import { Route, StaticRouter } from 'react-router'; import { createStore, type Store } from 'redux'; import { promisify } from 'util'; import { daysToEntriesFromEntryInfos } from 'lib/reducers/entry-reducer'; import { freshMessageStore } from 'lib/reducers/message-reducer'; import { mostRecentReadThread } from 'lib/selectors/thread-selectors'; import { mostRecentMessageTimestamp } from 'lib/shared/message-utils'; import { threadHasPermission } from 'lib/shared/thread-utils'; import { defaultCalendarFilters } from 'lib/types/filter-types'; import { defaultNumberPerThread } from 'lib/types/message-types'; import { defaultConnectionInfo } from 'lib/types/socket-types'; import { threadPermissions } from 'lib/types/thread-types'; import type { ServerVerificationResult } from 'lib/types/verify-types'; import { currentDateInTimeZone } from 'lib/utils/date-utils'; import { ServerError } from 'lib/utils/errors'; import { promiseAll } from 'lib/utils/promises'; import App from 'web/dist/app.build.cjs'; import { reducer } from 'web/redux/redux-setup'; import type { AppState, Action } from 'web/redux/redux-setup'; +import getTitle from 'web/title/getTitle'; import { navInfoFromURL } from 'web/url-utils'; import urlFacts from '../../facts/url'; import { fetchEntryInfos } from '../fetchers/entry-fetchers'; import { fetchMessageInfos } from '../fetchers/message-fetchers'; import { fetchThreadInfos } from '../fetchers/thread-fetchers'; import { fetchCurrentUserInfo, fetchKnownUserInfos, } from '../fetchers/user-fetchers'; import { handleCodeVerificationRequest } from '../models/verification'; import { setNewSession } from '../session/cookies'; import { Viewer } from '../session/viewer'; import { streamJSON, waitForStream } from '../utils/json-stream'; const { basePath, baseDomain } = urlFacts; const { renderToNodeStream } = ReactDOMServer; const baseURL = basePath.replace(/\/$/, ''); const baseHref = baseDomain + baseURL; const access = promisify(fs.access); const googleFontsURL = 'https://fonts.googleapis.com/css?family=Open+Sans:300,600%7CAnaheim'; const localFontsURL = 'fonts/local-fonts.css'; async function getFontsURL() { try { await access(localFontsURL); return localFontsURL; } catch { return googleFontsURL; } } type AssetInfo = {| jsURL: string, fontsURL: string, cssInclude: string |}; let assetInfo: ?AssetInfo = null; async function getAssetInfo() { if (assetInfo) { return assetInfo; } if (process.env.NODE_ENV === 'dev') { const fontsURL = await getFontsURL(); assetInfo = { jsURL: 'http://localhost:8080/dev.build.js', fontsURL, cssInclude: '', }; return assetInfo; } // $FlowFixMe compiled/assets.json doesn't always exist const { default: assets } = await import('../../compiled/assets'); assetInfo = { jsURL: `compiled/${assets.browser.js}`, fontsURL: googleFontsURL, cssInclude: html` `, }; return assetInfo; } async function websiteResponder( viewer: Viewer, req: $Request, res: $Response, ): Promise { let initialNavInfo; try { initialNavInfo = navInfoFromURL(req.url, { now: currentDateInTimeZone(viewer.timeZone), }); } catch (e) { throw new ServerError(e.message); } const calendarQuery = { startDate: initialNavInfo.startDate, endDate: initialNavInfo.endDate, filters: defaultCalendarFilters, }; const threadSelectionCriteria = { joinedThreads: true }; const initialTime = Date.now(); const assetInfoPromise = getAssetInfo(); const threadInfoPromise = fetchThreadInfos(viewer); const messageInfoPromise = fetchMessageInfos( viewer, threadSelectionCriteria, defaultNumberPerThread, ); const entryInfoPromise = fetchEntryInfos(viewer, [calendarQuery]); const currentUserInfoPromise = fetchCurrentUserInfo(viewer); const serverVerificationResultPromise = handleVerificationRequest( viewer, initialNavInfo.verify, ); const userInfoPromise = fetchKnownUserInfos(viewer); const sessionIDPromise = (async () => { if (viewer.loggedIn) { await setNewSession(viewer, calendarQuery, initialTime); } return viewer.sessionID; })(); const threadStorePromise = (async () => { const { threadInfos } = await threadInfoPromise; return { threadInfos, inconsistencyReports: [] }; })(); const messageStorePromise = (async () => { const [ { threadInfos }, { rawMessageInfos, truncationStatuses }, ] = await Promise.all([threadInfoPromise, messageInfoPromise]); return freshMessageStore( rawMessageInfos, truncationStatuses, mostRecentMessageTimestamp(rawMessageInfos, initialTime), threadInfos, ); })(); const entryStorePromise = (async () => { const { rawEntryInfos } = await entryInfoPromise; return { entryInfos: _keyBy('id')(rawEntryInfos), daysToEntries: daysToEntriesFromEntryInfos(rawEntryInfos), lastUserInteractionCalendar: initialTime, inconsistencyReports: [], }; })(); const userStorePromise = (async () => { const userInfos = await userInfoPromise; return { userInfos, inconsistencyReports: [] }; })(); const navInfoPromise = (async () => { const [{ threadInfos }, messageStore] = await Promise.all([ threadInfoPromise, messageStorePromise, ]); let finalNavInfo = initialNavInfo; const requestedActiveChatThreadID = finalNavInfo.activeChatThreadID; if ( requestedActiveChatThreadID && !threadHasPermission( threadInfos[requestedActiveChatThreadID], threadPermissions.VISIBLE, ) ) { finalNavInfo.activeChatThreadID = null; } if (!finalNavInfo.activeChatThreadID) { const mostRecentThread = mostRecentReadThread(messageStore, threadInfos); if (mostRecentThread) { finalNavInfo.activeChatThreadID = mostRecentThread; } } return finalNavInfo; })(); const { jsURL, fontsURL, cssInclude } = await assetInfoPromise; // prettier-ignore res.write(html` - SquadCal + ${getTitle(0)} ${cssInclude}
`); const statePromises = { navInfo: navInfoPromise, currentUserInfo: currentUserInfoPromise, sessionID: sessionIDPromise, serverVerificationResult: serverVerificationResultPromise, entryStore: entryStorePromise, threadStore: threadStorePromise, userStore: userStorePromise, messageStore: messageStorePromise, updatesCurrentAsOf: initialTime, loadingStatuses: {}, calendarFilters: defaultCalendarFilters, // We can use paths local to the on web urlPrefix: '', windowDimensions: { width: 0, height: 0 }, baseHref, connection: { ...defaultConnectionInfo('web', viewer.timeZone), actualizedCalendarQuery: calendarQuery, }, watchedThreadIDs: [], foreground: true, nextLocalID: 0, queuedReports: [], timeZone: viewer.timeZone, userAgent: viewer.userAgent, cookie: undefined, deviceToken: undefined, dataLoaded: viewer.loggedIn, windowActive: true, }; const stateResult = await promiseAll(statePromises); const state: AppState = { ...stateResult }; const store: Store = createStore(reducer, state); const routerContext = {}; const reactStream = renderToNodeStream( , ); if (routerContext.url) { throw new ServerError('URL modified during server render!'); } reactStream.pipe(res, { end: false }); await waitForStream(reactStream); res.write(html`
`); } async function handleVerificationRequest( viewer: Viewer, code: ?string, ): Promise { if (!code) { return null; } try { return await handleCodeVerificationRequest(viewer, code); } catch (e) { if (e instanceof ServerError && e.message === 'invalid_code') { return { success: false }; } throw e; } } export { websiteResponder }; diff --git a/web/app.react.js b/web/app.react.js index 8c0dd96b7..7b3aa5140 100644 --- a/web/app.react.js +++ b/web/app.react.js @@ -1,375 +1,380 @@ // @flow import { config as faConfig } from '@fortawesome/fontawesome-svg-core'; import { faCalendar, faComments } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import invariant from 'invariant'; import _isEqual from 'lodash/fp/isEqual'; import * as React from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { useDispatch } from 'react-redux'; import { fetchEntriesActionTypes, updateCalendarQueryActionTypes, } from 'lib/actions/entry-actions'; import { createLoadingStatusSelector, combineLoadingStatuses, } from 'lib/selectors/loading-selectors'; import { mostRecentReadThreadSelector, unreadCount, } from 'lib/selectors/thread-selectors'; import { isLoggedIn } from 'lib/selectors/user-selectors'; import type { LoadingStatus } from 'lib/types/loading-types'; import type { Dispatch } from 'lib/types/redux-types'; import { verifyField, type ServerVerificationResult, } from 'lib/types/verify-types'; import { registerConfig } from 'lib/utils/config'; import AccountBar from './account-bar.react'; import Calendar from './calendar/calendar.react'; import Chat from './chat/chat.react'; import InputStateContainer from './input/input-state-container.react'; import LoadingIndicator from './loading-indicator.react'; import ResetPasswordModal from './modals/account/reset-password-modal.react'; import VerificationModal from './modals/account/verification-modal.react'; import FocusHandler from './redux/focus-handler.react'; import { type NavInfo, updateNavInfoActionType } from './redux/redux-setup'; import { useSelector } from './redux/redux-utils'; import VisibilityHandler from './redux/visibility-handler.react'; import history from './router-history'; import Splash from './splash/splash.react'; import css from './style.css'; +import getTitle from './title/getTitle'; import { canonicalURLFromReduxState, navInfoFromURL } from './url-utils'; // We want Webpack's css-loader and style-loader to handle the Fontawesome CSS, // so we disable the autoAddCss logic and import the CSS file. Otherwise every // icon flashes huge for a second before the CSS is loaded. import '@fortawesome/fontawesome-svg-core/styles.css'; faConfig.autoAddCss = false; registerConfig({ // We can't securely cache credentials on web, so we have no way to recover // from a cookie invalidation resolveInvalidatedCookie: null, // We use httponly cookies on web to protect against XSS attacks, so we have // no access to the cookies from JavaScript setCookieOnRequest: false, setSessionIDOnRequest: true, // Never reset the calendar range calendarRangeInactivityLimit: null, platformDetails: { platform: 'web' }, }); type BaseProps = {| +location: { +pathname: string, ... }, |}; type Props = {| ...BaseProps, // Redux state +navInfo: NavInfo, +serverVerificationResult: ?ServerVerificationResult, +entriesLoadingStatus: LoadingStatus, +loggedIn: boolean, +mostRecentReadThread: ?string, +activeThreadCurrentlyUnread: boolean, +viewerID: ?string, +unreadCount: number, // Redux dispatch functions +dispatch: Dispatch, |}; type State = {| +currentModal: ?React.Node, |}; class App extends React.PureComponent { state: State = { currentModal: null, }; componentDidMount() { const { navInfo, serverVerificationResult } = this.props; if (navInfo.verify && serverVerificationResult) { if (serverVerificationResult.field === verifyField.RESET_PASSWORD) { this.showResetPasswordModal(); } else { const newURL = canonicalURLFromReduxState( { ...navInfo, verify: null }, this.props.location.pathname, ); history.replace(newURL); this.setModal(); } } if (this.props.loggedIn) { const newURL = canonicalURLFromReduxState( navInfo, this.props.location.pathname, ); if (this.props.location.pathname !== newURL) { history.replace(newURL); } } else if (this.props.location.pathname !== '/') { history.replace('/'); } } componentDidUpdate(prevProps: Props) { if (this.props.loggedIn) { if (this.props.location.pathname !== prevProps.location.pathname) { const newNavInfo = navInfoFromURL(this.props.location.pathname, { navInfo: this.props.navInfo, }); if (!_isEqual(newNavInfo)(this.props.navInfo)) { this.props.dispatch({ type: updateNavInfoActionType, payload: newNavInfo, }); } } else if (!_isEqual(this.props.navInfo)(prevProps.navInfo)) { const newURL = canonicalURLFromReduxState( this.props.navInfo, this.props.location.pathname, ); if (newURL !== this.props.location.pathname) { history.push(newURL); } } } const justLoggedIn = this.props.loggedIn && !prevProps.loggedIn; if (justLoggedIn) { const newURL = canonicalURLFromReduxState( this.props.navInfo, this.props.location.pathname, ); if (this.props.location.pathname !== newURL) { history.replace(newURL); } } const justLoggedOut = !this.props.loggedIn && prevProps.loggedIn; if (justLoggedOut && this.props.location.pathname !== '/') { history.replace('/'); } const { navInfo, serverVerificationResult } = this.props; if ( serverVerificationResult && serverVerificationResult.field === verifyField.RESET_PASSWORD ) { if (navInfo.verify && !prevProps.navInfo.verify) { this.showResetPasswordModal(); } else if (!navInfo.verify && prevProps.navInfo.verify) { this.clearModal(); } } } showResetPasswordModal() { const newURL = canonicalURLFromReduxState( { ...this.props.navInfo, verify: null, }, this.props.location.pathname, ); const onClose = () => history.push(newURL); const onSuccess = () => history.replace(newURL); this.setModal( , ); } render() { let content; if (this.props.loggedIn) { content = this.renderMainContent(); } else { content = ( ); } return ( {content} {this.state.currentModal} ); } renderMainContent() { const calendarNavClasses = classNames({ [css['current-tab']]: this.props.navInfo.tab === 'calendar', }); const chatNavClasses = classNames({ [css['current-tab']]: this.props.navInfo.tab === 'chat', }); let mainContent; if (this.props.navInfo.tab === 'calendar') { mainContent = ( ); } else if (this.props.navInfo.tab === 'chat') { mainContent = ; } const { viewerID, unreadCount: curUnreadCount } = this.props; invariant(viewerID, 'should be set'); let chatBadge = null; if (curUnreadCount > 0) { chatBadge =
{curUnreadCount}
; } return (
{mainContent}
); } setModal = (modal: ?React.Node) => { this.setState({ currentModal: modal }); }; clearModal = () => { this.setModal(null); }; onClickCalendar = (event: SyntheticEvent) => { event.preventDefault(); this.props.dispatch({ type: updateNavInfoActionType, payload: { tab: 'calendar' }, }); }; onClickChat = (event: SyntheticEvent) => { event.preventDefault(); this.props.dispatch({ type: updateNavInfoActionType, payload: { tab: 'chat', activeChatThreadID: this.props.activeThreadCurrentlyUnread ? this.props.mostRecentReadThread : this.props.navInfo.activeChatThreadID, }, }); }; } const fetchEntriesLoadingStatusSelector = createLoadingStatusSelector( fetchEntriesActionTypes, ); const updateCalendarQueryLoadingStatusSelector = createLoadingStatusSelector( updateCalendarQueryActionTypes, ); export default React.memo(function ConnectedApp(props: BaseProps) { const activeChatThreadID = useSelector( (state) => state.navInfo.activeChatThreadID, ); const navInfo = useSelector((state) => state.navInfo); const serverVerificationResult = useSelector( (state) => state.serverVerificationResult, ); const fetchEntriesLoadingStatus = useSelector( fetchEntriesLoadingStatusSelector, ); const updateCalendarQueryLoadingStatus = useSelector( updateCalendarQueryLoadingStatusSelector, ); const entriesLoadingStatus = combineLoadingStatuses( fetchEntriesLoadingStatus, updateCalendarQueryLoadingStatus, ); const loggedIn = useSelector(isLoggedIn); const mostRecentReadThread = useSelector(mostRecentReadThreadSelector); const activeThreadCurrentlyUnread = useSelector( (state) => !activeChatThreadID || !!state.threadStore.threadInfos[activeChatThreadID].currentUser.unread, ); const viewerID = useSelector( (state) => state.currentUserInfo && state.currentUserInfo.id, ); const boundUnreadCount = useSelector(unreadCount); + React.useEffect(() => { + document.title = getTitle(boundUnreadCount); + }, [boundUnreadCount]); + const dispatch = useDispatch(); return ( ); }); diff --git a/web/title/getTitle.js b/web/title/getTitle.js new file mode 100644 index 000000000..2d27f781f --- /dev/null +++ b/web/title/getTitle.js @@ -0,0 +1,11 @@ +// @flow + +const getTitle = (count: number): string => { + const title = 'SquadCal'; + if (count > 0) { + return `${title} (${count})`; + } + return title; +}; + +export default getTitle;