feat(simulations): bouton Suggestions d'idées + modal DeepSeek (G5)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
67eb3411c5
commit
dee3c181f6
3 changed files with 146 additions and 2 deletions
|
|
@ -11,18 +11,23 @@
|
|||
*/
|
||||
|
||||
import { useEffect, useRef, useState, type FormEvent } from 'react'
|
||||
import { Clock, Loader2, Shuffle } from 'lucide-react'
|
||||
import { Clock, Lightbulb, Loader2, Shuffle } from 'lucide-react'
|
||||
import { z } from 'zod'
|
||||
import { Button } from '@/shared/components/ui/button'
|
||||
import { formatTache } from '@/entities/production/lib'
|
||||
import { hasAccess, type Plan } from '@/entities/user/lib'
|
||||
import type { SujetData, Tache } from '@/entities/production/types'
|
||||
import type { ApiError } from '@/shared/types/api'
|
||||
import { countWords, getSimulationConfig } from '../lib/simulationConfig'
|
||||
import { useTimer } from '../hooks/useTimer'
|
||||
import { useIdees } from '../hooks/useIdees'
|
||||
import { SujetDisplay } from './SujetDisplay'
|
||||
import { SpecialCharsKeyboard } from './SpecialCharsKeyboard'
|
||||
import { TimerDisplay } from './TimerDisplay'
|
||||
import { WordCountBar } from './WordCountBar'
|
||||
import { IdeesSuggestions } from './IdeesSuggestions'
|
||||
|
||||
const MIN_WORDS_IDEES = 30
|
||||
|
||||
const textSchema = z.object({
|
||||
texte: z
|
||||
|
|
@ -49,6 +54,7 @@ function mapCorrectError(err: ApiError | null): string | null {
|
|||
interface Props {
|
||||
tache: Tache
|
||||
sujet: SujetData | null
|
||||
plan: Plan
|
||||
isSubmitting: boolean
|
||||
error: ApiError | null
|
||||
onSubmit: (texte: string) => void
|
||||
|
|
@ -59,6 +65,7 @@ interface Props {
|
|||
export function SimulationForm({
|
||||
tache,
|
||||
sujet,
|
||||
plan,
|
||||
isSubmitting,
|
||||
error,
|
||||
onSubmit,
|
||||
|
|
@ -69,12 +76,38 @@ export function SimulationForm({
|
|||
const hasAutoSubmittedRef = useRef(false)
|
||||
const [texte, setTexte] = useState('')
|
||||
const [fieldError, setFieldError] = useState<string | null>(null)
|
||||
const [isIdeesOpen, setIsIdeesOpen] = useState(false)
|
||||
|
||||
const config = getSimulationConfig(tache)
|
||||
const wordCount = countWords(texte)
|
||||
const canSubmit = wordCount >= config.motsMin
|
||||
|
||||
const timer = useTimer(config.dureeMinutes, !isSubmitting)
|
||||
const idees = useIdees()
|
||||
|
||||
const tipsAllowed = hasAccess(plan, 'tips')
|
||||
const ideesDisabled =
|
||||
isSubmitting ||
|
||||
idees.isLoading ||
|
||||
!sujet ||
|
||||
!tipsAllowed ||
|
||||
wordCount < MIN_WORDS_IDEES
|
||||
const ideesTitle = !tipsAllowed
|
||||
? 'Disponible en Standard'
|
||||
: wordCount < MIN_WORDS_IDEES
|
||||
? `Écrivez au moins ${MIN_WORDS_IDEES} mots`
|
||||
: undefined
|
||||
|
||||
function handleIdeesClick() {
|
||||
if (!sujet) return
|
||||
setIsIdeesOpen(true)
|
||||
idees.fetchIdees({ consigne: sujet.consigne, contenu: texte })
|
||||
}
|
||||
|
||||
function handleIdeesClose() {
|
||||
setIsIdeesOpen(false)
|
||||
idees.reset()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const el = textareaRef.current
|
||||
|
|
@ -149,7 +182,18 @@ export function SimulationForm({
|
|||
<SujetDisplay sujet={sujet} />
|
||||
|
||||
{sujet && (
|
||||
<div className="flex justify-end">
|
||||
<div className="flex flex-wrap justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
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"
|
||||
aria-label="Obtenir des suggestions d'idées"
|
||||
>
|
||||
<Lightbulb className="size-4" aria-hidden="true" />
|
||||
Suggestions d'idées
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onChangeSujet}
|
||||
|
|
@ -163,6 +207,14 @@ export function SimulationForm({
|
|||
</div>
|
||||
)}
|
||||
|
||||
<IdeesSuggestions
|
||||
idees={idees.idees}
|
||||
isLoading={idees.isLoading}
|
||||
error={idees.error}
|
||||
isOpen={isIdeesOpen}
|
||||
onClose={handleIdeesClose}
|
||||
/>
|
||||
|
||||
{apiError && (
|
||||
<div
|
||||
role="alert"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue