import React, { useEffect, useState } from "react" import { Controller, useFormContext } from "react-hook-form" import { AlertCircle, CheckCircle2 } from "lucide-react" import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { Checkbox } from "@/components/ui/checkbox" import { Input } from "@/components/ui/input" import { Separator } from "@/components/ui/separator" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { clampInt } from "@/lib/utils" import type { ResumeProjectCatalogItem } from "@shared/types" import { UpdateSettingsInput } from "@shared/settings-schema" import { BaseResumeSelection } from "./BaseResumeSelection" type ReactiveResumeSectionProps = { rxResumeBaseResumeIdDraft: string | null setRxResumeBaseResumeIdDraft: (value: string | null) => void // True when v4 credentials or v5 API key are configured. hasRxResumeAccess: boolean profileProjects: ResumeProjectCatalogItem[] lockedCount: number maxProjectsTotal: number isProjectsLoading: boolean isLoading: boolean isSaving: boolean } export const ReactiveResumeSection: React.FC = ({ rxResumeBaseResumeIdDraft, setRxResumeBaseResumeIdDraft, hasRxResumeAccess, profileProjects, lockedCount, maxProjectsTotal, isProjectsLoading, isLoading, isSaving, }) => { const { control, formState: { errors } } = useFormContext() return ( Reactive Resume
{!hasRxResumeAccess ? ( RxResume Access Missing Configure RxResume credentials in settings (email + password) or set RXRESUME_API_KEY to enable access. ) : ( <> RxResume Access Ready Reactive Resume access is active.
{!rxResumeBaseResumeIdDraft ? (
Choose a PDF to configure resume projects.
) : ( <>
Max projects to choose
( { if (!field.value) return const next = Number(event.target.value) const clamped = clampInt(next, lockedCount, maxProjectsTotal) field.onChange({ ...field.value, maxProjects: clamped }) }} disabled={isLoading || isSaving || isProjectsLoading || !field.value} /> )} /> {errors.resumeProjects?.maxProjects && (

{errors.resumeProjects.maxProjects.message}

)}
( Project Visible in template Must Include AI selectable {profileProjects.map((project) => { const locked = Boolean(field.value?.lockedProjectIds.includes(project.id)) const aiSelectable = Boolean(field.value?.aiSelectableProjectIds.includes(project.id)) return (
{project.name || project.id}
{[project.description, project.date].filter(Boolean).join(" - ")}
{project.isVisibleInBase ? "Yes" : "No"} { if (!field.value) return const isChecked = checked === true const lockedIds = field.value.lockedProjectIds.slice() const selectableIds = field.value.aiSelectableProjectIds.slice() if (isChecked) { if (!lockedIds.includes(project.id)) lockedIds.push(project.id) const nextSelectable = selectableIds.filter((id) => id !== project.id) const minCap = lockedIds.length field.onChange({ ...field.value, lockedProjectIds: lockedIds, aiSelectableProjectIds: nextSelectable, maxProjects: Math.max(field.value.maxProjects, minCap), }) return } const nextLocked = lockedIds.filter((id) => id !== project.id) if (!selectableIds.includes(project.id)) selectableIds.push(project.id) field.onChange({ ...field.value, lockedProjectIds: nextLocked, aiSelectableProjectIds: selectableIds, maxProjects: clampInt(field.value.maxProjects, nextLocked.length, maxProjectsTotal), }) }} /> { if (!field.value) return const isChecked = checked === true const selectableIds = field.value.aiSelectableProjectIds.slice() const nextSelectable = isChecked ? selectableIds.includes(project.id) ? selectableIds : [...selectableIds, project.id] : selectableIds.filter((id) => id !== project.id) field.onChange({ ...field.value, aiSelectableProjectIds: nextSelectable }) }} />
) })}
)} /> )}
)}
) }