import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { motion, useScroll, useTransform } from 'framer-motion'; import { ArrowLeftOutlined, ShareAltOutlined, CalendarOutlined, ClockCircleOutlined, EnvironmentOutlined, UserOutlined } from '@ant-design/icons'; import confetti from 'canvas-confetti'; import { message, Spin, Button, Result, Modal, Form, Input } from 'antd'; import { getActivityDetail, signUpActivity } from '../../api'; import styles from '../../components/activity/activity.module.less'; import { pageTransition, buttonTap } from '../../animation'; import LoginModal from '../../components/LoginModal'; import { useAuth } from '../../context/AuthContext'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; const ActivityDetail = () => { const { id } = useParams(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { scrollY } = useScroll(); const { login } = useAuth(); const [loginVisible, setLoginVisible] = useState(false); const [signupFormVisible, setSignupFormVisible] = useState(false); const [form] = Form.useForm(); // Header animation: transparent to white with shadow const headerBg = useTransform(scrollY, [0, 60], ['rgba(255,255,255,0)', 'rgba(255,255,255,1)']); const headerShadow = useTransform(scrollY, [0, 60], ['none', '0 2px 8px rgba(0,0,0,0.1)']); const headerColor = useTransform(scrollY, [0, 60], ['rgba(255,255,255,1)', 'rgba(0,0,0,0.85)']); const titleOpacity = useTransform(scrollY, [100, 200], [0, 1]); const { data: activity, isLoading, error, refetch } = useQuery({ queryKey: ['activity', id], queryFn: async () => { try { const res = await getActivityDetail(id); return res.data; } catch (err) { throw new Error(err.response?.data?.detail || 'Failed to load activity'); } }, staleTime: 0, // Ensure fresh data refetchOnMount: 'always', // Force refetch on mount }); // Force a refresh if needed (as requested by user) useEffect(() => { // 1. Force React Query refetch refetch(); // 2. Hard refresh logic after 1 second delay const timer = setTimeout(() => { const hasRefreshedKey = `has_refreshed_activity_${id}`; if (!sessionStorage.getItem(hasRefreshedKey)) { sessionStorage.setItem(hasRefreshedKey, 'true'); window.location.reload(); } }, 0); return () => clearTimeout(timer); }, [id, refetch]); const signUpMutation = useMutation({ mutationFn: (values) => signUpActivity(id, { signup_info: values || {} }), onSuccess: () => { message.success('报名成功!'); setSignupFormVisible(false); confetti({ particleCount: 150, spread: 70, origin: { y: 0.6 }, colors: ['#00b96b', '#1890ff', '#ffffff'] }); queryClient.invalidateQueries(['activity', id]); queryClient.invalidateQueries(['activities']); }, onError: (err) => { message.error(err.response?.data?.detail || err.response?.data?.error || '报名失败,请稍后重试'); } }); const handleShare = async () => { const url = window.location.href; if (navigator.share) { try { await navigator.share({ title: activity?.title, text: '来看看这个精彩活动!', url: url }); } catch (err) { console.log('Share canceled'); } } else { navigator.clipboard.writeText(url); message.success('链接已复制到剪贴板'); } }; const handleSignUp = () => { if (!localStorage.getItem('token')) { message.warning('请先登录后报名'); setLoginVisible(true); return; } // Check if we need to collect info if (activity.signup_form_config && activity.signup_form_config.length > 0) { setSignupFormVisible(true); } else { // Direct signup if no info needed signUpMutation.mutate({}); } }; const handleFormSubmit = (values) => { signUpMutation.mutate(values); }; if (isLoading) { return (
{children}
)
}
}}
>
{activity.description || activity.content || '暂无详情描述'}