refactor(simulation-ee): Sprint 3.5 clean — FTD-17/18/19 résolus, factorisation SimulationForm
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
385b29679e
commit
18f92098cb
11 changed files with 36 additions and 66 deletions
|
|
@ -12,8 +12,9 @@
|
|||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { getPlanStatus } from '@/entities/user/api'
|
||||
import { PLAN_QUERY_KEY } from '@/entities/user/query-keys'
|
||||
|
||||
export const PLAN_QUERY_KEY = ['plan'] as const
|
||||
export { PLAN_QUERY_KEY }
|
||||
|
||||
export function usePlan() {
|
||||
return useQuery({
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
import { useEffect, useRef, useState, type FormEvent } from 'react'
|
||||
import { Clock, Lightbulb, Loader2, Shuffle } from 'lucide-react'
|
||||
import { z } from 'zod'
|
||||
import { Button } from '@/shared/components/ui/button'
|
||||
import { Button } from '@/shared/ui/Button'
|
||||
import { formatTache } from '@/entities/production/lib'
|
||||
import { hasAccess, type Plan } from '@/entities/user/lib'
|
||||
import type { SujetData, Tache } from '@/entities/production/types'
|
||||
|
|
@ -32,6 +32,9 @@ import { IdeesSuggestions } from './IdeesSuggestions'
|
|||
const MIN_WORDS_IDEES = 30
|
||||
const LS_SIMULATION_ID_KEY = 'expria_simulation_id'
|
||||
|
||||
const secondaryActionBtn =
|
||||
'inline-flex items-center gap-1.5 rounded-md border border-line bg-surface px-3 py-1.5 text-sm text-ink-2 transition-colors hover:border-expria hover:text-expria focus:border-expria focus:outline-none focus:shadow-focus disabled:cursor-not-allowed disabled:opacity-50'
|
||||
|
||||
const textSchema = z.object({
|
||||
texte: z
|
||||
.string()
|
||||
|
|
@ -212,7 +215,7 @@ export function SimulationForm({
|
|||
onClick={handleIdeesClick}
|
||||
disabled={ideesDisabled}
|
||||
title={ideesTitle}
|
||||
className="inline-flex items-center gap-1.5 rounded-md border border-line bg-surface px-3 py-1.5 text-sm text-ink-2 transition-colors hover:border-expria hover:text-expria focus:border-expria focus:outline-none focus:ring-2 focus:ring-expria/20 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className={secondaryActionBtn}
|
||||
aria-label="Obtenir des suggestions d'idées"
|
||||
>
|
||||
<Lightbulb className="size-4" aria-hidden="true" />
|
||||
|
|
@ -222,7 +225,7 @@ export function SimulationForm({
|
|||
type="button"
|
||||
onClick={onChangeSujet}
|
||||
disabled={isSubmitting}
|
||||
className="inline-flex items-center gap-1.5 rounded-md border border-line bg-surface px-3 py-1.5 text-sm text-ink-2 transition-colors hover:border-expria hover:text-expria focus:border-expria focus:outline-none focus:ring-2 focus:ring-expria/20 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className={secondaryActionBtn}
|
||||
aria-label="Changer de sujet"
|
||||
>
|
||||
<Shuffle className="size-4" aria-hidden="true" />
|
||||
|
|
@ -302,7 +305,7 @@ export function SimulationForm({
|
|||
placeholder="Rédigez votre texte ici…"
|
||||
aria-invalid={!!fieldError}
|
||||
aria-describedby={fieldError ? 'texte-error' : undefined}
|
||||
className="w-full resize-none overflow-y-hidden rounded-md border border-line bg-surface p-3 text-sm text-ink-1 placeholder:text-ink-5 focus:border-expria focus:outline-none focus:ring-2 focus:ring-expria/20 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="w-full resize-none overflow-y-hidden rounded-md border border-line bg-surface p-3 text-sm text-ink-1 placeholder:text-ink-5 focus:border-expria focus:outline-none focus:shadow-focus disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
<WordCountBar count={wordCount} config={config} />
|
||||
{autosave.savedAt && !fieldError && (
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export function SpecialCharsKeyboard({ onInsert, disabled = false }: Props) {
|
|||
onMouseDown={(e) => e.preventDefault()}
|
||||
onClick={() => onInsert(char)}
|
||||
aria-label={`Insérer le caractère ${char}`}
|
||||
className="size-8 shrink-0 rounded-md border border-line bg-surface text-sm font-medium text-ink-1 transition-colors hover:border-expria hover:bg-expria-50 hover:text-expria focus:border-expria focus:outline-none focus:ring-2 focus:ring-expria/20 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="size-8 shrink-0 rounded-md border border-line bg-surface text-sm font-medium text-ink-1 transition-colors hover:border-expria hover:bg-expria-50 hover:text-expria focus:border-expria focus:outline-none focus:shadow-focus disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{char}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
* staleTime Infinity : un rapport ne change jamais après correction.
|
||||
*
|
||||
* Règle H : aucune logique métier — expose les données brutes.
|
||||
* FTD-17 : queryKey ['plan'] déjà utilisé dans SimulationPage — ['rapport', id] est distinct.
|
||||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
import { useEffect } from 'react'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Lock } from 'lucide-react'
|
||||
import { getPlanStatus } from '@/entities/user/api'
|
||||
import { usePlan } from '@/features/dashboard/hooks/usePlan'
|
||||
import { isSectionVisible } from '@/entities/report/lib'
|
||||
import { useRapport } from '../hooks/useRapport'
|
||||
import { Card } from '@/shared/ui/Card'
|
||||
|
|
@ -130,11 +129,7 @@ export function RapportPage() {
|
|||
data: planData,
|
||||
isLoading: isPlanLoading,
|
||||
isError: isPlanError,
|
||||
} = useQuery({
|
||||
queryKey: ['plan'],
|
||||
queryFn: getPlanStatus,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
})
|
||||
} = usePlan()
|
||||
|
||||
const onUpgrade = () => navigate('/plan')
|
||||
|
||||
|
|
|
|||
|
|
@ -6,15 +6,11 @@
|
|||
*
|
||||
* Règle D : quotas et permissions passent par canSimulate() — jamais de plan === '...'
|
||||
* Règle H : aucune logique métier — tout est dans useSimulation() et les entités.
|
||||
*
|
||||
* Nota : queryKey ['plan'] est dupliqué depuis features/dashboard/hooks/usePlan.
|
||||
* TanStack Query partage le cache par clé — FTD-17.
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { getPlanStatus } from '@/entities/user/api'
|
||||
import { usePlan } from '@/features/dashboard/hooks/usePlan'
|
||||
import { Button } from '@/shared/ui/Button'
|
||||
import { useSimulation } from '../hooks/useSimulation'
|
||||
import { TaskSelector } from '../components/TaskSelector'
|
||||
|
|
@ -41,11 +37,7 @@ export function SimulationPage() {
|
|||
isLoading: isPlanLoading,
|
||||
isError: isPlanError,
|
||||
refetch: refetchPlan,
|
||||
} = useQuery({
|
||||
queryKey: ['plan'],
|
||||
queryFn: getPlanStatus,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
})
|
||||
} = usePlan()
|
||||
|
||||
const {
|
||||
step,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue