]> git.digitality.be Git - pdw25-26/commitdiff
Mobile : navigation + setting screen + auto refresh
authorThibaud Moustier <thibaudmoustier0@gmail.com>
Mon, 23 Feb 2026 12:27:01 +0000 (13:27 +0100)
committerThibaud Moustier <thibaudmoustier0@gmail.com>
Mon, 23 Feb 2026 12:27:01 +0000 (13:27 +0100)
mobile-ui/App.tsx
mobile-ui/package-lock.json
mobile-ui/package.json
mobile-ui/src/screens/DashboardScreen.tsx

index a4eeb87981fcca40e22a6055c3d640403a7c0b0f..c94646d7b9b25f0bca3621acfcad9e1d18e06650 100644 (file)
@@ -1,6 +1,32 @@
+import { NavigationContainer } from "@react-navigation/native";
+import { createNativeStackNavigator } from "@react-navigation/native-stack";
+
 import DashboardScreen from "./src/screens/DashboardScreen";
 import SettingsScreen from "./src/screens/SettingsScreen";
 
+// Types des routes (pour éviter les erreurs de navigation)
+export type RootStackParamList = {
+  Dashboard: undefined;
+  Settings: undefined;
+};
+
+const Stack = createNativeStackNavigator<RootStackParamList>();
+
 export default function App() {
-  return <DashboardScreen />;
+  return (
+    <NavigationContainer>
+      <Stack.Navigator id="MainStack" initialRouteName="Dashboard">
+        <Stack.Screen
+          name="Dashboard"
+          component={DashboardScreen}
+          options={{ title: "Dashboard" }}
+        />
+        <Stack.Screen
+          name="Settings"
+          component={SettingsScreen}
+          options={{ title: "Paramètres" }}
+        />
+      </Stack.Navigator>
+    </NavigationContainer>
+  );
 }
\ No newline at end of file
index f065b536136f5e99310a1e429d1690e6cadb9c4b..29d59918d560b3e43e83d5ab0bbf6523b595c5b7 100644 (file)
@@ -9,11 +9,14 @@
       "version": "1.0.0",
       "dependencies": {
         "@react-native-async-storage/async-storage": "2.2.0",
+        "@react-navigation/native": "^7.1.28",
+        "@react-navigation/native-stack": "^7.13.0",
         "expo": "~54.0.33",
         "expo-status-bar": "~3.0.9",
         "react": "19.1.0",
         "react-native": "0.81.5",
-        "react-native-safe-area-context": "~5.6.0"
+        "react-native-safe-area-context": "~5.6.0",
+        "react-native-screens": "~4.16.0"
       },
       "devDependencies": {
         "@types/react": "~19.1.0",
       "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==",
       "license": "MIT"
     },
+    "node_modules/@react-navigation/core": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.14.0.tgz",
+      "integrity": "sha512-tMpzskBzVp0E7CRNdNtJIdXjk54Kwe/TF9ViXAef+YFM1kSfGv4e/B2ozfXE+YyYgmh4WavTv8fkdJz1CNyu+g==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/routers": "^7.5.3",
+        "escape-string-regexp": "^4.0.0",
+        "fast-deep-equal": "^3.1.3",
+        "nanoid": "^3.3.11",
+        "query-string": "^7.1.3",
+        "react-is": "^19.1.0",
+        "use-latest-callback": "^0.2.4",
+        "use-sync-external-store": "^1.5.0"
+      },
+      "peerDependencies": {
+        "react": ">= 18.2.0"
+      }
+    },
+    "node_modules/@react-navigation/core/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@react-navigation/core/node_modules/react-is": {
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz",
+      "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==",
+      "license": "MIT"
+    },
+    "node_modules/@react-navigation/elements": {
+      "version": "2.9.5",
+      "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.5.tgz",
+      "integrity": "sha512-iHZU8rRN1014Upz73AqNVXDvSMZDh5/ktQ1CMe21rdgnOY79RWtHHBp9qOS3VtqlUVYGkuX5GEw5mDt4tKdl0g==",
+      "license": "MIT",
+      "dependencies": {
+        "color": "^4.2.3",
+        "use-latest-callback": "^0.2.4",
+        "use-sync-external-store": "^1.5.0"
+      },
+      "peerDependencies": {
+        "@react-native-masked-view/masked-view": ">= 0.2.0",
+        "@react-navigation/native": "^7.1.28",
+        "react": ">= 18.2.0",
+        "react-native": "*",
+        "react-native-safe-area-context": ">= 4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-masked-view/masked-view": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-navigation/native": {
+      "version": "7.1.28",
+      "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.28.tgz",
+      "integrity": "sha512-d1QDn+KNHfHGt3UIwOZvupvdsDdiHYZBEj7+wL2yDVo3tMezamYy60H9s3EnNVE1Ae1ty0trc7F2OKqo/RmsdQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/core": "^7.14.0",
+        "escape-string-regexp": "^4.0.0",
+        "fast-deep-equal": "^3.1.3",
+        "nanoid": "^3.3.11",
+        "use-latest-callback": "^0.2.4"
+      },
+      "peerDependencies": {
+        "react": ">= 18.2.0",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-navigation/native-stack": {
+      "version": "7.13.0",
+      "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.13.0.tgz",
+      "integrity": "sha512-5OOp1IKEd5woHl9hGBU0qCAfrQ4+7Tqej0HzDzGQeXzS8tg9gq84x1qUdRvFk5BXbhuAyvJliY9F1/I07d2X0A==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/elements": "^2.9.5",
+        "color": "^4.2.3",
+        "sf-symbols-typescript": "^2.1.0",
+        "warn-once": "^0.1.1"
+      },
+      "peerDependencies": {
+        "@react-navigation/native": "^7.1.28",
+        "react": ">= 18.2.0",
+        "react-native": "*",
+        "react-native-safe-area-context": ">= 4.0.0",
+        "react-native-screens": ">= 4.0.0"
+      }
+    },
+    "node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@react-navigation/routers": {
+      "version": "7.5.3",
+      "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz",
+      "integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==",
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11"
+      }
+    },
     "node_modules/@sinclair/typebox": {
       "version": "0.27.10",
       "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz",
         "node": ">=0.8"
       }
     },
+    "node_modules/color": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1",
+        "color-string": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=12.5.0"
+      }
+    },
     "node_modules/color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "license": "MIT"
     },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "node_modules/color/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
     "node_modules/commander": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
         }
       }
     },
+    "node_modules/decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
     "node_modules/deep-extend": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
       "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
       "license": "Apache-2.0"
     },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "license": "MIT"
+    },
     "node_modules/fast-json-stable-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
         "node": ">=8"
       }
     },
+    "node_modules/filter-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
+      "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/finalhandler": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
         "loose-envify": "^1.0.0"
       }
     },
+    "node_modules/is-arrayish": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+      "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+      "license": "MIT"
+    },
     "node_modules/is-core-module": {
       "version": "2.16.1",
       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
         "qrcode-terminal": "bin/qrcode-terminal.js"
       }
     },
+    "node_modules/query-string": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
+      "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
+      "license": "MIT",
+      "dependencies": {
+        "decode-uri-component": "^0.2.2",
+        "filter-obj": "^1.1.0",
+        "split-on-first": "^1.0.0",
+        "strict-uri-encode": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/queue": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
         "ws": "^7"
       }
     },
+    "node_modules/react-freeze": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
+      "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "react": ">=17.0.0"
+      }
+    },
     "node_modules/react-is": {
       "version": "18.3.1",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
       "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
       "integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
       "license": "MIT",
+      "peer": true,
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-screens": {
+      "version": "4.16.0",
+      "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
+      "integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "react-freeze": "^1.0.0",
+        "react-native-is-edge-to-edge": "^1.2.1",
+        "warn-once": "^0.1.0"
+      },
       "peerDependencies": {
         "react": "*",
         "react-native": "*"
       "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
       "license": "ISC"
     },
+    "node_modules/sf-symbols-typescript": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz",
+      "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/shebang-command": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
         "plist": "^3.0.5"
       }
     },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+      "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
     "node_modules/sisteransi": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
         "node": ">=0.10.0"
       }
     },
+    "node_modules/split-on-first": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
         "node": ">= 0.10.0"
       }
     },
+    "node_modules/strict-uri-encode": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+      "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
         "browserslist": ">= 4.21.0"
       }
     },
+    "node_modules/use-latest-callback": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz",
+      "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": ">=16.8"
+      }
+    },
+    "node_modules/use-sync-external-store": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+      "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
     "node_modules/utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
         "makeerror": "1.0.12"
       }
     },
+    "node_modules/warn-once": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
+      "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
+      "license": "MIT"
+    },
     "node_modules/wcwidth": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
index 095c042d9f86a30134cdb04f06a46fc422e98e2c..e7af7ea6784a14ae7ffb5b7e903cfc729137d780 100644 (file)
   },
   "dependencies": {
     "@react-native-async-storage/async-storage": "2.2.0",
+    "@react-navigation/native": "^7.1.28",
+    "@react-navigation/native-stack": "^7.13.0",
     "expo": "~54.0.33",
     "expo-status-bar": "~3.0.9",
     "react": "19.1.0",
     "react-native": "0.81.5",
-    "react-native-safe-area-context": "~5.6.0"
+    "react-native-safe-area-context": "~5.6.0",
+    "react-native-screens": "~4.16.0"
   },
   "devDependencies": {
     "@types/react": "~19.1.0",
index 30d380b860af28ca8fd114756902cedbdd7eb9a2..5fe177bebdbc65bc530feb5b4d1d577f0a7713ae 100644 (file)
-import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
-import { useEffect, useState } from "react";
-import { DashboardSummary, TradeDecision, AlertLevel } from "../types/DashboardSummary";
-import { fetchDashboardSummary } from "../services/dashboardService";
+import {
+  View,
+  Text,
+  StyleSheet,
+  ScrollView,
+  TouchableOpacity,
+} from "react-native";
+import { useState, useCallback, useEffect } from "react";
 import { SafeAreaView } from "react-native-safe-area-context";
-import { loadSettings } from "../utils/settingsStorage";
-import { UserSettings } from "../models/UserSettings";
+import { useFocusEffect, useNavigation } from "@react-navigation/native";
 
+import type {
+  DashboardSummary,
+  TradeDecision,
+  AlertLevel,
+} from "../types/DashboardSummary";
+import { fetchDashboardSummary } from "../services/dashboardService";
+import { loadSettings } from "../utils/settingsStorage";
+import type { UserSettings } from "../models/UserSettings";
+
+/**
+ * DashboardScreen
+ * --------------
+ * Écran principal mobile (Step 1).
+ * Rôle : afficher des données (consommateur API) :
+ * - Marché (prix)
+ * - Signal (BUY/SELL/HOLD/STOP_LOSS) + niveau d'alerte (CRITICAL/WARNING/INFO)
+ * - Portefeuille (placeholder Step 1)
+ * - Actions rapides (dont accès aux Paramètres)
+ *
+ * Spécificité :
+ * - On recharge les données quand l'écran reprend le focus (retour depuis Settings).
+ * - Si refreshMode === "auto", on rafraîchit le dashboard périodiquement.
+ */
 export default function DashboardScreen() {
+  // Données du dashboard (mock pour l'instant)
   const [summary, setSummary] = useState<DashboardSummary | null>(null);
-  const [loading, setLoading] = useState<boolean>(true);
-  const [error, setError] = useState<string | null>(null);
+
+  // Paramètres utilisateur (AsyncStorage)
   const [settings, setSettings] = useState<UserSettings | null>(null);
 
-useEffect(() => {
-  async function loadData() {
-    try {
-      const [dashboardData, userSettings] = await Promise.all([
-        fetchDashboardSummary(),
-        loadSettings(),
-      ]);
-
-      setSummary(dashboardData);
-      setSettings(userSettings);
-    } catch (err) {
-      setError("Impossible de charger le dashboard.");
-    } finally {
-      setLoading(false);
-    }
-  }
+  // États UI (loading / erreur)
+  const [loading, setLoading] = useState<boolean>(true);
+  const [error, setError] = useState<string | null>(null);
 
-  loadData();
-}, []);
+  // Navigation (Stack)
+  const navigation = useNavigation();
+
+  /**
+   * Charge dashboard + settings à chaque focus sur l'écran.
+   * (utile quand on revient des Paramètres)
+   */
+  useFocusEffect(
+    useCallback(() => {
+      let isActive = true;
+
+      async function loadData() {
+        try {
+          setError(null);
+          setLoading(true);
+
+          const [dashboardData, userSettings] = await Promise.all([
+            fetchDashboardSummary(),
+            loadSettings(),
+          ]);
+
+          if (isActive) {
+            setSummary(dashboardData);
+            setSettings(userSettings);
+          }
+        } catch (e) {
+          if (isActive) {
+            setError("Impossible de charger le dashboard.");
+          }
+        } finally {
+          if (isActive) {
+            setLoading(false);
+          }
+        }
+      }
+
+      loadData();
+
+      return () => {
+        isActive = false;
+      };
+    }, [])
+  );
 
+  /**
+   * Rafraîchissement automatique si l'utilisateur l'a activé.
+   * On ne relance pas le loading global (pour éviter que l'écran "clignote"),
+   * on met juste à jour le summary.
+   */
+  useEffect(() => {
+    // Pas de settings => impossible de savoir le mode
+    if (!settings) return;
+
+    // Mode manuel => pas d'interval
+    if (settings.refreshMode !== "auto") return;
+
+    let cancelled = false;
+
+    const intervalId = setInterval(async () => {
+      try {
+        const data = await fetchDashboardSummary();
+        if (!cancelled) setSummary(data);
+      } catch {
+        // On évite de spammer l'utilisateur : on peut juste logguer
+        // ou afficher une erreur discrète.
+        if (!cancelled) setError("Erreur lors du rafraîchissement automatique.");
+      }
+    }, 5000); // toutes les 5 secondes
+
+    return () => {
+      cancelled = true;
+      clearInterval(intervalId);
+    };
+  }, [settings]);
+
+  // UI : Chargement
   if (loading) {
     return (
       <View style={styles.container}>
@@ -40,22 +127,27 @@ useEffect(() => {
     );
   }
 
-  if (error) {
+  // UI : Erreur (erreur "bloquante")
+  if (error && (!summary || !settings)) {
     return (
       <View style={styles.container}>
-        <Text style={{ color: "red" }}>{error}</Text>
+        <Text style={styles.errorText}>{error}</Text>
       </View>
     );
   }
 
-if (!summary || !settings) {
-  return (
-    <View style={styles.container}>
-      <Text>Initialisation…</Text>
-    </View>
-  );
-}
+  // Fallback sécurité
+  if (!summary || !settings) {
+    return (
+      <View style={styles.container}>
+        <Text>Initialisation…</Text>
+      </View>
+    );
+  }
 
+  /**
+   * Helpers d'affichage (couleurs) pour respecter le contrat mobile
+   */
   const getDecisionColor = (decision: TradeDecision) => {
     switch (decision) {
       case "BUY":
@@ -64,6 +156,7 @@ if (!summary || !settings) {
         return "#dc2626";
       case "STOP_LOSS":
         return "#991b1b";
+      case "HOLD":
       default:
         return "#ca8a04";
     }
@@ -76,16 +169,21 @@ if (!summary || !settings) {
       case "WARNING":
         return "#ca8a04";
       case "INFO":
-        return "#2563eb";
       default:
-        return "#6b7280";
+        return "#2563eb";
     }
   };
 
   return (
     <SafeAreaView style={styles.safeArea}>
       <ScrollView contentContainerStyle={styles.container}>
-        
+        {/* Petit warning non bloquant si l'auto-refresh a eu un souci */}
+        {error && (
+          <View style={styles.warningBanner}>
+            <Text style={styles.warningText}>{error}</Text>
+          </View>
+        )}
+
         {/* Carte Marché */}
         <View style={styles.card}>
           <Text style={styles.sectionTitle}>Marché</Text>
@@ -95,17 +193,16 @@ if (!summary || !settings) {
           <View style={styles.priceRow}>
             <Text style={styles.value}>Prix actuel</Text>
             <Text style={styles.valueBold}>
-              {summary.price.toFixed(2)} 
+              {summary.price.toFixed(2)} {settings.currency}
             </Text>
           </View>
 
           <Text style={styles.updated}>
-            Dernière mise à jour :{" "}
-            {new Date(summary.timestamp).toLocaleString()}
+            Dernière mise à jour : {new Date(summary.timestamp).toLocaleString()}
           </Text>
         </View>
 
-        {/* Carte Stratégie */}
+        {/* Carte Stratégie + Signal */}
         <View style={styles.card}>
           <Text style={styles.sectionTitle}>Stratégie</Text>
 
@@ -121,12 +218,10 @@ if (!summary || !settings) {
           </Text>
 
           <Text
-            style={{
-              textAlign: "center",
-              fontWeight: "bold",
-              color: getAlertColor(summary.alertLevel),
-              marginBottom: 6,
-            }}
+            style={[
+              styles.alertLevel,
+              { color: getAlertColor(summary.alertLevel) },
+            ]}
           >
             {summary.alertLevel}
           </Text>
@@ -141,18 +236,16 @@ if (!summary || !settings) {
           <Text style={styles.reason}>{summary.reason}</Text>
         </View>
 
-        {/* Carte Portefeuille */}
+        {/* Carte Portefeuille (placeholder Step 1) */}
         <View style={styles.card}>
           <Text style={styles.sectionTitle}>Portefeuille</Text>
 
           <View style={styles.priceRow}>
             <Text style={styles.value}>Valeur totale</Text>
-            <Text style={styles.valueBold}>10 000 </Text>
+            <Text style={styles.valueBold}>10 000 {settings.currency}</Text>
           </View>
 
-          <Text style={styles.updated}>
-            Step 1 : mono-utilisateur / mono-crypto
-          </Text>
+          <Text style={styles.updated}>Step 1 : mono-utilisateur / mono-crypto</Text>
         </View>
 
         {/* Carte Actions */}
@@ -167,6 +260,13 @@ if (!summary || !settings) {
             <TouchableOpacity style={styles.button}>
               <Text style={styles.buttonText}>Historique</Text>
             </TouchableOpacity>
+
+            <TouchableOpacity
+              style={styles.button}
+              onPress={() => navigation.navigate("Settings" as never)}
+            >
+              <Text style={styles.buttonText}>Paramètres</Text>
+            </TouchableOpacity>
           </View>
         </View>
       </ScrollView>
@@ -174,16 +274,18 @@ if (!summary || !settings) {
   );
 }
 
-const styles = StyleSheet.create({
-  container: {
-    padding: 16,
-  },
+/* ===================== STYLES ===================== */
 
+const styles = StyleSheet.create({
   safeArea: {
     flex: 1,
     backgroundColor: "#fff",
   },
 
+  container: {
+    padding: 16,
+  },
+
   card: {
     borderWidth: 1,
     borderColor: "#aaa",
@@ -212,10 +314,16 @@ const styles = StyleSheet.create({
     marginVertical: 10,
   },
 
+  alertLevel: {
+    textAlign: "center",
+    fontWeight: "bold",
+    marginBottom: 6,
+  },
+
   row: {
     flexDirection: "row",
-    justifyContent: "space-between",
-    alignItems: "center",
+    flexWrap: "wrap",
+    gap: 8,
   },
 
   priceRow: {
@@ -242,8 +350,11 @@ const styles = StyleSheet.create({
   button: {
     backgroundColor: "#555",
     paddingHorizontal: 10,
-    paddingVertical: 6,
+    paddingVertical: 10,
     borderRadius: 4,
+    flexGrow: 1,
+    flexBasis: "48%",
+    alignItems: "center",
   },
 
   buttonText: {
@@ -257,5 +368,22 @@ const styles = StyleSheet.create({
     marginTop: 6,
     textAlign: "center",
   },
-});
 
+  errorText: {
+    color: "#dc2626",
+    fontWeight: "bold",
+  },
+
+  warningBanner: {
+    borderWidth: 1,
+    borderColor: "#ca8a04",
+    padding: 10,
+    borderRadius: 6,
+    marginBottom: 12,
+  },
+
+  warningText: {
+    color: "#ca8a04",
+    fontWeight: "bold",
+  },
+});
\ No newline at end of file