Adds the full Next.js app (app/, components/, lib/, scripts/, assets/, docs/, Dockerfile, compose, configs) to version control. Security: - CIPC BizPortal customer-code logins (Login 1 + Login 3) now read CIPC_LOGIN1_CODE / CIPC_LOGIN1_PASSWORD / CIPC_LOGIN3_CODE / CIPC_LOGIN3_PASSWORD from .env.local instead of source. - BizPortal personal login in apply-bizportal route reads BIZPORTAL_ID_NO / BIZPORTAL_PASSWORD. - Added .env.example as the committed template. .gitignore excludes .env*, node_modules, .next, logs, sqlite, Playwright storage_state.json (live CIPC cookies), scratch dirs, client PDFs and debug screenshots.
51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
interface ActionButtonProps {
|
|
label: string;
|
|
description: string;
|
|
status: string;
|
|
variant?: "blue" | "green" | "purple" | "red";
|
|
id: string;
|
|
}
|
|
|
|
const VARIANT = {
|
|
blue: "border-blue-300 bg-blue-50 text-blue-700 hover:bg-blue-100",
|
|
green: "border-green-300 bg-green-50 text-green-700 hover:bg-green-100",
|
|
purple: "border-purple-300 bg-purple-50 text-purple-700 hover:bg-purple-100",
|
|
red: "border-red-300 bg-red-50 text-red-700 hover:bg-red-100",
|
|
};
|
|
|
|
export default function ActionButton({ label, description, status, variant = "blue", id }: ActionButtonProps) {
|
|
const router = useRouter();
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
async function handle() {
|
|
if (!confirm(`Set status to "${status}"?`)) return;
|
|
setLoading(true);
|
|
await fetch("/api/register/update-status", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ id, status }),
|
|
});
|
|
router.refresh();
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={handle}
|
|
disabled={loading}
|
|
className={`w-full text-left p-5 rounded-lg border-2 transition-colors disabled:opacity-50 ${VARIANT[variant]}`}
|
|
>
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div>
|
|
<p className="font-bold text-sm">{loading ? "…" : label}</p>
|
|
<p className="text-xs mt-1 opacity-75">{description}</p>
|
|
</div>
|
|
{!loading && <span className="text-lg mt-0.5">→</span>}
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|