feat: enhance dropdown components by integrating useClickOutside hook for improved user experience and accessibility in NewWorkshopDropdown and WorkshopTabs

This commit is contained in:
Julien Froidefond
2026-02-18 08:25:08 +01:00
parent d50a8a0266
commit ee13f8ba99
9 changed files with 189 additions and 197 deletions

View File

@@ -4,6 +4,7 @@ import { useState, useTransition, useEffect } from 'react';
import { createOrUpdateWeatherEntry } from '@/actions/weather';
import { Avatar } from '@/components/ui/Avatar';
import { Textarea } from '@/components/ui/Textarea';
import { Select } from '@/components/ui/Select';
const WEATHER_EMOJIS = [
{ emoji: '', label: 'Aucun' },
@@ -140,29 +141,14 @@ export function WeatherCard({ sessionId, currentUserId, entry, canEdit }: Weathe
{/* Performance */}
<td className="w-24 px-2 py-3">
{canEditThis ? (
<div className="relative mx-auto w-fit">
<select
value={performanceEmoji || ''}
onChange={(e) => handleEmojiChange('performance', e.target.value || null)}
className="w-16 appearance-none rounded-lg border border-border bg-card px-2 py-2.5 pr-8 text-center text-lg text-foreground transition-colors hover:bg-card-hover focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
>
{WEATHER_EMOJIS.map(({ emoji }) => (
<option key={emoji || 'none'} value={emoji}>
{emoji}
</option>
))}
</select>
<div className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2">
<svg
className="h-3 w-3 text-muted"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<Select
value={performanceEmoji || ''}
onChange={(e) => handleEmojiChange('performance', e.target.value || null)}
options={WEATHER_EMOJIS.map(({ emoji }) => ({ value: emoji, label: emoji }))}
size="sm"
wrapperClassName="!w-fit mx-auto"
className="!w-16 min-w-16 text-center text-lg py-2.5"
/>
) : (
<div className="text-2xl text-center">{performanceEmoji || '-'}</div>
)}
@@ -171,29 +157,14 @@ export function WeatherCard({ sessionId, currentUserId, entry, canEdit }: Weathe
{/* Moral */}
<td className="w-24 px-2 py-3">
{canEditThis ? (
<div className="relative mx-auto w-fit">
<select
value={moralEmoji || ''}
onChange={(e) => handleEmojiChange('moral', e.target.value || null)}
className="w-16 appearance-none rounded-lg border border-border bg-card px-2 py-2.5 pr-8 text-center text-lg text-foreground transition-colors hover:bg-card-hover focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
>
{WEATHER_EMOJIS.map(({ emoji }) => (
<option key={emoji || 'none'} value={emoji}>
{emoji}
</option>
))}
</select>
<div className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2">
<svg
className="h-3 w-3 text-muted"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<Select
value={moralEmoji || ''}
onChange={(e) => handleEmojiChange('moral', e.target.value || null)}
options={WEATHER_EMOJIS.map(({ emoji }) => ({ value: emoji, label: emoji }))}
size="sm"
wrapperClassName="!w-fit mx-auto"
className="!w-16 min-w-16 text-center text-lg py-2.5"
/>
) : (
<div className="text-2xl text-center">{moralEmoji || '-'}</div>
)}
@@ -202,29 +173,14 @@ export function WeatherCard({ sessionId, currentUserId, entry, canEdit }: Weathe
{/* Flux */}
<td className="w-24 px-2 py-3">
{canEditThis ? (
<div className="relative mx-auto w-fit">
<select
value={fluxEmoji || ''}
onChange={(e) => handleEmojiChange('flux', e.target.value || null)}
className="w-16 appearance-none rounded-lg border border-border bg-card px-2 py-2.5 pr-8 text-center text-lg text-foreground transition-colors hover:bg-card-hover focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
>
{WEATHER_EMOJIS.map(({ emoji }) => (
<option key={emoji || 'none'} value={emoji}>
{emoji}
</option>
))}
</select>
<div className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2">
<svg
className="h-3 w-3 text-muted"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<Select
value={fluxEmoji || ''}
onChange={(e) => handleEmojiChange('flux', e.target.value || null)}
options={WEATHER_EMOJIS.map(({ emoji }) => ({ value: emoji, label: emoji }))}
size="sm"
wrapperClassName="!w-fit mx-auto"
className="!w-16 min-w-16 text-center text-lg py-2.5"
/>
) : (
<div className="text-2xl text-center">{fluxEmoji || '-'}</div>
)}
@@ -233,29 +189,14 @@ export function WeatherCard({ sessionId, currentUserId, entry, canEdit }: Weathe
{/* Création de valeur */}
<td className="w-24 px-2 py-3">
{canEditThis ? (
<div className="relative mx-auto w-fit">
<select
value={valueCreationEmoji || ''}
onChange={(e) => handleEmojiChange('valueCreation', e.target.value || null)}
className="w-16 appearance-none rounded-lg border border-border bg-card px-2 py-2.5 pr-8 text-center text-lg text-foreground transition-colors hover:bg-card-hover focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
>
{WEATHER_EMOJIS.map(({ emoji }) => (
<option key={emoji || 'none'} value={emoji}>
{emoji}
</option>
))}
</select>
<div className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2">
<svg
className="h-3 w-3 text-muted"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<Select
value={valueCreationEmoji || ''}
onChange={(e) => handleEmojiChange('valueCreation', e.target.value || null)}
options={WEATHER_EMOJIS.map(({ emoji }) => ({ value: emoji, label: emoji }))}
size="sm"
wrapperClassName="!w-fit mx-auto"
className="!w-16 min-w-16 text-center text-lg py-2.5"
/>
) : (
<div className="text-2xl text-center">{valueCreationEmoji || '-'}</div>
)}