You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
7.8 KiB
227 lines
7.8 KiB
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Button from "@/components/ui/button";
|
|
import { useFlutterBridge } from "@/hooks/useFlutterBridge";
|
|
|
|
const EXIT_ANIMATION_MS = 220;
|
|
|
|
type ReportActionsSheetProps = {
|
|
onClose?: () => void;
|
|
};
|
|
|
|
export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) {
|
|
const [isVisible, setIsVisible] = useState(true);
|
|
const [isEntering, setIsEntering] = useState(true);
|
|
const [isClosing, setIsClosing] = useState(false);
|
|
const [showLogs, setShowLogs] = useState(false);
|
|
|
|
const { sendToFlutter, logs, lastEvent, isReady } = useFlutterBridge({
|
|
enableLogging: true,
|
|
});
|
|
|
|
const closeSheet = () => {
|
|
if (isClosing) return;
|
|
setIsClosing(true);
|
|
};
|
|
|
|
// ✅ دکمه WEB_READY
|
|
const handleSendWebReady = () => {
|
|
sendToFlutter("WEB_READY", {
|
|
timestamp: Date.now(),
|
|
url: window.location.href,
|
|
userAgent: navigator.userAgent,
|
|
});
|
|
console.log("✅ WEB_READY ارسال شد");
|
|
};
|
|
|
|
// ✅ دکمه دریافت موقعیت مکانی
|
|
// پل اکنون از کانال واقعی HabibApp استفاده میکند، پس یکبار ارسال کافی است.
|
|
const handleGetLocation = () => {
|
|
sendToFlutter("REQUEST_LOCATION");
|
|
console.log("📍 REQUEST_LOCATION ارسال شد");
|
|
};
|
|
|
|
// ✅ دکمه مشاور
|
|
const handleOpenConsultant = () => {
|
|
sendToFlutter("REQUEST_CONSULTANT", {
|
|
consultant: "habib@gmail.com",
|
|
});
|
|
console.log("👨⚕️ REQUEST_CONSULTANT ارسال شد");
|
|
};
|
|
|
|
useEffect(() => {
|
|
const frameId = window.requestAnimationFrame(() => {
|
|
setIsEntering(false);
|
|
});
|
|
return () => window.cancelAnimationFrame(frameId);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!isVisible) return;
|
|
const previousBodyOverflow = document.body.style.overflow;
|
|
const previousHtmlOverflow = document.documentElement.style.overflow;
|
|
document.body.style.overflow = "hidden";
|
|
document.documentElement.style.overflow = "hidden";
|
|
return () => {
|
|
document.body.style.overflow = previousBodyOverflow;
|
|
document.documentElement.style.overflow = previousHtmlOverflow;
|
|
};
|
|
}, [isVisible]);
|
|
|
|
useEffect(() => {
|
|
if (!isClosing) return;
|
|
const timeoutId = window.setTimeout(() => {
|
|
setIsVisible(false);
|
|
onClose?.();
|
|
}, EXIT_ANIMATION_MS);
|
|
return () => window.clearTimeout(timeoutId);
|
|
}, [isClosing, onClose]);
|
|
|
|
useEffect(() => {
|
|
const handleFlutterResponse: NonNullable<Window["onFlutterResponse"]> = (event) => {
|
|
if (event.action === "get_location" && event.success && event.data) {
|
|
const message = `Location: ${event.data.latitude}, ${event.data.longitude}`;
|
|
alert(message);
|
|
}
|
|
};
|
|
|
|
const unsubscribe = window.addFlutterResponseListener?.(handleFlutterResponse);
|
|
|
|
return () => {
|
|
unsubscribe?.();
|
|
};
|
|
}, []);
|
|
|
|
if (!isVisible) return null;
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
"fixed inset-0 z-50 flex items-end justify-center transition-all duration-[220ms]",
|
|
isClosing || isEntering
|
|
? "bg-[#171717]/0 opacity-0"
|
|
: "bg-[#171717]/55 opacity-100",
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ")}
|
|
role="dialog"
|
|
aria-modal="true"
|
|
onClick={(event) => {
|
|
if (event.target === event.currentTarget) closeSheet();
|
|
}}
|
|
>
|
|
<section
|
|
className={[
|
|
"w-full sm:max-w-[375px] rounded-t-[15px] bg-[#F9F8F8] shadow-[0_20px_60px_rgba(15,23,42,0.08)] transition-transform duration-[220ms] ease-out max-h-[85vh] overflow-y-auto",
|
|
isClosing || isEntering ? "translate-y-full" : "translate-y-0",
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ")}
|
|
>
|
|
{/* Header */}
|
|
<div className="sticky top-0 bg-[#F9F8F8] p-3.5 border-b border-gray-200/50">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<h3 className="font-semibold text-gray-800">تنظیمات و پشتیبانی</h3>
|
|
<div
|
|
className={`w-2 h-2 rounded-full ${isReady ? "bg-green-500" : "bg-gray-400"}`}
|
|
title={isReady ? "متصل به Flutter" : "غیرفعال"}
|
|
/>
|
|
</div>
|
|
<button
|
|
onClick={closeSheet}
|
|
className="text-2xl text-gray-500 hover:text-gray-700 leading-none"
|
|
aria-label="بستن"
|
|
>
|
|
×
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-3.5 flex flex-col gap-3">
|
|
{/* دکمههای اصلی */}
|
|
<div className="flex flex-col gap-2">
|
|
<Button onClick={handleGetLocation}>📍 دریافت موقعیت مکانی</Button>
|
|
<Button onClick={handleOpenConsultant}>👨⚕️ مشاوره با حبیب</Button>
|
|
</div>
|
|
|
|
{/* دکمه تست WEB_READY */}
|
|
<div className="bg-blue-50 rounded-lg p-3 border border-blue-200">
|
|
<p className="text-xs text-blue-800 mb-2 font-semibold">
|
|
🧪 تست ارتباط با Flutter:
|
|
</p>
|
|
<Button onClick={handleSendWebReady}>
|
|
🚀 ارسال WEB_READY
|
|
</Button>
|
|
</div>
|
|
|
|
{/* نمایش آخرین ایونت دریافتی */}
|
|
{lastEvent && (
|
|
<div className="bg-green-50 rounded-lg p-3 border border-green-200">
|
|
<p className="text-xs text-green-800 font-semibold mb-2">
|
|
📥 آخرین ایونت از Flutter:
|
|
</p>
|
|
<div className="bg-white rounded p-2 text-xs font-mono break-all">
|
|
<div className="text-green-600 font-bold">
|
|
{lastEvent.type}
|
|
</div>
|
|
<div className="text-gray-600 mt-1">
|
|
{JSON.stringify(lastEvent.payload, null, 2)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* لاگها */}
|
|
<div className="bg-gray-50 rounded-lg p-3 border border-gray-200">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<p className="text-xs text-gray-700 font-semibold">
|
|
📋 لاگها ({logs.length})
|
|
</p>
|
|
<button
|
|
onClick={() => setShowLogs(!showLogs)}
|
|
className="text-xs text-blue-600 hover:text-blue-800"
|
|
>
|
|
{showLogs ? "مخفی کردن" : "نمایش"}
|
|
</button>
|
|
</div>
|
|
{showLogs && (
|
|
<div className="max-h-[150px] overflow-y-auto space-y-1">
|
|
{logs.length === 0 ? (
|
|
<p className="text-xs text-gray-500 text-center py-2">
|
|
هنوز لاگی ثبت نشده
|
|
</p>
|
|
) : (
|
|
logs.slice(-10).map((log, index) => (
|
|
<div
|
|
key={index}
|
|
className="text-[10px] font-mono bg-white p-1.5 rounded border border-gray-300 break-all"
|
|
>
|
|
{log}
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* راهنما */}
|
|
<div className="bg-yellow-50 rounded-lg p-3 border border-yellow-200">
|
|
<p className="text-xs text-yellow-900">
|
|
<strong>💡 راهنما:</strong>
|
|
<br />
|
|
• WEB_READY هنگام باز شدن این شیت بهصورت خودکار از کانال
|
|
HabibApp ارسال میشود
|
|
<br />
|
|
• نقطهٔ سبز یعنی کانال HabibApp در دسترس است
|
|
<br />• برای ارسال دستی، دکمه «ارسال WEB_READY» را بزنید
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default ReportActionsSheet;
|