take shorturl data

This commit is contained in:
2025-04-07 23:20:48 +08:00
parent ed327ad3f0
commit d0e83f697b
6 changed files with 153 additions and 3 deletions

View File

@@ -11,6 +11,8 @@ import { EventsSummary, TimeSeriesData, GeoData, DeviceAnalytics as DeviceAnalyt
import { TeamSelector } from '@/app/components/ui/TeamSelector';
import { ProjectSelector } from '@/app/components/ui/ProjectSelector';
import { TagSelector } from '@/app/components/ui/TagSelector';
import { useSearchParams } from 'next/navigation';
import { useShortUrlStore } from '@/app/utils/store';
// 事件类型定义
interface Event {
@@ -114,6 +116,29 @@ const extractEventInfo = (event: Event) => {
};
export default function AnalyticsPage() {
// 从 URL 获取查询参数
const searchParams = useSearchParams();
const shorturlParam = searchParams.get('shorturl');
// 使用 Zustand store
const { selectedShortUrl } = useShortUrlStore();
// 存储 shorturl 参数
const [selectedShortUrlString, setSelectedShortUrlString] = useState<string | null>(null);
// 当 URL 参数变化时更新状态
useEffect(() => {
if (shorturlParam) {
setSelectedShortUrlString(shorturlParam);
console.log('Selected shorturl from URL:', shorturlParam);
// 已经通过 Zustand store 传递了完整数据
if (selectedShortUrl) {
console.log('Complete shortUrl data from store:', selectedShortUrl);
}
}
}, [shorturlParam, selectedShortUrl]);
// 默认日期范围为最近7天
const today = new Date();
const [dateRange, setDateRange] = useState({
@@ -247,6 +272,33 @@ export default function AnalyticsPage() {
<div className="flex justify-between items-center mb-8">
<h1 className="text-2xl font-bold text-gray-900">Analytics Dashboard</h1>
<div className="flex flex-col gap-4 md:flex-row md:items-center">
{/* 如果有选定的 shorturl可以显示一个提示显示更多详细信息 */}
{selectedShortUrl && (
<div className="bg-blue-100 text-blue-800 px-3 py-2 rounded-md text-sm flex flex-col">
<div className="flex items-center">
<span className="font-medium">{selectedShortUrl.title || 'Untitled'}</span>
<span className="mx-2">-</span>
<span>{selectedShortUrl.shortUrl}</span>
</div>
{selectedShortUrl.tags && selectedShortUrl.tags.length > 0 && (
<div className="flex flex-wrap gap-1 mt-1">
{selectedShortUrl.tags.map((tag, index) => (
<span key={index} className="bg-blue-50 text-blue-700 text-xs px-1.5 py-0.5 rounded">
{tag}
</span>
))}
</div>
)}
</div>
)}
{/* 如果只有 URL 参数但没有完整数据,则显示简单提示 */}
{selectedShortUrlString && !selectedShortUrl && (
<div className="bg-blue-100 text-blue-800 px-3 py-1 rounded-md text-sm flex items-center">
<span>Filtered by Short URL:</span>
<span className="ml-2 font-medium">{selectedShortUrlString}</span>
</div>
)}
<TeamSelector
value={selectedTeamIds}
onChange={(value) => {

View File

@@ -36,7 +36,7 @@ export default function Header() {
<ul className="flex space-x-4">
<li>
<Link href="/analytics" className="text-sm text-gray-700 hover:text-blue-500">
Dashboard
Analytics
</Link>
</li>
<li>

View File

@@ -5,6 +5,8 @@ import { getSupabaseClient } from '../utils/supabase';
import { AuthChangeEvent } from '@supabase/supabase-js';
import { Loader2, ExternalLink, Search } from 'lucide-react';
import { TeamSelector } from '@/app/components/ui/TeamSelector';
import { useRouter } from 'next/navigation';
import { useShortUrlStore, ShortUrlData } from '@/app/utils/store';
// Define attribute type to avoid using 'any'
interface LinkAttributes {
@@ -108,7 +110,37 @@ export default function LinksPage() {
const [totalLinks, setTotalLinks] = useState(0);
const [totalPages, setTotalPages] = useState(0);
const [searchDebounce, setSearchDebounce] = useState<NodeJS.Timeout | null>(null);
const router = useRouter();
// 使用 Zustand store
const { setSelectedShortUrl } = useShortUrlStore();
// 处理链接记录点击
const handleLinkClick = (shortUrl: string, link: ShortLink, metadata: any) => {
// 编码 shortUrl 以确保 URL 安全
const encodedShortUrl = encodeURIComponent(shortUrl);
// 创建完整的 ShortUrlData 对象
const shortUrlData: ShortUrlData = {
id: link.id,
slug: metadata.slug,
originalUrl: metadata.originalUrl,
title: metadata.title,
shortUrl: shortUrl,
teams: metadata.teamNames,
tags: metadata.tagNames,
projects: metadata.projectNames,
createdAt: metadata.createdAt,
domain: metadata.domain
};
// 使用 Zustand store 保存数据
setSelectedShortUrl(shortUrlData);
// 导航到 analytics 页面并带上参数
router.push(`/analytics?shorturl=${encodedShortUrl}`);
};
// Extract link metadata from attributes
const getLinkMetadata = (link: ShortLink) => {
try {
@@ -391,7 +423,7 @@ export default function LinksPage() {
const shortUrl = `https://${metadata.domain}/${metadata.slug}`;
return (
<tr key={link.id} className="hover:bg-gray-50">
<tr key={link.id} className="hover:bg-gray-50 cursor-pointer" onClick={() => handleLinkClick(shortUrl, link, metadata)}>
<td className="px-6 py-4">
<div className="flex flex-col space-y-1">
<span className="font-medium text-gray-900">{metadata.title}</span>

29
app/utils/store.ts Normal file
View File

@@ -0,0 +1,29 @@
import { create } from 'zustand';
// 定义 ShortUrl 数据类型
export interface ShortUrlData {
id: string;
slug: string;
originalUrl: string;
title?: string;
shortUrl: string;
teams?: any[];
projects?: any[];
tags?: any[];
createdAt?: string;
domain?: string;
}
// 定义 store 类型
interface ShortUrlStore {
selectedShortUrl: ShortUrlData | null;
setSelectedShortUrl: (shortUrl: ShortUrlData | null) => void;
clearSelectedShortUrl: () => void;
}
// 创建 store
export const useShortUrlStore = create<ShortUrlStore>((set) => ({
selectedShortUrl: null,
setSelectedShortUrl: (shortUrl) => set({ selectedShortUrl: shortUrl }),
clearSelectedShortUrl: () => set({ selectedShortUrl: null }),
}));