import React, { useState, useEffect } from 'react'; import { getNonce } from '../../Helpers'; import PollAnswerEditor from './PollAnswerEditor'; import QuestionEditor from './QuestionEditor'; import PollSettings from './PollSettings'; import NoticeModal from '../NoticeModal/NoticeModal'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import SaveIcon from '@mui/icons-material/Save'; import AddIcon from '@mui/icons-material/Add'; import PreviewIcon from '@mui/icons-material/Preview'; import SettingsIcon from '@mui/icons-material/Settings'; import PollIcon from '@mui/icons-material/Poll'; import ImageIcon from '@mui/icons-material/Image'; import '../../styles/_pools.scss'; // Declare wp global for WordPress declare const wp: any; interface Answer { id: string; text: string; image_url?: string; } interface Question { id: string; text: string; description?: string; answers: Answer[]; required: boolean; allow_multiple: boolean; } interface PollSettings { allow_multiple: boolean; show_results: 'always' | 'after_vote' | 'never'; allow_revote: boolean; require_login: boolean; close_date: string; result_display: 'percentage' | 'count' | 'both'; collect_name: boolean; collect_email: boolean; hide_after_submit: boolean; reward_type: 'none' | 'redirect' | 'coupon'; redirect_url: string; coupon_code: string; vote_tracking: 'ip_address' | 'browser_storage' | 'hybrid'; display_mode: 'all_at_once' | 'step_by_step'; answers_per_step: number; step_navigation: 'numbers' | 'custom' | 'progress_bar'; custom_step_labels: string[]; poll_type: 'single_question' | 'multiple_questions'; } interface PollBuilderProps { pollId?: number; onBack: () => void; onSave: () => void; } const PollBuilder: React.FC = ({ pollId, onBack, onSave }) => { const [pollName, setPollName] = useState(''); const [description, setDescription] = useState(''); const [featuredImage, setFeaturedImage] = useState(''); const [answers, setAnswers] = useState([]); const [questions, setQuestions] = useState([]); const [settings, setSettings] = useState({ allow_multiple: false, show_results: 'after_vote', allow_revote: false, require_login: false, close_date: '', result_display: 'percentage', collect_name: false, collect_email: false, hide_after_submit: true, reward_type: 'none', redirect_url: '', coupon_code: '', vote_tracking: 'hybrid', display_mode: 'all_at_once', answers_per_step: 2, step_navigation: 'numbers', custom_step_labels: [], poll_type: 'single_question', }); // Initialize questions when poll type changes to multiple_questions useEffect(() => { if (settings.poll_type === 'multiple_questions' && questions.length === 0) { const generateId = () => `id_${Math.random().toString(36).substr(2, 9)}`; // If we have existing answers (from single question mode), convert them to the first question if (answers.length > 0) { const firstQuestion: Question = { id: generateId(), text: pollName || 'Question 1', // Use poll name as first question text description: description || '', answers: answers.map(answer => ({ ...answer })), // Copy existing answers required: true, allow_multiple: settings.allow_multiple }; setQuestions([firstQuestion]); } else { // Create a default empty question const initialQuestion: Question = { id: generateId(), text: '', description: '', answers: [ { id: generateId(), text: '', image_url: '' }, { id: generateId(), text: '', image_url: '' } ], required: true, allow_multiple: false }; setQuestions([initialQuestion]); } } }, [settings.poll_type, questions.length, answers, pollName, description, settings.allow_multiple]); const [activeTab, setActiveTab] = useState<'answers' | 'settings'>('answers'); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [previewUrl, setPreviewUrl] = useState(null); const [modalConfig, setModalConfig] = useState({ isOpen: false, type: 'confirmation', title: '', message: '', onConfirm: () => { }, confirmText: 'Confirm', declineText: 'Cancel', mode: 'success', position: 'center' as 'center' | 'top-right' }); const closeModal = () => { setModalConfig(prev => ({ ...prev, isOpen: false })); }; const handlePreview = () => { if (!pollId) { alert('Please save the poll first before previewing.'); return; } wp.ajax.send('simpleform_get_poll_preview_url', { data: { nonce: getNonce(), poll_id: pollId, }, success(response: any) { if (response.preview_url) { setPreviewUrl(response.preview_url); } }, error(error: any) { console.error('Error getting preview URL:', error); setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Failed to generate preview URL.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); }, }); }; const closePreview = () => { setPreviewUrl(null); }; useEffect(() => { if (pollId) { loadPoll(); } else { // Add first two answers for new poll addAnswer(); addAnswer(); } }, [pollId]); const loadPoll = () => { if (!pollId) return; setLoading(true); (wp as any).ajax.send('simpleform_get_poll', { data: { nonce: getNonce(), poll_id: pollId, }, success(response: any) { if (response.poll) { const poll = response.poll; setPollName(poll.poll_name); setDescription(poll.description || ''); setFeaturedImage(poll.featured_image || ''); setAnswers(poll.answers || []); setQuestions(poll.questions || []); // Convert string booleans to actual booleans const loadedSettings = poll.settings || {}; const normalizedSettings = { ...settings, ...loadedSettings, allow_multiple: loadedSettings.allow_multiple === 'true' || loadedSettings.allow_multiple === true, allow_revote: loadedSettings.allow_revote === 'true' || loadedSettings.allow_revote === true, require_login: loadedSettings.require_login === 'true' || loadedSettings.require_login === true, collect_name: loadedSettings.collect_name === 'true' || loadedSettings.collect_name === true, collect_email: loadedSettings.collect_email === 'true' || loadedSettings.collect_email === true, hide_after_submit: loadedSettings.hide_after_submit === 'true' || loadedSettings.hide_after_submit === true, show_results: loadedSettings.show_results || 'after_vote', result_display: loadedSettings.result_display || 'percentage', close_date: loadedSettings.close_date || '', reward_type: loadedSettings.reward_type || 'none', redirect_url: loadedSettings.redirect_url || '', coupon_code: loadedSettings.coupon_code || '', vote_tracking: loadedSettings.vote_tracking || 'hybrid', display_mode: loadedSettings.display_mode || 'all_at_once', answers_per_step: loadedSettings.answers_per_step || 2, step_navigation: loadedSettings.step_navigation || 'numbers', custom_step_labels: loadedSettings.custom_step_labels || [], poll_type: loadedSettings.poll_type || 'single_question', }; setSettings(normalizedSettings); } setLoading(false); }, error(error: any) { console.error('Error loading poll:', error); setLoading(false); }, }); }; const generateId = () => { return 'id_' + Math.random().toString(36).substr(2, 9); }; const addAnswer = () => { const newAnswer: Answer = { id: generateId(), text: '', image_url: '', }; setAnswers(prev => [...prev, newAnswer]); }; const updateAnswer = (answerId: string, updatedAnswer: Answer) => { setAnswers(prev => prev.map(a => a.id === answerId ? updatedAnswer : a) ); }; const deleteAnswer = (answerId: string) => { if (answers.length <= 2) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'A poll must have at least two answers.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } setAnswers(prev => prev.filter(a => a.id !== answerId)); }; const moveAnswer = (index: number, direction: 'up' | 'down') => { const newAnswers = [...answers]; const targetIndex = direction === 'up' ? index - 1 : index + 1; if (targetIndex < 0 || targetIndex >= newAnswers.length) { return; } [newAnswers[index], newAnswers[targetIndex]] = [newAnswers[targetIndex], newAnswers[index]]; setAnswers(newAnswers); }; const openMediaUploader = () => { if (typeof (window as any).wp !== 'undefined' && (window as any).wp.media) { const mediaUploader = (window as any).wp.media({ title: 'Select Featured Image', button: { text: 'Use Image' }, multiple: false, library: { type: 'image' } }); mediaUploader.on('select', () => { const attachment = mediaUploader.state().get('selection').first().toJSON(); setFeaturedImage(attachment.url); }); mediaUploader.open(); } else { alert('WordPress media uploader is not available.'); } }; const handleSave = () => { if (!pollName.trim()) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please enter a poll name.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } // Validation based on poll type if (settings.poll_type === 'multiple_questions') { // Validate questions if (questions.length === 0) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please add at least one question.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } // Validate each question for (const question of questions) { if (!question.text.trim()) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please fill in all question texts.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } if (question.answers.length < 2) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Each question must have at least two answers.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } // Validate question answers for (const answer of question.answers) { if (!answer.text.trim()) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please fill in all answer texts for all questions.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } } } } else { // Validate single question (traditional answers) if (answers.length < 2) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please add at least two answers.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } // Validate answers for (const answer of answers) { if (!answer.text.trim()) { setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: 'Please fill in all answer texts.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); return; } } } setSaving(true); const pollData = { poll_name: pollName, description, featured_image: featuredImage, answers, questions, settings, }; const action = pollId ? 'simpleform_update_poll' : 'simpleform_create_poll'; const data: any = { nonce: getNonce(), poll_data: pollData, }; if (pollId) { data.poll_id = pollId; } (wp as any).ajax.send(action, { data, success(response: any) { setSaving(false); setModalConfig({ isOpen: true, type: 'toast', title: 'Success', message: response.message || 'Poll saved successfully!', position: 'top-right', mode: 'success', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); // Don't redirect after save - stay on the same page }, error(error: any) { console.error('Error saving poll:', error); setSaving(false); setModalConfig({ isOpen: true, type: 'toast', title: 'Error', message: error.message || 'Failed to save poll. Please try again.', position: 'top-right', mode: 'error', onConfirm: () => {}, confirmText: 'OK', declineText: 'Cancel', }); setTimeout(closeModal, 3000); }, }); }; if (loading) { return (

Loading poll...

); } return (

{pollId ? 'Edit Poll' : 'Create Poll'}

setPollName(e.target.value)} placeholder="Enter your poll question" />