lv 1 miesiąc temu
rodzic
commit
810fd175f0

+ 4 - 3
app.json

@@ -2,7 +2,7 @@
   "expo": {
     "name": "Loan Assistant",
     "slug": "assistant",
-    "version": "1.0.0",
+    "version": "1.0.1",
     "orientation": "portrait",
     "icon": "./assets/images/icon.png",
     "scheme": "loanassistant",
@@ -57,14 +57,15 @@
         }
       ],
       [
-      "expo-build-properties",
+        "expo-build-properties",
         {
           "android": {
             "enableMinifyInReleaseBuilds": true,
             "enableBundleCompression": true
           }
         }
-      ]
+      ],
+      "expo-web-browser"
     ],
     "experiments": {
       "typedRoutes": true,

+ 34 - 2
ios/Podfile.lock

@@ -52,6 +52,8 @@ PODS:
     - SDWebImageWebPCoder (~> 0.14.6)
   - ExpoKeepAwake (55.0.6):
     - ExpoModulesCore
+  - ExpoLinearGradient (55.0.13):
+    - ExpoModulesCore
   - ExpoLinking (55.0.11):
     - ExpoModulesCore
   - ExpoLogBox (55.0.10):
@@ -95,7 +97,7 @@ PODS:
     - ExpoModulesCore
   - ExpoSystemUI (55.0.14):
     - ExpoModulesCore
-  - ExpoWebBrowser (55.0.13):
+  - ExpoWebBrowser (55.0.14):
     - ExpoModulesCore
   - EXStructuredHeaders (55.0.2)
   - EXUpdates (55.0.20):
@@ -1661,6 +1663,28 @@ PODS:
     - ReactCommon/turbomodule/core
     - ReactNativeDependencies
     - Yoga
+  - react-native-webview (13.16.0):
+    - hermes-engine
+    - RCTRequired
+    - RCTTypeSafety
+    - React-Core
+    - React-Core-prebuilt
+    - React-debug
+    - React-Fabric
+    - React-featureflags
+    - React-graphics
+    - React-ImageManager
+    - React-jsi
+    - React-NativeModulesApple
+    - React-RCTFabric
+    - React-renderercss
+    - React-rendererdebug
+    - React-utils
+    - ReactCodegen
+    - ReactCommon/turbomodule/bridging
+    - ReactCommon/turbomodule/core
+    - ReactNativeDependencies
+    - Yoga
   - React-NativeModulesApple (0.83.4):
     - hermes-engine
     - React-callinvoker
@@ -2308,6 +2332,7 @@ DEPENDENCIES:
   - ExpoGlassEffect (from `../node_modules/expo-glass-effect/ios`)
   - ExpoImage (from `../node_modules/expo-image/ios`)
   - ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
+  - ExpoLinearGradient (from `../node_modules/expo-linear-gradient/ios`)
   - ExpoLinking (from `../node_modules/expo-linking/ios`)
   - "ExpoLogBox (from `../node_modules/@expo/log-box`)"
   - ExpoModulesCore (from `../node_modules/expo-modules-core`)
@@ -2362,6 +2387,7 @@ DEPENDENCIES:
   - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
   - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
   - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
+  - react-native-webview (from `../node_modules/react-native-webview`)
   - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
   - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`)
   - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
@@ -2442,6 +2468,8 @@ EXTERNAL SOURCES:
     :path: "../node_modules/expo-image/ios"
   ExpoKeepAwake:
     :path: "../node_modules/expo-keep-awake/ios"
+  ExpoLinearGradient:
+    :path: "../node_modules/expo-linear-gradient/ios"
   ExpoLinking:
     :path: "../node_modules/expo-linking/ios"
   ExpoLogBox:
@@ -2549,6 +2577,8 @@ EXTERNAL SOURCES:
     :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
   react-native-safe-area-context:
     :path: "../node_modules/react-native-safe-area-context"
+  react-native-webview:
+    :path: "../node_modules/react-native-webview"
   React-NativeModulesApple:
     :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
   React-networking:
@@ -2644,6 +2674,7 @@ SPEC CHECKSUMS:
   ExpoGlassEffect: 72bcb9dc634262c59897ff7c53c16e2ff03990d0
   ExpoImage: ef931bba1fd3e907c2262216d17eb21095c9ac2b
   ExpoKeepAwake: a1baf9810a2dee1905aa9bdd336852598f7220e9
+  ExpoLinearGradient: c654e92d726a6d64c588a0988bb22bea331d5e79
   ExpoLinking: b42fd76bdda8662ddf797b17cb4cc793adabfe98
   ExpoLogBox: a3de999775d423ac9cb85d24bd47628e5392761f
   ExpoModulesCore: 964f01116faf01b68467a6c8ea06e14d65fe7b3c
@@ -2652,7 +2683,7 @@ SPEC CHECKSUMS:
   ExpoSplashScreen: 5d16d7a0ada0671b5c59080b1ce9126c987baee7
   ExpoSymbols: 8b63e859ba013df1f2fc666f535fddb3d5270569
   ExpoSystemUI: 8f1d5aac902dada8df8cc2944563c56e2179fcb9
-  ExpoWebBrowser: f81f8e35afd7f61ec809622ef354c579a3b580e2
+  ExpoWebBrowser: f88a3ba50a025b673236a46d2654a49b985953d6
   EXStructuredHeaders: 93ad4f31a2eec124428675e28aca11de243ee1e4
   EXUpdates: 1457ed285cd7c5e9d4c388ace518af55fa4b21ec
   EXUpdatesInterface: 39d05400a9226c438565dbaaa8447b5f0672ba45
@@ -2702,6 +2733,7 @@ SPEC CHECKSUMS:
   React-Mapbuffer: 274cb203819492f7fb594bbb3a1f3f5061fa794d
   React-microtasksnativemodule: 563b4dcc8b8570814d6de4fc1196f48d2944acd4
   react-native-safe-area-context: 37e680fc4cace3c0030ee46e8987d24f5d3bdab2
+  react-native-webview: 3e303e80cadb5f17118c8c1502aa398e9287e415
   React-NativeModulesApple: f3eb751b0ea23645a5283ed8c8bb8ebeeda32d15
   React-networking: af5eba8ccda3334cd2f6246b599d3b55bb73eb2e
   React-oscompat: 3774ed6bc0e9866ff7236b94adbc7ad33ceaecdd

+ 2 - 1
package.json

@@ -37,7 +37,7 @@
     "expo-symbols": "~55.0.7",
     "expo-system-ui": "~55.0.14",
     "expo-updates": "~55.0.20",
-    "expo-web-browser": "~55.0.13",
+    "expo-web-browser": "~55.0.14",
     "nativewind": "^4.2.3",
     "react": "19.2.0",
     "react-dom": "19.2.0",
@@ -50,6 +50,7 @@
     "react-native-safe-area-context": "~5.6.2",
     "react-native-screens": "~4.23.0",
     "react-native-web": "~0.21.0",
+    "react-native-webview": "13.16.0",
     "react-native-worklets": "0.7.2"
   },
   "devDependencies": {

+ 50 - 32
pnpm-lock.yaml

@@ -33,7 +33,7 @@ importers:
         version: 1.14.0
       expo:
         specifier: ~55.0.12
-        version: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+        version: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-build-properties:
         specifier: ~55.0.13
         version: 55.0.13(expo@55.0.12)
@@ -74,8 +74,8 @@ importers:
         specifier: ~55.0.20
         version: 55.0.20(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-web-browser:
-        specifier: ~55.0.13
-        version: 55.0.13(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))
+        specifier: ~55.0.14
+        version: 55.0.14(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))
       nativewind:
         specifier: ^4.2.3
         version: 4.2.3(react-native-reanimated@4.2.1(react-native-worklets@0.7.2(@babel/core@7.29.0)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(tailwindcss@3.4.19(yaml@2.8.3))
@@ -112,6 +112,9 @@ importers:
       react-native-web:
         specifier: ~0.21.0
         version: 0.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      react-native-webview:
+        specifier: 13.16.0
+        version: 13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       react-native-worklets:
         specifier: 0.7.2
         version: 0.7.2(@babel/core@7.29.0)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
@@ -1806,6 +1809,7 @@ packages:
   '@xmldom/xmldom@0.8.12':
     resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==}
     engines: {node: '>=10.0.0'}
+    deprecated: this version has critical issues, please update to the latest version
 
   abort-controller@3.0.0:
     resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
@@ -2815,8 +2819,8 @@ packages:
       react: '*'
       react-native: '*'
 
-  expo-web-browser@55.0.13:
-    resolution: {integrity: sha512-phzsFucUw0uHm0f2f4tJ7ZO3vYnGm0Y7izyWDD71TjP8pyMsvNOh5RKJGLUqk1diSrAFUbHKZYdt6D2b30deiw==}
+  expo-web-browser@55.0.14:
+    resolution: {integrity: sha512-bTDkBSQBnrlnYcM7Aak72AOvJuvdgA3M8p//Lazrm0Nfa77T9cRXzQ6KhLrB08V39n1+00d1dvuTWznJslkmdg==}
     peerDependencies:
       expo: '*'
       react-native: '*'
@@ -4368,6 +4372,12 @@ packages:
       react: ^18.0.0 || ^19.0.0
       react-dom: ^18.0.0 || ^19.0.0
 
+  react-native-webview@13.16.0:
+    resolution: {integrity: sha512-Nh13xKZWW35C0dbOskD7OX01nQQavOzHbCw9XoZmar4eXCo7AvrYJ0jlUfRVVIJzqINxHlpECYLdmAdFsl9xDA==}
+    peerDependencies:
+      react: '*'
+      react-native: '*'
+
   react-native-worklets@0.7.2:
     resolution: {integrity: sha512-DuLu1kMV/Uyl9pQHp3hehAlThoLw7Yk2FwRTpzASOmI+cd4845FWn3m2bk9MnjUw8FBRIyhwLqYm2AJaXDXsog==}
     peerDependencies:
@@ -6284,7 +6294,7 @@ snapshots:
       connect: 3.7.0
       debug: 4.4.3
       dnssd-advertise: 1.1.4
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-server: 55.0.7
       fetch-nodeshim: 0.4.10
       getenv: 2.0.0
@@ -6399,7 +6409,7 @@ snapshots:
 
   '@expo/dom-webview@55.0.5(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)':
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
 
@@ -6454,7 +6464,7 @@ snapshots:
     dependencies:
       '@expo/dom-webview': 55.0.5(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       anser: 1.4.10
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
       stacktrace-parser: 0.1.11
@@ -6481,7 +6491,7 @@ snapshots:
       postcss: 8.4.49
       resolve-from: 5.0.0
     optionalDependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
     transitivePeerDependencies:
       - bufferutil
       - supports-color
@@ -6492,7 +6502,7 @@ snapshots:
     dependencies:
       '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       anser: 1.4.10
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       pretty-format: 29.7.0
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
@@ -6552,7 +6562,7 @@ snapshots:
       '@expo/json-file': 10.0.13
       '@react-native/normalize-colors': 0.83.4
       debug: 4.4.3
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       resolve-from: 5.0.0
       semver: 7.7.4
       xml2js: 0.6.0
@@ -6583,7 +6593,7 @@ snapshots:
   '@expo/router-server@55.0.13(@expo/metro-runtime@55.0.9)(expo-constants@55.0.12)(expo-font@55.0.6)(expo-router@55.0.11)(expo-server@55.0.7)(expo@55.0.12)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
     dependencies:
       debug: 4.4.3
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-constants: 55.0.12(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3)
       expo-font: 55.0.6(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       expo-server: 55.0.7
@@ -7684,7 +7694,7 @@ snapshots:
       resolve-from: 5.0.0
     optionalDependencies:
       '@babel/runtime': 7.29.2
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
     transitivePeerDependencies:
       - '@babel/core'
       - supports-color
@@ -8434,7 +8444,7 @@ snapshots:
   expo-asset@55.0.13(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
     dependencies:
       '@expo/image-utils': 0.8.12
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-constants: 55.0.12(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
@@ -8445,7 +8455,7 @@ snapshots:
   expo-build-properties@55.0.13(expo@55.0.12):
     dependencies:
       '@expo/schema-utils': 55.0.3
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       resolve-from: 5.0.0
       semver: 7.7.4
 
@@ -8453,7 +8463,7 @@ snapshots:
     dependencies:
       '@expo/config': 55.0.13(typescript@5.9.3)
       '@expo/env': 2.1.1
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
     transitivePeerDependencies:
       - supports-color
@@ -8461,32 +8471,32 @@ snapshots:
 
   expo-device@55.0.13(expo@55.0.12):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       ua-parser-js: 0.7.41
 
   expo-eas-client@55.0.5: {}
 
   expo-file-system@55.0.15(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
 
   expo-font@55.0.6(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       fontfaceobserver: 2.3.0
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
 
   expo-glass-effect@55.0.10(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
 
   expo-image@55.0.8(expo@55.0.12)(react-native-web@0.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
       sf-symbols-typescript: 2.2.0
@@ -8497,7 +8507,7 @@ snapshots:
 
   expo-keep-awake@55.0.6(expo@55.0.12)(react@19.2.0):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react: 19.2.0
 
   expo-linking@55.0.11(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
@@ -8514,7 +8524,7 @@ snapshots:
   expo-manifests@55.0.15(expo@55.0.12)(typescript@5.9.3):
     dependencies:
       '@expo/config': 55.0.15(typescript@5.9.3)
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-json-utils: 55.0.2
     transitivePeerDependencies:
       - supports-color
@@ -8549,7 +8559,7 @@ snapshots:
       client-only: 0.0.1
       debug: 4.4.3
       escape-string-regexp: 4.0.0
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-constants: 55.0.12(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3)
       expo-glass-effect: 55.0.10(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       expo-image: 55.0.8(expo@55.0.12)(react-native-web@0.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
@@ -8589,7 +8599,7 @@ snapshots:
   expo-splash-screen@55.0.16(expo@55.0.12)(typescript@5.9.3):
     dependencies:
       '@expo/prebuild-config': 55.0.13(expo@55.0.12)(typescript@5.9.3)
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
     transitivePeerDependencies:
       - supports-color
       - typescript
@@ -8605,7 +8615,7 @@ snapshots:
   expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
     dependencies:
       '@expo-google-fonts/material-symbols': 0.4.29
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-font: 55.0.6(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       react: 19.2.0
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
@@ -8615,7 +8625,7 @@ snapshots:
     dependencies:
       '@react-native/normalize-colors': 0.83.4
       debug: 4.4.3
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
     optionalDependencies:
       react-native-web: 0.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -8624,7 +8634,7 @@ snapshots:
 
   expo-updates-interface@55.1.5(expo@55.0.12):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
 
   expo-updates@55.0.20(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
     dependencies:
@@ -8634,7 +8644,7 @@ snapshots:
       arg: 4.1.3
       chalk: 4.1.2
       debug: 4.4.3
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       expo-eas-client: 55.0.5
       expo-manifests: 55.0.15(expo@55.0.12)(typescript@5.9.3)
       expo-structured-headers: 55.0.2
@@ -8649,12 +8659,12 @@ snapshots:
       - supports-color
       - typescript
 
-  expo-web-browser@55.0.13(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)):
+  expo-web-browser@55.0.14(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)):
     dependencies:
-      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+      expo: 55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
       react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
 
-  expo@55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
+  expo@55.0.12(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.11)(react-dom@19.2.0(react@19.2.0))(react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
     dependencies:
       '@babel/runtime': 7.29.2
       '@expo/cli': 55.0.22(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.12)(expo-font@55.0.6)(expo-router@55.0.11)(expo@55.0.12)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
@@ -8684,6 +8694,7 @@ snapshots:
     optionalDependencies:
       '@expo/dom-webview': 55.0.5(expo@55.0.12)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
       '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.12)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
+      react-native-webview: 13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
     transitivePeerDependencies:
       - '@babel/core'
       - bufferutil
@@ -10344,6 +10355,13 @@ snapshots:
     transitivePeerDependencies:
       - encoding
 
+  react-native-webview@13.16.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
+    dependencies:
+      escape-string-regexp: 4.0.0
+      invariant: 2.2.4
+      react: 19.2.0
+      react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
+
   react-native-worklets@0.7.2(@babel/core@7.29.0)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
     dependencies:
       '@babel/core': 7.29.0

+ 5 - 8
src/app/(tabs)/_layout.tsx

@@ -4,17 +4,14 @@ import { router } from 'expo-router';
 import React, { useEffect } from 'react';
 
 export default function TabLayout() {
-  const { isAuthenticated } = useAuth();
+  const { authStatus } = useAuth();
 
   useEffect(() => {
-    if (!isAuthenticated) {
-      router.replace('/sign-in');
+    if (authStatus === 'fail') {
+      router.push('/sign-in');
     }
-  }, [isAuthenticated]);
+  }, [authStatus]);
 
-  if (!isAuthenticated) {
-    return null;
-  }
 
-  return <AppTabs />;
+  return authStatus === 'auth' && <AppTabs />;
 }

+ 20 - 20
src/app/(tabs)/analytics.tsx

@@ -30,22 +30,22 @@ export default function AnalyticsScreen() {
     <SafeAreaView className="flex-1 bg-surface" edges={['top']}>
       <ScrollView
         className="flex-1"
-        contentContainerClassName="px-6 pt-4 pb-28"
+        contentContainerClassName="px-5 pt-3 pb-24"
         showsVerticalScrollIndicator={false}
       >
-        <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
+        <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">
           征信分析
         </Text>
-        <Text className="mb-8 text-base leading-7 text-on-surface-variant">
+        <Text className="mb-6 text-base leading-7 text-on-surface-variant">
           先选择客户,再上传征信文件,系统会自动生成评分和建议动作
         </Text>
 
-        <View className="mb-4 rounded-2xl bg-surface-container-lowest p-5 shadow-sm">
+        <View className="mb-3 rounded-2xl border border-outline-variant bg-surface-container-lowest p-4">
           <Text className="mb-3 text-xs font-bold uppercase tracking-widest text-outline">
             选择客户
           </Text>
           <Pressable
-            className="flex-row items-center rounded-2xl bg-surface-container-low px-4 py-4"
+            className="flex-row items-center rounded-2xl bg-surface-container-low px-4 py-3.5"
             style={({ pressed }) => ({
               opacity: pressed ? 0.9 : 1,
             })}
@@ -58,32 +58,32 @@ export default function AnalyticsScreen() {
           </Pressable>
         </View>
 
-        <View className="mb-4 rounded-2xl bg-surface-container-lowest p-5 shadow-sm">
+        <View className="mb-3 rounded-2xl border border-outline-variant bg-surface-container-lowest p-4">
           <Text className="mb-3 text-xs font-bold uppercase tracking-widest text-outline">
             上传征信文件
           </Text>
           <Pressable
             onPress={() => Toast.info('演示页暂未接入真实上传能力')}
-            className="items-center rounded-2xl border-2 border-dashed border-outline-variant/40 bg-surface-container-low/50 px-6 py-10"
+            className="items-center rounded-2xl border-2 border-dashed border-outline-variant/40 bg-surface-container-low/50 px-6 py-8"
             style={({ pressed }) => ({
               opacity: pressed ? 0.92 : 1,
             })}
           >
-            <View className="mb-4 h-16 w-16 items-center justify-center rounded-full bg-primary-fixed">
+            <View className="mb-3 h-14 w-14 items-center justify-center rounded-full bg-primary-fixed">
               <Ionicons name="cloud-upload-outline" size={30} color="#004ac6" />
             </View>
-            <Text className="mb-1 text-lg font-bold text-on-surface">点击上传征信报告</Text>
+            <Text className="mb-1 text-base font-bold text-on-surface">点击上传征信报告</Text>
             <Text className="text-sm leading-6 text-on-surface-variant">
               支持 PDF、图片格式,最大 20MB
             </Text>
           </Pressable>
         </View>
 
-        <View className="mb-6 rounded-2xl bg-surface-container-lowest p-5 shadow-sm">
+        <View className="mb-5 rounded-2xl border border-outline-variant bg-surface-container-lowest p-4">
           <Text className="mb-3 text-xs font-bold uppercase tracking-widest text-outline">
             解析模式
           </Text>
-          <View className="flex-row gap-3">
+          <View className="flex-row gap-2.5">
             {[
               {
                 key: 'fast' as const,
@@ -103,7 +103,7 @@ export default function AnalyticsScreen() {
                 <Pressable
                   key={item.key}
                   onPress={() => setAnalysisMode(item.key)}
-                  className={`flex-1 rounded-2xl px-4 py-5 ${
+                  className={`flex-1 rounded-2xl px-4 py-4 ${
                     active ? 'bg-primary-container' : 'bg-surface-container-low'
                   }`}
                   style={({ pressed }) => ({
@@ -116,14 +116,14 @@ export default function AnalyticsScreen() {
                     color={active ? '#ffffff' : '#737686'}
                   />
                   <Text
-                    className={`mt-4 text-lg font-bold ${
+                    className={`mt-3 text-base font-bold ${
                       active ? 'text-on-primary' : 'text-on-surface'
                     }`}
                   >
                     {item.title}
                   </Text>
                   <Text
-                    className={`mt-2 text-sm leading-6 ${
+                    className={`mt-1.5 text-sm leading-6 ${
                       active ? 'text-on-primary/80' : 'text-on-surface-variant'
                     }`}
                   >
@@ -137,27 +137,27 @@ export default function AnalyticsScreen() {
 
         <Pressable
           onPress={() => Toast.success('解析任务已加入队列')}
-          className="mb-10 items-center rounded-2xl bg-primary-container py-4 shadow-lg"
+          className="mb-8 items-center rounded-2xl bg-primary py-3.5"
           style={({ pressed }) => ({
             opacity: pressed ? 0.88 : 1,
             transform: [{ scale: pressed ? 0.985 : 1 }],
           })}
         >
-          <Text className="text-lg font-bold text-on-primary">开始解析</Text>
+          <Text className="text-base font-bold text-on-primary">开始解析</Text>
         </Pressable>
 
         <SectionHeader title="解析记录" actionText="查看全部" />
-        <View className="gap-4">
+        <View className="gap-3">
           {ANALYSIS_RECORDS.map((record) => (
             <Pressable
               key={record.id}
-              className="flex-row items-center rounded-2xl bg-surface-container-lowest px-4 py-4 shadow-sm"
+              className="flex-row items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-3.5"
               style={({ pressed }) => ({
                 opacity: pressed ? 0.93 : 1,
               })}
             >
               <View
-                className={`mr-4 h-12 w-12 items-center justify-center rounded-full ${
+                className={`mr-3 h-11 w-11 items-center justify-center rounded-full ${
                   record.status === '已完成'
                     ? 'bg-green-50'
                     : record.status === '解析中'
@@ -186,7 +186,7 @@ export default function AnalyticsScreen() {
 
               <View className="flex-1">
                 <View className="mb-1 flex-row items-center justify-between gap-3">
-                  <Text className="text-lg font-bold text-on-surface">
+                  <Text className="text-base font-bold text-on-surface">
                     {record.customerName}
                   </Text>
                   <Text className="text-xs text-on-surface-variant">{record.time}</Text>

+ 21 - 21
src/app/(tabs)/customer.tsx

@@ -114,18 +114,18 @@ export default function CustomerScreen() {
     <SafeAreaView className="flex-1 bg-surface" edges={['top']}>
       <ScrollView
         className="flex-1"
-        contentContainerClassName="px-6 pt-4 pb-28"
+        contentContainerClassName="px-5 pt-3 pb-24"
         keyboardShouldPersistTaps="handled"
         showsVerticalScrollIndicator={false}
       >
-        <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
+        <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">
           客户
         </Text>
-        <Text className="mb-6 text-base leading-7 text-on-surface-variant">
+        <Text className="mb-5 text-base leading-7 text-on-surface-variant">
           统一跟进客户资料、征信进度和产品匹配状态
         </Text>
 
-        <View className="mb-4 flex-row items-center rounded-2xl bg-surface-container-low px-4 py-3.5">
+        <View className="mb-3 flex-row items-center rounded-2xl bg-surface-container-low px-4 py-3">
           <Ionicons name="search-outline" size={20} color="#737686" />
           <TextInput
             value={search}
@@ -144,8 +144,8 @@ export default function CustomerScreen() {
         <ScrollView
           horizontal
           showsHorizontalScrollIndicator={false}
-          contentContainerClassName="gap-2 pb-2"
-          className="mb-6"
+          contentContainerClassName="gap-2 pb-1"
+          className="mb-5"
         >
           {FILTERS.map((filter) => {
             const active = activeFilter === filter;
@@ -153,7 +153,7 @@ export default function CustomerScreen() {
               <Pressable
                 key={filter}
                 onPress={() => setActiveFilter(filter)}
-                className={`rounded-full px-4 py-2.5 ${
+                className={`rounded-full px-4 py-2 ${
                   active ? 'bg-primary-container' : 'bg-surface-container-lowest'
                 }`}
                 style={({ pressed }) => ({
@@ -172,9 +172,9 @@ export default function CustomerScreen() {
           })}
         </ScrollView>
 
-        <View className="gap-4">
+        <View className="gap-3">
           {filteredCustomers.length === 0 ? (
-            <View className="items-center rounded-2xl bg-surface-container-lowest px-6 py-16 shadow-sm">
+            <View className="items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-6 py-14">
               <Ionicons name="people-outline" size={44} color="#c3c6d7" />
               <Text className="mt-4 text-base text-on-surface-variant">暂无匹配客户</Text>
             </View>
@@ -182,19 +182,19 @@ export default function CustomerScreen() {
             filteredCustomers.map((item) => (
               <Pressable
                 key={item.id}
-                className="rounded-2xl bg-surface-container-lowest px-5 py-5 shadow-sm"
+                className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
                 style={({ pressed }) => ({
                   opacity: pressed ? 0.93 : 1,
                   transform: [{ scale: pressed ? 0.995 : 1 }],
                 })}
               >
-                <View className="mb-4 flex-row items-start justify-between gap-3">
+                <View className="mb-3 flex-row items-start justify-between gap-3">
                   <View className="flex-1 flex-row items-center gap-3">
-                    <View className="h-12 w-12 items-center justify-center rounded-full bg-primary-fixed">
-                      <Text className="text-lg font-bold text-primary">{item.name[0]}</Text>
+                    <View className="h-11 w-11 items-center justify-center rounded-full bg-primary-fixed">
+                      <Text className="text-base font-bold text-primary">{item.name[0]}</Text>
                     </View>
                     <View className="flex-1">
-                      <Text className="text-xl font-bold text-on-surface">{item.name}</Text>
+                      <Text className="text-lg font-bold text-on-surface">{item.name}</Text>
                       <Text className="mt-1 text-sm text-on-surface-variant">
                         {item.phone}
                       </Text>
@@ -206,11 +206,11 @@ export default function CustomerScreen() {
                   />
                 </View>
 
-                <Text className="mb-3 text-sm leading-6 text-on-surface-variant">
+                <Text className="mb-2.5 text-sm leading-6 text-on-surface-variant">
                   {item.note}
                 </Text>
 
-                <View className="mb-4 flex-row flex-wrap items-center gap-3">
+                <View className="mb-3 flex-row flex-wrap items-center gap-3">
                   <View className="flex-row items-center gap-1">
                     <Ionicons name="document-text-outline" size={14} color="#737686" />
                     <Text className="text-xs text-on-surface-variant">{item.loanType}</Text>
@@ -228,7 +228,7 @@ export default function CustomerScreen() {
 
                 <View className="flex-row gap-3">
                   <Pressable
-                    className="flex-1 items-center rounded-xl bg-primary-container py-3"
+                    className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
                     style={({ pressed }) => ({
                       opacity: pressed ? 0.88 : 1,
                     })}
@@ -238,7 +238,7 @@ export default function CustomerScreen() {
                     </Text>
                   </Pressable>
                   <Pressable
-                    className="flex-1 items-center rounded-xl bg-surface-container-high py-3"
+                    className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
                     style={({ pressed }) => ({
                       opacity: pressed ? 0.88 : 1,
                     })}
@@ -252,15 +252,15 @@ export default function CustomerScreen() {
         </View>
       </ScrollView>
 
-      <View className="absolute bottom-8 right-6">
+      <View className="absolute bottom-7 right-5">
         <Pressable
-          className="h-16 w-16 items-center justify-center rounded-full bg-primary-container shadow-xl"
+          className="h-14 w-14 items-center justify-center rounded-full bg-primary-container"
           style={({ pressed }) => ({
             opacity: pressed ? 0.88 : 1,
             transform: [{ scale: pressed ? 0.94 : 1 }],
           })}
         >
-          <Ionicons name="person-add" size={24} color="#ffffff" />
+          <Ionicons name="person-add" size={22} color="#ffffff" />
         </Pressable>
       </View>
     </SafeAreaView>

+ 53 - 47
src/app/(tabs)/index.tsx

@@ -1,10 +1,8 @@
 import { SectionHeader } from '@/components/ui/section-header';
 import { StatusBadge } from '@/components/ui/status-badge';
 import { Ionicons } from '@expo/vector-icons';
-import React from 'react';
-import { Pressable, ScrollView, Text, View } from 'react-native';
+import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
-
 type QuickAction = {
   icon: keyof typeof Ionicons.glyphMap;
   label: string;
@@ -96,12 +94,12 @@ function getGreeting() {
 export default function HomeScreen() {
   return (
     <SafeAreaView className="flex-1 bg-surface" edges={['top']}>
-      <View className="h-16 flex-row items-center justify-between border-b border-outline-variant/20 bg-surface-container-lowest px-7">
+      <View className="h-14 flex-row items-center justify-between border-b border-outline-variant/20 bg-surface-container-lowest px-5">
         <View className="flex-row items-center gap-3">
-          <View className="h-10 w-10 items-center justify-center rounded-full bg-slate-900">
+          <View className="h-9 w-9 items-center justify-center rounded-full bg-slate-900">
             <Ionicons name="person" size={18} color="#ffffff" />
           </View>
-          <Text className="text-2xl font-extrabold tracking-tight text-on-surface">
+          <Text className="text-xl font-extrabold tracking-tight text-on-surface">
             贷款助手
           </Text>
         </View>
@@ -112,22 +110,22 @@ export default function HomeScreen() {
 
       <ScrollView
         className="flex-1"
-        contentContainerClassName="px-7 pt-6 pb-28"
+        contentContainerClassName="px-5 pt-4 pb-24"
         showsVerticalScrollIndicator={false}
       >
-        <View className="mb-8">
-          <Text className="mb-2 text-base tracking-wide text-on-surface-variant">
+        <View className="mb-6">
+          <Text className="mb-1.5 text-base tracking-wide text-on-surface-variant">
             {formatToday()}
           </Text>
-          <Text className="text-4xl font-extrabold tracking-tight text-on-surface">
-            {getGreeting()},王经理
+          <Text className="text-3xl font-extrabold tracking-tight text-on-surface">
+            {getGreeting()},助贷人
           </Text>
         </View>
 
-        <View className="mb-10 gap-4">
-          <View className="rounded-2xl bg-primary-container px-6 py-6 shadow-lg">
-            <View className="mb-6 flex-row items-start justify-between">
-              <View className="h-12 w-12 items-center justify-center rounded-2xl bg-white/20">
+        <View className="mb-8 gap-3">
+          <View className="rounded-2xl bg-primary-container px-5 py-5">
+            <View className="mb-5 flex-row items-start justify-between">
+              <View className="h-11 w-11 items-center justify-center rounded-2xl bg-white/20">
                 <Ionicons name="briefcase-outline" size={22} color="#ffffff" />
               </View>
               <View className="rounded-full bg-white/20 px-3 py-1">
@@ -135,24 +133,24 @@ export default function HomeScreen() {
               </View>
             </View>
             <Text className="mb-2 text-base text-on-primary/80">待处理申请</Text>
-            <Text className="text-6xl font-extrabold text-on-primary">24</Text>
+            <Text className="text-5xl font-extrabold text-on-primary">24</Text>
           </View>
 
-          <View className="flex-row gap-4">
-            <View className="flex-1 rounded-2xl bg-surface-container-lowest px-5 py-6 shadow-sm">
+          <View className="flex-row gap-3">
+            <View className="flex-1 rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-5">
               <Text className="mb-2 text-base text-on-surface-variant">进行中</Text>
-              <Text className="text-5xl font-bold text-on-surface">156</Text>
-              <View className="mt-5 h-1.5 rounded-full bg-surface-container">
+              <Text className="text-4xl font-bold text-on-surface">156</Text>
+              <View className="mt-4 h-1.5 rounded-full bg-surface-container">
                 <View
                   className="h-full rounded-full bg-secondary"
                   style={{ width: '65%' }}
                 />
               </View>
             </View>
-            <View className="flex-1 rounded-2xl bg-surface-container-lowest px-5 py-6 shadow-sm">
+            <View className="flex-1 rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-5">
               <Text className="mb-2 text-base text-on-surface-variant">成功撮合</Text>
-              <Text className="text-5xl font-bold text-on-surface">1,280</Text>
-              <View className="mt-5 h-1.5 rounded-full bg-surface-container">
+              <Text className="text-4xl font-bold text-on-surface">1,280</Text>
+              <View className="mt-4 h-1.5 rounded-full bg-surface-container">
                 <View
                   className="h-full rounded-full bg-tertiary-container"
                   style={{ width: '88%' }}
@@ -162,7 +160,7 @@ export default function HomeScreen() {
           </View>
         </View>
 
-        <View className="mb-10">
+        <View className="mb-8">
           <SectionHeader title="快捷操作" />
           <View className="flex-row items-start justify-between">
             {QUICK_ACTIONS.map((action) => (
@@ -174,7 +172,7 @@ export default function HomeScreen() {
                   transform: [{ scale: pressed ? 0.96 : 1 }],
                 })}
               >
-                <View className="mb-3 h-16 w-16 items-center justify-center rounded-2xl bg-surface-container-high">
+                <View className="mb-2.5 h-14 w-14 items-center justify-center rounded-2xl bg-surface-container-high">
                   <Ionicons name={action.icon} size={26} color="#004ac6" />
                 </View>
                 <Text className="text-sm font-medium text-on-surface-variant">
@@ -185,27 +183,27 @@ export default function HomeScreen() {
           </View>
         </View>
 
-        <View className="mb-10">
+        <View className="mb-8">
           <SectionHeader title="最近动态" actionText="查看全部" />
-          <View className="gap-4">
+          <View className="gap-3">
             {RECENT_ACTIVITIES.map((item) => (
               <Pressable
                 key={item.id}
-                className="flex-row items-center gap-4 rounded-2xl bg-surface-container-lowest px-4 py-4 shadow-sm"
+                className="flex-row items-center gap-3 rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-3.5"
                 style={({ pressed }) => ({
                   opacity: pressed ? 0.92 : 1,
                   transform: [{ scale: pressed ? 0.99 : 1 }],
                 })}
               >
                 <View
-                  className="h-14 w-14 items-center justify-center rounded-full"
+                  className="h-12 w-12 items-center justify-center rounded-full"
                   style={{ backgroundColor: item.avatarBackground }}
                 >
                   <Ionicons name="person" size={20} color={item.avatarColor} />
                 </View>
                 <View className="flex-1">
-                  <View className="mb-1 flex-row items-start justify-between gap-3">
-                    <Text className="flex-1 text-2xl font-bold text-on-surface">
+                  <View className="mb-1 flex-row items-start justify-between gap-2">
+                    <Text className="flex-1 text-xl font-bold text-on-surface">
                       {item.name} - {item.loanType}
                     </Text>
                     <Text className="text-xs text-on-surface-variant">{item.time}</Text>
@@ -223,9 +221,9 @@ export default function HomeScreen() {
           </View>
         </View>
 
-        <View className="mb-4 h-48 overflow-hidden rounded-2xl bg-slate-950">
+        <View className="mb-3 h-44 overflow-hidden rounded-2xl bg-slate-950">
           <View className="absolute inset-0 bg-primary/10" />
-          <View className="absolute bottom-0 right-0 h-full w-44 flex-row items-end gap-1 px-6 pb-6">
+          <View className="absolute bottom-0 right-0 h-full w-40 flex-row items-end gap-1 px-5 pb-5">
             {CHART_BARS.map((height, index) => (
               <View
                 key={`${height}-${index}`}
@@ -235,8 +233,8 @@ export default function HomeScreen() {
             ))}
           </View>
           <View className="absolute inset-y-0 right-0 w-1/2 bg-primary/5" />
-          <View className="relative flex-1 justify-end px-7 py-7">
-            <Text className="mb-3 text-4xl font-extrabold text-on-primary">
+          <View className="relative flex-1 justify-end px-5 py-5">
+            <Text className="mb-3 text-3xl font-extrabold text-on-primary">
               行业洞察
             </Text>
             <Text
@@ -246,7 +244,7 @@ export default function HomeScreen() {
               本周 LPR 利率下调,建议优先推荐对流水稳定要求更高的产品。
             </Text>
             <Pressable
-              className="mt-5 self-start rounded-full bg-surface-container-lowest px-5 py-3"
+              className="mt-4 self-start rounded-full bg-surface-container-lowest px-4 py-2.5"
               style={({ pressed }) => ({
                 opacity: pressed ? 0.86 : 1,
               })}
@@ -256,18 +254,26 @@ export default function HomeScreen() {
           </View>
         </View>
       </ScrollView>
-
-      <View className="absolute bottom-8 ios:bottom-28 right-7">
-        <Pressable
-          className="h-16 w-16 items-center justify-center rounded-full bg-primary-container shadow-xl"
-          style={({ pressed }) => ({
-            opacity: pressed ? 0.86 : 1,
-            transform: [{ scale: pressed ? 0.94 : 1 }],
-          })}
+        <View
+          className="absolute z-50 h-9 w-24 items-center justify-center rounded-full bg-primary"
+          style={styles.aiButton}
         >
-          <Ionicons name="sparkles" size={28} color="#ffffff" />
-        </Pressable>
-      </View>
+            <Text className="text-lg font-bold text-white">
+            AI 助理
+            </Text>
+        </View>
     </SafeAreaView>
   );
 }
+
+const styles = StyleSheet.create({
+  aiButton: {
+    right: 24,
+    bottom: 128,
+    shadowColor: '#2563eb',
+    shadowOffset: { width: 10, height: 10 },
+    shadowOpacity: 0.28,
+    shadowRadius: 14,
+    elevation: 10,
+  },
+});

+ 32 - 28
src/app/(tabs)/profile.tsx

@@ -1,23 +1,27 @@
 import { MenuRow } from '@/components/ui/menu-row';
-import { useAuthContext } from '@/utils/auth';
+import { signOut, useAuthContext } from '@/utils/auth';
+import { Modal, Toast } from '@ant-design/react-native';
 import { Ionicons } from '@expo/vector-icons';
-import { router } from 'expo-router';
-import React from 'react';
-import { Alert, Pressable, ScrollView, Text, View } from 'react-native';
+import { Pressable, ScrollView, Text, View } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
-
 export default function ProfileScreen() {
   const { setToken } = useAuthContext();
 
   const handleLogout = () => {
-    Alert.alert('退出登录', '确定要退出当前账号吗?', [
+    Modal.alert('退出登录', '确定要退出当前账号吗?', [
       { text: '取消', style: 'cancel' },
       {
         text: '退出',
         style: 'destructive',
-        onPress: () => {
+        onPress: async () => {
+          const l = Toast.loading("请稍候");
+          try {
+            await signOut();
+          } catch(e) {
+            console.warn(e);
+          }
           setToken(null);
-          router.replace('/sign-in');
+          Toast.remove(l);
         },
       },
     ]);
@@ -25,12 +29,12 @@ export default function ProfileScreen() {
 
   return (
     <SafeAreaView className="flex-1 bg-surface" edges={['top']}>
-      <View className="h-16 flex-row items-center justify-between border-b border-outline-variant/20 bg-surface-container-lowest px-7">
+      <View className="h-14 flex-row items-center justify-between border-b border-outline-variant/20 bg-surface-container-lowest px-5">
         <View className="flex-row items-center gap-3">
-          <View className="h-10 w-10 items-center justify-center rounded-full bg-slate-900">
+          <View className="h-9 w-9 items-center justify-center rounded-full bg-slate-900">
             <Ionicons name="person" size={18} color="#ffffff" />
           </View>
-          <Text className="text-2xl font-extrabold tracking-tight text-on-surface">
+          <Text className="text-xl font-extrabold tracking-tight text-on-surface">
             贷款助手
           </Text>
         </View>
@@ -41,21 +45,21 @@ export default function ProfileScreen() {
 
       <ScrollView
         className="flex-1"
-        contentContainerClassName="px-6 pt-6 pb-28"
+        contentContainerClassName="px-5 pt-4 pb-24"
         showsVerticalScrollIndicator={false}
       >
-        <View className="mb-10 items-center">
-          <View className="relative mb-5">
-            <View className="h-32 w-32 rounded-full bg-primary-container p-1.5">
+        <View className="mb-8 items-center">
+          <View className="relative mb-4">
+            <View className="h-28 w-28 rounded-full bg-primary-container p-1.5">
               <View className="h-full w-full items-center justify-center rounded-full border-4 border-surface-container-lowest bg-slate-900">
                 <Ionicons name="person" size={48} color="#ffffff" />
               </View>
             </View>
-            <View className="absolute bottom-1 right-1 h-9 w-9 items-center justify-center rounded-full border-4 border-surface-container-lowest bg-primary shadow-lg">
+            <View className="absolute bottom-1 right-1 h-8 w-8 items-center justify-center rounded-full border-4 border-surface-container-lowest bg-primary">
               <Ionicons name="checkmark" size={15} color="#ffffff" />
             </View>
           </View>
-          <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
+          <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">
             张建华
           </Text>
           <Text className="text-base font-medium text-on-surface-variant">
@@ -63,22 +67,22 @@ export default function ProfileScreen() {
           </Text>
         </View>
 
-        <View className="mb-10 flex-row gap-4">
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-4 py-5 shadow-sm">
-            <Text className="text-4xl font-extrabold text-primary">128</Text>
+        <View className="mb-8 flex-row gap-3">
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-4">
+            <Text className="text-3xl font-extrabold text-primary">128</Text>
             <Text className="mt-2 text-sm font-bold text-outline">已完成</Text>
           </View>
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-4 py-5 shadow-sm">
-            <Text className="text-4xl font-extrabold text-primary">94%</Text>
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-4">
+            <Text className="text-3xl font-extrabold text-primary">94%</Text>
             <Text className="mt-2 text-sm font-bold text-outline">成功率</Text>
           </View>
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-4 py-5 shadow-sm">
-            <Text className="text-4xl font-extrabold text-primary">¥42k</Text>
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-4">
+            <Text className="text-3xl font-extrabold text-primary">¥42k</Text>
             <Text className="mt-2 text-sm font-bold text-outline">本月收入</Text>
           </View>
         </View>
 
-        <View className="mb-6 overflow-hidden rounded-2xl bg-surface-container-lowest shadow-sm">
+        <View className="mb-5 overflow-hidden rounded-2xl border border-outline-variant bg-surface-container-lowest">
           <MenuRow icon="people-outline" label="我的客户" iconBgClass="bg-blue-50" />
           <MenuRow
             icon="business-outline"
@@ -88,7 +92,7 @@ export default function ProfileScreen() {
           />
         </View>
 
-        <View className="mb-6 overflow-hidden rounded-2xl bg-surface-container-lowest shadow-sm">
+        <View className="mb-5 overflow-hidden rounded-2xl border border-outline-variant bg-surface-container-lowest">
           <MenuRow
             icon="shield-outline"
             label="安全设置"
@@ -111,14 +115,14 @@ export default function ProfileScreen() {
 
         <Pressable
           onPress={handleLogout}
-          className="mt-3 flex-row items-center justify-center gap-2 rounded-2xl bg-surface-container-low py-4"
+          className="mt-2 flex-row items-center justify-center gap-2 rounded-2xl bg-surface-container-low py-3.5"
           style={({ pressed }) => ({
             opacity: pressed ? 0.86 : 1,
             transform: [{ scale: pressed ? 0.985 : 1 }],
           })}
         >
           <Ionicons name="log-out-outline" size={20} color="#ba1a1a" />
-          <Text className="text-lg font-bold text-error">退出登录</Text>
+          <Text className="text-base font-bold text-error">退出登录</Text>
         </Pressable>
       </ScrollView>
     </SafeAreaView>

+ 30 - 30
src/app/(tabs)/reports.tsx

@@ -102,38 +102,38 @@ export default function ReportsScreen() {
     <SafeAreaView className="flex-1 bg-surface" edges={['top']}>
       <ScrollView
         className="flex-1"
-        contentContainerClassName="px-6 pt-4 pb-28"
+        contentContainerClassName="px-5 pt-3 pb-24"
         showsVerticalScrollIndicator={false}
       >
-        <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
+        <Text className="mb-2 text-3xl font-extrabold tracking-tight text-on-surface">
           报表
         </Text>
-        <Text className="mb-6 text-base leading-7 text-on-surface-variant">
+        <Text className="mb-5 text-base leading-7 text-on-surface-variant">
           汇总查看征信分析结果、匹配建议和当前处理进度
         </Text>
 
-        <View className="mb-6 flex-row gap-3">
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-3 py-4 shadow-sm">
-            <Text className="text-3xl font-extrabold text-primary">{REPORTS.length}</Text>
+        <View className="mb-5 flex-row gap-2.5">
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-3.5">
+            <Text className="text-2xl font-extrabold text-primary">{REPORTS.length}</Text>
             <Text className="mt-2 text-xs font-bold uppercase tracking-widest text-outline">
               总报告数
             </Text>
           </View>
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-3 py-4 shadow-sm">
-            <Text className="text-3xl font-extrabold text-primary">{completedCount}</Text>
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-3.5">
+            <Text className="text-2xl font-extrabold text-primary">{completedCount}</Text>
             <Text className="mt-2 text-xs font-bold uppercase tracking-widest text-outline">
               已完成
             </Text>
           </View>
-          <View className="flex-1 items-center rounded-2xl bg-surface-container-lowest px-3 py-4 shadow-sm">
-            <Text className="text-3xl font-extrabold text-primary">92%</Text>
+          <View className="flex-1 items-center rounded-2xl border border-outline-variant bg-surface-container-lowest px-3 py-3.5">
+            <Text className="text-2xl font-extrabold text-primary">92%</Text>
             <Text className="mt-2 text-xs font-bold uppercase tracking-widest text-outline">
               最高匹配
             </Text>
           </View>
         </View>
 
-        <View className="mb-6 rounded-2xl bg-surface-container-low p-1">
+        <View className="mb-5 rounded-2xl bg-surface-container-low p-1">
           <View className="flex-row">
             {TABS.map((tab) => {
               const active = activeTab === tab;
@@ -141,7 +141,7 @@ export default function ReportsScreen() {
                 <Pressable
                   key={tab}
                   onPress={() => setActiveTab(tab)}
-                  className={`flex-1 rounded-xl py-3 ${
+                  className={`flex-1 rounded-xl py-2.5 ${
                     active ? 'bg-surface-container-lowest' : ''
                   }`}
                   style={({ pressed }) => ({
@@ -161,19 +161,19 @@ export default function ReportsScreen() {
           </View>
         </View>
 
-        <View className="gap-4">
+        <View className="gap-3">
           {filteredReports.map((report) => (
             <Pressable
               key={report.id}
-              className="rounded-2xl bg-surface-container-lowest px-5 py-5 shadow-sm"
+              className="rounded-2xl border border-outline-variant bg-surface-container-lowest px-4 py-4"
               style={({ pressed }) => ({
                 opacity: pressed ? 0.93 : 1,
               })}
             >
-              <View className="mb-4 flex-row items-start justify-between gap-3">
+              <View className="mb-3 flex-row items-start justify-between gap-3">
                 <View className="flex-1 flex-row items-center gap-3">
                   <View
-                    className={`h-12 w-12 items-center justify-center rounded-2xl ${
+                    className={`h-11 w-11 items-center justify-center rounded-2xl ${
                       report.type === '征信报告' ? 'bg-blue-50' : 'bg-green-50'
                     }`}
                   >
@@ -188,7 +188,7 @@ export default function ReportsScreen() {
                     />
                   </View>
                   <View className="flex-1">
-                    <Text className="text-xl font-bold text-on-surface">
+                    <Text className="text-lg font-bold text-on-surface">
                       {report.customerName}
                     </Text>
                     <Text className="mt-1 text-sm text-on-surface-variant">
@@ -197,7 +197,7 @@ export default function ReportsScreen() {
                   </View>
                 </View>
                 <View className="items-end">
-                  <Text className="mb-2 text-xs text-on-surface-variant">{report.time}</Text>
+                  <Text className="mb-1.5 text-xs text-on-surface-variant">{report.time}</Text>
                   <StatusBadge
                     text={report.status}
                     variant={getStatusVariant(report.status)}
@@ -207,14 +207,14 @@ export default function ReportsScreen() {
 
               {report.type === '征信报告' && report.status === '已完成' ? (
                 <View>
-                  <View className="mb-4 flex-row items-center gap-4">
-                    <View className="h-16 w-16 items-center justify-center rounded-full border-4 border-primary-fixed bg-surface-container-lowest">
-                      <Text className="text-xl font-extrabold text-primary">
+                  <View className="mb-3 flex-row items-center gap-3">
+                    <View className="h-14 w-14 items-center justify-center rounded-full border-4 border-primary-fixed bg-surface-container-lowest">
+                      <Text className="text-lg font-extrabold text-primary">
                         {report.score}
                       </Text>
                     </View>
                     <View className="flex-1">
-                      <Text className="mb-2 text-sm text-on-surface-variant">关键标签</Text>
+                      <Text className="mb-1.5 text-sm text-on-surface-variant">关键标签</Text>
                       <View className="flex-row flex-wrap gap-2">
                         {report.tags?.map((tag) => (
                           <StatusBadge
@@ -233,15 +233,15 @@ export default function ReportsScreen() {
               ) : null}
 
               {report.type === '匹配结果' && report.status === '已完成' ? (
-                <View className="flex-row gap-3">
-                  <View className="flex-1 rounded-xl bg-surface-container-low px-4 py-4">
-                    <Text className="text-3xl font-bold text-on-surface">
+                <View className="flex-row gap-2.5">
+                  <View className="flex-1 rounded-xl bg-surface-container-low px-4 py-3.5">
+                    <Text className="text-2xl font-bold text-on-surface">
                       {report.matchCount}
                     </Text>
                     <Text className="mt-1 text-xs text-on-surface-variant">匹配产品数</Text>
                   </View>
-                  <View className="flex-1 rounded-xl bg-surface-container-low px-4 py-4">
-                    <Text className="text-3xl font-bold text-primary">
+                  <View className="flex-1 rounded-xl bg-surface-container-low px-4 py-3.5">
+                    <Text className="text-2xl font-bold text-primary">
                       {report.matchRate}
                     </Text>
                     <Text className="mt-1 text-xs text-on-surface-variant">最高匹配度</Text>
@@ -271,9 +271,9 @@ export default function ReportsScreen() {
               ) : null}
 
               {report.status === '已完成' ? (
-                <View className="mt-4 flex-row gap-3">
+                <View className="mt-3 flex-row gap-2.5">
                   <Pressable
-                    className="flex-1 items-center rounded-xl bg-primary-container py-3"
+                    className="flex-1 items-center rounded-xl bg-primary-container py-2.5"
                     style={({ pressed }) => ({
                       opacity: pressed ? 0.88 : 1,
                     })}
@@ -283,7 +283,7 @@ export default function ReportsScreen() {
                     </Text>
                   </Pressable>
                   <Pressable
-                    className="flex-1 items-center rounded-xl bg-surface-container-high py-3"
+                    className="flex-1 items-center rounded-xl bg-surface-container-high py-2.5"
                     style={({ pressed }) => ({
                       opacity: pressed ? 0.88 : 1,
                     })}

+ 8 - 7
src/app/_layout.tsx

@@ -7,15 +7,13 @@ import {
 import * as updates from 'expo-updates';
 
 import { AnimatedSplashOverlay } from '@/components/animated-icon';
+import { antdTheme } from '@/constants/antd-theme';
 import { AuthProvider } from '@/utils/auth';
-import { Modal, Provider, Toast } from '@ant-design/react-native';
-import antdDefaultTheme from '@ant-design/react-native/lib/style/themes/default';
+import { Icon, Modal, Provider, Toast } from '@ant-design/react-native';
 import { useFonts } from 'expo-font';
-import { Stack } from 'expo-router';
+import { Stack, useRouter } from 'expo-router';
 import { useEffect, useState } from 'react';
 
-const antdTheme = antdDefaultTheme;
-
 export const DefaultTheme: Theme = {
   ...ReactNavigationDefaultTheme,
   colors: {
@@ -55,6 +53,7 @@ export default function RootLayout() {
               try {
                 await updates.fetchUpdateAsync();
                 await updates.reloadAsync();
+              // eslint-disable-next-line @typescript-eslint/no-unused-vars
               } catch(e) {
                 Modal.alert("提示", "更新遇到问题" );
               }
@@ -64,6 +63,7 @@ export default function RootLayout() {
         ], ()=>false);
       }
         
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
       } catch(e) {
         // alert(e?.message || e+"");
       }
@@ -74,7 +74,7 @@ export default function RootLayout() {
   }, []);
 
 
-  
+  const router = useRouter();
 
 
   return (
@@ -83,9 +83,10 @@ export default function RootLayout() {
         {(!initing && fontsLoaded) &&
         <AuthProvider>
           <AnimatedSplashOverlay />
-          <Stack screenOptions={{ headerShown: false }}>
+          <Stack screenOptions={{ headerShown: false, headerTransparent: true,  headerLeft:({canGoBack})=>canGoBack&&<Icon name="arrow-left" onPress={router.back} />}}>
             <Stack.Screen name="(tabs)" />
             <Stack.Screen name="sign-in" />
+            <Stack.Screen name="web" options={{headerShown: true}} />
           </Stack>
         </AuthProvider>}
       </Provider>

+ 40 - 39
src/app/sign-in.tsx

@@ -1,7 +1,8 @@
-import { smsSignIn, useAuthContext } from '@/utils/auth';
+import { signIn, smsSignIn, useAuth } from '@/utils/auth';
 import { Button, Toast } from '@ant-design/react-native';
 import { Ionicons } from '@expo/vector-icons';
-import { router, useLocalSearchParams } from 'expo-router';
+import { Link, router, useLocalSearchParams } from 'expo-router';
+import { openBrowserAsync } from 'expo-web-browser';
 import React, { useRef, useState } from 'react';
 import {
   KeyboardAvoidingView,
@@ -13,7 +14,9 @@ import {
   TextInput,
   View,
 } from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+
+import { site } from '@/config.json';
 
 function FieldLabel({ children }: { children: React.ReactNode }) {
   return (
@@ -23,11 +26,7 @@ function FieldLabel({ children }: { children: React.ReactNode }) {
   );
 }
 
-export default function SignInScreen({
-  callback,
-}: {
-  callback?: (signin: boolean) => void;
-}) {
+export default function SignInScreen() {
   const [authMode, setAuthMode] = useState<'sms' | 'password'>('sms');
   const [agreed, setAgreed] = useState(false);
   const [flushAgree, setFlushAgree] = useState(false);
@@ -37,7 +36,7 @@ export default function SignInScreen({
   const [password, setPassword] = useState('');
 
   const { redirectTo } = useLocalSearchParams<{ redirectTo?: string }>();
-  const { setToken } = useAuthContext();
+  const { setToken } = useAuth();
   const scrollView = useRef<ScrollView>(null);
   const handleSendCode = () => {
     if (mobile.trim().length !== 11) {
@@ -52,19 +51,17 @@ export default function SignInScreen({
     setFlushAgree(false);
     if (mobile.trim().length !== 11) {
       Toast.fail('请输入正确的手机号');
-      callback?.(false);
       return;
     }
 
+  
     if (authMode === 'sms' && code.trim().length !== 6) {
       Toast.fail('请输入 6 位验证码');
-      callback?.(false);
       return;
     }
 
-    if (authMode === 'password' && password.trim().length < 6) {
+    if (authMode === 'password' && password.length < 6) {
       Toast.fail('请输入不少于 6 位的密码');
-      callback?.(false);
       return;
     }
 
@@ -81,28 +78,26 @@ export default function SignInScreen({
     const toastKey = Toast.loading('正在登录...');
 
     try {
-      const token = await smsSignIn(mobile, code);
+      const token = authMode === 'sms' ? await smsSignIn(mobile, code) : await signIn(mobile, password);
       setToken(token);
       Toast.success('登录成功');
-      callback?.(true);
 
-      const nextRoute =
-        typeof redirectTo === 'string' && redirectTo.startsWith('/')
-          ? redirectTo
-          : '/';
-      router.replace(nextRoute as never);
+      if (redirectTo) {
+        router.replace(redirectTo as never);
+      } else {
+        router.dismiss();
+      }
     } catch (error) {
       console.error('登录失败:', error);
       Toast.fail('登录失败,请稍后重试');
-      callback?.(false);
     } finally {
       setLoading(false);
       Toast.remove(toastKey);
     }
   };
-
+  const insets = useSafeAreaInsets();
   return (
-    <SafeAreaView className="flex-1 bg-surface">
+    <View className="flex-1 bg-surface">
       <KeyboardAvoidingView
         className="flex-1"
         behavior={Platform.OS === 'ios' ? 'padding' : undefined}
@@ -110,8 +105,8 @@ export default function SignInScreen({
         <ScrollView
         ref={scrollView}
           className="flex-1"
-          contentContainerClassName="px-8 pt-12 pb-10"
-          contentContainerStyle={{ flexGrow: 1 }}
+          contentContainerClassName="px-8"
+          contentInset={{top: insets.top ?? 8, bottom: insets.bottom ?? 8}}
           keyboardShouldPersistTaps="handled"
           showsVerticalScrollIndicator={false}
         >
@@ -121,14 +116,14 @@ export default function SignInScreen({
 
           <View className="flex-1 justify-between">
             <View>
-              <View className="mb-12">
-                <View className="mb-6 h-16 w-16 items-center justify-center rounded-2xl bg-primary-container shadow-lg">
+              <View className="mb-6">
+                <View className="mb-3 h-16 w-16 items-center justify-center rounded-2xl bg-primary-container shadow-lg">
                   <Ionicons name="business" size={30} color="#ffffff" />
                 </View>
                 <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
                   欢迎回来
                 </Text>
-                <Text className="text-base font-medium leading-7 text-on-surface-variant">
+                <Text className="text-base font-medium leading-6 text-on-surface-variant">
                   登录贷款助手,开启您的
                 </Text>
               </View>
@@ -202,7 +197,7 @@ export default function SignInScreen({
                       placeholder={
                         authMode === 'sms'
                           ? '请输入 6 位验证码'
-                          : '请输入登录密码'
+                          : '请输入 6-20 位登录密码'
                       }
                       placeholderTextColor="#9ca3af"
                       className="flex-1 p-0 text-xl font-medium text-on-surface"
@@ -227,11 +222,11 @@ export default function SignInScreen({
                 </View>
               </View>
 
-              <View className="mb-8 gap-4">
+              <View className="mb-6 gap-3">
                 <Button type='primary' onPress={handleLogin}>登录</Button>
 
                 <View className="flex-row items-center justify-between px-3">
-                  <Pressable hitSlop={8} onPress={() => router.push('/sign-up')}>
+                  <Pressable hitSlop={8} onPress={() => router.push({pathname: '/sign-up', params: {signIn: 1, redirectTo}})}>
                     <Text className="text-lg font-medium text-on-surface-variant">
                       注册账号
                     </Text>
@@ -245,8 +240,8 @@ export default function SignInScreen({
               </View>
             </View>
 
-            <View className="pt-4">
-              <View className="mb-8 flex-row items-center gap-4">
+            <View className="pt-1">
+              <View className="mb-5 flex-row items-center gap-3">
                 <View className="h-px flex-1 bg-surface-container-highest" />
                 <Text className="text-sm font-bold tracking-widest text-outline">
                   其他方式登录
@@ -254,7 +249,7 @@ export default function SignInScreen({
                 <View className="h-px flex-1 bg-surface-container-highest" />
               </View>
 
-              <View className="mb-10 flex-row justify-center gap-10">
+              <View className="mb-6 flex-row justify-center gap-8">
                 {[
                   ['chatbubble-ellipses-outline', '#6b7280'],
                   ['logo-apple', '#6b7280'],
@@ -283,7 +278,7 @@ export default function SignInScreen({
                   className="pt-1"
                 >
                   <View
-                    className={`h-6 w-6 items-center justify-center rounded-full cursor-pointer ${
+                    className={`h-6 w-6 mt-2 items-center justify-center border-2 border-primary/50 rounded-full cursor-pointer ${
                       agreed
                         ? 'border-primary bg-primary'
                         : 'border-outline-variant bg-surface-container-low'
@@ -294,11 +289,16 @@ export default function SignInScreen({
                     ) : null}
                   </View>
                 </Pressable>
-                <Text className="flex-1 text-sm leading-7 text-on-surface-variant">
+                <Text className="flex-1 text-sm leading-6 text-on-surface-variant">
                   登录即代表您已阅读并同意
-                  <Text className="font-semibold text-primary cursor-pointer">《用户服务协议》</Text>
+                  <Link href={{
+                    pathname: '/web',
+                    params: {uri: site}
+                  }}>
+                    <Text className="font-semibold text-primary">《用户服务协议》</Text>
+                  </Link>
-                  <Text className="font-semibold text-primary cursor-pointer">《隐私政策》</Text>
+                  <Text className="font-semibold text-primary cursor-pointer" onPress={()=>openBrowserAsync(`${site}`)}>《隐私政策》</Text>
                   ,以及授权该应用获取您的公开信息。
                 </Text>
               </View>
@@ -306,6 +306,7 @@ export default function SignInScreen({
           </View>
         </ScrollView>
       </KeyboardAvoidingView>
-    </SafeAreaView>
+      {/* <CaptchaBox visible onClose={alert} /> */}
+    </View>
   );
 }

+ 98 - 32
src/app/sign-up.tsx

@@ -1,6 +1,9 @@
+import { site } from '@/config.json';
+import { signUp, useAuth } from '@/utils/auth';
 import { Button, Toast } from '@ant-design/react-native';
 import { Ionicons } from '@expo/vector-icons';
-import { router } from 'expo-router';
+import { router, useLocalSearchParams } from 'expo-router';
+import { openBrowserAsync } from 'expo-web-browser';
 import React, { useRef, useState } from 'react';
 import {
   KeyboardAvoidingView,
@@ -12,7 +15,7 @@ import {
   TextInput,
   View,
 } from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
 
 function FieldLabel({ children }: { children: React.ReactNode }) {
   return (
@@ -24,7 +27,9 @@ function FieldLabel({ children }: { children: React.ReactNode }) {
 
 export default function SignUpScreen() {
   const [mobile, setMobile] = useState('');
+  const [code, setCode] = useState('');
   const [password, setPassword] = useState('');
+  const [rePass, setRepass] = useState('');
   const [email, setEmail] = useState('');
   const [name, setName] = useState('');
   const [organization, setOrganization] = useState('');
@@ -32,6 +37,17 @@ export default function SignUpScreen() {
   const [flushAgree, setFlushAgree] = useState(false);
   const [loading, setLoading] = useState(false);
   const scrollView = useRef<ScrollView>(null);
+  const { setToken } = useAuth();
+
+  const {signIn, } = useLocalSearchParams<{ signIn: string; redirectTo?: string }>();
+  const handleSendCode = () => {
+    if (mobile.trim().length !== 11) {
+      Toast.fail('请先输入 11 位手机号');
+      return;
+    }
+
+    Toast.success('验证码已发送');
+  };
 
   const handleRegister = async () => {
     setFlushAgree(false);
@@ -41,10 +57,19 @@ export default function SignUpScreen() {
       return;
     }
 
-    if (password.trim().length < 6) {
+    if (code.trim().length !== 6) {
+      Toast.fail('请输入 6 位验证码');
+      return;
+    }
+
+    if (password.length < 6) {
       Toast.fail('请输入不少于 6 位的登录密码');
       return;
     }
+    if (rePass !== password) {
+      Toast.fail("两次密码输入不一至");
+      return;
+    }
 
     if (!email.includes('@')) {
       Toast.fail('请输入正确的邮箱');
@@ -56,10 +81,7 @@ export default function SignUpScreen() {
       return;
     }
 
-    if (!organization.trim()) {
-      Toast.fail('请输入所属机构');
-      return;
-    }
+    
 
     if (!agreed) {
       Toast.fail('请先阅读并同意协议');
@@ -69,23 +91,32 @@ export default function SignUpScreen() {
     }
 
     setLoading(true);
+
     const toastKey = Toast.loading('正在创建账号...');
 
     try {
-      await new Promise((resolve) => setTimeout(resolve, 600));
-      Toast.success('注册成功,请登录');
-      router.replace('/sign-in');
+      const token = await signUp({
+        mobile, password, captcha: code, name, email,
+      });
+      setToken(token);
+      Toast.success('登录成功');
+      
+      if (signIn) {
+        router.dismissTo("/");
+      } else {
+        router.dismiss();
+      }
     } catch (error) {
-      console.error('注册失败:', error);
-      Toast.fail('注册失败,请稍后重试');
+      console.error('登录失败:', error);
+      Toast.fail('登录失败,请稍后重试');
     } finally {
       setLoading(false);
       Toast.remove(toastKey);
     }
   };
-
+  const insets = useSafeAreaInsets();
   return (
-    <SafeAreaView className="flex-1 bg-surface">
+    <View className="flex-1 bg-surface">
       <KeyboardAvoidingView
         className="flex-1"
         behavior={Platform.OS === 'ios' ? 'padding' : undefined}
@@ -93,7 +124,8 @@ export default function SignUpScreen() {
         <ScrollView
           ref={scrollView}
           className="flex-1"
-          contentContainerClassName="px-8 pt-12 pb-10"
+          contentContainerClassName="px-8"
+          contentInset={{ top: (insets.top ?? 10) + 2, bottom: (insets.bottom ?? 8) + 4 }}
           contentContainerStyle={{ flexGrow: 1 }}
           keyboardShouldPersistTaps="handled"
           showsVerticalScrollIndicator={false}
@@ -142,6 +174,32 @@ export default function SignUpScreen() {
                     />
                   </View>
 
+                  <FieldLabel>验证码</FieldLabel>
+                  <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
+                    <TextInput
+                      value={code}
+                      onChangeText={setCode}
+                      editable={!loading}
+                      keyboardType="number-pad"
+                      maxLength={6}
+                      placeholder="请输入 6 位验证码"
+                      placeholderTextColor="#9ca3af"
+                      className="flex-1 p-0 text-xl font-medium text-on-surface"
+                    />
+                    <Pressable
+                      disabled={loading}
+                      hitSlop={8}
+                      onPress={handleSendCode}
+                      style={({ pressed }) => ({
+                        opacity: loading ? 0.5 : pressed ? 0.72 : 1,
+                      })}
+                    >
+                      <Text className="text-lg font-bold leading-6 text-primary">
+                        获取验证码
+                      </Text>
+                    </Pressable>
+                  </View>
+
                   <FieldLabel>登录密码</FieldLabel>
                   <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
                     <TextInput
@@ -156,6 +214,20 @@ export default function SignUpScreen() {
                     />
                     <Ionicons name="lock-closed-outline" size={22} color="#c3c6d7" />
                   </View>
+                  <FieldLabel>重复密码</FieldLabel>
+                  <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
+                    <TextInput
+                      value={rePass}
+                      onChangeText={setRepass}
+                      editable={!loading}
+                      secureTextEntry
+                      maxLength={20}
+                      placeholder="请再输入一次密码"
+                      placeholderTextColor="#9ca3af"
+                      className="flex-1 p-0 text-xl font-medium text-on-surface"
+                    />
+                    <Ionicons name="lock-closed-outline" size={22} color="#c3c6d7" />
+                  </View>
 
                   <FieldLabel>邮箱</FieldLabel>
                   <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
@@ -222,9 +294,8 @@ export default function SignUpScreen() {
 
             <View className="pt-4">
               <View
-                className={`flex-row items-start gap-3 rounded-md border-2 border-transparent px-2 transition delay-300 ${
-                  flushAgree ? 'border-primary/50' : ''
-                }`}
+                className={`flex-row items-start gap-3 rounded-md border-2 border-transparent px-2 transition delay-300 ${flushAgree ? 'border-primary/50' : ''
+                  }`}
               >
                 <Pressable
                   onPress={() => setAgreed((value) => !value)}
@@ -232,33 +303,28 @@ export default function SignUpScreen() {
                   className="pt-1"
                 >
                   <View
-                    className={`h-6 w-6 items-center justify-center rounded-full ${
-                      agreed
-                        ? 'border-primary bg-primary'
-                        : 'border-outline-variant bg-surface-container-low'
-                    }`}
+                    className={`h-6 w-6 mt-2 items-center justify-center border-2 border-primary/50 rounded-full cursor-pointer ${agreed
+                      ? 'border-primary bg-primary'
+                      : 'border-outline-variant bg-surface-container-low'
+                      }`}
                   >
                     {agreed ? (
                       <Ionicons name="checkmark" size={14} color="#ffffff" />
                     ) : null}
                   </View>
                 </Pressable>
-                <Text className="flex-1 text-sm leading-7 text-on-surface-variant">
+                <Text className="flex-1 text-sm leading-6 text-on-surface-variant">
                   注册即代表您已阅读并同意
-                  <Text className="cursor-pointer font-semibold text-primary">
-                    《用户服务协议》
-                  </Text>
+                  <Text className="font-semibold text-primary cursor-pointer" onPress={() => openBrowserAsync(`${site}`)}>《用户服务协议》</Text>
-                  <Text className="cursor-pointer font-semibold text-primary">
-                    《隐私政策》
-                  </Text>
-                  ,并授权该应用用于账户创建与服务通知。
+                  <Text className="font-semibold text-primary cursor-pointer" onPress={() => openBrowserAsync(`${site}`)}>《隐私政策》</Text>
+                  ,以及授权该应用获取您的公开信息。
                 </Text>
               </View>
             </View>
           </View>
         </ScrollView>
       </KeyboardAvoidingView>
-    </SafeAreaView>
+    </View>
   );
 }

+ 18 - 0
src/app/web.tsx

@@ -0,0 +1,18 @@
+import { useNavigation } from "expo-router";
+import { useLocalSearchParams } from "expo-router/build/hooks";
+import WebView from "react-native-webview";
+
+export default function WebScreen() {
+
+    const nav = useNavigation();
+
+    const {uri} = useLocalSearchParams<{uri: string}>();
+    return <WebView className="flex-1"
+        source={{uri}}
+        onNavigationStateChange={(navState) => {
+      if (navState.title) {
+        nav.setOptions({ title: navState.title });
+      }
+    }}
+    />;
+}

+ 23 - 0
src/components/captcha-box.tsx

@@ -0,0 +1,23 @@
+import { site } from '@/config.json';
+import { Modal, View } from "@ant-design/react-native";
+import { Image } from "expo-image";
+import { useState } from "react";
+import { TextInput } from 'react-native-gesture-handler';
+
+export default function CaptchaBox({onClose, visible}: {onClose: (code?: string)=>void; visible: boolean}) {
+    const [t, setT] = useState(1);
+    const [value, setValue] = useState("");
+
+    return <Modal closable visible={visible} animated animationType='slide-down'>
+        <View className='items-center w-24 h-24'>
+            <Image className="w-12 h-8" source={{uri: `${site}/index.php?s=/app_captcha&_t=`+t}} />
+            <TextInput
+                value={value}
+                onChangeText={setValue}
+                placeholder="请输上图中的字符"
+                placeholderTextColor="#9ca3af"
+                className="flex-1 p-0 text-xl font-medium text-center text-on-surface"
+            />
+        </View>
+    </Modal>
+}

+ 2 - 4
src/components/themed-text.tsx

@@ -1,7 +1,6 @@
 import { Platform, StyleSheet, Text, type TextProps } from 'react-native';
 
-import { Fonts, ThemeColor } from '@/constants/theme';
-import { useTheme } from '@/hooks/use-theme';
+import { Colors, Fonts, ThemeColor } from '@/constants/theme';
 
 export type ThemedTextProps = TextProps & {
   type?: 'default' | 'title' | 'small' | 'smallBold' | 'subtitle' | 'link' | 'linkPrimary' | 'code';
@@ -9,12 +8,11 @@ export type ThemedTextProps = TextProps & {
 };
 
 export function ThemedText({ style, type = 'default', themeColor, ...rest }: ThemedTextProps) {
-  const theme = useTheme();
 
   return (
     <Text
       style={[
-        { color: theme[themeColor ?? 'text'] },
+        { color: themeColor ?? Colors.text},
         type === 'default' && styles.default,
         type === 'title' && styles.title,
         type === 'small' && styles.small,

+ 2 - 4
src/components/themed-view.tsx

@@ -1,7 +1,6 @@
 import { View, type ViewProps } from 'react-native';
 
-import { ThemeColor } from '@/constants/theme';
-import { useTheme } from '@/hooks/use-theme';
+import { Colors, ThemeColor } from '@/constants/theme';
 
 export type ThemedViewProps = ViewProps & {
   lightColor?: string;
@@ -10,7 +9,6 @@ export type ThemedViewProps = ViewProps & {
 };
 
 export function ThemedView({ style, lightColor, darkColor, type, ...otherProps }: ThemedViewProps) {
-  const theme = useTheme();
 
-  return <View style={[{ backgroundColor: theme[type ?? 'background'] }, style]} {...otherProps} />;
+  return <View style={[{ backgroundColor: Colors[type as keyof typeof Colors] as any ??Colors.background }, style]} {...otherProps} />;
 }

+ 2 - 2
src/components/ui/activity-card.tsx

@@ -17,7 +17,7 @@ interface ActivityCardProps {
 
 /**
  * 动态卡片 — 展示客户最近操作动态
- * surface-container-lowest 底色 + shadow-sm 微浮
+ * 采用浅底色和细边框,避免阴影带来的悬浮感。
  */
 export function ActivityCard({
   avatarUri,
@@ -32,7 +32,7 @@ export function ActivityCard({
   return (
     <Pressable
       onPress={onPress}
-      className="bg-surface-container-lowest p-4 rounded-xl flex-row items-center gap-4 shadow-sm"
+      className="bg-surface-container-lowest border border-outline-variant p-4 rounded-xl flex-row items-center gap-4"
     >
       {/* 头像 */}
       <View className="w-12 h-12 rounded-full overflow-hidden bg-surface-container">

+ 2 - 4
src/components/ui/collapsible.tsx

@@ -5,12 +5,10 @@ import Animated, { FadeIn } from 'react-native-reanimated';
 
 import { ThemedText } from '@/components/themed-text';
 import { ThemedView } from '@/components/themed-view';
-import { Spacing } from '@/constants/theme';
-import { useTheme } from '@/hooks/use-theme';
+import { Colors, Spacing } from '@/constants/theme';
 
 export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
   const [isOpen, setIsOpen] = useState(false);
-  const theme = useTheme();
 
   return (
     <ThemedView>
@@ -22,7 +20,7 @@ export function Collapsible({ children, title }: PropsWithChildren & { title: st
             name={{ ios: 'chevron.right', android: 'chevron_right', web: 'chevron_right' }}
             size={14}
             weight="bold"
-            tintColor={theme.text}
+            tintColor={Colors.text}
             style={{ transform: [{ rotate: isOpen ? '-90deg' : '90deg' }] }}
           />
         </ThemedView>

+ 2 - 2
src/components/ui/confirm-dialog.tsx

@@ -29,7 +29,7 @@ export function ConfirmDialog({
   onConfirm,
 }: ConfirmDialogProps) {
   return (
-    <View className="bg-surface-container-lowest p-6 rounded-xl shadow-lg">
+    <View className="bg-surface-container-lowest border border-outline-variant p-6 rounded-xl">
       {/* 头部 */}
       <View className="flex-row items-start gap-4 mb-6">
         <View className="p-3 bg-tertiary-fixed rounded-xl">
@@ -66,7 +66,7 @@ export function ConfirmDialog({
         </Pressable>
         <Pressable
           onPress={onConfirm}
-          className="flex-1 py-4 bg-primary rounded-xl items-center shadow-md"
+          className="flex-1 py-4 bg-primary rounded-xl items-center"
           style={({ pressed }) => ({ opacity: pressed ? 0.8 : 1 })}
         >
           <Text className="font-semibold text-on-primary">{confirmText}</Text>

+ 2 - 3
src/components/ui/primary-button.tsx

@@ -9,14 +9,13 @@ interface PrimaryButtonProps {
 }
 
 /**
- * 主操作按钮 — 设计稿采用 primary-container → primary 135° 渐变,
- * 此处使用纯 primary-container 底色,如需渐变可接入 expo-linear-gradient。
+ * 主操作按钮 — 保持纯色和边界清晰,避免过强立体感。
  */
 export function PrimaryButton({ title, onPress, className = '' }: PrimaryButtonProps) {
   return (
     <Pressable
       onPress={onPress}
-      className={`w-full py-4 bg-primary-container rounded-lg items-center justify-center shadow-md ${className}`}
+      className={`w-full py-4 bg-primary rounded-lg items-center justify-center ${className}`}
       style={({ pressed }) => ({ opacity: pressed ? 0.92 : 1, transform: [{ scale: pressed ? 0.98 : 1 }] })}
     >
       <Text className="text-on-primary font-bold text-base">{title}</Text>

+ 2 - 2
src/components/ui/success-modal.tsx

@@ -24,7 +24,7 @@ export function SuccessModal({
   onSecondary,
 }: SuccessModalProps) {
   return (
-    <View className="bg-surface-container-lowest p-8 rounded-xl items-center shadow-lg">
+    <View className="bg-surface-container-lowest border border-outline-variant p-8 rounded-xl items-center">
       <View className="w-16 h-16 rounded-full bg-green-50 items-center justify-center mb-4">
         <Ionicons name="checkmark-circle" size={40} color="#22c55e" />
       </View>
@@ -34,7 +34,7 @@ export function SuccessModal({
       </Text>
       <Pressable
         onPress={onPrimary}
-        className="w-full py-4 bg-primary-container rounded-xl items-center shadow-md mb-3"
+        className="w-full py-4 bg-primary rounded-xl items-center mb-3"
         style={({ pressed }) => ({ opacity: pressed ? 0.9 : 1 })}
       >
         <Text className="text-on-primary font-semibold">{primaryAction}</Text>

+ 1 - 1
src/config.json

@@ -4,6 +4,6 @@
         "url": "https://loan.ewaga.com/api/v1/",
         "timeout": 15000
     },
-    
+    "site": "https://loan.ewaga.com/",
     "jsVersion": "1"
 }

+ 18 - 0
src/constants/antd-theme.ts

@@ -0,0 +1,18 @@
+import antdDefaultTheme from '@ant-design/react-native/lib/style/themes/default';
+
+export const antdTheme: typeof antdDefaultTheme = {
+  ...antdDefaultTheme,
+  brand_primary: '#2158e8',
+  fill_base: '#ffffff',
+  fill_body: '#f8fafc',
+  fill_tap: '#eff6ff',
+  fill_grey: '#f1f5f9',
+  color_text_base: '#0f172a',
+  color_text_paragraph: '#64748b',
+  color_text_caption: '#64748b',
+  color_icon_base: '#64748b',
+  border_color_base: '#e2e8f0',
+  border_color_thin: '#dbeafe',
+  primary_button_fill: '#2158e8',
+  primary_button_fill_tap: '#1d4ed8',
+};

+ 7 - 9
src/constants/theme.ts

@@ -6,16 +6,14 @@
 import '@/global.css';
 
 import { Platform } from 'react-native';
-
-
-import antdDefaultTheme from '@ant-design/react-native/lib/style/themes/default';
+import { antdTheme } from './antd-theme';
 export const Colors = {
-    text: antdDefaultTheme.color_text_base,
-    background: antdDefaultTheme.fill_base,
-    backgroundElement:  antdDefaultTheme.fill_body,
-    backgroundSelected: antdDefaultTheme.fill_tap,
-    textSecondary: antdDefaultTheme.color_text_paragraph,
-    ...antdDefaultTheme,
+    text: antdTheme.color_text_base,
+    background: antdTheme.fill_base,
+    backgroundElement:  antdTheme.fill_body,
+    backgroundSelected: antdTheme.fill_tap,
+    textSecondary: antdTheme.color_text_paragraph,
+    ...antdTheme,
   } as const;
 
 export type ThemeColor = keyof typeof Colors;

+ 0 - 13
src/hooks/use-theme.ts

@@ -1,13 +0,0 @@
-/**
- * Learn more about light and dark modes:
- * https://docs.expo.dev/guides/color-schemes/
- */
-
-import { Colors } from '@/constants/theme';
-
-export function useTheme() {
-  // const scheme = 'light';
-  // const theme = scheme === 'unspecified' ? 'light' : scheme;
-
-  return Colors['light'];
-}

+ 21 - 4
src/utils/api.ts

@@ -2,8 +2,25 @@
 import axios from 'axios';
 import Constants from 'expo-constants';
 import { Platform } from 'react-native';
-import { getAccessToken } from './auth';
+import { type AccessToken } from './auth';
 const {api: apiConfig, jsVersion} = require('@/config.json') as AppConfig;
+let accessToken: AccessToken | undefined | null = null;
+
+export function setAccessToken(token?: AccessToken | null) {
+    
+    accessToken = token;
+}
+
+export function getAccessToken() {
+  if (!accessToken) {
+    return null;
+  }
+  const now = Date.now() / 1000;
+  if (accessToken.expiresAt < now - 30) {
+    accessToken = null;
+  }
+  return accessToken;
+}
 
 
 
@@ -169,15 +186,15 @@ async function request<T>(url: string, method: 'get' | 'post' | 'put' | 'delete'
 }
 
 
-async function get<T>(api: string, params: Record<string, any>): Promise<T> {
+async function get<T>(api: string, params?: Record<string, any>): Promise<T> {
     return await request<T>(api, 'get', params, undefined);
 }
 
-async function post<T>(api: string, data: any): Promise<T> {
+async function post<T>(api: string, data?: any): Promise<T> {
     return await request<T>(api, 'post', {}, data);
 }
 
-async function put<T>(api: string, data: any): Promise<T> {
+async function put<T>(api: string, data?: any): Promise<T> {
     return await request<T>(api, 'put', {}, data);
 }
 

+ 74 - 27
src/utils/auth.tsx

@@ -1,7 +1,8 @@
-import React, { createContext, useContext, useState } from 'react';
-import api from './api';
+import React, { createContext, useContext, useEffect, useState } from 'react';
+import api, { setAccessToken } from './api';
+import { getGlobalStorage } from './storage';
 
-interface AccessToken {
+export interface AccessToken {
   token: string;
   expiresIn: number;
   tokenType?: string;
@@ -10,20 +11,21 @@ interface AccessToken {
 }
 
 interface AuthContextType {
-  token: AccessToken | null;
-  isAuthenticated: boolean;
-  setToken: (token: AccessToken | null) => boolean;
+  authStatus: 'auth' | 'loading' | 'fail';
+  setToken: (token: AccessToken |undefined | null) => void;
+
 }
 
-let tokenCache: AccessToken | null = null;
 
-const AuthContext = createContext<AuthContextType | undefined>(undefined);
+const AuthContext = createContext<AuthContextType>(null!);
 
 export function AuthProvider({ children }: { children: React.ReactNode }) {
-  const [token, setTokenState] = useState<AccessToken | null>(tokenCache);
+  const [authStatus, setAuthStatus] = useState<'auth' | 'loading' | 'fail'>('loading');
+
 
-  const setToken = (nextToken: AccessToken | null) => {
+  const setToken = (nextToken: AccessToken |undefined | null) => {
     // tokenCache = nextToken;
+
     if (nextToken && nextToken.token && nextToken.expiresIn) {
       // if (!tokenCache.expiresAt) {
         nextToken.expiresAt = nextToken.expiresIn + Date.now() / 1000;
@@ -32,16 +34,31 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
     } else {
       nextToken = null;
     }
-    tokenCache = nextToken;
-    setTokenState(nextToken);
-    return true;
+    if (nextToken) {
+        setAuthStatus('auth');
+        getGlobalStorage().set("access_token", JSON.stringify(nextToken));
+    } else {
+        setAuthStatus('fail');
+        getGlobalStorage().remove("access_token");
+    }
+    setAccessToken(nextToken);
   };
 
+  useEffect(() => {
+    try {
+      const token = JSON.parse(getGlobalStorage().getString("access_token")||"null");
+      setToken(token);
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    }catch(e) {
+      setToken(null);
+    }
+  }, []);
+
+
   return (
     <AuthContext.Provider
       value={{
-        token,
-        isAuthenticated: !!token,
+        authStatus,
         setToken,
       }}
     >
@@ -58,21 +75,26 @@ export function useAuthContext() {
   return context;
 }
 
-export function getAccessToken() {
-  if (!tokenCache) {
-    return null;
-  }
-  const now = Date.now() / 1000;
-  if (tokenCache.expiresAt < now - 30) {
-    tokenCache = null;
-  }
-  return tokenCache;
-}
-
 export function useAuth() {
   return useAuthContext();
 }
 
+export async function signIn(mobile: string, password: string) {
+  const {
+    token,
+    expires_in
+  } = await api.post<{
+    token: string,
+    expires_in: number,
+  }>("/user/login", {
+    mobile, password
+  });
+  return {
+    token,
+    expiresIn: expires_in
+  } as AccessToken;
+}
+
 export async function smsSignIn(mobile: string, captcha: string) {
   const {
     token,
@@ -89,4 +111,29 @@ export async function smsSignIn(mobile: string, captcha: string) {
   } as AccessToken;
 }
 
-export type { AccessToken };
+export async function signUp(info: {
+  mobile: string;
+  captcha: string;
+  password: string;
+  name: string;
+  email: string;
+}) {
+  const {
+    token,
+    expires_in
+  } = await api.post<{
+    token: string,
+    expires_in: number,
+  }>("/user/register", info);
+  return {
+    token,
+    expiresIn: expires_in
+  } as AccessToken;
+}
+
+
+
+
+export async function signOut() {
+  return api.get("/user/logout")
+}

+ 32 - 0
src/utils/storage.web.ts

@@ -0,0 +1,32 @@
+// import RNDeviceInfo from 'react-native-device-info';
+import { createMMKV, MMKV } from 'react-native-mmkv';
+
+let globalStorage: MMKV | null = null;
+export function getGlobalStorage() {
+    if (!globalStorage) {
+        globalStorage = createMMKV({
+            id: `global`,
+        });
+    }
+    return globalStorage;
+}
+
+let caches: MMKV | null = null;
+export function getCaches() {
+    if (!caches) {
+        caches = createMMKV({
+            id: `caches`
+        });
+    }
+    return caches;
+}
+
+let apiCache: MMKV | null = null;
+export function getApiCache() {
+    if (!apiCache) {
+        apiCache = createMMKV({
+            id: `api_cache`
+        });
+    }
+    return apiCache;
+}

+ 59 - 54
tailwind.config.js

@@ -5,91 +5,96 @@ module.exports = {
   theme: {
     extend: {
       colors: {
-        // — Primary —
         primary: {
-          DEFAULT: "#004ac6",
+          DEFAULT: "#2563eb",
           container: "#2563eb",
-          fixed: "#dbe1ff",
-          "fixed-dim": "#b4c5ff",
+          fixed: "#dbeafe",
+          "fixed-dim": "#bfdbfe",
         },
         "on-primary": {
           DEFAULT: "#ffffff",
-          container: "#eeefff",
-          fixed: "#00174b",
-          "fixed-variant": "#003ea8",
+          container: "#ffffff",
+          fixed: "#1e3a8a",
+          "fixed-variant": "#1d4ed8",
         },
-        // — Secondary —
         secondary: {
-          DEFAULT: "#495c95",
-          container: "#acbfff",
-          fixed: "#dbe1ff",
-          "fixed-dim": "#b4c5ff",
+          DEFAULT: "#475569",
+          container: "#eff6ff",
+          fixed: "#f8fafc",
+          "fixed-dim": "#e2e8f0",
         },
         "on-secondary": {
           DEFAULT: "#ffffff",
-          container: "#394c84",
-          fixed: "#00174b",
-          "fixed-variant": "#31447b",
+          container: "#2158e8",
+          fixed: "#334155",
+          "fixed-variant": "#64748b",
         },
-        // — Tertiary —
         tertiary: {
-          DEFAULT: "#943700",
-          container: "#bc4800",
-          fixed: "#ffdbcd",
-          "fixed-dim": "#ffb596",
+          DEFAULT: "#f59e0b",
+          container: "#fef3c7",
+          fixed: "#fef3c7",
+          "fixed-dim": "#fde68a",
         },
         "on-tertiary": {
           DEFAULT: "#ffffff",
-          container: "#ffede6",
-          fixed: "#360f00",
-          "fixed-variant": "#7d2d00",
+          container: "#92400e",
+          fixed: "#92400e",
+          "fixed-variant": "#b45309",
         },
-        // — Error —
         error: {
-          DEFAULT: "#ba1a1a",
-          container: "#ffdad6",
+          DEFAULT: "#dc2626",
+          container: "#fee2e2",
         },
         "on-error": {
           DEFAULT: "#ffffff",
-          container: "#93000a",
+          container: "#991b1b",
+        },
+        success: {
+          DEFAULT: "#16a34a",
+          container: "#dcfce7",
+        },
+        "on-success": {
+          DEFAULT: "#ffffff",
+          container: "#166534",
         },
-        // — Surface (Tonal Architecture) —
         surface: {
-          DEFAULT: "#f9f9fe",
-          dim: "#d9dade",
-          bright: "#f9f9fe",
-          variant: "#e2e2e7",
-          tint: "#0053db",
+          DEFAULT: "#f8fafc",
+          dim: "#eef2f7",
+          bright: "#ffffff",
+          variant: "#f1f5f9",
+          tint: "#2158e8",
           container: {
-            DEFAULT: "#ededf2",
+            DEFAULT: "#f1f5f9",
             lowest: "#ffffff",
-            low: "#f3f3f8",
-            high: "#e8e8ed",
-            highest: "#e2e2e7",
+            low: "#f8fafc",
+            high: "#eef2f7",
+            highest: "#e2e8f0",
           },
         },
         "on-surface": {
-          DEFAULT: "#1a1c1f",
-          variant: "#434655",
+          DEFAULT: "#0f172a",
+          variant: "#64748b",
         },
-        // — Outline —
         outline: {
-          DEFAULT: "#737686",
-          variant: "#c3c6d7",
+          DEFAULT: "#94a3b8",
+          variant: "#e2e8f0",
         },
-        // — Background —
-        background: "#f9f9fe",
-        "on-background": "#1a1c1f",
-        // — Inverse —
-        "inverse-surface": "#2e3034",
-        "inverse-on-surface": "#f0f0f5",
-        "inverse-primary": "#b4c5ff",
+        line: "#e2e8f0",
+        background: "#eef2ff",
+        "on-background": "#0f172a",
+        card: "#ffffff",
+        ok: "#16a34a",
+        warn: "#f59e0b",
+        danger: "#dc2626",
+        "inverse-surface": "#0f172a",
+        "inverse-on-surface": "#f8fafc",
+        "inverse-primary": "#bfdbfe",
       },
       borderRadius: {
-        DEFAULT: "0.25rem",
-        lg: "1rem",
-        xl: "1.5rem",
-        "2xl": "2rem",
+        DEFAULT: "0.5rem",
+        lg: "0.625rem",
+        xl: "0.75rem",
+        "2xl": "0.75rem",
         full: "9999px",
       },
       fontFamily: {
@@ -100,4 +105,4 @@ module.exports = {
     },
   },
   plugins: [],
-};
+};