Files
ai-scoring-application/components/share-modal.tsx

297 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState, useEffect } from "react"
import { Copy, Check, Share2, QrCode, Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { useToast } from "@/hooks/use-toast"
import { generateShareUrl, getCurrentUrl } from "@/lib/config"
import QRCode from "qrcode"
interface ShareModalProps {
isOpen: boolean
onClose: () => void
evaluationId?: string
projectTitle?: string
}
export function ShareModal({ isOpen, onClose, evaluationId, projectTitle }: ShareModalProps) {
const [qrCodeUrl, setQrCodeUrl] = useState<string>("")
const [isGeneratingQR, setIsGeneratingQR] = useState(false)
const [copiedLink, setCopiedLink] = useState(false)
const [copiedQR, setCopiedQR] = useState(false)
const { toast } = useToast()
// 生成分享連結
const shareUrl = evaluationId
? generateShareUrl(evaluationId)
: getCurrentUrl()
// 生成 QR Code
useEffect(() => {
if (isOpen && shareUrl) {
setIsGeneratingQR(true)
QRCode.toDataURL(shareUrl, {
width: 160,
margin: 2,
color: {
dark: '#000000',
light: '#FFFFFF'
}
})
.then(url => {
setQrCodeUrl(url)
setIsGeneratingQR(false)
})
.catch(err => {
console.error('生成 QR Code 失敗:', err)
setIsGeneratingQR(false)
toast({
title: "錯誤",
description: "生成 QR Code 失敗,請稍後再試",
variant: "destructive",
})
})
}
}, [isOpen, shareUrl, toast])
// 複製連結
const copyLink = async () => {
try {
await navigator.clipboard.writeText(shareUrl)
setCopiedLink(true)
toast({
title: "成功",
description: "連結已複製到剪貼板",
})
setTimeout(() => setCopiedLink(false), 2000)
} catch (err) {
console.error('複製失敗:', err)
toast({
title: "錯誤",
description: "複製失敗,請手動複製連結",
variant: "destructive",
})
}
}
// 複製 QR Code
const copyQRCode = async () => {
if (!qrCodeUrl) return
try {
// 將 base64 轉換為 blob
const response = await fetch(qrCodeUrl)
const blob = await response.blob()
// 複製到剪貼板
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
])
setCopiedQR(true)
toast({
title: "成功",
description: "QR Code 已複製到剪貼板",
})
setTimeout(() => setCopiedQR(false), 2000)
} catch (err) {
console.error('複製 QR Code 失敗:', err)
toast({
title: "錯誤",
description: "複製 QR Code 失敗,請截圖保存",
variant: "destructive",
})
}
}
// 分享到社群媒體
const shareToSocial = (platform: string) => {
const encodedUrl = encodeURIComponent(shareUrl)
const encodedTitle = encodeURIComponent(`評審結果 - ${projectTitle || 'AI 智能評審系統'}`)
let shareUrl_template = ""
switch (platform) {
case 'line':
shareUrl_template = `https://social-plugins.line.me/lineit/share?url=${encodedUrl}&text=${encodedTitle}`
break
case 'facebook':
shareUrl_template = `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`
break
case 'email':
const emailBody = encodeURIComponent(`您好,\n\n我想與您分享這個評審結果\n\n${projectTitle || 'AI 智能評審系統'}\n\n請點擊以下連結查看詳細報告\n${shareUrl}\n\n感謝`)
shareUrl_template = `mailto:?subject=${encodedTitle}&body=${emailBody}`
break
default:
return
}
if (platform === 'email') {
window.location.href = shareUrl_template
} else {
window.open(shareUrl_template, '_blank', 'width=600,height=400')
}
}
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-lg max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Share2 className="h-5 w-5" />
</DialogTitle>
<DialogDescription>
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
{/* 分享連結 */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-base"></CardTitle>
<CardDescription className="text-sm">
</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-2">
<div className="flex-1 p-2 bg-muted rounded-md text-sm font-mono break-all min-w-0">
{shareUrl}
</div>
<Button
onClick={copyLink}
size="sm"
variant="outline"
className="shrink-0 w-full sm:w-auto hover:bg-primary/5 hover:border-primary/20 hover:text-primary transition-colors"
>
{copiedLink ? (
<>
<Check className="h-4 w-4 mr-2" />
</>
) : (
<>
<Copy className="h-4 w-4 mr-2" />
</>
)}
</Button>
</div>
</CardContent>
</Card>
{/* QR Code */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-base flex items-center gap-2">
<QrCode className="h-4 w-4" />
QR Code
</CardTitle>
<CardDescription className="text-sm">
QR Code
</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex flex-col items-center space-y-3">
{isGeneratingQR ? (
<div className="w-40 h-40 flex items-center justify-center bg-muted rounded-lg">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
</div>
) : qrCodeUrl ? (
<div className="flex flex-col items-center space-y-3">
<img
src={qrCodeUrl}
alt="QR Code"
className="w-40 h-40 border rounded-lg"
/>
<Button
onClick={copyQRCode}
size="sm"
variant="outline"
disabled={copiedQR}
className="w-full sm:w-auto hover:bg-primary/5 hover:border-primary/20 hover:text-primary transition-colors disabled:hover:bg-transparent disabled:hover:border-border disabled:hover:text-muted-foreground"
>
{copiedQR ? (
<>
<Check className="h-4 w-4 mr-2" />
</>
) : (
<>
<Copy className="h-4 w-4 mr-2" />
QR Code
</>
)}
</Button>
</div>
) : (
<div className="w-40 h-40 flex items-center justify-center bg-muted rounded-lg text-muted-foreground">
...
</div>
)}
</div>
</CardContent>
</Card>
{/* 社群分享 */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-base"></CardTitle>
<CardDescription className="text-sm">
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
<Button
onClick={() => shareToSocial('line')}
variant="outline"
size="sm"
className="flex flex-col items-center gap-2 h-auto py-4 hover:bg-green-50 hover:border-green-300 hover:text-green-700 transition-colors"
>
<div className="w-7 h-7 bg-green-500 rounded text-white text-sm flex items-center justify-center font-bold">
L
</div>
<span className="text-xs font-medium">LINE</span>
</Button>
<Button
onClick={() => shareToSocial('facebook')}
variant="outline"
size="sm"
className="flex flex-col items-center gap-2 h-auto py-4 hover:bg-blue-50 hover:border-blue-300 hover:text-blue-700 transition-colors"
>
<div className="w-7 h-7 bg-blue-600 rounded text-white text-sm flex items-center justify-center font-bold">
f
</div>
<span className="text-xs font-medium">Facebook</span>
</Button>
<Button
onClick={() => shareToSocial('email')}
variant="outline"
size="sm"
className="flex flex-col items-center gap-2 h-auto py-4 col-span-2 sm:col-span-1 hover:bg-slate-50 hover:border-slate-300 hover:text-slate-700 transition-colors"
>
<Mail className="w-7 h-7 text-blue-600" />
<span className="text-xs font-medium">Email</span>
</Button>
</div>
</CardContent>
</Card>
</div>
</DialogContent>
</Dialog>
)
}