Files
Makers3D/apps/web/app/components/InquiryWizardClient.tsx

256 lines
9.3 KiB
TypeScript

"use client";
import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { browserFetch } from "../lib/api";
type Props = {
makerId: string;
sourceType: "profile" | "service" | "work";
sourceId?: string;
makerName: string;
contextTitle: string;
returnTo: string;
};
type Draft = {
needText: string;
sizeText: string;
usageText: string;
materialPreference: string;
quantity: number;
urgency: string;
deliveryType: string;
hasModel: boolean;
referenceNotes: string;
};
const initialDraft: Draft = {
needText: "",
sizeText: "",
usageText: "",
materialPreference: "",
quantity: 1,
urgency: "medium",
deliveryType: "shipping",
hasModel: false,
referenceNotes: ""
};
export default function InquiryWizardClient({ makerId, sourceType, sourceId, makerName, contextTitle, returnTo }: Props) {
const router = useRouter();
const [step, setStep] = useState(1);
const [status, setStatus] = useState("");
const [me, setMe] = useState<{ id: string } | null>(null);
const [draft, setDraft] = useState<Draft>(initialDraft);
const storageKey = useMemo(
() => `makers3d_inquiry_draft:${makerId}:${sourceType}:${sourceId || "root"}`,
[makerId, sourceId, sourceType]
);
useEffect(() => {
const saved = window.sessionStorage.getItem(storageKey);
if (saved) {
try {
setDraft({ ...initialDraft, ...JSON.parse(saved) as Draft });
} catch {
window.sessionStorage.removeItem(storageKey);
}
}
void browserFetch<{ user: { id: string } | null }>("/auth/me")
.then((result) => setMe(result.user))
.catch(() => setMe(null));
}, [storageKey]);
useEffect(() => {
window.sessionStorage.setItem(storageKey, JSON.stringify(draft));
}, [draft, storageKey]);
function nextStep() {
setStep((current) => Math.min(5, current + 1));
}
function previousStep() {
setStep((current) => Math.max(1, current - 1));
}
async function submitInquiry() {
if (!me) {
const nextUrl = `/consultas/nueva?makerId=${encodeURIComponent(makerId)}&sourceType=${encodeURIComponent(sourceType)}&sourceId=${encodeURIComponent(sourceId || "")}&makerName=${encodeURIComponent(makerName)}&contextTitle=${encodeURIComponent(contextTitle)}`;
window.location.href = `/register?returnTo=${encodeURIComponent(nextUrl)}`;
return;
}
setStatus("Enviando consulta...");
try {
await browserFetch("/inquiries", {
method: "POST",
body: JSON.stringify({
makerId,
sourceType,
sourceId,
needText: `${draft.needText}\n\nUso final: ${draft.usageText}\nReferencia: ${draft.referenceNotes}`.trim(),
sizeText: draft.sizeText,
hasModel: draft.hasModel,
materialPreference: draft.materialPreference,
quantity: draft.quantity,
urgency: draft.urgency,
deliveryType: draft.deliveryType
})
});
window.sessionStorage.removeItem(storageKey);
setStatus("Consulta enviada.");
router.push("/account/inbox");
router.refresh();
} catch (error) {
setStatus(error instanceof Error ? error.message : "No se pudo enviar la consulta");
}
}
return (
<div className="wizard-shell">
<div className="panel wizard-context stack">
<span className="eyebrow">Consulta guiada</span>
<h1 className="section-title">Paso {step} de 5</h1>
<div className="list-item stack">
<strong>{contextTitle}</strong>
<span className="mini-note">Maker: {makerName}</span>
<span className="mini-note">Si vuelves tras registrarte, el borrador se conserva.</span>
</div>
<div className="wizard-progress">
{[1, 2, 3, 4, 5].map((value) => (
<span key={value} className={`wizard-dot ${value <= step ? "active" : ""}`} />
))}
</div>
</div>
<div className="panel stack">
{step === 1 && (
<>
<span className="eyebrow">Necesidad</span>
<h2 className="section-title">Que necesitas resolver?</h2>
<textarea
className="textarea"
placeholder="Quiero algo igual, modificar una pieza o fabricar algo parecido..."
value={draft.needText}
onChange={(event) => setDraft((current) => ({ ...current, needText: event.target.value }))}
/>
</>
)}
{step === 2 && (
<>
<span className="eyebrow">Detalles del trabajo</span>
<h2 className="section-title">Dimension, material y referencia</h2>
<div className="input-grid-compact">
<input
className="field"
placeholder="Tamano o medidas"
value={draft.sizeText}
onChange={(event) => setDraft((current) => ({ ...current, sizeText: event.target.value }))}
/>
<input
className="field"
placeholder="Material preferido"
value={draft.materialPreference}
onChange={(event) => setDraft((current) => ({ ...current, materialPreference: event.target.value }))}
/>
</div>
<label className="choice-chip">
<input
type="checkbox"
checked={draft.hasModel}
onChange={(event) => setDraft((current) => ({ ...current, hasModel: event.target.checked }))}
/>
<span>Ya tengo archivo o una pieza de referencia</span>
</label>
<textarea
className="textarea"
placeholder="Describe el archivo, la pieza o lo que puedes adjuntar despues en la conversacion."
value={draft.referenceNotes}
onChange={(event) => setDraft((current) => ({ ...current, referenceNotes: event.target.value }))}
/>
</>
)}
{step === 3 && (
<>
<span className="eyebrow">Uso final</span>
<h2 className="section-title">Para que se utilizara?</h2>
<textarea
className="textarea"
placeholder="Pieza funcional, exterior, calor, agua, decoracion, prototipo..."
value={draft.usageText}
onChange={(event) => setDraft((current) => ({ ...current, usageText: event.target.value }))}
/>
</>
)}
{step === 4 && (
<>
<span className="eyebrow">Urgencia y entrega</span>
<h2 className="section-title">Cantidad, plazo y modalidad</h2>
<div className="input-grid-compact">
<input
className="field"
type="number"
min={1}
value={draft.quantity}
onChange={(event) => setDraft((current) => ({ ...current, quantity: Number(event.target.value) }))}
/>
<select
className="select"
value={draft.urgency}
onChange={(event) => setDraft((current) => ({ ...current, urgency: event.target.value }))}
>
<option value="low">Sin urgencia</option>
<option value="medium">Esta semana</option>
<option value="high">Urgente</option>
</select>
<select
className="select"
value={draft.deliveryType}
onChange={(event) => setDraft((current) => ({ ...current, deliveryType: event.target.value }))}
>
<option value="shipping">Necesito envio</option>
<option value="local">Puedo retirar</option>
</select>
</div>
</>
)}
{step === 5 && (
<>
<span className="eyebrow">Resumen</span>
<h2 className="section-title">Revisa antes de enviar</h2>
<div className="checklist-list">
<div className="checklist-item"><strong>Necesidad</strong><span>{draft.needText || "Pendiente"}</span></div>
<div className="checklist-item"><strong>Detalles</strong><span>{draft.sizeText || "Sin medidas"} / {draft.materialPreference || "Sin material"}</span></div>
<div className="checklist-item"><strong>Uso final</strong><span>{draft.usageText || "No indicado"}</span></div>
<div className="checklist-item"><strong>Entrega</strong><span>{draft.quantity} unidad / {draft.deliveryType}</span></div>
</div>
{!me ? (
<p className="muted">Para enviar la consulta necesitas crear cuenta o entrar. El borrador no se pierde.</p>
) : null}
</>
)}
<div className="wizard-actions">
<a href={returnTo} className="button button-ghost">Volver</a>
<div className="wizard-actions-right">
{step > 1 ? <button className="button button-secondary" type="button" onClick={previousStep}>Anterior</button> : null}
{step < 5 ? (
<button className="button button-primary" type="button" onClick={nextStep}>Continuar</button>
) : (
<button className="button button-primary" type="button" onClick={submitInquiry}>Enviar consulta</button>
)}
</div>
</div>
{status ? <p className="muted">{status}</p> : null}
</div>
</div>
);
}