This commit is contained in:
alma 2026-01-18 14:15:12 +01:00
parent 534c613e71
commit 6414e85a78
3 changed files with 12 additions and 221 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -1,184 +0,0 @@
# Problème TypeScript : Block-scoped variable 'status' used before its declaration
## Contexte du projet
- **Framework** : Next.js 16.1.1 (App Router)
- **TypeScript** : Mode strict activé (`"strict": true` dans `tsconfig.json`)
- **Fichier concerné** : `components/calendar/calendar-widget.tsx`
- **Erreur** : `Type error: Block-scoped variable 'status' used before its declaration.`
## Description du problème
L'erreur TypeScript se produit à la ligne 33 du fichier `components/calendar/calendar-widget.tsx` :
```typescript
export function CalendarWidget() {
const { data: session, status } = useSession(); // Ligne 25 - Déclaration
const [events, setEvents] = useState<Event[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const { triggerNotification } = useWidgetNotification();
const lastEventCountRef = useRef<number>(-1);
useEffect(() => {
console.log("Calendar Widget - Session Status:", status); // Ligne 33 - ERREUR ICI
// ...
}, [session, status, triggerNotification]);
}
```
**Erreur exacte :**
```
./components/calendar/calendar-widget.tsx:33:54
Type error: Block-scoped variable 'status' used before its declaration.
```
## Constat important
Le code est **identique en structure** à `components/email.tsx` qui **compile sans erreur** :
```typescript
// components/email.tsx - FONCTIONNE
export function Email() {
const { data: session, status } = useSession(); // Même déclaration
// ... autres hooks ...
useEffect(() => {
if (status === 'authenticated') { // Même utilisation
loadAccounts();
}
}, [status]);
}
```
## Ce qui a été testé
### 1. Tentatives de solutions (toutes échouées)
#### Tentative 1 : Déclaration dans le useEffect
```typescript
useEffect(() => {
const session = sessionHook.data;
const status = sessionHook.status;
// ...
}, [sessionHook.data, sessionHook.status, triggerNotification]);
```
**Résultat** : Erreur `Block-scoped variable 'sessionHook' used before its declaration`
#### Tentative 2 : Séparation de la destructuration
```typescript
const sessionResult = useSession();
const session = sessionResult.data;
const status = sessionResult.status;
```
**Résultat** : Même erreur avec `sessionResult`
#### Tentative 3 : Ordre des hooks modifié
- Déplacer `useSession()` avant les autres hooks
- Déplacer `useSession()` après les autres hooks
**Résultat** : Même erreur
#### Tentative 4 : Alignement avec email.tsx
Copie exacte de la structure de `email.tsx` qui fonctionne
**Résultat** : Même erreur
### 2. Vérifications effectuées
**Pas de conflit de noms** : Aucune autre déclaration de `status` dans le fichier
**Pas de cache** :
- `rm -rf .next` exécuté
- `rm -rf node_modules/.cache` exécuté
- Erreur persiste après nettoyage
**Fichier sur disque vérifié** : Le code est correct (pas de `sessionResult` ou autre)
```bash
sed -n '32,45p' components/calendar/calendar-widget.tsx
# Confirme que le code est correct
```
**Comparaison avec email.tsx** : Structure identique, même ordre de déclaration
**Recherche dans le projet** : Aucune autre référence à `sessionResult` trouvée
### 3. État actuel du code
Le fichier `components/calendar/calendar-widget.tsx` contient :
```typescript
"use client";
import { useState, useEffect, useRef } from "react";
import { format, isToday, isTomorrow, addDays } from "date-fns";
import { fr } from "date-fns/locale";
import { CalendarIcon, ChevronRight } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { useSession } from "next-auth/react";
import { useWidgetNotification } from "@/hooks/use-widget-notification";
type Event = {
id: string;
title: string;
start: Date;
end: Date;
isAllDay: boolean;
calendarId: string;
calendarName?: string;
calendarColor?: string;
};
export function CalendarWidget() {
const { data: session, status } = useSession(); // Ligne 25
const [events, setEvents] = useState<Event[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const { triggerNotification } = useWidgetNotification();
const lastEventCountRef = useRef<number>(-1);
useEffect(() => {
console.log("Calendar Widget - Session Status:", status); // Ligne 33 - ERREUR
console.log("Calendar Widget - Session Data:", session);
if (status === "loading") {
console.log("Calendar Widget - Session is loading");
return;
}
if (status !== "authenticated" || !session) {
console.log("Calendar Widget - Not authenticated, skipping fetch");
setLoading(false);
return;
}
// ... reste du code ...
}, [session, status, triggerNotification]);
// ... reste du composant ...
}
```
## Hypothèses
1. **Bug TypeScript** : Problème d'analyse statique avec les hooks React dans ce contexte spécifique
2. **Incompatibilité de versions** : Possible problème entre Next.js 16.1.1 et TypeScript
3. **Analyse séquentielle** : TypeScript pourrait analyser le `useEffect` avant que la destructuration de `useSession()` soit complètement résolue
## Informations techniques
- **Next.js** : 16.1.1
- **TypeScript** : Version dans `tsconfig.json` avec `"strict": true`
- **React** : Version via Next.js 16.1.1
- **next-auth** : Utilisé pour `useSession()`
## Question
Pourquoi TypeScript signale-t-il que `status` est utilisé avant sa déclaration alors que :
1. `status` est déclaré ligne 25
2. `status` est utilisé ligne 33 (dans un `useEffect` qui est déclaré après)
3. La même structure fonctionne dans `components/email.tsx`
4. Aucun conflit de noms n'existe
5. Les caches ont été nettoyés
Quelle est la solution pour résoudre cette erreur TypeScript sans compromettre la structure du code qui fonctionne ailleurs dans le projet ?

View File

@ -1,7 +1,7 @@
"use client";
import { signIn, useSession } from "next-auth/react";
import { useEffect, useState, useRef } from "react";
import { useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
export default function SignIn() {
@ -10,7 +10,6 @@ export default function SignIn() {
const searchParams = useSearchParams();
const [initializationStatus, setInitializationStatus] = useState<string | null>(null);
const [isLoggingIn, setIsLoggingIn] = useState(false);
const hasAttemptedLogin = useRef(false);
// Check URL parameters for logout flag
const logoutParam = searchParams.get('logout');
@ -18,7 +17,7 @@ export default function SignIn() {
// Debug logging
useEffect(() => {
console.log('[SignIn] Status:', status, 'Session:', !!session, 'Logout redirect:', isLogoutRedirect, 'Has attempted:', hasAttemptedLogin.current);
console.log('[SignIn] Status:', status, 'Session:', !!session, 'Logout redirect:', isLogoutRedirect);
}, [status, session, isLogoutRedirect]);
// Clear stale force_login_prompt cookie on mount (it should only last 5 minutes)
@ -45,32 +44,9 @@ export default function SignIn() {
return;
}
// Don't auto-login if this is a logout redirect
if (isLogoutRedirect) {
console.log('[SignIn] Logout redirect detected, showing login button');
return;
}
// Don't auto-login if we've already attempted or are currently logging in
if (hasAttemptedLogin.current || isLoggingIn) {
return;
}
// Don't auto-login if status is still loading
if (status === "loading") {
return;
}
// Auto-login for new users (SSO natural flow)
if (status === "unauthenticated") {
console.log('[SignIn] Status is unauthenticated, triggering Keycloak login');
hasAttemptedLogin.current = true;
setIsLoggingIn(true);
// Trigger Keycloak sign-in immediately
signIn("keycloak", { callbackUrl: "/" });
}
}, [status, session, router, isLogoutRedirect, isLoggingIn]);
// Auto-login disabled - user must click the button to connect
// This allows users to see and appreciate the sign-in page
}, [status, session, router]);
useEffect(() => {
if (session?.user) {
@ -128,23 +104,22 @@ export default function SignIn() {
: initializationStatus === "failed"
? "Échec de l'initialisation. Veuillez réessayer."
: isLoggingIn
? "Connexion à Keycloak en cours..."
? "Connexion en cours..."
: status === "loading"
? "Chargement..."
: "Redirection vers la page de connexion..."}
: "Bienvenue"}
</h2>
{/* Show login button after logout OR if auto-login failed */}
{(isLogoutRedirect || (status === "unauthenticated" && hasAttemptedLogin.current && !isLoggingIn)) && (
<div className="mt-4 text-center">
{/* Show login button when user is not authenticated and not currently logging in */}
{status === "unauthenticated" && !isLoggingIn && (
<div className="mt-8 text-center">
<button
onClick={() => {
console.log('[SignIn] Manual login button clicked');
hasAttemptedLogin.current = false;
console.log('[SignIn] Login button clicked');
setIsLoggingIn(true);
signIn("keycloak", { callbackUrl: "/" });
}}
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold text-lg shadow-lg hover:shadow-xl"
>
Se connecter
</button>