import { useState, useRef, useEffect } from 'react'; import { useNavigate, useParams } from 'react-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { adminPinnedMessagesApi, PinnedMessageCreateRequest, PinnedMessageUpdateRequest, } from '../api/adminPinnedMessages'; import { AdminBackButton, Toggle } from '../components/admin'; // Icons const PinIcon = () => ( ); const XIcon = () => ( ); const RefreshIcon = () => ( ); const PhotoIcon = () => ( ); const VideoIcon = () => ( ); const SaveIcon = () => ( ); export default function AdminPinnedMessageCreate() { const { t } = useTranslation(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { id } = useParams<{ id: string }>(); const fileInputRef = useRef(null); const isEditing = Boolean(id); const messageId = id ? parseInt(id, 10) : null; // Form state const [content, setContent] = useState(''); const [sendBeforeMenu, setSendBeforeMenu] = useState(true); const [sendOnEveryStart, setSendOnEveryStart] = useState(true); const [broadcastOnCreate, setBroadcastOnCreate] = useState(false); // Media state const [mediaFile, setMediaFile] = useState(null); const [mediaType, setMediaType] = useState<'photo' | 'video'>('photo'); const [mediaPreview, setMediaPreview] = useState(null); const [uploadedFileId, setUploadedFileId] = useState(null); const [isUploading, setIsUploading] = useState(false); const [existingMediaType, setExistingMediaType] = useState<'photo' | 'video' | null>(null); const mediaPreviewRef = useRef(null); // Revoke blob URLs on unmount to prevent memory leaks useEffect(() => { return () => { if (mediaPreviewRef.current) URL.revokeObjectURL(mediaPreviewRef.current); }; }, []); // Load existing message for editing const { data: existingMessage, isLoading: isLoadingMessage } = useQuery({ queryKey: ['admin', 'pinned-messages', 'detail', messageId], queryFn: () => adminPinnedMessagesApi.get(messageId!), enabled: isEditing && messageId !== null, }); // Pre-fill form when editing useEffect(() => { if (existingMessage) { setContent(existingMessage.content || ''); setSendBeforeMenu(existingMessage.send_before_menu); setSendOnEveryStart(existingMessage.send_on_every_start); if (existingMessage.media_file_id && existingMessage.media_type) { setUploadedFileId(existingMessage.media_file_id); setExistingMediaType(existingMessage.media_type); setMediaType(existingMessage.media_type); } } }, [existingMessage]); // Create mutation const createMutation = useMutation({ mutationFn: (data: PinnedMessageCreateRequest) => adminPinnedMessagesApi.create(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin', 'pinned-messages'] }); navigate('/admin/pinned-messages'); }, }); // Update mutation const updateMutation = useMutation({ mutationFn: (data: PinnedMessageUpdateRequest) => adminPinnedMessagesApi.update(messageId!, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin', 'pinned-messages'] }); navigate('/admin/pinned-messages'); }, }); // Handle file selection const handleFileSelect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setMediaFile(file); setExistingMediaType(null); let detectedType: 'photo' | 'video' = 'photo'; if (file.type.startsWith('image/')) { detectedType = 'photo'; if (mediaPreviewRef.current) URL.revokeObjectURL(mediaPreviewRef.current); const url = URL.createObjectURL(file); mediaPreviewRef.current = url; setMediaPreview(url); } else if (file.type.startsWith('video/')) { detectedType = 'video'; setMediaPreview(null); } setMediaType(detectedType); setIsUploading(true); try { const result = await adminPinnedMessagesApi.uploadMedia(file, detectedType); setUploadedFileId(result.file_id); } catch { setMediaFile(null); setMediaPreview(null); } finally { setIsUploading(false); } }; // Remove media const handleRemoveMedia = () => { if (mediaPreviewRef.current) { URL.revokeObjectURL(mediaPreviewRef.current); mediaPreviewRef.current = null; } setMediaFile(null); setMediaPreview(null); setUploadedFileId(null); setExistingMediaType(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } }; // Validate const isValid = content.trim().length > 0 || uploadedFileId !== null; // Submit const handleSubmit = () => { if (!isValid) return; if (isEditing && messageId !== null) { const data: PinnedMessageUpdateRequest = { content, send_before_menu: sendBeforeMenu, send_on_every_start: sendOnEveryStart, }; if (uploadedFileId) { data.media = { type: mediaType, file_id: uploadedFileId }; } updateMutation.mutate(data); } else { const data: PinnedMessageCreateRequest = { content, send_before_menu: sendBeforeMenu, send_on_every_start: sendOnEveryStart, broadcast: broadcastOnCreate, }; if (uploadedFileId) { data.media = { type: mediaType, file_id: uploadedFileId }; } createMutation.mutate(data); } }; const isPending = createMutation.isPending || updateMutation.isPending; if (isEditing && isLoadingMessage) { return (

{t('common.loading')}

); } return (
{/* Header */}

{isEditing ? t('admin.pinnedMessages.editMessage') : t('admin.pinnedMessages.create')}

{t('admin.pinnedMessages.subtitle')}

{/* Content */}
{/* Message text */}