diff --git a/assets/translations/ko.json b/assets/translations/ko.json index a752af9..63b3234 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -71,5 +71,7 @@ "findIdPw": "아이디/비밀번호 찾기", "signUp": "회원가입", "pleaseEnterValidEmail": "! 올바른 이메일을 입력해주세요.", - "pleaseEnterValidPassword": "! 8자리 이상의 비밀번호를 입력하세요." + "pleaseEnterValidPassword": "! 8자리 이상의 비밀번호를 입력하세요.", + "man": "남자", + "woman": "여자" } diff --git a/lib/core/types/gender_type.dart b/lib/core/types/gender_type.dart new file mode 100644 index 0000000..a130ba3 --- /dev/null +++ b/lib/core/types/gender_type.dart @@ -0,0 +1,22 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:withu_app/core/core.dart'; + +/// 계약 타입 +@JsonEnum(valueField: 'serverKey') +enum GenderType with L10nKeyProvider { + man(l10nKey: 'man', serverKey: 'MAN'), + + woman(l10nKey: 'woman', serverKey: 'WOMAN'); + + @override + final String l10nKey; + + final String serverKey; + + const GenderType({ + required this.l10nKey, + required this.serverKey, + }); + + bool get isMan => this == GenderType.man; +} diff --git a/lib/core/types/login_type.dart b/lib/core/types/login_type.dart index 3db3140..ecea572 100644 --- a/lib/core/types/login_type.dart +++ b/lib/core/types/login_type.dart @@ -2,6 +2,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; @JsonEnum(valueField: 'serverKey') enum LoginType { + none(serverKey: ''), email(serverKey: 'EMAIL'), kakao(serverKey: 'KAKAO'), naver(serverKey: 'NAVER'), diff --git a/lib/core/utils/resource/string_res.dart b/lib/core/utils/resource/string_res.dart index b033a61..0997426 100644 --- a/lib/core/utils/resource/string_res.dart +++ b/lib/core/utils/resource/string_res.dart @@ -73,6 +73,8 @@ enum StringRes { signUp, pleaseEnterValidEmail, pleaseEnterValidPassword, + man, + woman, } extension StringResEx on StringRes { diff --git a/lib/feature/account/data/data_sources/dto/dto.dart b/lib/feature/account/data/data_sources/dto/dto.dart index fdde49e..3345305 100644 --- a/lib/feature/account/data/data_sources/dto/dto.dart +++ b/lib/feature/account/data/data_sources/dto/dto.dart @@ -1 +1,2 @@ export 'login/login.dart'; +export 'sign_up/sign_up.dart'; diff --git a/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.dart b/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.dart new file mode 100644 index 0000000..32334f6 --- /dev/null +++ b/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.dart @@ -0,0 +1,25 @@ +import 'package:withu_app/core/core.dart'; +import 'package:withu_app/core/types/gender_type.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'sign_up_request_dto.freezed.dart'; + +part 'sign_up_request_dto.g.dart'; + +part 'sign_up_request_dto.mock.dart'; + +@freezed +class SignUpRequestDto with _$SignUpRequestDto { + factory SignUpRequestDto({ + required String name, + required String birth, + required String cellPhoneNo, + required String loginId, // 이메일 + required String password, + required LoginType type, + required GenderType gender, + }) = _SignUpRequestDto; + + factory SignUpRequestDto.fromJson(Map json) => + _$SignUpRequestDtoFromJson(json); +} diff --git a/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.mock.dart b/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.mock.dart new file mode 100644 index 0000000..3dc01de --- /dev/null +++ b/lib/feature/account/data/data_sources/dto/sign_up/request/sign_up_request_dto.mock.dart @@ -0,0 +1,15 @@ +part of 'sign_up_request_dto.dart'; + +extension SignUpRequestDtoMock on SignUpRequestDto { + static SignUpRequestDto mock() { + return SignUpRequestDto( + name: '홍길동', + birth: '1993-06-04', + cellPhoneNo: '01049212480', + loginId: 'test@test.com', + password: '123qwe!@', + type: LoginType.email, + gender: GenderType.man, + ); + } +} diff --git a/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.dart b/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.dart new file mode 100644 index 0000000..a6c3141 --- /dev/null +++ b/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.dart @@ -0,0 +1,22 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'sign_up_response_dto.freezed.dart'; + +part 'sign_up_response_dto.g.dart'; + +part 'sign_up_response_dto.mock.dart'; + +@freezed +class SignUpResponseDto with _$SignUpResponseDto { + factory SignUpResponseDto({ + required bool status, + required String message, + String? userId, + String? loginId, + String? birthDate, + String? sessionId, + }) = _SignUpResponseDto; + + factory SignUpResponseDto.fromJson(Map json) => + _$SignUpResponseDtoFromJson(json); +} diff --git a/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.mock.dart b/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.mock.dart new file mode 100644 index 0000000..98f2c3f --- /dev/null +++ b/lib/feature/account/data/data_sources/dto/sign_up/response/sign_up_response_dto.mock.dart @@ -0,0 +1,21 @@ +part of 'sign_up_response_dto.dart'; + +extension SignUpResponseDtoMock on SignUpResponseDto { + static SignUpResponseDto successEmail() { + return SignUpResponseDto( + status: true, + message: "가입이 완료되었습니다", + userId: "1", + loginId: "test@test.com", + birthDate: "1993-06-04", + sessionId: "test-session-id", + ); + } + + static SignUpResponseDto fail() { + return SignUpResponseDto( + status: false, + message: "회원가입에 실패하셨습니다.", + ); + } +} diff --git a/lib/feature/account/data/data_sources/dto/sign_up/sign_up.dart b/lib/feature/account/data/data_sources/dto/sign_up/sign_up.dart new file mode 100644 index 0000000..f9e1813 --- /dev/null +++ b/lib/feature/account/data/data_sources/dto/sign_up/sign_up.dart @@ -0,0 +1,2 @@ +export 'request/sign_up_request_dto.dart'; +export 'response/sign_up_response_dto.dart'; diff --git a/lib/feature/account/data/data_sources/mock/mock_api.dart b/lib/feature/account/data/data_sources/mock/mock_api.dart index 497f7e4..4f24769 100644 --- a/lib/feature/account/data/data_sources/mock/mock_api.dart +++ b/lib/feature/account/data/data_sources/mock/mock_api.dart @@ -28,4 +28,23 @@ class AccountMockApi extends AccountApiImpl { return await super.login(requestData: requestData); } + + /// 회원가입 API + @override + FutureOr> signUp({ + required SignUpRequestDto requestData, + }) async { + /// Mock 응답 등록 + dioAdapter.onPost( + signUpPath, + (server) => server.reply( + 200, + SignUpResponseDtoMock.successEmail().toJson(), + delay: const Duration(seconds: 1), + ), + data: requestData.toJson(), + ); + + return await super.signUp(requestData: requestData); + } } diff --git a/lib/feature/account/data/data_sources/remote/api.dart b/lib/feature/account/data/data_sources/remote/api.dart index b92aaa3..dc464ad 100644 --- a/lib/feature/account/data/data_sources/remote/api.dart +++ b/lib/feature/account/data/data_sources/remote/api.dart @@ -9,8 +9,16 @@ abstract class AccountApi { /// 로그인 주소 late final loginPath = '$path/login'; + /// 회원가입 주소 + late final signUpPath = '$path/signUp'; + /// 로그인 API FutureOr> login({ required LoginRequestDto requestData, }); + + /// 회원가입 API + FutureOr> signUp({ + required SignUpRequestDto requestData, + }); } diff --git a/lib/feature/account/data/data_sources/remote/api_impl.dart b/lib/feature/account/data/data_sources/remote/api_impl.dart index c0eac95..6ab54fa 100644 --- a/lib/feature/account/data/data_sources/remote/api_impl.dart +++ b/lib/feature/account/data/data_sources/remote/api_impl.dart @@ -25,4 +25,22 @@ class AccountApiImpl extends AccountApi { (_) => ApiResponse.fail(FailResponse.error()), ); } + + /// 회원가입 API + @override + FutureOr> signUp({ + required SignUpRequestDto requestData, + }) async { + return network.dio + .post( + signUpPath, + data: requestData.toJson(), + ) + .then((response) => ApiResponse.success( + SignUpResponseDto.fromJson(response.data), + )) + .catchError( + (_) => ApiResponse.fail(FailResponse.error()), + ); + } } diff --git a/lib/feature/account/data/repository/repository_impl.dart b/lib/feature/account/data/repository/repository_impl.dart index 66ef593..4a860ad 100644 --- a/lib/feature/account/data/repository/repository_impl.dart +++ b/lib/feature/account/data/repository/repository_impl.dart @@ -31,10 +31,17 @@ class AccountRepositoryImpl implements AccountRepository { accountStorage.setSessionId(id: id); } - /// Session Id Storage 에 조회 @override Future getSessionId() async { return await accountStorage.getSessionId(); } + + /// 회원 가입 + @override + FutureOr> signUp({ + required SignUpRequestDto requestData, + }) async { + return await accountApi.signUp(requestData: requestData); + } } diff --git a/lib/feature/account/domain/entity/entity.dart b/lib/feature/account/domain/entity/entity.dart index fdde49e..3345305 100644 --- a/lib/feature/account/domain/entity/entity.dart +++ b/lib/feature/account/domain/entity/entity.dart @@ -1 +1,2 @@ export 'login/login.dart'; +export 'sign_up/sign_up.dart'; diff --git a/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.dart b/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.dart new file mode 100644 index 0000000..407296b --- /dev/null +++ b/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:withu_app/core/core.dart'; + +part 'sign_up_result_entity.freezed.dart'; + +part 'sign_up_result_entity.mock.dart'; + +@freezed +class SignUpResultEntity with _$SignUpResultEntity { + factory SignUpResultEntity({ + required bool status, + required String message, + @Default('') String name, + @Default(LoginType.none) LoginType type, + }) = _SignUpResultEntity; +} diff --git a/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.mock.dart b/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.mock.dart new file mode 100644 index 0000000..541eddb --- /dev/null +++ b/lib/feature/account/domain/entity/sign_up/result/sign_up_result_entity.mock.dart @@ -0,0 +1,21 @@ +part of 'sign_up_result_entity.dart'; + +extension SignUpResultEntityMock on SignUpResultEntity { + static SignUpResultEntity successEmail() { + return SignUpResultEntity( + status: true, + message: '', + name: '홍길동', + type: LoginType.email, + ); + } + + static SignUpResultEntity failure() { + return SignUpResultEntity( + status: false, + message: '회원가입에 실패하셨습니다.', + name: '', + type: LoginType.none, + ); + } +} diff --git a/lib/feature/account/domain/entity/sign_up/sign_up.dart b/lib/feature/account/domain/entity/sign_up/sign_up.dart new file mode 100644 index 0000000..2b055cd --- /dev/null +++ b/lib/feature/account/domain/entity/sign_up/sign_up.dart @@ -0,0 +1 @@ +export 'result/sign_up_result_entity.dart'; diff --git a/lib/feature/account/domain/repository/repository.dart b/lib/feature/account/domain/repository/repository.dart index 3b78505..1d3a64a 100644 --- a/lib/feature/account/domain/repository/repository.dart +++ b/lib/feature/account/domain/repository/repository.dart @@ -25,4 +25,9 @@ abstract class AccountRepository { /// Session Id Storage 에 조회 Future getSessionId() ; + + /// 회원 가입 + FutureOr> signUp({ + required SignUpRequestDto requestData, + }); } diff --git a/lib/feature/account/domain/usecase/sign_up/sign_up_usecase.dart b/lib/feature/account/domain/usecase/sign_up/sign_up_usecase.dart new file mode 100644 index 0000000..fb37dae --- /dev/null +++ b/lib/feature/account/domain/usecase/sign_up/sign_up_usecase.dart @@ -0,0 +1,12 @@ +import 'package:withu_app/feature/account/account.dart'; + +part 'sign_up_usecase_imple.dart'; + +abstract class SignUpUseCase { + final AccountRepository accountRepo; + + SignUpUseCase({required this.accountRepo}); + + /// 로그인 + Future exec({required LoginRequestEntity entity}); +} diff --git a/lib/feature/account/domain/usecase/sign_up/sign_up_usecase_imple.dart b/lib/feature/account/domain/usecase/sign_up/sign_up_usecase_imple.dart new file mode 100644 index 0000000..d8722c4 --- /dev/null +++ b/lib/feature/account/domain/usecase/sign_up/sign_up_usecase_imple.dart @@ -0,0 +1,13 @@ +part of 'sign_up_usecase.dart'; + +class SignUpUseCaseImpl implements SignUpUseCase { + @override + final AccountRepository accountRepo; + + SignUpUseCaseImpl({required this.accountRepo}); + + @override + Future exec({required LoginRequestEntity entity}) async { + return SignUpResultEntityMock.failure(); + } +} diff --git a/lib/feature/account/init_injections.dart b/lib/feature/account/init_injections.dart index 953171f..72ab28d 100644 --- a/lib/feature/account/init_injections.dart +++ b/lib/feature/account/init_injections.dart @@ -1,5 +1,6 @@ import 'package:withu_app/core/core.dart'; import 'package:withu_app/feature/account/account.dart'; +import 'package:withu_app/feature/account/domain/usecase/sign_up/sign_up_usecase.dart'; void initAccountInjections() { getIt.registerSingleton( @@ -16,10 +17,20 @@ void initAccountInjections() { accountStorage: getIt(), ), ); + + /// 로그인 getIt.registerSingleton( AccountUseCaseImpl(accountRepo: getIt()), ); getIt.registerFactory( () => LoginBloc(accountUseCase: getIt()), ); + + /// 회원가입 + getIt.registerSingleton( + SignUpUseCaseImpl(accountRepo: getIt()), + ); + getIt.registerFactory( + () => SignUpBloc(signUpUseCase: getIt()), + ); } diff --git a/lib/feature/account/presentation/bloc/bloc.dart b/lib/feature/account/presentation/bloc/bloc.dart index 675d5a3..b875a4c 100644 --- a/lib/feature/account/presentation/bloc/bloc.dart +++ b/lib/feature/account/presentation/bloc/bloc.dart @@ -1 +1,2 @@ export 'login/login_bloc.dart'; +export 'sign_up/sign_up_bloc.dart'; diff --git a/lib/feature/account/presentation/bloc/sign_up/sign_up_bloc.dart b/lib/feature/account/presentation/bloc/sign_up/sign_up_bloc.dart new file mode 100644 index 0000000..e5e0ee2 --- /dev/null +++ b/lib/feature/account/presentation/bloc/sign_up/sign_up_bloc.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:withu_app/core/utils/bloc/base_bloc.dart'; +import 'package:withu_app/feature/account/domain/usecase/sign_up/sign_up_usecase.dart'; + +part 'sign_up_event.dart'; + +part 'sign_up_state.dart'; + +part 'sign_up_bloc.freezed.dart'; + +class SignUpBloc extends BaseBloc { + final SignUpUseCase signUpUseCase; + + SignUpBloc({required this.signUpUseCase}) + : super( + SignUpState(status: BaseBlocStatus.initial()), + ); +} diff --git a/lib/feature/account/presentation/bloc/sign_up/sign_up_event.dart b/lib/feature/account/presentation/bloc/sign_up/sign_up_event.dart new file mode 100644 index 0000000..8129993 --- /dev/null +++ b/lib/feature/account/presentation/bloc/sign_up/sign_up_event.dart @@ -0,0 +1,2 @@ +part of 'sign_up_bloc.dart'; +sealed class SignUpEvent extends BaseBlocEvent {} diff --git a/lib/feature/account/presentation/bloc/sign_up/sign_up_state.dart b/lib/feature/account/presentation/bloc/sign_up/sign_up_state.dart new file mode 100644 index 0000000..ff9aae6 --- /dev/null +++ b/lib/feature/account/presentation/bloc/sign_up/sign_up_state.dart @@ -0,0 +1,13 @@ +part of 'sign_up_bloc.dart'; + + +@freezed +class SignUpState extends BaseBlocState with _$SignUpState { + factory SignUpState({ + /// 상태. + required BaseBlocStatus status, + + /// 다이얼로그 메시지 + @Default('') String message, + }) = _SignUpState; +} diff --git a/lib/feature/account/presentation/page/sign_up/sign_up_page.dart b/lib/feature/account/presentation/page/sign_up/sign_up_page.dart new file mode 100644 index 0000000..0a185dd --- /dev/null +++ b/lib/feature/account/presentation/page/sign_up/sign_up_page.dart @@ -0,0 +1,25 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:withu_app/core/core.dart'; +import 'package:withu_app/feature/account/account.dart'; + +class SignUpPage extends StatelessWidget { + const SignUpPage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(), + child: const SignUpPageContent(), + ); + } +} + +class SignUpPageContent extends StatelessWidget { + const SignUpPageContent({super.key}); + + @override + Widget build(BuildContext context) { + return const SizedBox(); + } +} diff --git a/test/feature/account/domain/usecase/sign_up/usecase_test.dart b/test/feature/account/domain/usecase/sign_up/usecase_test.dart index ab73b3a..d30207d 100644 --- a/test/feature/account/domain/usecase/sign_up/usecase_test.dart +++ b/test/feature/account/domain/usecase/sign_up/usecase_test.dart @@ -1 +1,3 @@ + + void main() {}