Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions lib/presentation/sign_up/provider/sign_up_provider.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import 'package:grimity/app/base/result.dart';
import 'package:grimity/app/enum/grimity.enum.dart';
import 'package:grimity/app/extension/string_extension.dart';
import 'package:grimity/app/service/toast_service.dart';
import 'package:grimity/app/util/device_info_util.dart';
import 'package:grimity/app/util/validator_util.dart';
import 'package:grimity/domain/dto/auth_request_params.dart';
import 'package:grimity/domain/entity/user.dart';
import 'package:grimity/domain/usecase/auth_usecases.dart';
import 'package:grimity/domain/usecase/users_usecase.dart';
import 'package:grimity/presentation/common/provider/auth_credential_provider.dart';
import 'package:grimity/presentation/common/provider/user_auth_provider.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'sign_up_provider.g.dart';

enum SignUpViewState { nickname, url }
enum SignUpViewState { nickname, url, welcome }

/// 회원가입 상태를 관리하는 프로바이더
@riverpod
Expand Down Expand Up @@ -51,7 +51,7 @@ class SignUp extends _$SignUp {
state = state.copyWith(
isNicknameChecking: false,
signUpViewState: SignUpViewState.url,
nicknameState: GrimityTextFieldState.normal,
nicknameState: GrimityTextFieldState.success,
);
},
onFailure: (error) {
Expand Down Expand Up @@ -82,7 +82,10 @@ class SignUp extends _$SignUp {
return;
}

state = state.copyWith(isUrlChecking: false, urlState: GrimityTextFieldState.normal);
state = state.copyWith(
isUrlChecking: false,
urlState: GrimityTextFieldState.success,
);
} catch (e) {
state = state.copyWith(
isUrlChecking: false,
Expand All @@ -93,14 +96,14 @@ class SignUp extends _$SignUp {
}

/// 회원가입 진행
Future<Result<User>> signUp(WidgetRef ref) async {
Future<void> signUp(WidgetRef ref) async {
if (!isInformationValid()) {
return Result.failure(Exception('회원가입 정보가 유효하지 않습니다.'));
return ToastService.showFailure('회원가입 정보가 유효하지 않아요');
}

final authCredential = ref.read(authCredentialProvider);
if (authCredential.provider == null) {
return Result.failure(Exception('OAuth 인증 정보가 없습니다.'));
return ToastService.showFailure('OAuth 인증 정보가 없어요');
}

final param = RegisterRequestParam(
Expand All @@ -111,7 +114,19 @@ class SignUp extends _$SignUp {
url: state.url,
);

return await completeRegisterUseCase.execute(param, this.ref);
final result = await completeRegisterUseCase.execute(param, this.ref);

result.fold(
onSuccess: (user) {
// 회원 가입 이후 UserAuthProvider User 갱신
ref.read(userAuthProvider.notifier).setUser(user);

state = state.copyWith(signUpViewState: SignUpViewState.welcome);
},
onFailure: (error) {
ToastService.showFailure('회원가입에 실패했어요');
},
);
}

/// 유효성 검사
Expand All @@ -120,6 +135,10 @@ class SignUp extends _$SignUp {
ValidatorUtil.isAvailableUrl(state.url) &&
state.isTermsAgreed;
}

void setSignUpState(SignUpViewState newViewState) {
state = state.copyWith(signUpViewState: newViewState);
}
}

/// 회원가입 상태 클래스
Expand Down
8 changes: 2 additions & 6 deletions lib/presentation/sign_up/sign_up_page.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'package:flutter/material.dart';
import 'package:grimity/presentation/sign_up/view/sign_up_view.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_check_nick_button.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_check_url_button.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_nickname_text_field.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_term_agree_widget.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_term_agree.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_url_text_field.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

Expand All @@ -15,9 +13,7 @@ class SignUpPage extends ConsumerWidget {
return const SignUpView(
nicknameTextField: SignUpNicknameTextField(),
urlTextField: SignUpUrlTextField(),
termAgreeWidget: SignUpTermAgreeWidget(),
checkNicknameButton: SignUpCheckNickButton(),
registerButton: SignUpCheckUrlButton(),
termAgreeWidget: SignUpTermAgree(),
);
}
}
59 changes: 27 additions & 32 deletions lib/presentation/sign_up/view/sign_up_nickname_view.dart
Original file line number Diff line number Diff line change
@@ -1,50 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gap/gap.dart';
import 'package:grimity/app/config/app_color.dart';
import 'package:grimity/app/config/app_typeface.dart';
import 'package:gds/gds.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_subtitle.dart';

class SignUpNicknameView extends ConsumerWidget {
const SignUpNicknameView({
super.key,
required this.nicknameTextField,
required this.termAgreeWidget,
required this.checkNicknameButton,
});

final Widget nicknameTextField;
final Widget termAgreeWidget;
final Widget checkNicknameButton;

@override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_SignUpDescription(),
const Gap(24),
nicknameTextField,
const Gap(15),
termAgreeWidget,
const Spacer(),
checkNicknameButton,
],
);
}
}

class _SignUpDescription extends StatelessWidget {
const _SignUpDescription();

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('활동명을 정해주세요', style: AppTypeface.title3),
Gap(8),
Text('가입 후 활동명 변경이 가능해요', style: AppTypeface.label2.copyWith(color: AppColor.gray700)),
],
return SingleChildScrollView(
padding: EdgeInsets.only(
top: context.isMobile ? GdsSpacing.spacing40 : GdsSpacing.spacing48,
left: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
right: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
bottom: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: GdsSpacing.spacing40,
children: [
SignUpSubtitle(
subtitle: '활동명을 정해주세요',
description: '작품과 함께 그리미티에서 기억될 이름이에요',
),
Column(
mainAxisSize: MainAxisSize.min,
spacing: GdsSpacing.spacing12,
children: [
nicknameTextField,
termAgreeWidget,
],
),
],
),
);
}
}
57 changes: 31 additions & 26 deletions lib/presentation/sign_up/view/sign_up_url_view.dart
Original file line number Diff line number Diff line change
@@ -1,40 +1,45 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:grimity/app/config/app_color.dart';
import 'package:grimity/app/config/app_typeface.dart';
import 'package:gds/gds.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_subtitle.dart';

class SignUpUrlView extends StatelessWidget {
const SignUpUrlView({super.key, required this.nickname, required this.urlTextField, required this.registerButton});
const SignUpUrlView({
super.key,
required this.nickname,
required this.urlTextField,
});

final String nickname;
final Widget urlTextField;
final Widget registerButton;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [_SignUpDescription(nickname: nickname), const Gap(4), urlTextField, const Spacer(), registerButton],
);
}
}

class _SignUpDescription extends StatelessWidget {
const _SignUpDescription({required this.nickname});
final colors = context.gdsColors;

final String nickname;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('$nickname님,\n프로필 URL을 설정해주세요', style: AppTypeface.title3),
Gap(8),
Text('단 하나뿐인 프로필 주소로 사용되어요', style: AppTypeface.label2.copyWith(color: AppColor.gray700)),
Gap(24),
Text('www.grimity.com/', style: AppTypeface.label2.copyWith(color: AppColor.gray600)),
],
return SingleChildScrollView(
padding: EdgeInsets.only(
top: context.isMobile ? GdsSpacing.spacing40 : GdsSpacing.spacing48,
left: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
right: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
bottom: context.isMobile ? GdsSpacing.spacing16 : GdsSpacing.spacing40,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SignUpSubtitle(
subtitle: '프로필 URL을 정해주세요',
description: '단 하나뿐인 프로필 주소로 사용돼요',
),
Gap(GdsSpacing.spacing40),
Text(
'www.grimity.com/',
style: GdsTypography.title2.copyWith(color: colors.text.grayBold),
),
Gap(GdsSpacing.spacing12),
urlTextField,
],
),
);
}
}
103 changes: 56 additions & 47 deletions lib/presentation/sign_up/view/sign_up_view.dart
Original file line number Diff line number Diff line change
@@ -1,75 +1,84 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gap/gap.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gds/gds.dart';
import 'package:go_router/go_router.dart';
import 'package:grimity/app/config/app_router.dart';
import 'package:grimity/presentation/sign_up/provider/sign_up_provider.dart';
import 'package:grimity/presentation/sign_up/view/sign_up_nickname_view.dart';
import 'package:grimity/presentation/sign_up/view/sign_up_url_view.dart';
import 'package:grimity/presentation/sign_up/view/sign_up_welcome_view.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_app_bar.dart';
import 'package:grimity/presentation/sign_up/widget/sign_up_button.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

class SignUpView extends ConsumerWidget {
class SignUpView extends HookConsumerWidget {
const SignUpView({
super.key,
required this.nicknameTextField,
required this.urlTextField,
required this.termAgreeWidget,
required this.checkNicknameButton,
required this.registerButton,
});

final Widget nicknameTextField;
final Widget urlTextField;
final Widget termAgreeWidget;
final Widget checkNicknameButton;
final Widget registerButton;

@override
Widget build(BuildContext context, WidgetRef ref) {
final signUpRef = ref.watch(signUpProvider);
final pageController = usePageController();
final signUp = ref.watch(signUpProvider.notifier);
final state = ref.watch(signUpProvider);

return Scaffold(
WidgetsBinding.instance.addPostFrameCallback((_) {
final pageIndex = switch (state.signUpViewState) {
SignUpViewState.nickname => 0,
SignUpViewState.url => 1,
SignUpViewState.welcome => 2,
};

if (pageController.page?.toInt() != pageIndex) {
pageController.animateToPage(pageIndex, duration: Duration(milliseconds: 300), curve: Curves.ease);
}
});

return GdsScaffold(
appBar: SignUpAppBar(),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
body: PopScope(
canPop: state.signUpViewState == SignUpViewState.nickname,
onPopInvoked: (didPop) {
switch (state.signUpViewState) {
case SignUpViewState.nickname:
return context.pop();
case SignUpViewState.url:
signUp.setSignUpState(SignUpViewState.nickname);
case SignUpViewState.welcome:
return HomeRoute().go(context);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Gap(40),
Expanded(
child: PageTransitionSwitcher(
duration: const Duration(milliseconds: 200),
reverse: signUpRef.signUpViewState == SignUpViewState.nickname,
transitionBuilder: (
Widget child,
Animation<double> primaryAnimation,
Animation<double> secondaryAnimation,
) {
return SharedAxisTransition(
animation: primaryAnimation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.vertical,
fillColor: Colors.transparent,
child: child,
);
},
child: SafeArea(
child:
signUpRef.signUpViewState == SignUpViewState.nickname
? SignUpNicknameView(
key: const ValueKey('nickname'),
nicknameTextField: nicknameTextField,
termAgreeWidget: termAgreeWidget,
checkNicknameButton: checkNicknameButton,
)
: SignUpUrlView(
key: const ValueKey('url'),
nickname: signUpRef.nickname,
urlTextField: urlTextField,
registerButton: registerButton,
),
),
child: PageView(
physics: NeverScrollableScrollPhysics(),
controller: pageController,
children: [
SignUpNicknameView(
key: const ValueKey('nickname'),
nicknameTextField: nicknameTextField,
termAgreeWidget: termAgreeWidget,
),
SignUpUrlView(
key: const ValueKey('url'),
nickname: state.nickname,
urlTextField: urlTextField,
),
SignUpWelcomeView(
key: const ValueKey('welcome'),
),
],
),
),
SignUpButton(),
],
),
),
Expand Down
Loading
Loading