297 lines
9.9 KiB
TypeScript
297 lines
9.9 KiB
TypeScript
import React, { useState } from 'react';
|
||
import axios from 'axios';
|
||
import './MobileForm.css';
|
||
|
||
interface PsychotypeAnswers {
|
||
unfamiliar_env?: string;
|
||
stress_reaction?: string;
|
||
group_role?: string;
|
||
risk_taking?: string;
|
||
}
|
||
|
||
interface FormData {
|
||
age?: number;
|
||
gender?: string;
|
||
diagnosis_type?: string[];
|
||
psychotype_answers?: PsychotypeAnswers;
|
||
}
|
||
|
||
const MobileForm: React.FC = () => {
|
||
const [formData, setFormData] = useState<FormData>({
|
||
diagnosis_type: [],
|
||
psychotype_answers: {}
|
||
});
|
||
const [submitting, setSubmitting] = useState(false);
|
||
const [success, setSuccess] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
const handlePsychotypeAnswer = (question: keyof PsychotypeAnswers, value: string) => {
|
||
setFormData(prev => ({
|
||
...prev,
|
||
psychotype_answers: {
|
||
...prev.psychotype_answers,
|
||
[question]: value
|
||
}
|
||
}));
|
||
};
|
||
|
||
const isPsychotypeSelected = (question: keyof PsychotypeAnswers, value: string) => {
|
||
return formData.psychotype_answers?.[question] === value;
|
||
};
|
||
|
||
const validateForm = (): string | null => {
|
||
if (!formData.age || formData.age < 0 || formData.age > 120) {
|
||
return 'Укажите корректный возраст';
|
||
}
|
||
if (!formData.gender) {
|
||
return 'Выберите пол';
|
||
}
|
||
return null;
|
||
};
|
||
|
||
const handleSubmit = async () => {
|
||
const validationError = validateForm();
|
||
if (validationError) {
|
||
setError(validationError);
|
||
return;
|
||
}
|
||
|
||
setSubmitting(true);
|
||
setError(null);
|
||
|
||
try {
|
||
const response = await axios.post('/api/v1/cases', formData);
|
||
console.log('Case created:', response.data);
|
||
setSuccess(true);
|
||
|
||
setTimeout(() => {
|
||
setFormData({
|
||
diagnosis_type: [],
|
||
psychotype_answers: {}
|
||
});
|
||
setSuccess(false);
|
||
}, 2000);
|
||
} catch (err: any) {
|
||
setError(err.response?.data?.detail || 'Ошибка при создании карточки');
|
||
console.error('Submit error:', err);
|
||
} finally {
|
||
setSubmitting(false);
|
||
}
|
||
};
|
||
|
||
if (success) {
|
||
return (
|
||
<div className="mobile-form">
|
||
<div className="success-message">
|
||
<div className="success-icon">✓</div>
|
||
<h2>Карточка создана!</h2>
|
||
<p>Данные успешно сохранены</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="mobile-form">
|
||
<h1>Карточка пропавшего</h1>
|
||
|
||
{error && (
|
||
<div className="error-banner">
|
||
{error}
|
||
</div>
|
||
)}
|
||
|
||
<section className="form-section">
|
||
<h2>Основная информация</h2>
|
||
|
||
<div className="form-group">
|
||
<label>Возраст *</label>
|
||
<input
|
||
type="number"
|
||
placeholder="Лет"
|
||
value={formData.age || ''}
|
||
onChange={(e) => setFormData({...formData, age: parseInt(e.target.value)})}
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div className="form-group">
|
||
<label>Пол *</label>
|
||
<div className="button-group">
|
||
<button
|
||
type="button"
|
||
className={formData.gender === 'male' ? 'selected' : ''}
|
||
onClick={() => setFormData({...formData, gender: 'male'})}
|
||
>
|
||
Мужской
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={formData.gender === 'female' ? 'selected' : ''}
|
||
onClick={() => setFormData({...formData, gender: 'female'})}
|
||
>
|
||
Женский
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section className="form-section">
|
||
<h2>Диагнозы (если есть)</h2>
|
||
<div className="checkbox-group">
|
||
{['РАС', 'эпилепсия', 'СДВГ', 'деменция'].map(diagnosis => (
|
||
<label key={diagnosis} className="checkbox-label">
|
||
<input
|
||
type="checkbox"
|
||
checked={formData.diagnosis_type?.includes(diagnosis)}
|
||
onChange={(e) => {
|
||
const current = formData.diagnosis_type || [];
|
||
setFormData({
|
||
...formData,
|
||
diagnosis_type: e.target.checked
|
||
? [...current, diagnosis]
|
||
: current.filter(d => d !== diagnosis)
|
||
});
|
||
}}
|
||
/>
|
||
{diagnosis}
|
||
</label>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
<section className="form-section psychotype-section">
|
||
<div className="section-header">
|
||
<h2>Поведение ребёнка (спросить родителей)</h2>
|
||
<p className="section-subtitle">Помогает уточнить зону поиска</p>
|
||
</div>
|
||
|
||
<div className="psychotype-question">
|
||
<label className="question-label">Как ведёт себя в незнакомой обстановке?</label>
|
||
<div className="button-group-vertical">
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('unfamiliar_env', 'explore') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('unfamiliar_env', 'explore')}
|
||
>
|
||
Активно исследует
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('unfamiliar_env', 'wait') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('unfamiliar_env', 'wait')}
|
||
>
|
||
Ждёт
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('unfamiliar_env', 'freeze') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('unfamiliar_env', 'freeze')}
|
||
>
|
||
Замирает
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('unfamiliar_env', 'panic') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('unfamiliar_env', 'panic')}
|
||
>
|
||
Паникует
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="psychotype-question">
|
||
<label className="question-label">Реакция на неудачи?</label>
|
||
<div className="button-group-vertical">
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('stress_reaction', 'active') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('stress_reaction', 'active')}
|
||
>
|
||
Злится, кричит
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('stress_reaction', 'cry') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('stress_reaction', 'cry')}
|
||
>
|
||
Плачет, замыкается
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('stress_reaction', 'calm') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('stress_reaction', 'calm')}
|
||
>
|
||
Спокойно ищет выход
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="psychotype-question">
|
||
<label className="question-label">Лидер или ведомый?</label>
|
||
<div className="button-group-vertical">
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('group_role', 'leader') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('group_role', 'leader')}
|
||
>
|
||
Лидер
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('group_role', 'sometimes') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('group_role', 'sometimes')}
|
||
>
|
||
Иногда
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('group_role', 'follower') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('group_role', 'follower')}
|
||
>
|
||
Всегда ведомый
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="psychotype-question">
|
||
<label className="question-label">Любит рисковать?</label>
|
||
<div className="button-group-vertical">
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('risk_taking', 'high') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('risk_taking', 'high')}
|
||
>
|
||
Очень
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsycotypeSelected('risk_taking', 'medium') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('risk_taking', 'medium')}
|
||
>
|
||
Иногда
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className={'psychotype-btn ' + (isPsychotypeSelected('risk_taking', 'low') ? 'selected' : '')}
|
||
onClick={() => handlePsychotypeAnswer('risk_taking', 'low')}
|
||
>
|
||
Нет, осторожный
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<button
|
||
className="submit-btn"
|
||
onClick={handleSubmit}
|
||
disabled={submitting}
|
||
>
|
||
{submitting ? 'Создание...' : 'Создать карточку'}
|
||
</button>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default MobileForm;
|