import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // ★ 숫자만 입력 위해 import 'package:http/http.dart' as http; import 'dart:convert'; // 서버 API import '../plugins/api.dart'; // 메인 페이지 import '../views/room/main_page.dart'; // 알람 모달창 import '../dialogs/response_dialog.dart'; class SurveyPage extends StatefulWidget { final String nickname; const SurveyPage({ Key? key, required this.nickname, }) : super(key: key); @override State createState() => _SurveyPageState(); } class _SurveyPageState extends State { // 현재 페이지 인덱스 (0~4) int _currentIndex = 0; // 전체 질문 목록 (5개 예시) List _questions = []; List _questionsOriginal = []; /// 사용자가 입력한 답변(5개) final List _answers = List.filled(5, null, growable: false); // 각 페이지별 라디오 선택 값 final Map _selectedRadioValue = {}; // 각 페이지별 텍스트필드 컨트롤러 final Map _textControllers = {}; @override void initState() { super.initState(); // 질문들 세팅 _questions = [ "Q1. ${widget.nickname}님의 나이는 어떻게 되나요?", "Q2. ${widget.nickname}님의 직업이 무엇인가요?", "Q3. ${widget.nickname}님은 올스코어 앱을 어떻게 알게 됐나요?", "Q4. ${widget.nickname}님은 올스코어 앱을 어디서 경험하셨나요?", "Q5. 올스코어를 계속 사용할 의사가 있나요?", ]; _questionsOriginal = [ "나이는 어떻게 되나요?", "직업이 무엇인가요?", "올스코어 앱을 어떻게 알게 됐나요?", "올스코어 앱을 어디서 경험하셨나요?", "올스코어를 계속 사용할 의사가 있나요?", ]; // 페이지마다 TextEditingController 초기화 for (int i = 0; i < _questions.length; i++) { _textControllers[i] = TextEditingController(); } } @override void dispose() { // TextController 정리 for (var ctrl in _textControllers.values) { ctrl.dispose(); } super.dispose(); } /// (좌측 상단) 설문 그만하기 Future _onExitSurvey() async { // 필요 시 "정말 나가시겠습니까?" 등 확인 모달 추가 가능 Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false, ); } /// 다음 버튼 void _onNext() { if (!_validateCurrentPage()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('값을 모두 입력해 주세요.')), ); return; } if (_currentIndex < _questions.length - 1) { setState(() { _currentIndex++; }); } } /// 이전 버튼 void _onPrev() { if (_currentIndex > 0) { setState(() { _currentIndex--; }); } } /// 제출하기 Future _onSubmit() async { // 마지막 페이지도 값 확인 if (!_validateCurrentPage()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('값을 모두 입력해 주세요.')), ); return; } // body: {"QNA": ["질문1","답변1","질문2","답변2", ... ]} final List qnaList = []; for (int i = 0; i < _questionsOriginal.length; i++) { qnaList.add(_questionsOriginal[i]); qnaList.add(_answers[i] ?? ''); } final requestBody = { "QNA": qnaList.toString(), }; print('requestBody: $requestBody'); try { final response = await Api.serverRequest(uri: '/survey/collect', body: requestBody); if (response['result'] == 'OK') { final resp = response['response'] ?? {}; if (resp['result'] == 'OK') { // 설문 제출 성공 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('설문이 제출되었습니다. 감사합니다!')), ); Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false); } else { showResponseDialog(context, '오류', '설문 제출 실패'); } } else { showResponseDialog(context, '오류', '설문 제출 실패'); } } catch (e) { showResponseDialog(context, '오류', '설문 제출 실패'); } } /// 현재 페이지 입력값이 유효한지 체크 + _answers에 저장 bool _validateCurrentPage() { final index = _currentIndex; String? answer; switch (index) { case 0: // 나이(숫자만) final txt = _textControllers[index]?.text.trim() ?? ''; if (txt.isEmpty) { return false; } answer = '$txt 세'; break; case 1: // 직업 final selected = _selectedRadioValue[index]; if (selected == null || selected.isEmpty) { return false; } answer = selected; break; case 2: // 앱 알게된 경로 final selected2 = _selectedRadioValue[index]; if (selected2 == null || selected2.isEmpty) { return false; } if (selected2 == '기타') { final etc = _textControllers[index]?.text.trim() ?? ''; if (etc.isEmpty) { return false; } answer = "기타($etc)"; } else { answer = selected2; } break; case 3: // 어디서 경험? final sel3 = _selectedRadioValue[index]; if (sel3 == null || sel3.isEmpty) { return false; } answer = sel3; break; case 4: // 계속 사용할 의사? final sel4 = _selectedRadioValue[index]; if (sel4 == null || sel4.isEmpty) { return false; } final comment = _textControllers[index]?.text.trim() ?? ''; answer = sel4 + (comment.isNotEmpty ? " / 의견: $comment" : ""); break; default: return false; } _answers[index] = answer; return true; } @override Widget build(BuildContext context) { final questionText = _questions[_currentIndex]; final pageNumber = _currentIndex + 1; final totalPage = _questions.length; return WillPopScope( onWillPop: () async { _onExitSurvey(); return false; }, child: Scaffold( appBar: AppBar( // 좌측 위 '설문 그만하기' 버튼 leadingWidth: 120, // 버튼 가로폭 살짝 넓힘 leading: TextButton( onPressed: _onExitSurvey, child: const Text( '설문 그만하기', style: TextStyle(color: Colors.white), ), ), title: Text('설문조사 ($pageNumber/$totalPage)'), backgroundColor: Colors.black, ), body: SingleChildScrollView( child: Container( alignment: Alignment.center, padding: const EdgeInsets.all(16), child: Column( // 중앙 정렬 mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 질문 Text( questionText, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 24), // 페이지별 UI _buildSurveyPage(_currentIndex), ], ), ), ), bottomNavigationBar: Container( color: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: [ if (_currentIndex > 0) Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.grey), onPressed: _onPrev, child: const Text('이전'), ), ), if (_currentIndex > 0) const SizedBox(width: 8), Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.black), onPressed: (_currentIndex < totalPage - 1) ? _onNext : _onSubmit, child: Text( (_currentIndex < totalPage - 1) ? '다음' : '제출하기', style: const TextStyle(color: Colors.white), ), ), ), ], ), ), ), ); } /// 페이지별 UI Widget _buildSurveyPage(int index) { switch (index) { case 0: // 나이 (숫자 입력) return Column( children: [ const Text('(예: 나이를 숫자로 입력해 주세요.)', textAlign: TextAlign.center), const SizedBox(height: 16), TextField( controller: _textControllers[index], keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly], // 숫자만 입력 textAlign: TextAlign.center, // 중앙정렬 decoration: const InputDecoration( labelText: '나이', border: OutlineInputBorder(), ), ), ], ); case 1: // 직업 final jobs = ['학생', '회사원', '전문직', '교수/교사', '기술직', '공무원', '예술/스포츠', '기타']; return Column( mainAxisSize: MainAxisSize.min, children: jobs.map((job) { return RadioListTile( title: Text(job, textAlign: TextAlign.center), value: job, groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ); }).toList(), ); case 2: // 알게된 경로 final paths = ['친구/지인 추천', '소셜 미디어', '블로그/온라인 리뷰', '학교나 직장', '기타']; return Column( mainAxisSize: MainAxisSize.min, children: [ ...paths.map((p) { return RadioListTile( title: Text(p, textAlign: TextAlign.center), value: p, groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ); }).toList(), if (_selectedRadioValue[index] == '기타') Padding( padding: const EdgeInsets.only(top: 8.0), child: TextField( controller: _textControllers[index], textAlign: TextAlign.center, decoration: const InputDecoration( labelText: '기타 내용을 입력해 주세요.', border: OutlineInputBorder(), ), ), ), ], ); case 3: // 어디서 경험? final places = ['가족과 함께', '친구들과 모임', '학교 교육 목적', '직장 동호회', '카페나 공공장소', '여행 중', '기타']; return Column( mainAxisSize: MainAxisSize.min, children: places.map((pl) { return RadioListTile( title: Text(pl, textAlign: TextAlign.center), value: pl, groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ); }).toList(), ); case 4: // 계속 사용할 의사? return Column( mainAxisSize: MainAxisSize.min, children: [ RadioListTile( title: const Text('네', textAlign: TextAlign.center), value: '네', groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ), RadioListTile( title: const Text('아니오', textAlign: TextAlign.center), value: '아니오', groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ), const SizedBox(height: 16), const Text('추가 의견이 있다면 자유롭게 작성해 주세요.', textAlign: TextAlign.center), const SizedBox(height: 8), TextField( controller: _textControllers[index], maxLines: 3, textAlign: TextAlign.center, decoration: const InputDecoration( hintText: 'ex) 불편사항, 개선 아이디어 등', border: OutlineInputBorder(), ), ), ], ); default: return const Text('설문 문항 오류', textAlign: TextAlign.center); } } }