// components/Step2Actions.tsx // Action bar for the Step 2 page — Back to Step 1, Apply (BizPortal), Cancel. "use client"; import { useState } from "react"; import Link from "next/link"; interface Props { registrationId: string; status: string; proposedNames: string[]; } export default function Step2Actions({ registrationId, status, proposedNames }: Props) { const [busy, setBusy] = useState(null); const [msg, setMsg] = useState(""); const [msgKind, setMsgKind] = useState<"info" | "success" | "error" | "warn">("info"); const [showConfirm, setShowConfirm] = useState(false); const [showNameOnlyConfirm, setShowNameOnlyConfirm] = useState(false); const [bizportalResult, setBizportalResult] = useState(null); const [checkMailResult, setCheckMailResult] = useState(null); const [showRevertConfirm, setShowRevertConfirm] = useState(false); async function runAction(action: string, confirmText?: string) { if (confirmText && !confirm(confirmText)) return; setBusy(action); setMsg(""); setMsgKind("info"); try { const res = await fetch(`/api/register/${registrationId}/status?action=${action}`, { method: "POST" }); const data = await res.json(); if (!res.ok) { setMsgKind("error"); setMsg(`❌ ${data.error || `HTTP ${res.status}`}`); return; } if (action === "back_to_step1" || action === "bizportal_done") { window.location.reload(); } else if (action === "cancel" || action === "client_requested_changes") { window.location.href = "/registrations"; } } catch (err: unknown) { setMsgKind("error"); setMsg(`❌ ${err instanceof Error ? err.message : "Error"}`); } finally { setBusy(null); } } async function runBizportalApply(nameOnly: boolean = false) { setShowConfirm(false); setShowNameOnlyConfirm(false); setBusy(nameOnly ? "apply_name_only" : "apply"); setMsg(""); setMsgKind("info"); setBizportalResult(null); try { const res = await fetch(`/api/register/${registrationId}/apply-bizportal`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nameOnly }), }); const data = await res.json(); setBizportalResult(data); if (data.ok && data.status === "bizportal_done") { setMsgKind("success"); setMsg(`✅ ${data.message || "BizPortal name reservation confirmed. Now wait for the approval letter."}`); setTimeout(() => window.location.reload(), 2500); } else if (data.ok) { setMsgKind("warn"); setMsg(`⚠ ${data.message || "Submitted but status not auto-confirmed. Check BizPortal."}`); } else { setMsgKind("error"); setMsg(`❌ ${data.error || data.message || "Submission failed."}`); } } catch (err: unknown) { setMsgKind("error"); setMsg(`❌ ${err instanceof Error ? err.message : "Error"}`); } finally { setBusy(null); } } async function handleApplyClick() { setShowConfirm(true); } async function handleNameOnlyClick() { setShowNameOnlyConfirm(true); } async function runRevertNewNames() { setShowRevertConfirm(false); setBusy("revert_new_names"); setMsg(""); setMsgKind("info"); try { const res = await fetch(`/api/register/${registrationId}/status?action=revert_new_names`, { method: "POST" }); const data = await res.json(); if (!res.ok) { setMsgKind("error"); setMsg(`❌ ${data.error || `HTTP ${res.status}`}`); } else { setMsgKind("success"); setMsg(`✅ CIPC fields cleared. Registration reverted to Step 1 — client can submit 4 new proposed names.`); setTimeout(() => window.location.href = "/registrations", 2500); } } catch (err: unknown) { setMsgKind("error"); setMsg(`❌ ${err instanceof Error ? err.message : "Error"}`); } finally { setBusy(null); } } async function runCheckMail() { setMsg(""); setMsgKind("info"); setCheckMailResult(null); try { const res = await fetch(`/api/register/${registrationId}/check-cipc-mail`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}), }); const data = await res.json(); setCheckMailResult(data); if (!res.ok) { setMsgKind("error"); setMsg(`❌ ${data.error || `HTTP ${res.status}`}`); } else if (data.firstScanner?.found || data.secondScanner?.found) { setMsgKind("success"); setMsg(`✅ ${data.summary}`); setTimeout(() => window.location.reload(), 3000); } else { setMsgKind("info"); setMsg(`ℹ️ ${data.summary}`); } } catch (err: unknown) { setMsgKind("error"); setMsg(`❌ ${err instanceof Error ? err.message : "Error"}`); } finally { setBusy(null); } } async function runNameAlreadyApproved() { setBusy("name_already_approved"); setMsg(""); setMsgKind("info"); try { const res = await fetch(`/api/register/${registrationId}/name-already-approved`, { method: "POST", headers: { "Content-Type": "application/json" }, }); const data = await res.json(); if (!res.ok || !data.ok) { setMsgKind("error"); setMsg(`❌ ${data.error || "Failed to process."}`); } else if (data.decision === "approved") { setMsgKind("success"); setMsg(`✅ Name approved! Documents saved to PB. Reloading…`); setTimeout(() => window.location.reload(), 3000); } else if (data.decision === "rejected") { setMsgKind("warn"); setMsg(`⚠ Name rejected by CIPC. Client needs to propose new names.`); } else { setMsgKind("info"); setMsg(data.message || "Done."); } } catch (err: unknown) { setMsgKind("error"); setMsg(`❌ ${err instanceof Error ? err.message : "Error"}`); } finally { setBusy(null); } } const isRegistered = status === "registered"; const isBizportalInProgress = status === "bizportal_in_progress"; const isBizportalDone = status === "bizportal_done"; return (

Step 2 actions

{isRegistered && ( <> )} {isBizportalInProgress && ( <> ⏳ Bizportal submission in progress )} {isBizportalDone && ( <> ✓ BizPortal Done — awaiting approval letter )} {status === "name_approved" && ( <> ✓ Name approved by Bizportal )} {status === "name_reserved" && ( ✓ Name reserved — workflow complete )} {status === "cancelled" && ( ⚠ Cancelled )} ← Back to list
{msg && (
{msg}
)} {bizportalResult && (

BizPortal flow details

{bizportalResult.balance_before !== null && bizportalResult.balance_before !== undefined && (

Balance before: R {bizportalResult.balance_before.toFixed(2)}

)} {bizportalResult.balance_after !== null && bizportalResult.balance_after !== undefined && (

Balance after: R {bizportalResult.balance_after.toFixed(2)}

)} {bizportalResult.deduction !== null && bizportalResult.deduction !== undefined && (

Deduction: R {bizportalResult.deduction.toFixed(2)}

)} {bizportalResult.log && (
Show log
                {bizportalResult.log.join("\n")}
              
)}
)} {checkMailResult && (

📧 Check Mail result

Reference: {checkMailResult.registration?.reference_name} {" | "} Status: {checkMailResult.registration?.status_after || checkMailResult.registration?.status_before}

{checkMailResult.registration?.cipc_reference_no && (

CIPC Ref: {checkMailResult.registration.cipc_reference_no}

)} {checkMailResult.registration?.cipc_decision && (

Decision: {checkMailResult.registration.cipc_decision}

)} {checkMailResult.firstScanner?.found && (

✓ First email found and processed

)} {checkMailResult.secondScanner?.found && (

✓ Second email found — client notified

)} {!checkMailResult.firstScanner?.found && !checkMailResult.secondScanner?.found && (

No new emails found for this registration.

)}
)} {/* Confirmation popup */} {showConfirm && (
setShowConfirm(false)} >
e.stopPropagation()} >

Apply Name Reservation

Apply on BizPortal?

I will open BizPortal, login if needed, fill the 4 name boxes in the order supplied, and click Continue twice. The second Continue costs R50 from your BizPortal balance.

⚠ Before this runs I'll record your BizPortal balance, after the run I'll check it again. If R50 was deducted, I'll auto-mark BizPortal Done (green) so you know to wait for the approval letter.

Names to enter:

    {proposedNames.length === 0 &&
  1. No names provided
  2. } {proposedNames.map((n, i) => (
  3. {n}
  4. ))}
)} {/* Name Reservation Only confirmation popup */} {showNameOnlyConfirm && (
setShowNameOnlyConfirm(false)} >
e.stopPropagation()} >

Name Reservation Only

Apply just for the name reservation?

I will lodge a CIPC Name Reservation on BizPortal — R50 is debited from your prepaid balance. Once CIPC approves, this registration is done. No Steps 3/4.

Names to enter:

    {proposedNames.length === 0 &&
  1. No names provided
  2. } {proposedNames.map((n, i) => (
  3. {n}
  4. ))}
)} {/* Revert to Step 1 (New Names) confirmation popup */} {showRevertConfirm && (
setShowRevertConfirm(false)} >
e.stopPropagation()} >

CIPC Name Rejected

Revert to Step 1 — New Names?

This will clear the CIPC reference number and decision, and move the registration back to Step 1.

The client will receive the wizard link with their saved data and can submit 4 new proposed names.

This cannot be undone.

)}
); }