import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // /* 숫자만 입력 위해 */ import 'package:http/http.dart' as http; import 'dart:convert'; // Server API (서버 API) import '../plugins/api.dart'; // Main Page (메인 페이지) import '../views/room/main_page.dart'; // Alert modal dialog (알람 모달창) 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 { int _currentIndex = 0; /* 현재 페이지 인덱스 (0~4) */ List _questions = []; /* 전체 질문 목록 (5개 예시) */ List _questionsOriginal = []; /* 질문의 한글 원본 목록 */ final List _answers = List.filled(5, null, growable: false); /* 사용자가 입력한 답변(5개) */ final Map _selectedRadioValue = {}; /* 각 페이지별 라디오 선택 값 */ final Map _textControllers = {}; /* 각 페이지별 텍스트필드 컨트롤러 */ @override void initState() { super.initState(); // Set questions (질문 설정) _questions = [ "Q1. How old are you, ${widget.nickname}?", /* "Q1. ${widget.nickname}님의 나이는 어떻게 되나요?" */ "Q2. What is your occupation, ${widget.nickname}?", /* "Q2. ${widget.nickname}님의 직업이 무엇인가요?" */ "Q3. How did you hear about ALLSCORE, ${widget.nickname}?", /* "Q3. ${widget.nickname}님은 올스코어 앱을 어떻게 알게 됐나요?" */ "Q4. Where have you experienced ALLSCORE, ${widget.nickname}?", /* "Q4. ${widget.nickname}님은 올스코어 앱을 어디서 경험하셨나요?" */ "Q5. Do you plan to keep using ALLSCORE?", /* "Q5. 올스코어를 계속 사용할 의사가 있나요?" */ ]; // Original Korean questions (원래 한글 질문 목록) _questionsOriginal = [ "나이는 어떻게 되나요?", "직업이 무엇인가요?", "올스코어 앱을 어떻게 알게 됐나요?", "올스코어 앱을 어디서 경험하셨나요?", "올스코어를 계속 사용할 의사가 있나요?", ]; // Initialize TextEditingController for each page // (페이지마다 TextEditingController 초기화) for (int i = 0; i < _questions.length; i++) { _textControllers[i] = TextEditingController(); } } @override void dispose() { // Dispose text controllers (텍스트 컨트롤러 정리) for (var ctrl in _textControllers.values) { ctrl.dispose(); } super.dispose(); } /// Exit the survey (설문 그만하기) Future _onExitSurvey() async { Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false, ); } /// Next button (다음 버튼) void _onNext() { if (!_validateCurrentPage()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Please fill in all required fields.' /* '값을 모두 입력해 주세요.' */)), ); return; } if (_currentIndex < _questions.length - 1) { setState(() { _currentIndex++; }); } } /// Previous button (이전 버튼) void _onPrev() { if (_currentIndex > 0) { setState(() { _currentIndex--; }); } } /// Submit (제출하기) Future _onSubmit() async { if (!_validateCurrentPage()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Please fill in all required fields.' /* '값을 모두 입력해 주세요.' */)), ); 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, }; try { final response = await Api.serverRequest(uri: '/survey/collect', body: requestBody); if (response['result'] == 'OK') { final resp = response['response'] ?? {}; if (resp['result'] == 'OK') { // Survey submitted (설문 제출 성공) ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Your survey has been submitted. Thank you!' /* '설문이 제출되었습니다. 감사합니다!' */)), ); Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false, ); } else { showResponseDialog(context, 'Error' /* 오류 */, 'Failed to submit the survey.' /* '설문 제출 실패' */); } } else { showResponseDialog(context, 'Error' /* 오류 */, 'Failed to submit the survey.' /* '설문 제출 실패' */); } } catch (e) { showResponseDialog(context, 'Error' /* 오류 */, 'Failed to submit the survey.' /* '설문 제출 실패' */); } } /// Validate current page input (현재 페이지 입력값이 유효한지 체크) bool _validateCurrentPage() { final index = _currentIndex; String? answer; switch (index) { case 0: // Age (나이) final txt = _textControllers[index]?.text.trim() ?? ''; if (txt.isEmpty) { return false; } answer = '$txt yrs old' /* '$txt 세' */; break; case 1: // Occupation (직업) final selected = _selectedRadioValue[index]; if (selected == null || selected.isEmpty) { return false; } answer = selected; break; case 2: // How did you hear about ALLSCORE? (앱 알게된 경로) final selected2 = _selectedRadioValue[index]; if (selected2 == null || selected2.isEmpty) { return false; } if (selected2 == 'Others' /* '기타' */) { final etc = _textControllers[index]?.text.trim() ?? ''; if (etc.isEmpty) { return false; } answer = "Others($etc)" /* "기타($etc)" */; } else { answer = selected2; } break; case 3: // Where have you experienced? (어디서 경험?) final sel3 = _selectedRadioValue[index]; if (sel3 == null || sel3.isEmpty) { return false; } answer = sel3; break; case 4: // Will you continue using ALLSCORE? (계속 사용할 의사?) final sel4 = _selectedRadioValue[index]; if (sel4 == null || sel4.isEmpty) { return false; } final comment = _textControllers[index]?.text.trim() ?? ''; answer = sel4 + (comment.isNotEmpty ? " / comment: $comment" /* "/ 의견: $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( 'Stop Survey' /* '설문 그만하기' */, style: TextStyle(color: Colors.white), ), ), title: Text('Survey ($pageNumber/$totalPage)' /* '설문조사 ($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: [ // Question text (질문) Text( questionText, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 24), // Page-specific UI (페이지별 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('Previous' /* '이전' */), ), ), 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) ? 'Next' /* 다음 */ : 'Submit' /* 제출하기 */, style: const TextStyle(color: Colors.white), ), ), ), ], ), ), ), ); } /// Build UI for each page (페이지별 UI) Widget _buildSurveyPage(int index) { switch (index) { case 0: // Age input (나이 입력) return Column( children: [ const Text( '(e.g. Please enter your age in digits.)' /* '(예: 나이를 숫자로 입력해 주세요.)' */, textAlign: TextAlign.center, ), const SizedBox(height: 16), TextField( controller: _textControllers[index], keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly], textAlign: TextAlign.center, decoration: const InputDecoration( labelText: 'Age' /* '나이' */, border: OutlineInputBorder(), ), ), ], ); case 1: // Occupation (직업) final jobs = [ 'Student' /* '학생' */, 'Office Worker' /* '회사원' */, 'Professional' /* '전문직' */, 'Professor/Teacher' /* '교수/교사' */, 'Technical' /* '기술직' */, 'Government Official' /* '공무원' */, 'Art/Sports' /* '예술/스포츠' */, 'Others' /* '기타' */, ]; 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: // How did you hear about ALLSCORE? (앱 알게된 경로) final paths = [ 'Friend/Acquaintance' /* '친구/지인 추천' */, 'Social Media' /* '소셜 미디어' */, 'Blog/Online Review' /* '블로그/온라인 리뷰' */, 'School/Workplace' /* '학교나 직장' */, 'Others' /* '기타' */, ]; 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] == 'Others' /* '기타' */) Padding( padding: const EdgeInsets.only(top: 8.0), child: TextField( controller: _textControllers[index], textAlign: TextAlign.center, decoration: const InputDecoration( labelText: 'Please specify.' /* '기타 내용을 입력해 주세요.' */, border: OutlineInputBorder(), ), ), ), ], ); case 3: // Where have you experienced ALLSCORE? (어디서 경험?) final places = [ 'With Family' /* '가족과 함께' */, 'With Friends' /* '친구들과 모임' */, 'School (for education)' /* '학교 교육 목적' */, 'Work Club' /* '직장 동호회' */, 'Cafe or Public Space' /* '카페나 공공장소' */, 'Travel' /* '여행 중' */, 'Others' /* '기타' */, ]; 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: // Will you continue using ALLSCORE? (계속 사용할 의사?) return Column( mainAxisSize: MainAxisSize.min, children: [ RadioListTile( title: const Text('Yes' /* '네' */, textAlign: TextAlign.center), value: 'Yes' /* '네' */, groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ), RadioListTile( title: const Text('No' /* '아니오' */, textAlign: TextAlign.center), value: 'No' /* '아니오' */, groupValue: _selectedRadioValue[index], onChanged: (val) { setState(() { _selectedRadioValue[index] = val!; }); }, ), const SizedBox(height: 16), const Text( 'If you have any additional comments, feel free to write them here.' /* '추가 의견이 있다면 자유롭게 작성해 주세요.' */, textAlign: TextAlign.center, ), const SizedBox(height: 8), TextField( controller: _textControllers[index], maxLines: 3, textAlign: TextAlign.center, decoration: const InputDecoration( hintText: 'e.g. inconveniences, improvement ideas, etc.' /* 'ex) 불편사항, 개선 아이디어 등' */, border: OutlineInputBorder(), ), ), ], ); default: return const Text( 'Survey question error' /* '설문 문항 오류' */, textAlign: TextAlign.center ); } } }