]> git.digitality.be Git - pdw25-26/commitdiff
Mobile : petit oublie de ma part
authorThibaud Moustier <thibaudmoustier0@gmail.com>
Sun, 1 Mar 2026 21:04:41 +0000 (22:04 +0100)
committerThibaud Moustier <thibaudmoustier0@gmail.com>
Sun, 1 Mar 2026 21:04:41 +0000 (22:04 +0100)
Wallette/mobile/package-lock.json
Wallette/mobile/package.json
Wallette/mobile/src/config/env.ts
Wallette/mobile/src/screens/AlertsScreen.tsx
Wallette/mobile/src/services/api/http.ts
Wallette/mobile/src/types/Alert.ts

index 6377cc91b295926e087aa4190b13fe103d5d5b55..6d45584fda961ee48481557d790fdcc53f20afd3 100644 (file)
@@ -12,6 +12,7 @@
         "@react-native-async-storage/async-storage": "2.2.0",
         "@react-navigation/native": "^7.1.28",
         "@react-navigation/native-stack": "^7.13.0",
+        "buffer": "^6.0.3",
         "expo": "~54.0.33",
         "expo-crypto": "~15.0.8",
         "expo-notifications": "~0.32.16",
       }
     },
     "node_modules/buffer": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
-      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
       "funding": [
         {
           "type": "github",
       "license": "MIT",
       "dependencies": {
         "base64-js": "^1.3.1",
-        "ieee754": "^1.1.13"
+        "ieee754": "^1.2.1"
       }
     },
     "node_modules/buffer-from": {
         "node": ">=10"
       }
     },
+    "node_modules/whatwg-url-without-unicode/node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
index 813958d9d5e1e46ee372f1a125bd0b261b9b0e92..ba7175eb6b646716316308a862835c5e741e0fea 100644 (file)
@@ -13,6 +13,7 @@
     "@react-native-async-storage/async-storage": "2.2.0",
     "@react-navigation/native": "^7.1.28",
     "@react-navigation/native-stack": "^7.13.0",
+    "buffer": "^6.0.3",
     "expo": "~54.0.33",
     "expo-crypto": "~15.0.8",
     "expo-notifications": "~0.32.16",
index 15bff3d1edbcae05fd2ee3f3eaa21cf8836c2abd..282c6c4b6a55ac9033dc4809f3e948edee50c098 100644 (file)
@@ -3,29 +3,28 @@ import { Platform } from "react-native";
 /**
  * env.ts
  * ------
- * 1 seul point de config réseau.
- *
- * IMPORTANT :
- * - REST = https://wallette.duckdns.org/api
- * - Socket.IO = https://wallette.duckdns.org   (PAS /api)
- *
- * Expo = __DEV__ => on peut forcer PROD pour tester le serveur déployé.
+ * Source unique de config réseau.
  */
 
-// ✅ PROD (duckdns)
-const PROD_GATEWAY = "https://wallette.duckdns.org";
+const DEV_LAN_IP = "192.168.129.121";
+const DEV_GATEWAY = `http://${DEV_LAN_IP}:3000`;
 
-// ✅ DEV (pour test Expo sur tel) : force PROD
-// Si tu veux revenir au local plus tard : remets ton IP LAN + http://IP:3000
-const DEV_GATEWAY = "https://wallette.duckdns.org";
+const PROD_GATEWAY = "https://wallette.duckdns.org";
 
 export const GATEWAY_BASE_URL = __DEV__ ? DEV_GATEWAY : PROD_GATEWAY;
-
-// REST (via gateway)
 export const API_BASE_URL = `${GATEWAY_BASE_URL}/api`;
-
-// Socket.IO (via gateway) -> RACINE (pas /api)
 export const SERVER_URL = GATEWAY_BASE_URL;
 
 export const ENV_MODE = __DEV__ ? "DEV" : "PROD";
-export const PLATFORM = Platform.OS;
\ No newline at end of file
+export const PLATFORM = Platform.OS;
+
+/**
+ * Basic Auth (protection serveur / NGINX)
+ * --------------------------------------
+ * Sert à passer la barrière d’accès (HTTP 401).
+ *
+ * ⚠️ Oui, c’est “dans l’app”. Pour un projet étudiant, c’est acceptable.
+ * Si vous voulez mieux : variables EAS (secrets) plus tard.
+ */
+export const BASIC_AUTH_USER = "Thibaud";
+export const BASIC_AUTH_PASS = "ThibaudLCC";
\ No newline at end of file
index dee535c9047d43375ee762892fea9a7fa45bf577..4d4812df932af4567737df34096a8c6545f12c50 100644 (file)
@@ -70,7 +70,7 @@ export default function AlertsScreen() {
 
   const filteredSorted = useMemo(() => {
     const base =
-      filter === "ALL" ? items : items.filter((a) => (a.alertLevel ?? "INFO") === filter);
+      filter === "ALL" ? items : items.filter((a) => ((a.alertLevel ?? a.criticality ?? "INFO") === filter));
 
     return [...base].sort((a, b) => {
       const r = severityRank(b.alertLevel) - severityRank(a.alertLevel);
@@ -168,7 +168,7 @@ export default function AlertsScreen() {
                 </View>
 
                 <View style={[ui.badge, { backgroundColor: `${lColor}22`, marginTop: 0 }]}>
-                  <Text style={[ui.badgeText, { color: lColor }]}>{item.alertLevel ?? "INFO"}</Text>
+                  <Text style={[ui.badgeText, { color: lColor }]}>{item.alertLevel ?? item.criticality ?? "INFO"}</Text>
                 </View>
               </View>
 
index 68149033274407b132d23a977eca3586da0b0a20..a7f51063262e5c931ea35a26a87bfcad05c9a2f2 100644 (file)
@@ -1,13 +1,25 @@
 import { API_BASE_URL } from "../../config/env";
+import { BASIC_AUTH_USER, BASIC_AUTH_PASS } from "../../config/env";
+import { Buffer } from "buffer";
 
 /**
  * HTTP helper (fetch)
  * -------------------
- * Compatible avec 2 formats :
- * A) "wrap" : { ok:true, data: ... } / { ok:false, error:{message} }
- * B) "raw"  : { ... } / Alert[] etc.
+ * - Ajoute Basic Auth si configuré (pour passer la barrière 401)
+ * - Compatible avec 2 formats :
+ *   A) wrap : { ok:true, data: ... } / { ok:false, error:{message} }
+ *   B) raw  : { ... } / [...]
  */
 
+function getBasicAuthHeader(): string | null {
+  const u = (BASIC_AUTH_USER ?? "").trim();
+  const p = (BASIC_AUTH_PASS ?? "").trim();
+  if (!u || !p) return null;
+
+  const token = Buffer.from(`${u}:${p}`, "utf8").toString("base64");
+  return `Basic ${token}`;
+}
+
 async function parseJsonSafe(res: Response) {
   const text = await res.text();
   try {
@@ -31,10 +43,22 @@ function unwrapOrRaw<T>(json: any): T {
   return json as T;
 }
 
+function buildHeaders(extra?: Record<string, string>) {
+  const headers: Record<string, string> = {
+    Accept: "application/json",
+    ...(extra ?? {}),
+  };
+
+  const auth = getBasicAuthHeader();
+  if (auth) headers.Authorization = auth;
+
+  return headers;
+}
+
 export async function apiGet<T>(path: string): Promise<T> {
   const res = await fetch(buildUrl(path), {
     method: "GET",
-    headers: { Accept: "application/json" },
+    headers: buildHeaders(),
   });
 
   const json = await parseJsonSafe(res);
@@ -50,10 +74,7 @@ export async function apiGet<T>(path: string): Promise<T> {
 export async function apiPost<T>(path: string, body: unknown): Promise<T> {
   const res = await fetch(buildUrl(path), {
     method: "POST",
-    headers: {
-      Accept: "application/json",
-      "Content-Type": "application/json",
-    },
+    headers: buildHeaders({ "Content-Type": "application/json" }),
     body: JSON.stringify(body),
   });
 
index d1b7caabbc100cdf8a91965e17528058892bc6f3..4a7a405a1788b0cc519b1be88c4079abebef5d0a 100644 (file)
@@ -1,16 +1,35 @@
+/**
+ * Alert.ts
+ * --------
+ * Format d'alerte utilisé par :
+ * - Socket.IO (event "alert")
+ * - REST : GET /api/alerts/events?userId=...&limit=...
+ *
+ * Le backend peut envoyer :
+ * - alertLevel (ancien)
+ * - OU criticality (nouveau BotService)
+ *
+ * On accepte les deux.
+ */
+
 export type AlertLevel = "CRITICAL" | "WARNING" | "INFO";
 export type AlertAction = "BUY" | "SELL" | "HOLD" | "STOP_LOSS";
 
 export interface Alert {
   action?: AlertAction;
   pair?: string;
-  confidence?: number;
+  confidence?: number; // 0..1
   reason?: string;
 
-  // compat web
+  // compat: certains front/back utilisent 'message'
   message?: string;
 
+  // ancien nom
   alertLevel?: AlertLevel;
-  timestamp?: number;
+
+  // nouveau nom (BotService)
+  criticality?: AlertLevel;
+
+  timestamp?: number; // ms
   price?: number;
 }
\ No newline at end of file