+ {/* Top Navigation & Info Header */}
+
+
+
+
+ Quay lại danh sách liên kết
+
+
+
+ Thống kê:{" "}
+
+ /{url.short_code}
+
+
+ {url.is_password_protected && (
+
+ Có mật khẩu
+
+ )}
+ {url.display_on_portal && (
+
+ Trên Bio Link
+
+ )}
+
+
+ Đích đến:{" "}
+
+ {url.original_url}
+
+
+
+
+ {/* Quick action buttons */}
+
+
+
+ {/* 4 Summary Stat Cards */}
+
+
+
+
+
+
+ Tổng Lượt Click
+
+
+ {analytics.total_clicks}
+
+
+
+
+
+
+
+
+ Click Hôm Nay
+
+
+ {analytics.today_clicks}
+
+
+
+
+
+
+
+
+ Thiết Bị Hàng Đầu
+
+
+ {topDevice}
+
+
+
+
+
+
+
+
+ Quốc Gia Hàng Đầu
+
+
+ {topCountry}
+
+
+
+
+ {/* 7-Day Clicks Timeline Chart */}
+
+
+
+
+
+ Lưu lượng 7 ngày gần nhất
+
+
+ Số lượt nhấp chuột được ghi nhận theo từng ngày
+
+
+
+ 7 ngày qua:{" "}
+
+ {analytics.seven_days_stats.reduce((a, b) => a + b.count, 0)} clicks
+
+
+
+
+ {/* Visual Bar Chart */}
+
+ {analytics.seven_days_stats.map((item, idx) => {
+ const heightPercent = Math.max((item.count / maxSevenDays) * 100, item.count > 0 ? 8 : 2);
+ const dateObj = new Date(item.date);
+ const dayLabel = `${dateObj.getDate()}/${dateObj.getMonth() + 1}`;
+
+ return (
+
+ {/* Count tooltip on hover */}
+
+ {item.count} clicks
+
+
+ {/* Animated bar */}
+
0
+ ? "bg-gradient-to-t from-indigo-600 via-indigo-500 to-purple-500 shadow-md shadow-indigo-500/20 group-hover:brightness-110 group-hover:scale-y-105"
+ : "bg-slate-100 dark:bg-slate-800"
+ }`}
+ />
+
+ {/* Date Label */}
+
+ {dayLabel}
+
+
+ );
+ })}
+
+
+
+ {/* Grid 2x2: Devices, OS, Browsers, Countries */}
+
+ {/* Device Breakdown */}
+
+
+
+ Thiết bị truy cập (Device Types)
+
+ {analytics.devices.length === 0 ? (
+
Chưa có dữ liệu thiết bị
+ ) : (
+
+ {analytics.devices.map((d) => {
+ const total = analytics.total_clicks || 1;
+ const percent = Math.round((d.count / total) * 100);
+ return (
+
+
+
+ {d.name === "mobile" && }
+ {d.name === "desktop" && }
+ {d.name === "tablet" && }
+ {d.name}
+
+
+ {d.count} ({percent}%)
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+ {/* Countries Breakdown */}
+
+
+
+ Quốc gia truy cập (Top Countries)
+
+ {analytics.countries.length === 0 ? (
+
Chưa có dữ liệu vị trí
+ ) : (
+
+ {analytics.countries.map((c) => {
+ const total = analytics.total_clicks || 1;
+ const percent = Math.round((c.count / total) * 100);
+ return (
+
+
+
+
+ {c.code || "VN"}
+
+ {c.name}
+
+
+ {c.count} ({percent}%)
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+ {/* Operating Systems */}
+
+
+
+ Hệ điều hành (Operating Systems)
+
+ {analytics.os.length === 0 ? (
+
Chưa có dữ liệu hệ điều hành
+ ) : (
+
+ {analytics.os.map((item) => {
+ const total = analytics.total_clicks || 1;
+ const percent = Math.round((item.count / total) * 100);
+ return (
+
+
+ {item.name}
+
+
+ {percent}%
+
+ {item.count}
+
+
+
+ );
+ })}
+
+ )}
+
+
+ {/* Browsers & Referrers */}
+
+
+
+ Trình duyệt & Nguồn giới thiệu (Browsers & Referrers)
+
+
+
+
+ Trình duyệt phổ biến
+
+
+ {analytics.browsers.map((b) => (
+
+ {b.name}: {b.count}
+
+ ))}
+
+
+
+
+
+ Nguồn giới thiệu (Referrer)
+
+
+ {analytics.referrers.map((r) => (
+
+
+ {r.name}: {r.count}
+
+ ))}
+
+
+
+
+
+
+ {/* Recent Clicks Log Table */}
+
+
+
+ Nhật ký lượt click gần nhất (Recent Click Logs)
+
+
+ Chi tiết 25 lượt truy cập liên kết mới nhất
+
+
+ {analytics.recent_clicks.length === 0 ? (
+
+ Chưa có lượt click nào được ghi nhận cho liên kết này.
+
+ ) : (
+
+
+
+
+ | Thời gian |
+ Thiết bị |
+ Hệ điều hành / Trình duyệt |
+ Vị trí |
+ Nguồn |
+
+
+
+ {analytics.recent_clicks.map((click) => {
+ const d = new Date(click.created_at);
+ const timeFormatted = d.toLocaleString("vi-VN", {
+ hour: "2-digit",
+ minute: "2-digit",
+ second: "2-digit",
+ day: "2-digit",
+ month: "2-digit",
+ year: "numeric",
+ });
+
+ return (
+
+ |
+ {timeFormatted}
+ |
+
+
+ {click.device_type}
+
+ |
+
+ {click.os}
+ {click.browser}
+ |
+
+
+
+ {click.country_code}
+
+ {click.city ? `${click.city}, ` : ""}{click.country_name}
+
+ |
+
+ {click.referrer || "Trực tiếp"}
+ |
+
+ );
+ })}
+
+
+
+ )}
+
+
+ );
+}
diff --git a/src/app/dashboard/urls/page.tsx b/src/app/dashboard/urls/page.tsx
index cbbae23..47966c0 100644
--- a/src/app/dashboard/urls/page.tsx
+++ b/src/app/dashboard/urls/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useState, useEffect } from "react";
+import Link from "next/link";
import {
Link2,
Plus,
@@ -331,10 +332,14 @@ export default function UserUrlsPage() {