Untitled

 avatar
unknown
javascript
9 months ago
8.6 kB
12
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