diff --git a/front/lib/main.dart b/front/lib/main.dart index 3157de2..3158d63 100644 --- a/front/lib/main.dart +++ b/front/lib/main.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:figma_to_flutter/figma_to_flutter.dart'; import 'package:http/http.dart' as http; +import 'dart:convert'; void main() { runApp(const MyApp()); @@ -33,39 +33,65 @@ class _LoginScreenState extends State { final TextEditingController _idController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); + Future _login() async { final String id = _idController.text.trim(); final String password = _passwordController.text.trim(); - if (id.isEmpty || password.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('아이디와 비밀번호를 입력해주세요.')), - ); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('아이디와 비밀번호를 입력해주세요.')), + ); + } return; } try { - final Uri url = Uri.parse('http://localhost:3000/login'); // API 주소 - final response = await http.get(url, headers: { - 'Content-Type': 'application/json', - }); + final Uri url = Uri.parse('http://localhost:8081/user/login'); // 로그인 API 주소 + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode({'id': id, 'pw': password}), + ); if (response.statusCode == 200) { - // 성공 처리 - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('로그인 성공!')), - ); + final responseData = json.decode(response.body); + if (responseData['ok'] == true) { + final String userName = responseData['name']; + final String userId = responseData['id']; + final List cookie = responseData['cookie']; + if (mounted) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => NavigationBarScreen( + userName: userName, + userId: userId, + cookie: cookie, + ), + ), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('로그인 실패')), + ); + } + } } else { - // 실패 처리 + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('로그인 실패: ${response.body}')), + ); + } + } + } catch (e) { + if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('로그인 실패: ${response.body}')), + SnackBar(content: Text('오류 발생: $e')), ); } - } catch (e) { - // 예외 처리 - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('오류 발생: $e')), - ); } } @@ -148,3 +174,160 @@ class _LoginScreenState extends State { ); } } + +class NavigationBarScreen extends StatefulWidget { + final String userName; + final String userId; + final List cookie; + + const NavigationBarScreen({ + super.key, + required this.userName, + required this.userId, required this.cookie, + }); + + @override + _NavigationBarScreenState createState() => _NavigationBarScreenState(); +} + +class _NavigationBarScreenState extends State { + int _currentIndex = 3; + + late final List _pages; + + + @override + void initState() { + super.initState(); + _pages = [ + const Center(child: Text('홈 화면')), + const Center(child: Text('버스 화면')), + const Center(child: Text('지도 화면')), + UserInfoScreen(userName: widget.userName, userId: widget.userId, cookie: widget.cookie,), + ]; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _pages[_currentIndex], + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + label: '홈', + ), + BottomNavigationBarItem( + icon: Icon(Icons.directions_bus), + label: '버스', + ), + BottomNavigationBarItem( + icon: Icon(Icons.map), + label: '지도', + ), + BottomNavigationBarItem( + icon: Icon(Icons.person), + label: '내 정보', + ), + ], + ), + ); + } +} + +class UserInfoScreen extends StatelessWidget { + final String userName; + final String userId; + final List cookie; + + const UserInfoScreen({ + super.key, + required this.userName, + required this.userId, + required this.cookie, + }); + + Future _logout(BuildContext context) async { + try { + final Uri url = Uri.parse('http://localhost:8081/user/logout'); // 로그아웃 API 주소 + final response = await http.post( + url, + headers: { + 'Content-Type': 'application/json', + }, + body: json.encode({'id': userId, + 'cookie': cookie.join('; ')}), + ); + + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + if (responseData['ok'] == true) { + if (context.mounted) { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const LoginScreen()), + (route) => false, + ); + } + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('로그아웃 실패')), + ); + } + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('로그아웃 실패: ${response.body}')), + ); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('오류 발생: $e')), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('내 정보'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.account_circle, size: 100, color: Colors.black54), + const SizedBox(height: 20), + Text( + userName, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 10), + Text( + '학번: $userId', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 30), + ElevatedButton( + onPressed: () => _logout(context), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + ), + child: const Text( + '로그아웃', + style: TextStyle(color: Colors.white), + ), + ), + ], + ), + ), + ); + } +} + diff --git a/front/pubspec.lock b/front/pubspec.lock index f67801a..5621c10 100644 --- a/front/pubspec.lock +++ b/front/pubspec.lock @@ -1,6 +1,35 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + url: "https://pub.dev" + source: hosted + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + url: "https://pub.dev" + source: hosted + version: "6.7.0" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" async: dependency: transitive description: @@ -17,6 +46,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" characters: dependency: transitive description: @@ -33,6 +86,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" collection: dependency: transitive description: @@ -41,6 +102,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" crypto: dependency: transitive description: @@ -57,6 +126,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" + url: "https://pub.dev" + source: hosted + version: "2.3.7" fake_async: dependency: transitive description: @@ -81,6 +158,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.6" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -107,6 +200,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.6" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" google_fonts: dependency: transitive description: @@ -163,6 +264,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" matcher: dependency: transitive description: @@ -187,6 +304,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" + mockito: + dependency: "direct dev" + description: + name: mockito + sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" + url: "https://pub.dev" + source: hosted + version: "5.4.4" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -259,11 +392,27 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" source_span: dependency: transitive description: @@ -336,6 +485,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" web: dependency: transitive description: @@ -352,6 +509,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.5.1 <4.0.0" flutter: ">=3.24.0" diff --git a/front/pubspec.yaml b/front/pubspec.yaml index 29c1b28..3b5ec2b 100644 --- a/front/pubspec.yaml +++ b/front/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + mockito: ^5.0.16 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is diff --git a/front/test/widget_test.dart b/front/test/widget_test.dart index 6d28abc..6574f42 100644 --- a/front/test/widget_test.dart +++ b/front/test/widget_test.dart @@ -11,20 +11,24 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:front/main.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { + testWidgets('Login screen test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(const MyApp()); - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); + // Verify that the login screen is displayed. + expect(find.text('로그인'), findsOneWidget); + expect(find.text('아이디'), findsOneWidget); + expect(find.text('비밀번호'), findsOneWidget); - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); + // Enter text into the text fields. + await tester.enterText(find.byType(TextField).at(0), 'test_id'); + await tester.enterText(find.byType(TextField).at(1), 'test_password'); + + // Tap the login button. + await tester.tap(find.text('로그인')); await tester.pump(); - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); + // Verify that the login request is made and the next screen is displayed. + // (This part may require mocking the HTTP request and response) }); }