mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-23 23:28:17 +02:00
Fix: Correction modal ajout RDV et réorganisation layout
Corrections : 1. Bug modal ajout de rendez-vous : - Remplacement des composants Select par des éléments select natifs - Les composants shadcn/ui Select ne fonctionnaient pas avec FormData - Le modal affichait une page blanche à cause de ce problème - Maintenant le formulaire fonctionne correctement 2. Réorganisation du layout : - Box Todo et RSS maintenant côte à côte (au lieu d'empilées) - Largeur de la colonne droite passée de 380px à 760px - Grid à 2 colonnes dans la partie droite - Hauteur augmentée : max-h-[calc(100vh-300px)] pour les deux boxes - Plus d'espace pour afficher les tâches et articles 3. Amélioration affichage RSS : - Suppression de la rotation automatique toutes les 20s - Affichage de tous les articles (15) avec scroll - Suppression de l'état rssDisplayOffset inutile - Suppression du useEffect de rotation - Meilleure utilisation de l'espace vertical disponible
This commit is contained in:
1 file changed
+68
-91
+68
-91
@@ -56,7 +56,6 @@ const Index = () => {
|
|||||||
const [loadingModels, setLoadingModels] = useState(false);
|
const [loadingModels, setLoadingModels] = useState(false);
|
||||||
const [currentDateTime, setCurrentDateTime] = useState(new Date());
|
const [currentDateTime, setCurrentDateTime] = useState(new Date());
|
||||||
const [upcomingAlert, setUpcomingAlert] = useState<CalendarEvent | null>(null);
|
const [upcomingAlert, setUpcomingAlert] = useState<CalendarEvent | null>(null);
|
||||||
const [rssDisplayOffset, setRssDisplayOffset] = useState(0);
|
|
||||||
const [calendarAuthStatus, setCalendarAuthStatus] = useState<{
|
const [calendarAuthStatus, setCalendarAuthStatus] = useState<{
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
isExpired: boolean;
|
isExpired: boolean;
|
||||||
@@ -111,18 +110,6 @@ const Index = () => {
|
|||||||
return () => clearInterval(timer);
|
return () => clearInterval(timer);
|
||||||
}, [calendarEvents]);
|
}, [calendarEvents]);
|
||||||
|
|
||||||
// RSS articles rotation every 20 seconds
|
|
||||||
useEffect(() => {
|
|
||||||
if (rssArticles.length > 3) {
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
setRssDisplayOffset(prev => {
|
|
||||||
const maxOffset = Math.max(0, rssArticles.length - 3);
|
|
||||||
return (prev + 3) % (maxOffset + 3);
|
|
||||||
});
|
|
||||||
}, 20000); // Rotate every 20 seconds
|
|
||||||
return () => clearInterval(timer);
|
|
||||||
}
|
|
||||||
}, [rssArticles.length]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const userFromAuth = AuthService.getUser();
|
const userFromAuth = AuthService.getUser();
|
||||||
@@ -702,8 +689,8 @@ const Index = () => {
|
|||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<div className="max-w-[1920px] mx-auto px-8 py-8">
|
<div className="max-w-[1920px] mx-auto px-8 py-8">
|
||||||
{/* Three Column Layout: Calendar Left | Notes Middle | Todo/RSS Right */}
|
{/* Three Column Layout: Calendar Left | Notes Middle | Todo+RSS Right */}
|
||||||
<div className="grid grid-cols-[300px,1fr,380px] gap-6">
|
<div className="grid grid-cols-[300px,1fr,760px] gap-6">
|
||||||
{/* Left Column: Calendar */}
|
{/* Left Column: Calendar */}
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<Card className="shadow-lg">
|
<Card className="shadow-lg">
|
||||||
@@ -1192,8 +1179,8 @@ const Index = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Column: Todos & RSS Boxes stacked */}
|
{/* Right Column: Todos & RSS Boxes side by side */}
|
||||||
<div className="space-y-6 h-fit sticky top-24">
|
<div className="grid grid-cols-2 gap-6">
|
||||||
{/* Todos Box */}
|
{/* Todos Box */}
|
||||||
<Card className="shadow-lg">
|
<Card className="shadow-lg">
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
@@ -1215,7 +1202,7 @@ const Index = () => {
|
|||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="active" className="mt-0">
|
<TabsContent value="active" className="mt-0">
|
||||||
<div className="space-y-1.5 max-h-[350px] overflow-y-auto">
|
<div className="space-y-1.5 max-h-[calc(100vh-300px)] overflow-y-auto">
|
||||||
{todos.filter(t => !t.completed).length > 0 ? (
|
{todos.filter(t => !t.completed).length > 0 ? (
|
||||||
todos.filter(t => !t.completed).map(todo => (
|
todos.filter(t => !t.completed).map(todo => (
|
||||||
<div key={todo.id} className="flex items-center gap-2 p-2 border rounded hover:bg-accent/50 transition-colors group">
|
<div key={todo.id} className="flex items-center gap-2 p-2 border rounded hover:bg-accent/50 transition-colors group">
|
||||||
@@ -1244,7 +1231,7 @@ const Index = () => {
|
|||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="completed" className="mt-0">
|
<TabsContent value="completed" className="mt-0">
|
||||||
<div className="space-y-1.5 max-h-[350px] overflow-y-auto">
|
<div className="space-y-1.5 max-h-[calc(100vh-300px)] overflow-y-auto">
|
||||||
{todos.filter(t => t.completed).length > 0 ? (
|
{todos.filter(t => t.completed).length > 0 ? (
|
||||||
todos.filter(t => t.completed).map(todo => (
|
todos.filter(t => t.completed).map(todo => (
|
||||||
<div key={todo.id} className="flex items-center gap-2 p-2 border rounded hover:bg-accent/50 transition-colors group">
|
<div key={todo.id} className="flex items-center gap-2 p-2 border rounded hover:bg-accent/50 transition-colors group">
|
||||||
@@ -1294,9 +1281,9 @@ const Index = () => {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2 max-h-[calc(100vh-300px)] overflow-y-auto">
|
||||||
{rssArticles.length > 0 ? (
|
{rssArticles.length > 0 ? (
|
||||||
rssArticles.slice(rssDisplayOffset, rssDisplayOffset + 3).map(article => (
|
rssArticles.map(article => (
|
||||||
<div
|
<div
|
||||||
key={article.id}
|
key={article.id}
|
||||||
className="p-2.5 border rounded hover:bg-accent/50 transition-colors cursor-pointer"
|
className="p-2.5 border rounded hover:bg-accent/50 transition-colors cursor-pointer"
|
||||||
@@ -1328,20 +1315,6 @@ const Index = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{rssArticles.length > 3 && (
|
|
||||||
<div className="flex justify-center pt-2">
|
|
||||||
<div className="flex gap-1">
|
|
||||||
{Array.from({ length: Math.ceil(rssArticles.length / 3) }).map((_, i) => (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className={`h-1.5 w-1.5 rounded-full transition-colors ${
|
|
||||||
i === Math.floor(rssDisplayOffset / 3) ? 'bg-primary' : 'bg-muted'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -1954,6 +1927,9 @@ const Index = () => {
|
|||||||
const formData = new FormData(e.currentTarget);
|
const formData = new FormData(e.currentTarget);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const reminderMinutes = formData.get('reminderMinutes') as string;
|
||||||
|
const recurrenceValue = formData.get('recurrence') as string;
|
||||||
|
|
||||||
const eventData = {
|
const eventData = {
|
||||||
title: formData.get('title') as string,
|
title: formData.get('title') as string,
|
||||||
description: formData.get('description') as string || undefined,
|
description: formData.get('description') as string || undefined,
|
||||||
@@ -1961,10 +1937,10 @@ const Index = () => {
|
|||||||
endDateTime: new Date(formData.get('endDateTime') as string).toISOString(),
|
endDateTime: new Date(formData.get('endDateTime') as string).toISOString(),
|
||||||
location: formData.get('location') as string || undefined,
|
location: formData.get('location') as string || undefined,
|
||||||
attendees: (formData.get('attendees') as string || '').split(',').map(e => e.trim()).filter(e => e),
|
attendees: (formData.get('attendees') as string || '').split(',').map(e => e.trim()).filter(e => e),
|
||||||
reminders: formData.get('reminderMinutes') ? [
|
reminders: reminderMinutes && reminderMinutes !== '0' ? [
|
||||||
{ method: 'popup', minutes: parseInt(formData.get('reminderMinutes') as string) }
|
{ method: 'popup', minutes: parseInt(reminderMinutes) }
|
||||||
] : undefined,
|
] : undefined,
|
||||||
recurrence: formData.get('recurrence') ? [formData.get('recurrence') as string] : undefined,
|
recurrence: recurrenceValue ? [recurrenceValue] : undefined,
|
||||||
visibility: formData.get('visibility') as string || 'default',
|
visibility: formData.get('visibility') as string || 'default',
|
||||||
colorId: formData.get('colorId') as string || undefined
|
colorId: formData.get('colorId') as string || undefined
|
||||||
};
|
};
|
||||||
@@ -1973,6 +1949,7 @@ const Index = () => {
|
|||||||
showSuccess('Événement créé avec succès');
|
showSuccess('Événement créé avec succès');
|
||||||
setAddEventModal(false);
|
setAddEventModal(false);
|
||||||
await loadCalendarEvents();
|
await loadCalendarEvents();
|
||||||
|
e.currentTarget.reset();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
showError(error.response?.data?.error || 'Erreur lors de la création de l\'événement');
|
showError(error.response?.data?.error || 'Erreur lors de la création de l\'événement');
|
||||||
}
|
}
|
||||||
@@ -2032,71 +2009,71 @@ const Index = () => {
|
|||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="reminderMinutes">Rappel (minutes avant)</Label>
|
<Label htmlFor="reminderMinutes">Rappel (minutes avant)</Label>
|
||||||
<Select name="reminderMinutes" defaultValue="30">
|
<select
|
||||||
<SelectTrigger>
|
id="reminderMinutes"
|
||||||
<SelectValue placeholder="Sélectionner un rappel" />
|
name="reminderMinutes"
|
||||||
</SelectTrigger>
|
className="w-full h-10 px-3 py-2 border border-input rounded-md bg-background"
|
||||||
<SelectContent>
|
defaultValue="30"
|
||||||
<SelectItem value="0">Aucun</SelectItem>
|
>
|
||||||
<SelectItem value="10">10 minutes</SelectItem>
|
<option value="0">Aucun</option>
|
||||||
<SelectItem value="30">30 minutes</SelectItem>
|
<option value="10">10 minutes</option>
|
||||||
<SelectItem value="60">1 heure</SelectItem>
|
<option value="30">30 minutes</option>
|
||||||
<SelectItem value="1440">1 jour</SelectItem>
|
<option value="60">1 heure</option>
|
||||||
</SelectContent>
|
<option value="1440">1 jour</option>
|
||||||
</Select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="recurrence">Récurrence</Label>
|
<Label htmlFor="recurrence">Récurrence</Label>
|
||||||
<Select name="recurrence" defaultValue="">
|
<select
|
||||||
<SelectTrigger>
|
id="recurrence"
|
||||||
<SelectValue placeholder="Pas de récurrence" />
|
name="recurrence"
|
||||||
</SelectTrigger>
|
className="w-full h-10 px-3 py-2 border border-input rounded-md bg-background"
|
||||||
<SelectContent>
|
defaultValue=""
|
||||||
<SelectItem value="">Pas de récurrence</SelectItem>
|
>
|
||||||
<SelectItem value="RRULE:FREQ=DAILY">Tous les jours</SelectItem>
|
<option value="">Pas de récurrence</option>
|
||||||
<SelectItem value="RRULE:FREQ=WEEKLY">Toutes les semaines</SelectItem>
|
<option value="RRULE:FREQ=DAILY">Tous les jours</option>
|
||||||
<SelectItem value="RRULE:FREQ=MONTHLY">Tous les mois</SelectItem>
|
<option value="RRULE:FREQ=WEEKLY">Toutes les semaines</option>
|
||||||
<SelectItem value="RRULE:FREQ=YEARLY">Tous les ans</SelectItem>
|
<option value="RRULE:FREQ=MONTHLY">Tous les mois</option>
|
||||||
</SelectContent>
|
<option value="RRULE:FREQ=YEARLY">Tous les ans</option>
|
||||||
</Select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="visibility">Visibilité</Label>
|
<Label htmlFor="visibility">Visibilité</Label>
|
||||||
<Select name="visibility" defaultValue="default">
|
<select
|
||||||
<SelectTrigger>
|
id="visibility"
|
||||||
<SelectValue placeholder="Sélectionner la visibilité" />
|
name="visibility"
|
||||||
</SelectTrigger>
|
className="w-full h-10 px-3 py-2 border border-input rounded-md bg-background"
|
||||||
<SelectContent>
|
defaultValue="default"
|
||||||
<SelectItem value="default">Par défaut</SelectItem>
|
>
|
||||||
<SelectItem value="public">Public</SelectItem>
|
<option value="default">Par défaut</option>
|
||||||
<SelectItem value="private">Privé</SelectItem>
|
<option value="public">Public</option>
|
||||||
</SelectContent>
|
<option value="private">Privé</option>
|
||||||
</Select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="colorId">Couleur</Label>
|
<Label htmlFor="colorId">Couleur</Label>
|
||||||
<Select name="colorId" defaultValue="">
|
<select
|
||||||
<SelectTrigger>
|
id="colorId"
|
||||||
<SelectValue placeholder="Couleur par défaut" />
|
name="colorId"
|
||||||
</SelectTrigger>
|
className="w-full h-10 px-3 py-2 border border-input rounded-md bg-background"
|
||||||
<SelectContent>
|
defaultValue=""
|
||||||
<SelectItem value="">Par défaut</SelectItem>
|
>
|
||||||
<SelectItem value="1">Lavande</SelectItem>
|
<option value="">Par défaut</option>
|
||||||
<SelectItem value="2">Sauge</SelectItem>
|
<option value="1">Lavande</option>
|
||||||
<SelectItem value="3">Raisin</SelectItem>
|
<option value="2">Sauge</option>
|
||||||
<SelectItem value="4">Flamant rose</SelectItem>
|
<option value="3">Raisin</option>
|
||||||
<SelectItem value="5">Banane</SelectItem>
|
<option value="4">Flamant rose</option>
|
||||||
<SelectItem value="6">Mandarine</SelectItem>
|
<option value="5">Banane</option>
|
||||||
<SelectItem value="7">Paon</SelectItem>
|
<option value="6">Mandarine</option>
|
||||||
<SelectItem value="8">Graphite</SelectItem>
|
<option value="7">Paon</option>
|
||||||
<SelectItem value="9">Myrtille</SelectItem>
|
<option value="8">Graphite</option>
|
||||||
<SelectItem value="10">Basilic</SelectItem>
|
<option value="9">Myrtille</option>
|
||||||
<SelectItem value="11">Tomate</SelectItem>
|
<option value="10">Basilic</option>
|
||||||
</SelectContent>
|
<option value="11">Tomate</option>
|
||||||
</Select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 pt-4">
|
<div className="flex justify-end gap-2 pt-4">
|
||||||
|
|||||||
Reference in new issue
Block a user