diff --git a/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/DmsNavigator.kt b/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/DmsNavigator.kt index 38f5a53..92dfd09 100644 --- a/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/DmsNavigator.kt +++ b/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/DmsNavigator.kt @@ -10,6 +10,7 @@ import team.aliens.dms.kmp.feature.signup.navigation.navigateToEnterEmail import team.aliens.dms.kmp.feature.signup.navigation.navigateToEnterEmailVerificationCode import team.aliens.dms.kmp.feature.signup.navigation.navigateToEnterSchoolVerificationCode import team.aliens.dms.kmp.feature.signup.navigation.navigateToEnterSchoolVerificationQuestion +import team.aliens.dms.kmp.feature.signup.navigation.navigateToEnterStudentNumber import team.aliens.dms.kmp.feature.signup.navigation.navigateToSetId import team.aliens.dms.kmp.feature.signup.navigation.navigateToSetPassword import team.aliens.dms.kmp.feature.signup.navigation.navigateToSignUp @@ -48,6 +49,10 @@ internal class DmsNavigator( navController.navigateToEnterEmailVerificationCode(signUpData = signUpData) } + fun navigateToEnterStudentNumber(signUpData: SignUpData) { + navController.navigateToEnterStudentNumber(signUpData = signUpData) + } + fun navigateToSetId(signUpData: SignUpData) { navController.navigateToSetId(signUpData = signUpData) } diff --git a/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/navigation/authorized/AuthNavigation.kt b/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/navigation/authorized/AuthNavigation.kt index e00e308..638c8b0 100644 --- a/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/navigation/authorized/AuthNavigation.kt +++ b/composeApp/src/commonMain/kotlin/team/aliens/dms/kmp/navigation/authorized/AuthNavigation.kt @@ -32,6 +32,7 @@ internal fun NavGraphBuilder.authNavigation( navigateToEnterSchoolVerificationQuestion = navigator::navigateToEnterSchoolVerificationQuestion, navigateToEnterEmail = navigator::navigateToEnterEmail, navigateToEnterEmailVerificationCode = navigator::navigateToEnterEmailVerificationCode, + navigateToEnterStudentNumber = navigator::navigateToEnterStudentNumber, navigateToSetId = navigator::navigateToSetId, navigateToSetPassword = navigator::navigateToSetPassword, navigateToTerms = navigator::navigateToTerms, diff --git a/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/checkbox/DmsCheckbox.kt b/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/checkbox/DmsCheckbox.kt new file mode 100644 index 0000000..2a7bf2a --- /dev/null +++ b/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/checkbox/DmsCheckbox.kt @@ -0,0 +1,50 @@ +package team.aliens.dms.kmp.core.designsystem.checkbox + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material.Checkbox +import androidx.compose.material.CheckboxColors +import androidx.compose.material.CheckboxDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme + +@Composable +fun DmsCheckbox( + checked: Boolean, + onCheckedChange: ((Boolean) -> Unit)?, + modifier: Modifier = Modifier, + enabled: Boolean = true, + colors: CheckboxColors = DmsCheckboxDefaults.Colors(), + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, +) { + Checkbox( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier, + enabled = enabled, + colors = colors, + interactionSource = interactionSource, + ) +} + +object DmsCheckboxDefaults { + + private const val DISABLED_CONTAINER_OPACITY = 0.38f + + @Composable + fun Colors( + checkedColor: Color = DmsTheme.colors.secondary, + uncheckedColor: Color = DmsTheme.colors.inverseSurface, + checkmarkColor: Color = DmsTheme.colors.surfaceTint, + disabledColor: Color = DmsTheme.colors.primaryContainer, + disabledIndeterminateColor: Color = checkedColor.copy(alpha = DISABLED_CONTAINER_OPACITY), + ): CheckboxColors = CheckboxDefaults.colors( + checkedColor = checkedColor, + uncheckedColor = uncheckedColor, + checkmarkColor = checkmarkColor, + disabledColor = disabledColor, + disabledIndeterminateColor = disabledIndeterminateColor, + ) +} diff --git a/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/timer/DmsTimer.kt b/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/timer/DmsTimer.kt index ec5f123..8ca90d0 100644 --- a/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/timer/DmsTimer.kt +++ b/core/design-system/src/commonMain/kotlin/team/aliens/dms/kmp/core/designsystem/timer/DmsTimer.kt @@ -18,6 +18,7 @@ fun DmsTimer( modifier: Modifier = Modifier, timerTotalSeconds: Long = 180000L, timerInterval: Long = 1000L, + onTimerFinished: (Boolean) -> Unit, ) { var time by remember { mutableStateOf(timerTotalSeconds) } var timerFinished by remember { mutableStateOf(false) } @@ -35,6 +36,7 @@ fun DmsTimer( override fun onFinish() { timerFinished = true + onTimerFinished(timerFinished) } }, ) @@ -44,12 +46,16 @@ fun DmsTimer( modifier = modifier, text = formatTime(time / 1000), style = DmsTypography.Body1, - color = DmsTheme.colors.onSurface, + color = DmsTheme.colors.inversePrimary, ) } fun formatTime(seconds: Long): String { val minutes = seconds / 60 val secs = seconds % 60 - return "$minutes 분:$secs 초" + val time = when { + minutes > 0 -> "${minutes}분 ${secs}초" + else -> "${secs}초" + } + return time } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/component/SignUpInfoBanner.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/component/SignUpInfoBanner.kt new file mode 100644 index 0000000..b9f64c6 --- /dev/null +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/component/SignUpInfoBanner.kt @@ -0,0 +1,33 @@ +package team.aliens.dms.kmp.feature.signup.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTypography +import team.aliens.dms.kmp.core.designsystem.text.DmsText + +@Composable +internal fun SignUpInfoBanner( + modifier: Modifier = Modifier, + title: String, + description: String, +) { + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + DmsText( + text = title, + style = DmsTypography.Header3, + ) + DmsText( + text = description, + style = DmsTypography.Body1, + color = DmsTheme.colors.inverseOnSurface, + ) + } +} diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/di/SignIUpModel.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/di/SignIUpModel.kt index 93d077e..3e879db 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/di/SignIUpModel.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/di/SignIUpModel.kt @@ -6,6 +6,7 @@ import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailVerificationCodeVi import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailViewModel import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationCodeViewModel import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationQuestionViewModel +import team.aliens.dms.kmp.feature.signup.viewmodel.EnterStudentNumberViewModel import team.aliens.dms.kmp.feature.signup.viewmodel.SetIdViewModel import team.aliens.dms.kmp.feature.signup.viewmodel.SetPasswordViewModel import team.aliens.dms.kmp.feature.signup.viewmodel.TermsViewModel @@ -15,6 +16,7 @@ val signUpModule = module { viewModelOf(::EnterSchoolVerificationQuestionViewModel) viewModelOf(::EnterEmailViewModel) viewModelOf(::EnterEmailVerificationCodeViewModel) + viewModelOf(::EnterStudentNumberViewModel) viewModelOf(::SetIdViewModel) viewModelOf(::SetPasswordViewModel) viewModelOf(::TermsViewModel) diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterEmailVerificationCodeNavigation.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterEmailVerificationCodeNavigation.kt index 831bbf6..eba327b 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterEmailVerificationCodeNavigation.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterEmailVerificationCodeNavigation.kt @@ -14,7 +14,7 @@ const val NAVIGATION_ENTER_EMAIL_VERIFICATION_CODE = "enterEmailVerificationCode fun NavGraphBuilder.enterEmailVerificationCode( onBackPressed: () -> Unit, - navigateToSetId: (SignUpData) -> Unit, + navigateToEnterStudentNumber: (SignUpData) -> Unit, ) { composable( route = "$NAVIGATION_ENTER_EMAIL_VERIFICATION_CODE/{${ResourceKeys.SIGN_UP}}", @@ -22,7 +22,7 @@ fun NavGraphBuilder.enterEmailVerificationCode( ) { EnterEmailVerificationCode( onBackPressed = onBackPressed, - navigateToSetId = navigateToSetId, + navigateToEnterStudentNumber = navigateToEnterStudentNumber, signUpData = it.getSignUpData(), ) } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterStudentNumberNavigation.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterStudentNumberNavigation.kt new file mode 100644 index 0000000..68f296e --- /dev/null +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/EnterStudentNumberNavigation.kt @@ -0,0 +1,33 @@ +package team.aliens.dms.kmp.feature.signup.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import team.aliens.dms.kmp.core.common.utils.ResourceKeys +import team.aliens.dms.kmp.feature.signup.model.SignUpData +import team.aliens.dms.kmp.feature.signup.model.toJsonString +import team.aliens.dms.kmp.feature.signup.ui.EnterStudentNumber + +const val NAVIGATION_ENTER_STUDENT_NUMBER = "enterStudentNumber" + +fun NavGraphBuilder.enterStudentNumber( + onBackPressed: () -> Unit, + navigateToSetId: (SignUpData) -> Unit, +) { + composable( + route = "$NAVIGATION_ENTER_STUDENT_NUMBER/{${ResourceKeys.SIGN_UP}}", + arguments = listOf(navArgument(ResourceKeys.SIGN_UP) { type = NavType.StringType }), + ) { + EnterStudentNumber( + onBackPressed = onBackPressed, + navigateToSetId = navigateToSetId, + signUpData = it.getSignUpData(), + ) + } +} + +fun NavController.navigateToEnterStudentNumber(signUpData: SignUpData) { + navigate("$NAVIGATION_ENTER_STUDENT_NUMBER/${signUpData.toJsonString()}") +} diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/SignUpNavigation.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/SignUpNavigation.kt index 8be4bce..d6efdb6 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/SignUpNavigation.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/navigation/SignUpNavigation.kt @@ -15,6 +15,7 @@ fun NavGraphBuilder.signUp( navigateToEnterSchoolVerificationQuestion: (SignUpData) -> Unit, navigateToEnterEmail: (SignUpData) -> Unit, navigateToEnterEmailVerificationCode: (SignUpData) -> Unit, + navigateToEnterStudentNumber: (SignUpData) -> Unit, navigateToSetId: (SignUpData) -> Unit, navigateToSetPassword: (SignUpData) -> Unit, navigateToTerms: (SignUpData) -> Unit, @@ -38,6 +39,10 @@ fun NavGraphBuilder.signUp( navigateToEnterEmailVerificationCode = navigateToEnterEmailVerificationCode, ) enterEmailVerificationCode( + onBackPressed = onBackPressed, + navigateToEnterStudentNumber = navigateToEnterStudentNumber, + ) + enterStudentNumber( onBackPressed = onBackPressed, navigateToSetId = navigateToSetId, ) diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailScreen.kt index b1d4dad..8102170 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailScreen.kt @@ -2,14 +2,27 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.textfield.DmsTextField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailState @@ -54,5 +67,38 @@ private fun EnterEmailScreen( .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "이메일을 입력해주세요", + description = "인증 번호를 받을 이메일을 입력해주세요.", + ) + DmsTextField( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + value = state.email, + onValueChange = onEmailChange, + hint = "이메일 주소", + showClearIcon = true, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailVerificationCodeScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailVerificationCodeScreen.kt index 7abe9f9..ad1ec9a 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailVerificationCodeScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterEmailVerificationCodeScreen.kt @@ -1,24 +1,44 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTypography +import team.aliens.dms.kmp.core.designsystem.numberfield.DmsNumberField +import team.aliens.dms.kmp.core.designsystem.text.DmsText +import team.aliens.dms.kmp.core.designsystem.timer.DmsTimer import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailVerificationCodeSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailVerificationCodeState import team.aliens.dms.kmp.feature.signup.viewmodel.EnterEmailVerificationCodeViewModel +const val EMAIL_VERIFICATION_CODE_LENGTH = 6 + @Composable internal fun EnterEmailVerificationCode( onBackPressed: () -> Unit, - navigateToSetId: (SignUpData) -> Unit, + navigateToEnterStudentNumber: (SignUpData) -> Unit, signUpData: SignUpData, ) { val viewModel: EnterEmailVerificationCodeViewModel = koinInject() @@ -27,8 +47,8 @@ internal fun EnterEmailVerificationCode( LaunchedEffect(Unit) { viewModel.sideEffect.collect { when (it) { - is EnterEmailVerificationCodeSideEffect.MoveToSetId -> { - navigateToSetId(signUpData.copy(authCode = it.authCode)) + is EnterEmailVerificationCodeSideEffect.MoveToEnterStudentNumber -> { + navigateToEnterStudentNumber(signUpData.copy(authCode = it.authCode)) } } } @@ -39,6 +59,7 @@ internal fun EnterEmailVerificationCode( onNextClick = viewModel::onNextClick, state = state, onEmailVerificationCodeChange = viewModel::setEmailVerificationCode, + onTimerFinished = viewModel::setTimerFinished, ) } @@ -48,11 +69,81 @@ private fun EnterEmailVerificationCodeScreen( onNextClick: () -> Unit, state: EnterEmailVerificationCodeState, onEmailVerificationCodeChange: (String) -> Unit, + onTimerFinished: (Boolean) -> Unit, ) { Column( modifier = Modifier .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + EmailVerificationCodeInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + onTimerFinished = onTimerFinished, + ) + DmsNumberField( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + totalLength = EMAIL_VERIFICATION_CODE_LENGTH, + value = state.emailVerificationCode, + onValueChange = onEmailVerificationCodeChange, + ) + DmsButton( + modifier = Modifier + .align(alignment = Alignment.CenterHorizontally) + .topPadding(20.dp), + text = "인증코드 재발송", + buttonType = ButtonType.Text, + buttonColor = ButtonColor.Primary, + onClick = { }, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) + } +} + +@Composable +private fun EmailVerificationCodeInfoBanner( + modifier: Modifier = Modifier, + onTimerFinished: (Boolean) -> Unit, +) { + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + DmsText( + text = "이메일 인증번호를 입력해주세요", + style = DmsTypography.Header3, + ) + Row { + DmsText( + text = "이메일로 전송 번호 6자리를 ", + style = DmsTypography.Body1, + color = DmsTheme.colors.inverseOnSurface, + ) + DmsTimer { onTimerFinished(it) } + DmsText( + text = " 내로 입력해주세요.", + style = DmsTypography.Body1, + color = DmsTheme.colors.inverseOnSurface, + ) + } } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationCodeScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationCodeScreen.kt index 1f870de..e01eb3f 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationCodeScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationCodeScreen.kt @@ -2,20 +2,33 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.numberfield.DmsNumberField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationCodeSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationCodeState import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationCodeViewModel -const val VERIFICATION_CODE_LENGTH = 6 +const val SCHOOL_VERIFICATION_CODE_LENGTH = 8 @Composable internal fun EnterSchoolVerificationCode( @@ -55,5 +68,37 @@ private fun EnterSchoolVerificationCodeScreen( .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "학교 인증코드를 입력해주세요", + description = "학교 인증코드는 8자리에요.", + ) + DmsNumberField( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + totalLength = SCHOOL_VERIFICATION_CODE_LENGTH, + value = state.verificationCode, + onValueChange = onVerificationCodeChange, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationQuestionScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationQuestionScreen.kt index 252e88d..036ed03 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationQuestionScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterSchoolVerificationQuestionScreen.kt @@ -2,14 +2,27 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.textfield.DmsTextField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationQuestionSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.EnterSchoolVerificationQuestionState @@ -54,5 +67,38 @@ private fun EnterSchoolVerificationQuestionScreen( .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = state.schoolVerificationQuestion, + description = "학교 확인 질문이에요.", + ) + DmsTextField( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + value = state.schoolVerificationAnswer, + onValueChange = onVerificationAnswerChange, + hint = "답변", + showClearIcon = true, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterStudentNumberScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterStudentNumberScreen.kt new file mode 100644 index 0000000..f9971d1 --- /dev/null +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/EnterStudentNumberScreen.kt @@ -0,0 +1,173 @@ +package team.aliens.dms.kmp.feature.signup.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.textfield.DmsTextField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner +import team.aliens.dms.kmp.feature.signup.model.SignUpData +import team.aliens.dms.kmp.feature.signup.viewmodel.EnterStudentNumberSideEffect +import team.aliens.dms.kmp.feature.signup.viewmodel.EnterStudentNumberState +import team.aliens.dms.kmp.feature.signup.viewmodel.EnterStudentNumberViewModel + +@Composable +internal fun EnterStudentNumber( + onBackPressed: () -> Unit, + navigateToSetId: (SignUpData) -> Unit, + signUpData: SignUpData, +) { + val viewModel: EnterStudentNumberViewModel = koinInject() + val state by viewModel.state.collectAsState() + + LaunchedEffect(Unit) { + viewModel.sideEffect.collect { + when (it) { + is EnterStudentNumberSideEffect.MoveToSetId -> { + navigateToSetId( + signUpData.copy( + grade = 1, + classRoom = 1, + number = 1, + ), + ) + } + } + } + } + + EnterStudentNumberScreen( + onBackPressed = onBackPressed, + onNextClick = viewModel::onNextClick, + state = state, + onGradeChange = viewModel::setGrade, + onClassroomChange = viewModel::setClassRoom, + onNumberChange = viewModel::setNumber, + ) +} + +@Composable +private fun EnterStudentNumberScreen( + onBackPressed: () -> Unit, + onNextClick: () -> Unit, + state: EnterStudentNumberState, + onGradeChange: (String) -> Unit, + onClassroomChange: (String) -> Unit, + onNumberChange: (String) -> Unit, +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(DmsTheme.colors.background), + ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "학번을 입력해주세요", + description = "숫자만 입력해주세요.", + ) + StudentNumberInputs( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + grade = state.grade, + classroom = state.classroom, + number = state.number, + onGradeChange = onGradeChange, + onClassroomChange = onClassroomChange, + onNumberChange = onNumberChange, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) + } +} + +@Composable +private fun StudentNumberInputs( + modifier: Modifier = Modifier, + grade: String, + classroom: String, + number: String, + onGradeChange: (String) -> Unit, + onClassroomChange: (String) -> Unit, + onNumberChange: (String) -> Unit, +) { + val classroomFocusRequest = remember { FocusRequester() } + val numberFocusRequest = remember { FocusRequester() } + + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + DmsTextField( + modifier = Modifier.weight(1f), + value = grade, + onValueChange = { grade -> + onGradeChange(grade) + if (grade.isNotEmpty()) classroomFocusRequest.requestFocus() + }, + hint = "학년", + keyboardType = KeyboardType.Number, + ) + DmsTextField( + modifier = Modifier + .weight(1f) + .focusRequester(classroomFocusRequest), + value = classroom, + onValueChange = { classroom -> + onClassroomChange(classroom) + if (classroom.isNotEmpty()) numberFocusRequest.requestFocus() + }, + hint = "반", + keyboardType = KeyboardType.Number, + ) + DmsTextField( + modifier = Modifier + .weight(1f) + .focusRequester(numberFocusRequest), + value = number, + onValueChange = onNumberChange, + hint = "번호", + keyboardType = KeyboardType.Number, + ) + } +} diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetIdScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetIdScreen.kt index 308a58d..58c78fd 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetIdScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetIdScreen.kt @@ -2,14 +2,27 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.textfield.DmsTextField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.SetIdSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.SetIdState @@ -31,9 +44,6 @@ internal fun SetId( navigateToSetPassword( signUpData.copy( accountId = it.id, - grade = 1, - classRoom = 1, - number = 1, ), ) } @@ -45,9 +55,7 @@ internal fun SetId( onBackPressed = onBackPressed, onNextClick = viewModel::onNextClick, state = state, - onGradeChange = viewModel::setGrade, - onClassRoomChange = viewModel::setClassRoom, - onNumberChange = viewModel::setNumber, + onIdChange = viewModel::setId, ) } @@ -56,14 +64,45 @@ private fun SetIdScreen( onBackPressed: () -> Unit, onNextClick: () -> Unit, state: SetIdState, - onGradeChange: (String) -> Unit, - onClassRoomChange: (String) -> Unit, - onNumberChange: (String) -> Unit, + onIdChange: (String) -> Unit, ) { Column( modifier = Modifier .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "아이디를 입력해주세요", + description = "DMS에서 사용될 아이디를 입력해주세요.", + ) + DmsTextField( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + value = state.id, + onValueChange = onIdChange, + hint = "아이디", + showClearIcon = true, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetPasswordScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetPasswordScreen.kt index 4e1b27f..9dcdc32 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetPasswordScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/SetPasswordScreen.kt @@ -1,15 +1,29 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.textfield.DmsTextField +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.model.SignUpData import team.aliens.dms.kmp.feature.signup.viewmodel.SetPasswordSideEffect import team.aliens.dms.kmp.feature.signup.viewmodel.SetPasswordState @@ -41,7 +55,7 @@ internal fun SetPassword( onNextClick = viewModel::onNextClick, state = state, onPasswordChange = viewModel::setPassword, - onCheckPasswordChange = viewModel::setPasswordCheck, + onPasswordCheckChange = viewModel::setPasswordCheck, ) } @@ -51,12 +65,80 @@ private fun SetPasswordScreen( onNextClick: () -> Unit, state: SetPasswordState, onPasswordChange: (String) -> Unit, - onCheckPasswordChange: (String) -> Unit, + onPasswordCheckChange: (String) -> Unit, ) { Column( modifier = Modifier .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "비밀번호를 입력해주세요", + description = "영문, 숫자, 기호를 포함한 8~20자입니다.", + ) + PasswordInputs( + modifier = Modifier + .fillMaxWidth() + .horizontalPadding(24.dp) + .topPadding(44.dp), + password = state.password, + passwordCheck = state.passwordCheck, + onPasswordChange = onPasswordChange, + onPasswordCheckChange = onPasswordCheckChange, + isPasswordFormatError = state.showPasswordDescription, + isPasswordMatchError = state.showCheckPasswordDescription, + ) + Spacer(modifier = Modifier.weight(1f)) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = onNextClick, + enabled = state.buttonEnabled, + ) + } +} + +@Composable +private fun PasswordInputs( + modifier: Modifier = Modifier, + password: String, + passwordCheck: String, + onPasswordChange: (String) -> Unit, + onPasswordCheckChange: (String) -> Unit, + isPasswordFormatError: Boolean, + isPasswordMatchError: Boolean, +) { + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(44.dp), + ) { + DmsTextField( + value = password, + onValueChange = onPasswordChange, + hint = "비밀번호", + showVisibleIcon = true, + isError = isPasswordFormatError, + errorMessage = "형식이 일치하지 않습니다.", + ) + DmsTextField( + value = passwordCheck, + onValueChange = onPasswordCheckChange, + hint = "비밀번호 확인", + showVisibleIcon = true, + isError = isPasswordMatchError, + errorMessage = "비밀번호가 일치하지 않습니다.", + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/TermsScreen.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/TermsScreen.kt index 262acb3..2bf7798 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/TermsScreen.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/ui/TermsScreen.kt @@ -2,14 +2,33 @@ package team.aliens.dms.kmp.feature.signup.ui import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import org.koin.compose.koinInject +import team.aliens.dms.kmp.core.common.ui.horizontalPadding +import team.aliens.dms.kmp.core.common.ui.startPadding +import team.aliens.dms.kmp.core.common.ui.topPadding +import team.aliens.dms.kmp.core.designsystem.appbar.DmsTopAppBar +import team.aliens.dms.kmp.core.designsystem.button.ButtonColor +import team.aliens.dms.kmp.core.designsystem.button.ButtonType +import team.aliens.dms.kmp.core.designsystem.button.DmsButton +import team.aliens.dms.kmp.core.designsystem.checkbox.DmsCheckbox import team.aliens.dms.kmp.core.designsystem.foundation.DmsTheme +import team.aliens.dms.kmp.core.designsystem.foundation.DmsTypography +import team.aliens.dms.kmp.core.designsystem.text.DmsText +import team.aliens.dms.kmp.core.designsystem.webview.DmsWebView +import team.aliens.dms.kmp.feature.signup.component.SignUpInfoBanner import team.aliens.dms.kmp.feature.signup.viewmodel.TermsState import team.aliens.dms.kmp.feature.signup.viewmodel.TermsViewModel @@ -32,7 +51,7 @@ internal fun Terms( navigateToSignIn = navigateToSignIn, termsUrl = termsUrl, state = state, - onAllAgreeButtonClick = viewModel::setButtonEnabled, + onAgreeButtonClick = viewModel::setButtonEnabled, theme = theme, ) } @@ -43,7 +62,7 @@ private fun TermsScreen( navigateToSignIn: () -> Unit, termsUrl: String, state: TermsState, - onAllAgreeButtonClick: (Boolean) -> Unit, + onAgreeButtonClick: (Boolean) -> Unit, theme: String, ) { Column( @@ -51,5 +70,73 @@ private fun TermsScreen( .fillMaxSize() .background(DmsTheme.colors.background), ) { + DmsTopAppBar( + title = "회원가입", + onBackPressed = onBackPressed, + ) + SignUpInfoBanner( + modifier = Modifier + .fillMaxWidth() + .startPadding(24.dp) + .topPadding(48.dp), + title = "약관을 확인해주세요", + description = "동의 후 DMS를 사용할 수 있습니다.", + ) + DmsWebView( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .horizontalPadding(24.dp) + .topPadding(32.dp), + url = "$termsUrl/policy/privacy?theme=$theme", + ) + HorizontalDivider( + modifier = Modifier.fillMaxWidth(), + thickness = 1.dp, + color = DmsTheme.colors.surface, + ) + AgreeCheckBox( + modifier = Modifier.fillMaxWidth(), + isCheck = state.buttonEnabled, + onAgreeButtonClick = onAgreeButtonClick, + ) + DmsButton( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + text = "다음", + buttonType = ButtonType.Contained, + buttonColor = ButtonColor.Primary, + onClick = navigateToSignIn, + enabled = state.buttonEnabled, + ) + } +} + +@Composable +private fun AgreeCheckBox( + modifier: Modifier = Modifier, + isCheck: Boolean, + onAgreeButtonClick: (Boolean) -> Unit, +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(vertical = 12.dp), + horizontalArrangement = Arrangement.spacedBy( + alignment = Alignment.CenterHorizontally, + space = 12.dp, + ), + verticalAlignment = Alignment.CenterVertically, + ) { + DmsText( + text = "전체 약관 동의", + style = DmsTypography.Label, + color = DmsTheme.colors.tertiaryContainer, + ) + DmsCheckbox( + checked = isCheck, + onCheckedChange = onAgreeButtonClick, + ) } } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterEmailVerificationCodeViewModel.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterEmailVerificationCodeViewModel.kt index bee3faa..500b5ea 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterEmailVerificationCodeViewModel.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterEmailVerificationCodeViewModel.kt @@ -1,6 +1,7 @@ package team.aliens.dms.kmp.feature.signup.viewmodel import team.aliens.dms.kmp.core.common.base.BaseViewModel +import team.aliens.dms.kmp.feature.signup.ui.EMAIL_VERIFICATION_CODE_LENGTH internal class EnterEmailVerificationCodeViewModel : BaseViewModel( @@ -16,28 +17,38 @@ internal class EnterEmailVerificationCodeViewModel : setButtonEnabled() } + internal fun setTimerFinished(timerFinished: Boolean) { + setState { + state.value.copy( + timerFinished = timerFinished, + ) + } + } + private fun setButtonEnabled() = setState { val emailVerificationCode = state.value.emailVerificationCode - state.value.copy(buttonEnabled = emailVerificationCode.length == 6) + state.value.copy(buttonEnabled = emailVerificationCode.length == EMAIL_VERIFICATION_CODE_LENGTH) } internal fun onNextClick() { - postSideEffect(EnterEmailVerificationCodeSideEffect.MoveToSetId(authCode = "")) + postSideEffect(EnterEmailVerificationCodeSideEffect.MoveToEnterStudentNumber(authCode = "")) } } data class EnterEmailVerificationCodeState( val emailVerificationCode: String, + val timerFinished: Boolean, val buttonEnabled: Boolean, ) { companion object { fun getDefaultState() = EnterEmailVerificationCodeState( emailVerificationCode = "", + timerFinished = false, buttonEnabled = false, ) } } sealed interface EnterEmailVerificationCodeSideEffect { - data class MoveToSetId(val authCode: String) : EnterEmailVerificationCodeSideEffect + data class MoveToEnterStudentNumber(val authCode: String) : EnterEmailVerificationCodeSideEffect } diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterSchoolVerificationCodeViewModel.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterSchoolVerificationCodeViewModel.kt index e9792b1..91c381d 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterSchoolVerificationCodeViewModel.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterSchoolVerificationCodeViewModel.kt @@ -1,6 +1,7 @@ package team.aliens.dms.kmp.feature.signup.viewmodel import team.aliens.dms.kmp.core.common.base.BaseViewModel +import team.aliens.dms.kmp.feature.signup.ui.SCHOOL_VERIFICATION_CODE_LENGTH internal class EnterSchoolVerificationCodeViewModel : BaseViewModel( @@ -18,7 +19,7 @@ internal class EnterSchoolVerificationCodeViewModel : private fun setButtonEnabled() = setState { val verificationCode = state.value.verificationCode - state.value.copy(buttonEnabled = verificationCode.length == 6) + state.value.copy(buttonEnabled = verificationCode.length == SCHOOL_VERIFICATION_CODE_LENGTH) } internal fun onNextClick() { diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterStudentNumberViewModel.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterStudentNumberViewModel.kt new file mode 100644 index 0000000..a79ae5f --- /dev/null +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/EnterStudentNumberViewModel.kt @@ -0,0 +1,64 @@ +package team.aliens.dms.kmp.feature.signup.viewmodel + +import team.aliens.dms.kmp.core.common.base.BaseViewModel + +internal class EnterStudentNumberViewModel : + BaseViewModel(EnterStudentNumberState.getDefaultState()) { + + internal fun setGrade(grade: String) { + setState { state.value.copy(grade = grade) } + buttonEnabled() + } + + internal fun setClassRoom(classroom: String) { + setState { state.value.copy(classroom = classroom) } + buttonEnabled() + } + + internal fun setNumber(number: String) { + setState { state.value.copy(number = number) } + buttonEnabled() + } + + private fun buttonEnabled() = setState { + with(state.value) { + val isStudentNumberNotBlank = + grade.isNotBlank() && classroom.isNotBlank() && number.isNotBlank() + copy(buttonEnabled = isStudentNumberNotBlank) + } + } + + internal fun onNextClick() { + postSideEffect( + EnterStudentNumberSideEffect.MoveToSetId( + grade = "", + classroom = "", + number = "", + ), + ) + } +} + +data class EnterStudentNumberState( + val grade: String, + val classroom: String, + val number: String, + val buttonEnabled: Boolean, +) { + companion object { + fun getDefaultState() = EnterStudentNumberState( + grade = "", + classroom = "", + number = "", + buttonEnabled = false, + ) + } +} + +sealed interface EnterStudentNumberSideEffect { + data class MoveToSetId( + val grade: String, + val classroom: String, + val number: String, + ) : EnterStudentNumberSideEffect +} diff --git a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/SetIdViewModel.kt b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/SetIdViewModel.kt index 847e6c4..c8d395d 100644 --- a/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/SetIdViewModel.kt +++ b/feature/signup/src/commonMain/kotlin/team/aliens/dms/kmp/feature/signup/viewmodel/SetIdViewModel.kt @@ -5,25 +5,20 @@ import team.aliens.dms.kmp.core.common.base.BaseViewModel internal class SetIdViewModel : BaseViewModel(SetIdState.getDefaultState()) { - internal fun setGrade(grade: String) { - setState { state.value.copy(grade = grade) } + internal fun setId(id: String) { + setState { state.value.copy(id = id) } + setButtonEnabled() } - internal fun setClassRoom(classroom: String) { - setState { state.value.copy(classroom = classroom) } - } - - internal fun setNumber(number: String) { - setState { state.value.copy(number = number) } + private fun setButtonEnabled() = setState { + val id = state.value.id + state.value.copy(buttonEnabled = id.isNotEmpty()) } internal fun onNextClick() { postSideEffect( SetIdSideEffect.MoveToSetPassword( id = "", - grade = "", - classroom = "", - number = "", ), ) } @@ -31,16 +26,12 @@ internal class SetIdViewModel : data class SetIdState( val id: String, - val grade: String, - val classroom: String, - val number: String, + val buttonEnabled: Boolean, ) { companion object { fun getDefaultState() = SetIdState( id = "", - grade = "", - classroom = "", - number = "", + buttonEnabled = false, ) } } @@ -48,8 +39,5 @@ data class SetIdState( sealed interface SetIdSideEffect { data class MoveToSetPassword( val id: String, - val grade: String, - val classroom: String, - val number: String, ) : SetIdSideEffect }