Untitled
unknown
javascript
9 months ago
8.6 kB
14
Indexable
"use client";
import { useEffect, useMemo, useRef, useState } from "react";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import Tabs from "@/app/components/v3/ui/Tabs";
import TinhTrangPopup from "@/app/components/v3/ui/TinhTrangPopup";
import { HAN_TYPE } from "@/app/constant/luanhan/luanhan_constant";
import ReportLayout from "@/app/components/v3/ReportLayout";
import { PaymentPopup } from "@/app/components/v3/ui/PaymentPopup";
import LifeContent from "@/app/components/v3/content/LifeContent";
import VanHanContent from "@/app/components/v3/content/VanHanContent";
import LoadingBanner from "@/app/components/v3/ui/LoadingBanner";
import { GioiTinh } from "@/app/constant/tuvi_constant";
import { convertBirthToYin } from "@/app/utils/ansao/ansao_utils";
import { lapLaSo } from "@/app/utils/ansao/anlaso_utils";
import {api} from "@/lib/apiClient";
const CURRENT_YEAR = new Date().getFullYear();
export default function ReportV3Unified() {
const { friendlyId } = useParams();
const searchParams = useSearchParams();
const router = useRouter();
// --- State ---
const [report, setReport] = useState(null);
const [displayBirthHour, setDisplayBirthHour] = useState("");
const [showPaymentPopup, setShowPaymentPopup] = useState(false);
const [laSoFull, setLasoData] = useState(null);
const [loading, setLoading] = useState(true);
const [errorMsg, setErrorMsg] = useState("");
// --- Tabs ---
const tab = (searchParams.get("tab") || "life").toLowerCase();
const setTab = (next) => {
const sp = new URLSearchParams(Array.from(searchParams.entries()));
sp.set("tab", next);
router.replace(`?${sp.toString()}`, { scroll: false });
};
// --- Polling helpers ---
const pollRef = useRef(null);
const SECTIONS = ["toChat", "lonLen", "tinhDuyen", "suNghiep", "totXau", "taiSan"];
const isMiniLoaded = (r) =>
r?.luanGiaiMini && Object.keys(r.luanGiaiMini || {}).length > 0;
const isFullLoaded = (r) =>
r?.luanGiai && SECTIONS.every((k) => Boolean(r.luanGiai[k]));
const needPoll = (r) => {
if (!r) return true;
if (r.paymentStatus === "PENDING") return !isMiniLoaded(r);
if (r.paymentStatus === "PAID") return !isFullLoaded(r);
return false;
};
// --- Dynamic loading rule ---
const shouldShowLoading = useMemo(() => {
if (!report) return true;
if (report.paymentStatus === "PENDING" && !isMiniLoaded(report)) return true;
if (report.paymentStatus === "PAID" && !isFullLoaded(report)) return true;
return false;
}, [report]);
// --- Auto check & unlock missing sections ---
const checkAndUnlockMissing = async () => {
try {
await api.post(`/api/data/luangiai/unlock-missing/${friendlyId}`);
} catch (err) {
console.warn("⚠️ unlock-missing check failed:", err.message);
}
};
// --- Fetch function ---
const fetchData = async () => {
try {
const { data } = await api.get(`/api/data/luangiai/${friendlyId}`);
setReport(data);
if (data.birthHour === 0 || data.birthHour) setDisplayBirthHour(`${Math.max(data.birthHour - 1, 0)}-${data.birthHour + 1}h`);
setErrorMsg("");
} catch (err) {
console.error("❌ Failed to load report:", err);
setErrorMsg("Không thể tải dữ liệu, vui lòng thử lại sau.");
} finally {
setLoading(false);
}
};
// --- Fetch initial ---
useEffect(() => {
if (!friendlyId) return;
setLoading(true);
fetchData();
checkAndUnlockMissing()
}, [friendlyId]);
// --- Polling ---
useEffect(() => {
if (needPoll(report) && !pollRef.current) {
pollRef.current = setInterval(fetchData, 5000);
}
if (!needPoll(report) && pollRef.current) {
clearInterval(pollRef.current);
pollRef.current = null;
}
return () => {
if (pollRef.current) {
clearInterval(pollRef.current);
pollRef.current = null;
}
};
}, [report]);
// --- Lock check ---
const isLocked = useMemo(() => report?.paymentStatus !== "PAID", [report?.paymentStatus]);
// --- Build laSo data ---
useEffect(() => {
if (!report) return;
try {
const genderVal =
typeof report.gender === "string"
? GioiTinh[report.gender] ?? GioiTinh.NAM
: typeof report.gender === "number"
? (report.gender === 0 ? GioiTinh.NAM : GioiTinh.NU)
: report.gender?.key ?? GioiTinh.NAM;
const yinBirthdate = convertBirthToYin({
year: Number(report.birthYear),
month: Number(report.birthMonth),
day: Number(report.birthDay),
hours: Number(report.birthHour ?? 12),
minutes: 0,
gender: genderVal,
});
const yinNamHan = convertBirthToYin({
year: new Date().getFullYear(),
month: 6,
day: 30,
})
const laso = lapLaSo(yinBirthdate, yinNamHan);
setLasoData({
info: {
name: report.name,
year: Number(report.birthYear),
yearYin: yinBirthdate.year,
month: Number(report.birthMonth),
monthYin: yinBirthdate.month,
day: Number(report.birthDay),
dayYin: yinBirthdate.day,
hours: Number(report.birthHour ?? 12),
minutes: 0,
gender: genderVal,
},
laso,
});
} catch (e) {
console.error("Build laSoFull failed:", e);
setLasoData(null);
}
}, [report]);
// --- Render ---
return (
<ReportLayout report={report} displayBirthHour={displayBirthHour} laSoFull={laSoFull}>
<div className="max-w-5xl mx-auto px-5 pb-24 grid md:grid-cols-[220px,1fr] gap-8">
<Tabs
items={[
{ key: "life", label: "Chuyện một đời" },
{ key: "vanhan", label: "Vận hạn" },
]}
initialKey={tab}
onChange={(k) => setTab(k)}
className="mb-3 mt-10"
/>
<main className="space-y-24">
{errorMsg ? (
<p className="text-center text-red-600 mt-10">{errorMsg}</p>
) : shouldShowLoading ? (
<div className="max-w-4xl mx-auto mt-10">
<LoadingBanner />
</div>
) : tab === "life" ? (
<LifeContent
report={report}
isLocked={isLocked}
loading={loading}
onRequirePay={() => setShowPaymentPopup(true)}
/>
) : (
<VanHanContent report={report} friendlyId={friendlyId} year={CURRENT_YEAR} />
)}
</main>
</div>
{/* --- Popups --- */}
{tab === "life" && showPaymentPopup && (
<PaymentPopup
friendlyId={friendlyId}
onClose={() => setShowPaymentPopup(false)}
onSuccess={(data) => {
setReport(data);
fetchData(); // refresh immediately
}}
/>
)}
{tab === "vanhan" && (
<TinhTrangPopup
friendlyId={friendlyId}
hanType={HAN_TYPE.CONG_VIEC}
currentYear={CURRENT_YEAR}
onUpdated={(selected) => console.log("✅ Updated tình trạng:", selected)}
/>
)}
</ReportLayout>
);
}Editor is loading...
Leave a Comment