feat: actualizar CDC Brief con fecha limite de entrega
This commit is contained in:
+12
-1
@@ -75,7 +75,9 @@ export default function App() {
|
||||
const handleSendMessage = async (
|
||||
text: string,
|
||||
attachments: Attachment[],
|
||||
audio?: AudioRecording
|
||||
audio?: AudioRecording,
|
||||
deliveryDate?: string,
|
||||
deliveryDateStatus: 'defined' | 'pending' = 'defined'
|
||||
) => {
|
||||
const userMessageId = Math.random().toString(36).substring(7);
|
||||
|
||||
@@ -109,6 +111,15 @@ export default function App() {
|
||||
formData.append('submittedByEmail', submittedByEmail);
|
||||
formData.append('submittedByUid', user?.uid || '');
|
||||
formData.append('submittedByPhotoUrl', user?.photoURL || '');
|
||||
const deliveryDateValue = deliveryDateStatus === 'pending' ? '' : deliveryDate || '';
|
||||
const deliveryDateLabel = deliveryDateStatus === 'pending' ? 'Por confirmar' : deliveryDateValue;
|
||||
|
||||
formData.append('deliveryDate', deliveryDateValue);
|
||||
formData.append('fechaEntrega', deliveryDateValue);
|
||||
formData.append('deliveryDateStatus', deliveryDateStatus);
|
||||
formData.append('fechaEntregaEstado', deliveryDateStatus === 'pending' ? 'por_confirmar' : 'definida');
|
||||
formData.append('deliveryDateLabel', deliveryDateLabel);
|
||||
formData.append('fechaEntregaTexto', deliveryDateLabel);
|
||||
|
||||
let generalFileIndex = 0;
|
||||
let campaignFileIndex = 0;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Attachment, AttachmentCategory, AttachmentType, AudioRecording } from '
|
||||
import { cn } from '../lib/utils';
|
||||
|
||||
interface InputAreaProps {
|
||||
onSendMessage: (text: string, attachments: Attachment[], audio?: AudioRecording) => void;
|
||||
onSendMessage: (text: string, attachments: Attachment[], audio?: AudioRecording, deliveryDate?: string, deliveryDateStatus?: 'defined' | 'pending') => void;
|
||||
isProcessing: boolean;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,20 @@ const formatDuration = (seconds: number) => {
|
||||
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
const formatDeliveryDate = (dateString: string) => {
|
||||
if (!dateString) return 'Pendiente';
|
||||
|
||||
const [year, month, day] = dateString.split('-').map(Number);
|
||||
if (!year || !month || !day) return dateString;
|
||||
|
||||
const date = new Date(year, month - 1, day);
|
||||
return date.toLocaleDateString('es-DO', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
};
|
||||
|
||||
export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessing }) => {
|
||||
const [text, setText] = useState('');
|
||||
const [attachments, setAttachments] = useState<Attachment[]>([]);
|
||||
@@ -97,6 +111,8 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
const [currentStep, setCurrentStep] = useState<GuidedStep>('audio');
|
||||
const [hasCampaignAssets, setHasCampaignAssets] = useState<CampaignAnswer>(null);
|
||||
const [validationMessage, setValidationMessage] = useState<string | null>(null);
|
||||
const [deliveryDate, setDeliveryDate] = useState('');
|
||||
const [deliveryDatePending, setDeliveryDatePending] = useState(false);
|
||||
const [audioPreviewPlaying, setAudioPreviewPlaying] = useState(false);
|
||||
const [audioPreviewCurrentTime, setAudioPreviewCurrentTime] = useState(0);
|
||||
|
||||
@@ -132,7 +148,9 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
|
||||
const requiredCompleted = Boolean(audioRecording) && imageAttachments.length > 0;
|
||||
const campaignStepCompleted = hasCampaignAssets !== 'yes' || campaignAttachments.length > 0;
|
||||
const canSend = requiredCompleted && campaignStepCompleted;
|
||||
const hasDeliveryInfo = Boolean(deliveryDate) || deliveryDatePending;
|
||||
const deliveryDateLabel = deliveryDatePending ? 'Por confirmar' : formatDeliveryDate(deliveryDate);
|
||||
const canSend = requiredCompleted && campaignStepCompleted && hasDeliveryInfo;
|
||||
const progressValue = ((STEP_DEFINITIONS.findIndex((step) => step.id === currentStep) + 1) / STEP_DEFINITIONS.length) * 100;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -396,7 +414,8 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
`Nota de voz: ${audioRecording ? 'sí' : 'no'}`,
|
||||
`Imágenes de referencia: ${imageAttachments.length}`,
|
||||
`Documentos relacionados: ${documentAttachments.length}`,
|
||||
`Campaña o elementos gráficos existentes: ${hasCampaignAssets === 'yes' ? 'sí' : hasCampaignAssets === 'no' ? 'no' : 'no indicado'}`,
|
||||
`Fecha límite de entrega: ${deliveryDateLabel}`,
|
||||
`Campaña o elementos gráficos existentes: ${hasCampaignAssets === 'yes' ? 'sí' : hasCampaignAssets === 'no' ? 'no' : 'No indicado'}`,
|
||||
`Archivos de campaña / elementos gráficos: ${campaignAttachments.length}`,
|
||||
];
|
||||
|
||||
@@ -424,8 +443,19 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasDeliveryInfo) {
|
||||
setValidationMessage('Selecciona la fecha límite de entrega o marca la opción Por confirmar antes de enviar.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isProcessing) {
|
||||
onSendMessage(buildSubmissionText(), attachments, audioRecording || undefined);
|
||||
onSendMessage(
|
||||
buildSubmissionText(),
|
||||
attachments,
|
||||
audioRecording || undefined,
|
||||
deliveryDatePending ? '' : deliveryDate,
|
||||
deliveryDatePending ? 'pending' : 'defined'
|
||||
);
|
||||
setText('');
|
||||
setAttachments([]);
|
||||
if (audioPreviewRef.current) {
|
||||
@@ -438,6 +468,8 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
recordingDurationRef.current = 0;
|
||||
setRecordingDuration(0);
|
||||
setHasCampaignAssets(null);
|
||||
setDeliveryDate('');
|
||||
setDeliveryDatePending(false);
|
||||
setCurrentStep('audio');
|
||||
setValidationMessage(null);
|
||||
}
|
||||
@@ -789,19 +821,64 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
<p className="mb-5 text-sm leading-7 text-zinc-300">
|
||||
Revisa el resumen antes de enviar. Este es el único paso donde se puede finalizar la solicitud.
|
||||
</p>
|
||||
|
||||
<div className="mb-4 rounded-2xl border border-indigo-400/20 bg-indigo-500/10 p-4">
|
||||
<label htmlFor="delivery-date" className="flex flex-col gap-2">
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.22em] text-indigo-200">
|
||||
Fecha límite de entrega
|
||||
</span>
|
||||
<span className="text-sm leading-6 text-zinc-300">
|
||||
Indica para cuándo debe entregarse esta solicitud. Este dato se enviará al flujo, al correo y al brief generado.
|
||||
</span>
|
||||
<input
|
||||
id="delivery-date"
|
||||
type="date"
|
||||
value={deliveryDate}
|
||||
onChange={(event) => {
|
||||
setDeliveryDate(event.target.value);
|
||||
if (event.target.value) {
|
||||
setDeliveryDatePending(false);
|
||||
setValidationMessage(null);
|
||||
}
|
||||
}}
|
||||
disabled={isProcessing || deliveryDatePending}
|
||||
className="mt-2 w-full rounded-2xl border border-white/10 bg-black/25 px-4 py-3 text-sm font-semibold text-white outline-none transition focus:border-indigo-300/60 disabled:opacity-60 sm:max-w-xs"
|
||||
/>
|
||||
|
||||
<label className="mt-3 flex w-fit cursor-pointer items-center gap-3 rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-zinc-200 transition hover:border-white/20 hover:bg-black/30">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={deliveryDatePending}
|
||||
onChange={(event) => {
|
||||
const checked = event.target.checked;
|
||||
setDeliveryDatePending(checked);
|
||||
if (checked) {
|
||||
setDeliveryDate('');
|
||||
setValidationMessage(null);
|
||||
}
|
||||
}}
|
||||
disabled={isProcessing}
|
||||
className="h-4 w-4 rounded border-white/20 bg-black/40 text-indigo-500 focus:ring-indigo-400"
|
||||
/>
|
||||
<span>Por confirmar</span>
|
||||
</label>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className="rounded-2xl border border-white/10 bg-black/20 p-4">
|
||||
<p className="text-xs uppercase tracking-[0.22em] text-zinc-500">Obligatorios</p>
|
||||
<div className="mt-3 space-y-2 text-sm text-zinc-300">
|
||||
<p>Nota de voz: <span className={audioRecording ? 'text-emerald-300' : 'text-amber-300'}>{audioRecording ? 'lista' : 'pendiente'}</span></p>
|
||||
<p>Nota de voz: <span className={audioRecording ? 'text-emerald-300' : 'text-amber-300'}>{audioRecording ? 'Lista' : 'Pendiente'}</span></p>
|
||||
<p>Imágenes: <span className={imageAttachments.length ? 'text-emerald-300' : 'text-amber-300'}>{imageAttachments.length}</span></p>
|
||||
<p>Fecha de entrega: <span className={hasDeliveryInfo ? 'text-emerald-300' : 'text-amber-300'}>{hasDeliveryInfo ? deliveryDateLabel : 'Pendiente'}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-white/10 bg-black/20 p-4">
|
||||
<p className="text-xs uppercase tracking-[0.22em] text-zinc-500">Soporte</p>
|
||||
<div className="mt-3 space-y-2 text-sm text-zinc-300">
|
||||
<p>Documentos: <span className="text-white">{documentAttachments.length}</span></p>
|
||||
<p>Campaña / gráficos: <span className="text-white">{hasCampaignAssets === 'yes' ? `${campaignAttachments.length} archivo(s)` : hasCampaignAssets === 'no' ? 'no aplica' : 'no indicado'}</span></p>
|
||||
<p>Campaña / gráficos: <span className="text-white">{hasCampaignAssets === 'yes' ? `${campaignAttachments.length} archivo(s)` : hasCampaignAssets === 'no' ? 'no aplica' : 'No indicado'}</span></p>
|
||||
<p>Enlaces: <span className="text-white">{linksCount}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -829,7 +906,7 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
<div className="text-sm text-zinc-400">
|
||||
{canSend
|
||||
? 'Todo está listo. El envío solo se realiza desde el paso final.'
|
||||
: 'Completa primero la nota de voz y las imágenes. Si marcaste campaña, adjunta sus archivos.'}
|
||||
: 'Completa la nota de voz, las imágenes y la fecha límite de entrega o marca Por confirmar. Si marcaste campaña, adjunta sus archivos.'}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
@@ -875,6 +952,12 @@ export const InputArea: React.FC<InputAreaProps> = ({ onSendMessage, isProcessin
|
||||
{imageAttachments.length > 0 ? `${imageAttachments.length} cargada(s)` : 'Pendiente'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3 text-sm">
|
||||
<span className="text-zinc-300">Fecha de entrega</span>
|
||||
<span className={cn('text-right font-semibold', hasDeliveryInfo ? 'text-emerald-300' : 'text-zinc-500')}>
|
||||
{hasDeliveryInfo ? deliveryDateLabel : 'Pendiente'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user