import React, { useEffect, useMemo, useState } from 'react'; import { ProfileQuestion, ProfileQuestionInputType, ProfileQuestionOption, ProfileQuestionUpsertData, userService } from '../services/membershipService'; interface AdminProfileQuestionManagerProps { onQuestionsChanged?: () => void; } const INPUT_TYPES: ProfileQuestionInputType[] = ['text', 'number', 'boolean', 'date', 'select']; const optionsToText = (options: ProfileQuestionOption[] | null | undefined): string => { if (!options || options.length === 0) { return ''; } return options.map((option) => `${option.label}|${option.value}`).join('\n'); }; const textToOptions = (value: string): ProfileQuestionOption[] => { return value .split('\n') .map((line) => line.trim()) .filter(Boolean) .map((line) => { const [labelPart, valuePart] = line.split('|'); const label = (labelPart || '').trim(); const optionValue = (valuePart || labelPart || '').trim(); return { label, value: optionValue }; }) .filter((option) => option.label.length > 0 && option.value.length > 0); }; const AdminProfileQuestionManager: React.FC = ({ onQuestionsChanged }) => { const [questions, setQuestions] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [editingQuestionId, setEditingQuestionId] = useState(null); const [listSearch, setListSearch] = useState(''); const emptyForm: ProfileQuestionUpsertData = { key: '', label: '', help_text: '', input_type: 'text', placeholder: '', options: null, is_required: false, is_active: true, admin_only_edit: false, display_order: 0, depends_on_question_id: null, depends_on_value: null }; const [formData, setFormData] = useState(emptyForm); const [optionsText, setOptionsText] = useState(''); const loadQuestions = async () => { try { setLoading(true); const data = await userService.getAdminProfileQuestions(true); setQuestions(data); setError(null); } catch (err: any) { setError(err.response?.data?.detail || err.message || 'Failed to load questions'); } finally { setLoading(false); } }; useEffect(() => { loadQuestions(); }, []); const dependencyCandidates = useMemo(() => { return questions.filter((question) => question.id !== editingQuestionId); }, [questions, editingQuestionId]); const selectedDependencyQuestion = useMemo(() => { if (!formData.depends_on_question_id) { return null; } return questions.find((question) => question.id === formData.depends_on_question_id) || null; }, [questions, formData.depends_on_question_id]); const filteredQuestions = useMemo(() => { const term = listSearch.trim().toLowerCase(); if (!term) { return questions; } return questions.filter((question) => question.label.toLowerCase().includes(term) || question.key.toLowerCase().includes(term) ); }, [questions, listSearch]); const resetForm = () => { setFormData(emptyForm); setOptionsText(''); setEditingQuestionId(null); }; const handleEdit = (question: ProfileQuestion) => { setEditingQuestionId(question.id); setFormData({ key: question.key, label: question.label, help_text: question.help_text, input_type: question.input_type, placeholder: question.placeholder, options: question.options, is_required: question.is_required, is_active: question.is_active, admin_only_edit: question.admin_only_edit, display_order: question.display_order, depends_on_question_id: question.depends_on_question_id, depends_on_value: question.depends_on_value }); setOptionsText(optionsToText(question.options)); }; const handleSave = async () => { setSaving(true); setError(null); try { const payload: ProfileQuestionUpsertData = { ...formData, key: formData.key.trim(), label: formData.label.trim(), help_text: formData.help_text?.trim() || null, placeholder: formData.placeholder?.trim() || null, depends_on_value: formData.depends_on_value?.trim() || null, options: formData.input_type === 'select' ? textToOptions(optionsText) : null, }; if (editingQuestionId) { await userService.updateAdminProfileQuestion(editingQuestionId, payload); } else { await userService.createAdminProfileQuestion(payload); } await loadQuestions(); resetForm(); onQuestionsChanged?.(); } catch (err: any) { setError(err.response?.data?.detail || err.message || 'Failed to save question'); } finally { setSaving(false); } }; const handleDeactivate = async (questionId: number) => { if (!window.confirm('Deactivate this question? Existing answers are kept.')) { return; } try { await userService.deactivateAdminProfileQuestion(questionId); await loadQuestions(); onQuestionsChanged?.(); } catch (err: any) { setError(err.response?.data?.detail || err.message || 'Failed to deactivate question'); } }; return (

Profile Questions (Admin)

Manage the set of profile questions users can answer. You can add follow-up questions with dependencies.

{error &&
{error}
}
setFormData((prev) => ({ ...prev, key: event.target.value }))} style={{ padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }} /> setFormData((prev) => ({ ...prev, label: event.target.value }))} style={{ padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }} />