diff --git a/listfiles.sh b/listfiles.sh
index 68b1127..792ffa0 100644
--- a/listfiles.sh
+++ b/listfiles.sh
@@ -1,5 +1,55 @@
-for f in $(find src -type f \( -name "*.js" -o -name "*.jsx" -o -name "*.css" \) ! -name "maplibre.css"); do
- echo "================== FILE: $f =================="
- cat "$f"
- echo ""
-done | termux-clipboard-set
+#!/data/data/com.termux/files/usr/bin/bash
+set -euo pipefail
+
+# Nombre de parties voulues
+PARTS=3
+
+# Fichier temporaire qui contient tout le code
+TMPFILE=$(mktemp)
+cleanup() { rm -f "$TMPFILE" "${TMPFILE}"_part_* 2>/dev/null || true; }
+trap cleanup EXIT
+
+# 1) Construire le gros fichier avec tous les .js/.jsx/.css
+find src -type f \( -name "*.js" -o -name "*.jsx" -o -name "*.css" \) ! -name "maplibre.css" -print0 |
+while IFS= read -r -d '' f; do
+ printf '================== FILE: %s ==================\n' "$f" >> "$TMPFILE"
+ cat "$f" >> "$TMPFILE"
+ printf '\n' >> "$TMPFILE"
+done
+
+# 2) Découper en exactement PARTS morceaux (ou moins si très petit)
+# -n l/3 = découpe en 3 blocs de lignes à peu près égaux
+split -n l/"$PARTS" -d --additional-suffix=".txt" "$TMPFILE" "${TMPFILE}_part_"
+
+# 3) Envoyer chaque morceau dans le presse-papier, ENTER pour le suivant
+parts=( "${TMPFILE}_part_"*.txt )
+total=${#parts[@]}
+
+if [ "$total" -eq 0 ]; then
+ echo "Aucun contenu trouvé."
+ exit 0
+fi
+
+echo "📦 Total: $total partie(s) à envoyer dans ChatGPT."
+
+idx=1
+for p in "${parts[@]}"; do
+ # On ajoute une bannière claire DEBUT/FIN pour chaque partie
+ {
+ echo "===== SOCIOWIRE FRONTEND – PART $idx / $total (BEGIN) ====="
+ cat "$p"
+ echo
+ echo "===== END OF SOCIOWIRE FRONTEND – PART $idx / $total ====="
+ } | termux-clipboard-set
+
+ echo "➡️ Partie $idx / $total copiée dans le presse-papier."
+ if [ "$idx" -lt "$total" ]; then
+ echo "Colle cette partie dans ChatGPT, envoie le message,"
+ echo "puis reviens ici et appuie sur ENTER pour la suivante (ou 'q' + ENTER pour quitter)…"
+ read -r ans || true
+ [ "$ans" = "q" ] || [ "$ans" = "Q" ] && break
+ fi
+ idx=$((idx+1))
+done
+
+echo "✅ Terminé."
diff --git a/src/auth/AuthContext.jsx b/src/auth/AuthContext.jsx
index 0c2d9d6..4b16782 100644
--- a/src/auth/AuthContext.jsx
+++ b/src/auth/AuthContext.jsx
@@ -1,105 +1,153 @@
import React, { createContext, useContext, useEffect, useState } from "react";
-import keycloak from "./keycloak";
+
+// CONFIG KEYCLOAK
+const KC_BASE = "https://web.sociowire.com:8443";
+const KC_REALM = "sociowire";
+const KC_CLIENT_ID = "sociowire-frontend";
+
+const TOKEN_KEY = "sociowire:token";
const AuthContext = createContext(null);
+function parseJwt(token) {
+ try {
+ const [, payload] = token.split(".");
+ const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
+ return JSON.parse(json);
+ } catch {
+ return {};
+ }
+}
+
export function AuthProvider({ children }) {
- const [kc, setKc] = useState(null);
- const [loading, setLoading] = useState(true);
+ const [token, setToken] = useState(null);
const [authenticated, setAuthenticated] = useState(false);
const [username, setUsername] = useState("");
+ const [loading, setLoading] = useState(true);
const [lastError, setLastError] = useState("");
+ // charger token depuis localStorage au démarrage
useEffect(() => {
- let isMounted = true;
-
- async function init() {
- try {
- console.log("[AUTH] init keycloak…");
- const ok = await keycloak.init({
- onLoad: "check-sso", // ne force pas le login au chargement
- checkLoginIframe: false,
- });
-
- if (!isMounted) return;
-
- console.log("[AUTH] init result:", ok);
- window.kc = keycloak; // debug global
-
- setKc(keycloak);
- setAuthenticated(ok);
-
- if (ok && keycloak.tokenParsed) {
- const p = keycloak.tokenParsed;
- const name =
- p.preferred_username ||
- p.email ||
- p.name ||
- (p.sub ? String(p.sub) : "");
- setUsername(name || "");
- } else {
- setUsername("");
- }
- } catch (err) {
- console.error("[AUTH] keycloak init error", err);
- if (isMounted) {
- setLastError(String(err));
- }
- } finally {
- if (isMounted) setLoading(false);
- }
- }
-
- init();
-
- // refresh token simplifié
- const interval = setInterval(() => {
- if (!keycloak || !keycloak.authenticated) return;
- keycloak
- .updateToken(60)
- .then((refreshed) => {
- if (refreshed) {
- console.log("[AUTH] token refreshed");
+ try {
+ const saved = localStorage.getItem(TOKEN_KEY);
+ if (saved) {
+ const data = JSON.parse(saved);
+ if (data && data.access_token) {
+ const now = Date.now() / 1000;
+ const payload = parseJwt(data.access_token);
+ if (!payload.exp || payload.exp > now) {
+ setToken(data.access_token);
+ setAuthenticated(true);
+ const name =
+ payload.preferred_username ||
+ payload.email ||
+ payload.name ||
+ (payload.sub ? String(payload.sub) : "");
+ setUsername(name || "");
}
- })
- .catch((err) => {
- console.warn("[AUTH] token refresh error", err);
- });
- }, 30000);
-
- return () => {
- isMounted = false;
- clearInterval(interval);
- };
+ }
+ }
+ } catch (e) {
+ console.warn("[AUTH] load token error", e);
+ } finally {
+ setLoading(false);
+ }
}, []);
- const login = () => {
- keycloak.login({
- redirectUri: window.location.href,
- });
+ async function login(user, pass) {
+ setLastError("");
+ if (!user || !pass) {
+ setLastError("Username & password required.");
+ return;
+ }
+ setLoading(true);
+ try {
+ const params = new URLSearchParams();
+ params.set("grant_type", "password");
+ params.set("client_id", KC_CLIENT_ID);
+ params.set("username", user);
+ params.set("password", pass);
+
+ const res = await fetch(
+ `${KC_BASE}/realms/${KC_REALM}/protocol/openid-connect/token`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: params.toString(),
+ }
+ );
+
+ if (!res.ok) {
+ const text = await res.text();
+ console.error("[AUTH] login failed", res.status, text);
+ setLastError("Invalid credentials or auth error.");
+ setAuthenticated(false);
+ setToken(null);
+ setUsername("");
+ try {
+ localStorage.removeItem(TOKEN_KEY);
+ } catch {}
+ return;
+ }
+
+ const data = await res.json();
+ const accessToken = data.access_token;
+ if (!accessToken) {
+ setLastError("No access token returned.");
+ return;
+ }
+
+ const payload = parseJwt(accessToken);
+ const name =
+ payload.preferred_username ||
+ payload.email ||
+ payload.name ||
+ (payload.sub ? String(payload.sub) : "");
+
+ setToken(accessToken);
+ setAuthenticated(true);
+ setUsername(name || "");
+ setLastError("");
+
+ try {
+ localStorage.setItem(TOKEN_KEY, JSON.stringify(data));
+ } catch (e) {
+ console.warn("[AUTH] save token error", e);
+ }
+ } catch (err) {
+ console.error("[AUTH] login error", err);
+ setLastError("Network/auth error.");
+ setAuthenticated(false);
+ setToken(null);
+ setUsername("");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ function logout() {
+ setToken(null);
+ setAuthenticated(false);
+ setUsername("");
+ setLastError("");
+ try {
+ localStorage.removeItem(TOKEN_KEY);
+ } catch {}
+ }
+
+ const value = {
+ loading,
+ authenticated,
+ username,
+ token,
+ lastError,
+ login,
+ logout,
};
- const logout = () => {
- keycloak.logout({
- redirectUri: window.location.origin + "/",
- });
- };
-
- return (
-
- {children}
-
- );
+ return {children};
}
export function useAuth() {
@@ -109,3 +157,4 @@ export function useAuth() {
}
return ctx;
}
+// modif 1
\ No newline at end of file
diff --git a/src/components/Layout/TopBar.jsx b/src/components/Layout/TopBar.jsx
index f733643..186695e 100644
--- a/src/components/Layout/TopBar.jsx
+++ b/src/components/Layout/TopBar.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useState } from "react";
import { useAuth } from "../../auth/AuthContext";
const THEME_LABELS = {
@@ -8,12 +8,27 @@ const THEME_LABELS = {
};
export default function TopBar({ theme = "dark", onChangeTheme }) {
- const { loading, authenticated, username, login, logout, lastError } = useAuth();
+ const {
+ loading,
+ authenticated,
+ username,
+ login,
+ logout,
+ lastError,
+ } = useAuth();
+
+ const [user, setUser] = useState("");
+ const [pass, setPass] = useState("");
let authLabel = "AUTH: anon";
if (loading) authLabel = "AUTH: loading…";
else if (authenticated) authLabel = `AUTH: user=${username || "?"}`;
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ login(user.trim(), pass);
+ };
+
return (
SW
@@ -25,7 +40,7 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
{authLabel}
{lastError && (
- (auth err)
+ ({lastError})
)}
@@ -48,11 +63,7 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
))}
- {loading ? (
-
- ) : authenticated ? (
+ {authenticated ? (
{username}
) : (
-
+
)}
);
}
+// modif 2
\ No newline at end of file