application page
This commit is contained in:
@@ -255,13 +255,13 @@ export default function ApplicationTable({
|
||||
<TableCell className="px-5 py-4 text-gray-600 text-theme-sm dark:text-gray-400">
|
||||
{app.reviewer?.display_name || "-"}
|
||||
</TableCell>
|
||||
<TableCell className="group relative px-5 pb-4 text-start text-theme-xs text-gray-500 dark:text-gray-400 max-w-50">
|
||||
<TableCell className="group relative px-5 pb-4 text-start text-theme-xs text-gray-500 dark:text-gray-400 max-w-50 min-w-50">
|
||||
<div className="truncate">{app.review_note || "-"}</div>
|
||||
|
||||
{app.review_note && (
|
||||
<div className="invisible group-hover:visible absolute z-50 bottom-full left-1/2 -translate-x-1/2 mb-1 w-max max-w-75 p-2 backdrop-blur-sm text-black text-xs rounded-lg shadow-xl wrap-break-words whitespace-normal">
|
||||
<div className="invisible group-hover:visible absolute z-50 bottom-full left-1/2 -translate-x-1/2 w-max max-w-75 p-2 backdrop-blur-xs text-black text-xs rounded-lg shadow-xl wrap-break-words whitespace-normal">
|
||||
{app.review_note}
|
||||
{/* <div className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-gray-600"></div> */}
|
||||
<div className="absolute top-full left-1/2 border-6 border-transparent border-t-white"></div>
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
27
src/components/ui/parse/SafeHTMLRenderer.tsx
Normal file
27
src/components/ui/parse/SafeHTMLRenderer.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
"use client";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
// Component này đóng vai trò như một "vùng an toàn"
|
||||
export function SafeHTMLRenderer({ html }: { html: string }) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (containerRef.current) {
|
||||
// 1. Giải mã HTML Entities (Biến < thành <, " thành ", ...)
|
||||
const txt = document.createElement("textarea");
|
||||
txt.innerHTML = html;
|
||||
let decoded = txt.value;
|
||||
|
||||
// 2. Xử lý xóa thẻ <pre> bọc ngoài nếu API trả về dư thừa
|
||||
decoded = decoded.replace(/<pre[^>]*>/g, "").replace(/<\/pre>/g, "");
|
||||
|
||||
// 3. Khởi tạo Shadow DOM (nếu chưa có)
|
||||
const shadowRoot = containerRef.current.shadowRoot || containerRef.current.attachShadow({ mode: "open" });
|
||||
|
||||
// 4. Render nội dung vào trong vùng cô lập
|
||||
shadowRoot.innerHTML = decoded;
|
||||
}
|
||||
}, [html]);
|
||||
|
||||
return <div ref={containerRef} className="w-full h-auto" />;
|
||||
}
|
||||
32
src/components/user-profile/ApplicationList.tsx
Normal file
32
src/components/user-profile/ApplicationList.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { setSelectedApplication } from "@/store/features/userSlice";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
export default function ApplicationList({ applications }: { applications: any[] }) {
|
||||
const router = useRouter();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleViewDetail = (app: any) => {
|
||||
dispatch(setSelectedApplication(app));
|
||||
router.push(`/profile/applications`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{applications.map((app) => (
|
||||
<div
|
||||
key={app.id}
|
||||
onClick={() => handleViewDetail(app)}
|
||||
className="p-4 border rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<span>Loại: {app.verify_type}</span>
|
||||
<span className="text-blue-500 font-medium">Xem chi tiết →</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user