From 3387d9e68d0df85ecca5d33510d626214a257407 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 19:32:35 +0900 Subject: [PATCH 01/18] =?UTF-8?q?[CHORE]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C,=20=EC=88=98=EC=A0=95=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20dto=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/UpdateMyInfoRequestDto.kt | 12 +++++++ .../data/dto/response/MyInfoResponseDto.kt | 32 +++++++++++++++++++ .../dto/response/UpdateMyInfoResponseDto.kt | 16 ++++++++++ 3 files changed, 60 insertions(+) create mode 100644 composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/request/UpdateMyInfoRequestDto.kt create mode 100644 composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt create mode 100644 composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/request/UpdateMyInfoRequestDto.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/request/UpdateMyInfoRequestDto.kt new file mode 100644 index 0000000..c6d4f8e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/request/UpdateMyInfoRequestDto.kt @@ -0,0 +1,12 @@ +package org.whosin.client.data.dto.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UpdateMyInfoRequestDto( + @SerialName("nickName") + val nickName: String, + @SerialName("clubList") + val clubList: List? +) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt new file mode 100644 index 0000000..4efbb49 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt @@ -0,0 +1,32 @@ +package org.whosin.client.data.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MyInfoResponseDto( + @SerialName("success") + val success: Boolean, + @SerialName("status") + val status: Int, + @SerialName("message") + val message: String, + @SerialName("data") + val data: MyInfoData +) + +@Serializable +data class MyInfoData( + @SerialName("nickname") + val nickname: String, + @SerialName("clubList") + val clubList: List +) + +@Serializable +data class MyClubData( + @SerialName("id") + val id: Int, + @SerialName("name") + val name: String +) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt new file mode 100644 index 0000000..d073120 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt @@ -0,0 +1,16 @@ +package org.whosin.client.data.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UpdateMyInfoResponseDto( + @SerialName("success") + val success: Boolean, + @SerialName("status") + val status: Int, + @SerialName("message") + val message: String, + @SerialName("data") + val data: String? = null +) From f3bffc7b2c7d703244ee60d6806cb18d1fd6195e Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 19:35:47 +0900 Subject: [PATCH 02/18] =?UTF-8?q?[CHORE]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C,=20=EC=88=98=EC=A0=95=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20datasource=20=ED=95=A8=EC=88=98=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/remote/RemoteMemberDataSource.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt index 56f5c22..cc08ccc 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt @@ -3,13 +3,18 @@ package org.whosin.client.data.remote import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get +import io.ktor.client.request.patch import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse import io.ktor.http.isSuccess import org.whosin.client.core.network.ApiResult import org.whosin.client.data.dto.request.LoginRequestDto +import org.whosin.client.data.dto.request.UpdateMyInfoRequestDto +import org.whosin.client.data.dto.response.ErrorResponseDto import org.whosin.client.data.dto.response.LoginResponseDto +import org.whosin.client.data.dto.response.MyInfoResponseDto +import org.whosin.client.data.dto.response.UpdateMyInfoResponseDto class RemoteMemberDataSource( private val client: HttpClient @@ -38,4 +43,73 @@ class RemoteMemberDataSource( ApiResult.Error(message = t.message, cause = t) } } + + // 내 정보 조회 + suspend fun getMyInfo(): ApiResult { + return try { + val response: HttpResponse = client.get(urlString = "users/myPage") + + if (response.status.isSuccess()) { + ApiResult.Success( + data = response.body(), + statusCode = response.status.value + ) + } else { + // 에러 응답 파싱 시도 + try { + val errorResponse: ErrorResponseDto = response.body() + ApiResult.Error( + code = response.status.value, + message = errorResponse.message + ) + } catch (e: Exception) { + // 파싱 실패 시 기본 에러 메시지 + ApiResult.Error( + code = response.status.value, + message = "HTTP Error: ${response.status.value}" + ) + } + } + } catch (t: Throwable) { + ApiResult.Error(message = t.message, cause = t) + } + } + + // 내 정보 수정 + suspend fun updateMyInfo( + newNickName: String, + clubList: List? + ): ApiResult { + return try { + val response: HttpResponse = client.patch(urlString = "users/myPage/update"){ + setBody{ + UpdateMyInfoRequestDto(nickName = newNickName, clubList = clubList) + } + } + + if (response.status.isSuccess()) { + ApiResult.Success( + data = response.body(), + statusCode = response.status.value + ) + } else { + // 에러 응답 파싱 시도 + try { + val errorResponse: ErrorResponseDto = response.body() + ApiResult.Error( + code = response.status.value, + message = errorResponse.message + ) + } catch (e: Exception) { + // 파싱 실패 시 기본 에러 메시지 + ApiResult.Error( + code = response.status.value, + message = "HTTP Error: ${response.status.value}" + ) + } + } + } catch (t: Throwable) { + ApiResult.Error(message = t.message, cause = t) + } + } } \ No newline at end of file From 8215b4c258b736ac874d1de0448988bbfd8d353d Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 19:35:56 +0900 Subject: [PATCH 03/18] =?UTF-8?q?[CHORE]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C,=20=EC=88=98=EC=A0=95=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20repository=20=ED=95=A8=EC=88=98=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/data/repository/MemberRepository.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/MemberRepository.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/MemberRepository.kt index 71adf94..6ccbffe 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/MemberRepository.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/MemberRepository.kt @@ -3,6 +3,8 @@ package org.whosin.client.data.repository import org.whosin.client.data.remote.RemoteMemberDataSource import org.whosin.client.core.network.ApiResult import org.whosin.client.data.dto.response.LoginResponseDto +import org.whosin.client.data.dto.response.MyInfoResponseDto +import org.whosin.client.data.dto.response.UpdateMyInfoResponseDto class MemberRepository( private val dataSource: RemoteMemberDataSource @@ -10,4 +12,10 @@ class MemberRepository( suspend fun login(email: String, password: String): ApiResult = dataSource.login(email, password) + suspend fun getMyInfo(): ApiResult = + dataSource.getMyInfo() + + suspend fun updateMyInfo(newNickName: String, clubList: List?): ApiResult = + dataSource.updateMyInfo(newNickName = newNickName, clubList = clubList) + } \ No newline at end of file From ffdc5de3e5c471d7fff72f78481639826abf8206 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 19:43:08 +0900 Subject: [PATCH 04/18] =?UTF-8?q?[FEAT]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20=ED=95=A8=EC=88=98=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/MyPageViewModel.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index 91efcbd..3d6581f 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -1,10 +1,64 @@ package org.whosin.client.presentation.mypage import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.whosin.client.core.network.ApiResult +import org.whosin.client.data.dto.response.MyClubData import org.whosin.client.data.repository.MemberRepository +data class MyPageUiState( + val isLoading: Boolean = false, + val isEditable: Boolean = false, + val nickname: String = "", + val clubs: List = emptyList(), + val errorMessage: String? = null, +) + class MyPageViewModel( private val repository: MemberRepository ): ViewModel() { + private val _uiState = MutableStateFlow(MyPageUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + // 수정 모드 변경 + fun enableEditMode() { + _uiState.update { it.copy(isEditable = !it.isEditable) } + } + + // 내 정보 조회 + fun getMyInfo() { + viewModelScope.launch { + _uiState.update{ it.copy(isLoading = true) } + when (val result = repository.getMyInfo()) { + is ApiResult.Success -> { + val response = result.data.data + _uiState.update { + it.copy( + isLoading = false, + nickname = response.nickname, + clubs = response.clubList, + errorMessage = null + ) + } + println("MyPageViewModel: 내 정보 조회 성공") + } + is ApiResult.Error -> { + _uiState.value = _uiState.value.copy( + isLoading = false, + errorMessage = result.message ?: "내 정보 조회에 실패했습니다." + ) + println("MyPageViewModel: 내 정보 조회 실패 - ${result.message}") + } + } + } + } + + // TODO: 내 정보 수정 + } \ No newline at end of file From 481862febe0da1e79b078d015d815d436ef72b49 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 19:51:25 +0900 Subject: [PATCH 05/18] =?UTF-8?q?[FIX]:=20dto=20=EC=86=8D=EC=84=B1?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/data/dto/response/MyInfoResponseDto.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt index 4efbb49..6baa257 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/MyInfoResponseDto.kt @@ -17,8 +17,8 @@ data class MyInfoResponseDto( @Serializable data class MyInfoData( - @SerialName("nickname") - val nickname: String, + @SerialName("nickName") + val nickName: String, @SerialName("clubList") val clubList: List ) From 83673ec51cce10ace5dde7989eb9c9167e197dd0 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:05:55 +0900 Subject: [PATCH 06/18] =?UTF-8?q?[REFACTOR]:=20EditMyInfoScreen=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0(MyPageScreen=EC=97=90=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B8=B0=EB=B0=98=20=EA=B4=80=EB=A6=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whosin/client/core/navigation/Route.kt | 4 - .../client/core/navigation/WhosInNavGraph.kt | 17 ---- .../presentation/mypage/EditMyInfoScreen.kt | 99 ------------------- 3 files changed, 120 deletions(-) delete mode 100644 composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/EditMyInfoScreen.kt diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt index e704b89..f36d8b6 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt @@ -38,8 +38,4 @@ sealed interface Route { /* 마이 페이지 */ @Serializable data object MyPage: Route - - /* 내 정보 수정하기 */ - @Serializable - data object UpdateMyInfo: Route } diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt index 9c41efe..9981b8a 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt @@ -15,7 +15,6 @@ import org.whosin.client.presentation.auth.login.PasswordInputScreen import org.whosin.client.presentation.auth.login.SignupScreen import org.whosin.client.presentation.auth.login.SplashScreen import org.whosin.client.presentation.home.HomeScreen -import org.whosin.client.presentation.mypage.EditMyInfoScreen import org.whosin.client.presentation.mypage.MyPageScreen @Composable @@ -140,22 +139,6 @@ fun WhosInNavGraph( onNavigateBack = { navController.navigateUp() }, onNavigateToAddClub = { - }, - onNavigateToEdit = { - navController.navigate(Route.UpdateMyInfo) - }, - ) - } - - composable { - EditMyInfoScreen( - modifier = modifier, - onNavigateBack = { navController.navigateUp() }, - onNavigateToMyPage = { - navController.navigate(Route.MyPage) { - popUpTo(Route.UpdateMyInfo) { inclusive = true } - launchSingleTop = true - } } ) } diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/EditMyInfoScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/EditMyInfoScreen.kt deleted file mode 100644 index 1458948..0000000 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/EditMyInfoScreen.kt +++ /dev/null @@ -1,99 +0,0 @@ -package org.whosin.client.presentation.mypage - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -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.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.OutlinedTextFieldDefaults -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import org.jetbrains.compose.resources.stringResource -import org.jetbrains.compose.ui.tooling.preview.Preview -import org.whosin.client.presentation.mypage.component.MyPageButton -import org.whosin.client.presentation.mypage.component.MyPageTopAppBar -import whosinclient.composeapp.generated.resources.Res -import whosinclient.composeapp.generated.resources.complete_edit -import whosinclient.composeapp.generated.resources.edit_my_information -import whosinclient.composeapp.generated.resources.nickname -@Composable -fun EditMyInfoScreen(modifier: Modifier = Modifier, onNavigateBack: () -> Unit, onNavigateToMyPage: () -> Unit) { - var nickName by remember { mutableStateOf("조익성") } - Box( - modifier = modifier.fillMaxSize().background(Color.White).padding(16.dp) - ) { - Column( - verticalArrangement = Arrangement.spacedBy(32.dp) - ) { - MyPageTopAppBar(onNavigateBack) - Text( - text = stringResource(Res.string.edit_my_information), - fontSize = 24.sp, - color = Color.Black, - lineHeight = 24.sp, - fontWeight = FontWeight.SemiBold, - modifier = Modifier.fillMaxWidth() - ) - Column( - modifier = Modifier.fillMaxWidth() - ) { - Text( - text = stringResource(Res.string.nickname), - fontSize = 16.sp, - color = Color.Black, - fontWeight = FontWeight.SemiBold, - modifier = Modifier.padding(bottom = 12.dp) - ) - OutlinedTextField( - value = nickName, - onValueChange = { nickName = it }, - modifier = Modifier.fillMaxWidth(), - textStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Medium), - colors = OutlinedTextFieldDefaults.colors( - focusedContainerColor = Color(0xFFFBFBFB), - unfocusedContainerColor = Color(0xFFFBFBFB), - focusedBorderColor = Color(0xFFE5E5E5), - unfocusedBorderColor = Color(0xFFE5E5E5), - focusedTextColor = Color.Black, - unfocusedTextColor = Color.Black - ), - shape = RoundedCornerShape(10.dp) - ) - } - // 내 동아리 / 학과 목록 - Column( - modifier = Modifier.fillMaxWidth().background(Color.Gray).height(271.dp) - ) { - Text( - "내 동아리 / 학과 목록" - ) - } - Spacer(modifier = Modifier.weight(1f)) - // 내 정보 수정 버튼 - MyPageButton(onClick = onNavigateToMyPage, text = stringResource(Res.string.complete_edit), enabled = nickName.isNotEmpty()) - } - } - -} - -@Preview -@Composable -private fun EditMyInfoScreenPreview() { - EditMyInfoScreen(onNavigateBack = {}, onNavigateToMyPage = {}) -} From 8f4ae665b782c096dbea214bc432bea58f897246 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:12:52 +0900 Subject: [PATCH 07/18] =?UTF-8?q?[REFACTOR]:=20MyPageScreen=EC=97=90?= =?UTF-8?q?=EC=84=9C=20uiState=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=93=9C=EB=A1=9C=20=EC=A7=84?= =?UTF-8?q?=EC=9E=85=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/MyPageScreen.kt | 47 +++++++------------ .../presentation/mypage/MyPageViewModel.kt | 23 +++++++-- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index a5f9ac5..b52e36a 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -14,10 +14,6 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -25,6 +21,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.ui.tooling.preview.Preview import org.koin.compose.viewmodel.koinViewModel @@ -33,6 +30,7 @@ import org.whosin.client.presentation.mypage.component.MyClubComponent import org.whosin.client.presentation.mypage.component.MyPageButton import org.whosin.client.presentation.mypage.component.MyPageTopAppBar import whosinclient.composeapp.generated.resources.Res +import whosinclient.composeapp.generated.resources.complete_edit import whosinclient.composeapp.generated.resources.edit_my_information import whosinclient.composeapp.generated.resources.my_information import whosinclient.composeapp.generated.resources.nickname @@ -41,25 +39,11 @@ import whosinclient.composeapp.generated.resources.nickname fun MyPageScreen( modifier: Modifier = Modifier, onNavigateToAddClub: () -> Unit, - onNavigateBack: () -> Unit, - onNavigateToEdit: () -> Unit + onNavigateBack: () -> Unit ) { val viewModel: MyPageViewModel = koinViewModel() - var nickName by remember { mutableStateOf("조익성") } - val myClubs = listOf( - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ClubData(clubId = 1, clubName = "메이커스팜"), - ClubData(clubId = 2, clubName = "KUIT"), - ) + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + Box( modifier = modifier .fillMaxSize() @@ -72,7 +56,7 @@ fun MyPageScreen( MyPageTopAppBar(onNavigateBack) Spacer(modifier = Modifier.size(16.dp)) Text( - text = stringResource(Res.string.my_information), + text = stringResource(if(uiState.isEditable)Res.string.edit_my_information else Res.string.my_information), fontSize = 24.sp, color = Color.Black, lineHeight = 24.sp, @@ -91,9 +75,9 @@ fun MyPageScreen( modifier = Modifier.padding(bottom = 12.dp) ) OutlinedTextField( - readOnly = true, - value = nickName, - onValueChange = { nickName = it }, + readOnly = !uiState.isEditable, + value = uiState.nickname, + onValueChange = { viewModel.updateNickName(it) }, modifier = Modifier.fillMaxWidth(), textStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Medium), colors = OutlinedTextFieldDefaults.colors( @@ -114,7 +98,8 @@ fun MyPageScreen( .fillMaxWidth() .weight(1f) .padding(bottom = 72.dp), - myClubs = myClubs, + isEditable = uiState.isEditable, + myClubs = uiState.clubs, onDeleteClub = { // TODO: 동아리 삭제 // viewModel.deleteClub(it) @@ -125,9 +110,12 @@ fun MyPageScreen( // 내 정보 수정 버튼 - 하단에 고정 MyPageButton( - onClick = onNavigateToEdit, - text = stringResource(Res.string.edit_my_information), - enabled = nickName.isNotEmpty(), + onClick = { viewModel.enableEditMode() }, + text = stringResource( + if (uiState.isEditable) Res.string.complete_edit + else Res.string.edit_my_information + ), + enabled = uiState.nickname.isNotEmpty(), modifier = Modifier.align(Alignment.BottomCenter) ) } @@ -139,7 +127,6 @@ fun MyPageScreen( private fun MyPageScreenPreview() { MyPageScreen( onNavigateBack = {}, - onNavigateToEdit = {}, onNavigateToAddClub = {} ) } diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index 3d6581f..a4b1bc6 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.whosin.client.core.network.ApiResult +import org.whosin.client.data.dto.response.ClubData import org.whosin.client.data.dto.response.MyClubData import org.whosin.client.data.repository.MemberRepository @@ -15,7 +16,7 @@ data class MyPageUiState( val isLoading: Boolean = false, val isEditable: Boolean = false, val nickname: String = "", - val clubs: List = emptyList(), + val clubs: List = emptyList(), val errorMessage: String? = null, ) @@ -25,11 +26,20 @@ class MyPageViewModel( private val _uiState = MutableStateFlow(MyPageUiState()) val uiState: StateFlow = _uiState.asStateFlow() + init { + getMyInfo() + } + // 수정 모드 변경 fun enableEditMode() { _uiState.update { it.copy(isEditable = !it.isEditable) } } + // 닉네임 변경 + fun updateNickName(newNickname: String) { + _uiState.update { it.copy(nickname = newNickname) } + } + // 내 정보 조회 fun getMyInfo() { viewModelScope.launch { @@ -37,11 +47,16 @@ class MyPageViewModel( when (val result = repository.getMyInfo()) { is ApiResult.Success -> { val response = result.data.data - _uiState.update { + _uiState.update { it -> it.copy( isLoading = false, - nickname = response.nickname, - clubs = response.clubList, + nickname = response.nickName, + clubs = response.clubList.map { clubData -> + ClubData( + clubId = clubData.id, + clubName = clubData.name + ) + }, errorMessage = null ) } From 145f27322c1d0495670307460d22744519cb3b9d Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:14:01 +0900 Subject: [PATCH 08/18] =?UTF-8?q?[REFACTOR]:=20=EB=8F=99=EC=95=84=EB=A6=AC?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/component/MyClubComponent.kt | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/component/MyClubComponent.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/component/MyClubComponent.kt index 775e190..3d9577a 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/component/MyClubComponent.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/component/MyClubComponent.kt @@ -33,13 +33,14 @@ import whosinclient.composeapp.generated.resources.Res @Composable fun MyClubComponent( modifier: Modifier = Modifier, + isEditable: Boolean = false, myClubs: List, onDeleteClub: (Int) -> Unit, onNavigateToAddClub: () -> Unit ) { Column( modifier = modifier - ){ + ) { Row( modifier = Modifier .fillMaxWidth(), @@ -53,15 +54,17 @@ fun MyClubComponent( fontWeight = FontWeight.SemiBold, fontSize = 16.sp ) - Text( - modifier = Modifier - .clickable(onClick = onNavigateToAddClub), - text = "추가하기", - color = Color(0xFFF89531), - fontFamily = pretendardFontFamily(), - fontSize = 16.sp, - textDecoration = TextDecoration.Underline - ) + if (isEditable) { + Text( + modifier = Modifier + .clickable(onClick = onNavigateToAddClub), + text = "추가하기", + color = Color(0xFFF89531), + fontFamily = pretendardFontFamily(), + fontSize = 16.sp, + textDecoration = TextDecoration.Underline + ) + } } Spacer(modifier = Modifier.size(20.dp)) LazyColumn( @@ -78,7 +81,8 @@ fun MyClubComponent( items(myClubs) { clubData -> MyClubItem( modifier = Modifier, - clubName = clubData.clubName + clubName = clubData.clubName, + isEditable = isEditable, ) { println("clicked clubId : ${clubData.clubId}") onDeleteClub(clubData.clubId) @@ -91,6 +95,7 @@ fun MyClubComponent( @Composable fun MyClubItem( modifier: Modifier = Modifier, + isEditable: Boolean = false, clubName: String, onDeleteClub: () -> Unit ) { @@ -106,13 +111,15 @@ fun MyClubItem( fontFamily = pretendardFontFamily(), fontSize = 16.sp ) - AsyncImage( - model = Res.getUri("files/ic_x.svg"), - contentDescription = "Delete Club", - modifier = Modifier - .size(24.dp) - .clickable(onClick = onDeleteClub) - ) + if (isEditable) { + AsyncImage( + model = Res.getUri("files/ic_x.svg"), + contentDescription = "Delete Club", + modifier = Modifier + .size(24.dp) + .clickable(onClick = onDeleteClub) + ) + } } } From 2eb4fbbc2d3fc7ac65b2efa9cd789dea841c15ce Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:19:20 +0900 Subject: [PATCH 09/18] =?UTF-8?q?[REFACTOR]:=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=20=ED=95=A8=EC=88=98=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20backhandler=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/presentation/mypage/MyPageScreen.kt | 13 ++++++++++--- .../client/presentation/mypage/MyPageViewModel.kt | 3 +-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index b52e36a..5b38db2 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -1,7 +1,6 @@ package org.whosin.client.presentation.mypage import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -25,7 +24,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.ui.tooling.preview.Preview import org.koin.compose.viewmodel.koinViewModel -import org.whosin.client.data.dto.response.ClubData +import org.whosin.client.presentation.component.CommonBackHandler import org.whosin.client.presentation.mypage.component.MyClubComponent import org.whosin.client.presentation.mypage.component.MyPageButton import org.whosin.client.presentation.mypage.component.MyPageTopAppBar @@ -44,6 +43,14 @@ fun MyPageScreen( val viewModel: MyPageViewModel = koinViewModel() val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + CommonBackHandler { + if (uiState.isEditable) { + viewModel.toggleEditMode() + } else { + onNavigateBack() + } + } + Box( modifier = modifier .fillMaxSize() @@ -110,7 +117,7 @@ fun MyPageScreen( // 내 정보 수정 버튼 - 하단에 고정 MyPageButton( - onClick = { viewModel.enableEditMode() }, + onClick = { viewModel.toggleEditMode() }, text = stringResource( if (uiState.isEditable) Res.string.complete_edit else Res.string.edit_my_information diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index a4b1bc6..86ba38f 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -9,7 +9,6 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.whosin.client.core.network.ApiResult import org.whosin.client.data.dto.response.ClubData -import org.whosin.client.data.dto.response.MyClubData import org.whosin.client.data.repository.MemberRepository data class MyPageUiState( @@ -31,7 +30,7 @@ class MyPageViewModel( } // 수정 모드 변경 - fun enableEditMode() { + fun toggleEditMode() { _uiState.update { it.copy(isEditable = !it.isEditable) } } From 12cf31e55eaa0eea0fc244eea6f073df4e3b97c1 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:26:15 +0900 Subject: [PATCH 10/18] =?UTF-8?q?[FEAT]:=20=EC=82=AD=EC=A0=9C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20ui=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whosin/client/presentation/mypage/MyPageScreen.kt | 6 +++--- .../whosin/client/presentation/mypage/MyPageViewModel.kt | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index 5b38db2..6c38e81 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -46,6 +46,7 @@ fun MyPageScreen( CommonBackHandler { if (uiState.isEditable) { viewModel.toggleEditMode() + viewModel.getMyInfo() } else { onNavigateBack() } @@ -107,9 +108,8 @@ fun MyPageScreen( .padding(bottom = 72.dp), isEditable = uiState.isEditable, myClubs = uiState.clubs, - onDeleteClub = { - // TODO: 동아리 삭제 -// viewModel.deleteClub(it) + onDeleteClub = { clubId -> + viewModel.deleteClub(clubId) }, onNavigateToAddClub = onNavigateToAddClub ) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index 86ba38f..bee7b6d 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -74,5 +74,14 @@ class MyPageViewModel( // TODO: 내 정보 수정 + // 클럽 삭제 (UI 상태에서만 제거) + fun deleteClub(clubId: Int) { + _uiState.update { currentState -> + currentState.copy( + clubs = currentState.clubs.filter { it.clubId != clubId } + ) + } + println("MyPageViewModel: 클럽 삭제 - clubId: $clubId") + } } \ No newline at end of file From 9d53b1ad2fb18ee59b30287b7af2f03baaff22af Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:41:21 +0900 Subject: [PATCH 11/18] =?UTF-8?q?[FIX]:=20=EC=9D=91=EB=8B=B5=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt index d073120..88f3d4a 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/UpdateMyInfoResponseDto.kt @@ -12,5 +12,5 @@ data class UpdateMyInfoResponseDto( @SerialName("message") val message: String, @SerialName("data") - val data: String? = null + val data: MyInfoData ) From d5df7fbf907ce1aa828b6a0affdd647ec082efe8 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:41:42 +0900 Subject: [PATCH 12/18] =?UTF-8?q?[FIX]:=20=EC=9A=94=EC=B2=AD=EC=8B=9C=20se?= =?UTF-8?q?tBody=20=ED=95=A8=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/data/remote/RemoteMemberDataSource.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt index cc08ccc..aa47518 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteMemberDataSource.kt @@ -81,10 +81,10 @@ class RemoteMemberDataSource( clubList: List? ): ApiResult { return try { - val response: HttpResponse = client.patch(urlString = "users/myPage/update"){ - setBody{ + val response: HttpResponse = client.patch(urlString = "users/myPage/update") { + setBody( UpdateMyInfoRequestDto(nickName = newNickName, clubList = clubList) - } + ) } if (response.status.isSuccess()) { From 17978ed7656c43a38d29a97ae06db74b8aa568c0 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 20:45:26 +0900 Subject: [PATCH 13/18] =?UTF-8?q?[FEAT]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/MyPageScreen.kt | 13 +++++++---- .../presentation/mypage/MyPageViewModel.kt | 23 ++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index 6c38e81..d581edf 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -64,7 +64,7 @@ fun MyPageScreen( MyPageTopAppBar(onNavigateBack) Spacer(modifier = Modifier.size(16.dp)) Text( - text = stringResource(if(uiState.isEditable)Res.string.edit_my_information else Res.string.my_information), + text = stringResource(if (uiState.isEditable) Res.string.edit_my_information else Res.string.my_information), fontSize = 24.sp, color = Color.Black, lineHeight = 24.sp, @@ -111,13 +111,18 @@ fun MyPageScreen( onDeleteClub = { clubId -> viewModel.deleteClub(clubId) }, - onNavigateToAddClub = onNavigateToAddClub + onNavigateToAddClub = onNavigateToAddClub ) } - + // 내 정보 수정 버튼 - 하단에 고정 MyPageButton( - onClick = { viewModel.toggleEditMode() }, + onClick = { + if (uiState.isEditable) { + viewModel.updateMyInfo(uiState.nickname, uiState.clubs) + } + viewModel.toggleEditMode() + }, text = stringResource( if (uiState.isEditable) Res.string.complete_edit else Res.string.edit_my_information diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index bee7b6d..14bcb80 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -72,7 +72,28 @@ class MyPageViewModel( } } - // TODO: 내 정보 수정 + // 내 정보 수정 + fun updateMyInfo(newNickName: String, clubList: List?) { + viewModelScope.launch { + _uiState.update{ it.copy(isLoading = true) } + val newClubs = clubList?.map { + it.clubId + } + when (val result = repository.updateMyInfo(newNickName = newNickName, clubList = newClubs)) { + is ApiResult.Success -> { + getMyInfo() + println("MyPageViewModel: 내 정보 수정 성공") + } + is ApiResult.Error -> { + _uiState.value = _uiState.value.copy( + isLoading = false, + errorMessage = result.message ?: "내 정보 수정에 실패했습니다." + ) + println("MyPageViewModel: 내 정보 수정 실패 - ${result.message}") + } + } + } + } // 클럽 삭제 (UI 상태에서만 제거) fun deleteClub(clubId: Int) { From 42257b3c2621b50580c6049276d650ff18177e76 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 21:06:50 +0900 Subject: [PATCH 14/18] =?UTF-8?q?[FEAT]:=20MyPage=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=A7=84=EC=9E=85=ED=95=98=EB=A9=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=93=9C=20=ED=95=B4=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=83=88=EB=A1=9C?= =?UTF-8?q?=EA=B3=A0=EC=B9=A8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whosin/client/presentation/mypage/MyPageScreen.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index d581edf..c815364 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -43,6 +44,14 @@ fun MyPageScreen( val viewModel: MyPageViewModel = koinViewModel() val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + // MyPage로 돌아올 때마다 수정 모드 해제 및 데이터 새로고침 + LaunchedEffect(Unit) { + if (uiState.isEditable) { + viewModel.toggleEditMode() + } + viewModel.getMyInfo() + } + CommonBackHandler { if (uiState.isEditable) { viewModel.toggleEditMode() From c8d9394604dfe8201f460ba02b6eb142de2316b0 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 21:07:15 +0900 Subject: [PATCH 15/18] =?UTF-8?q?[REFACTOR]:=20MyPage=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EC=A7=84=EC=9E=85=20=EC=A7=80=EC=A0=90=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/core/navigation/Route.kt | 2 +- .../client/core/navigation/WhosInNavGraph.kt | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt index f36d8b6..904417f 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/Route.kt @@ -29,7 +29,7 @@ sealed interface Route { data object NicknameInput: Route @Serializable - data object ClubCodeInput: Route + data class ClubCodeInput(val returnToMyPage: Boolean = false): Route /* 메인 화면 */ @Serializable diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt index 9981b8a..e7698a3 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/core/navigation/WhosInNavGraph.kt @@ -6,6 +6,7 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navigation +import androidx.navigation.toRoute import org.whosin.client.presentation.auth.clubcode.ClubCodeInputScreen import org.whosin.client.presentation.auth.login.EmailVerificationScreen import org.whosin.client.presentation.auth.login.LoginScreen @@ -104,18 +105,25 @@ fun WhosInNavGraph( modifier = modifier, onNavigateBack = { navController.navigateUp() }, onNavigateToClubCode = { - navController.navigate(Route.ClubCodeInput) + navController.navigate(Route.ClubCodeInput(returnToMyPage = false)) } ) } - composable { + composable { backStackEntry -> + val route = backStackEntry.toRoute() ClubCodeInputScreen( modifier = modifier, onNavigateBack = { navController.navigateUp() }, onNavigateToHome = { - navController.navigate(Route.Home) { - popUpTo(Route.AuthGraph) { inclusive = true } + if (route.returnToMyPage) { + // MyPage에서 온 경우 단순히 뒤로가기 + navController.navigateUp() + } else { + // 회원가입 플로우에서 온 경우 Home으로 이동 + navController.navigate(Route.Home) { + popUpTo(Route.AuthGraph) { inclusive = true } + } } } ) @@ -138,7 +146,7 @@ fun WhosInNavGraph( modifier = modifier, onNavigateBack = { navController.navigateUp() }, onNavigateToAddClub = { - + navController.navigate(Route.ClubCodeInput(returnToMyPage = true)) } ) } From 796d54c7bcaa28ee954186da49d4eb9a89b7dd58 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 21:18:48 +0900 Subject: [PATCH 16/18] =?UTF-8?q?[FIX]:=20MyPage=20=ED=99=94=EB=A9=B4=20pa?= =?UTF-8?q?dding=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/presentation/mypage/MyPageScreen.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index c815364..2c9293a 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -65,7 +65,7 @@ fun MyPageScreen( modifier = modifier .fillMaxSize() .background(Color.White) - .padding(16.dp) + .padding(top = 16.dp, start = 16.dp, end = 16.dp) ) { Column( modifier = Modifier.fillMaxWidth() @@ -137,7 +137,9 @@ fun MyPageScreen( else Res.string.edit_my_information ), enabled = uiState.nickname.isNotEmpty(), - modifier = Modifier.align(Alignment.BottomCenter) + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 52.dp) ) } From eaf42c377e10008bfcb15dff5ac220948b0abef8 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 21:28:14 +0900 Subject: [PATCH 17/18] =?UTF-8?q?[FIX]:=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=EC=97=90=20singleLine=20=EC=86=8D=EC=84=B1?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80,=20=EC=8B=A4=EC=A0=9C=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=8B=9C=EC=97=90=EB=8A=94=20trim=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/presentation/mypage/MyPageScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt index 2c9293a..ae8be84 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageScreen.kt @@ -95,6 +95,7 @@ fun MyPageScreen( readOnly = !uiState.isEditable, value = uiState.nickname, onValueChange = { viewModel.updateNickName(it) }, + singleLine = true, modifier = Modifier.fillMaxWidth(), textStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Medium), colors = OutlinedTextFieldDefaults.colors( @@ -128,7 +129,7 @@ fun MyPageScreen( MyPageButton( onClick = { if (uiState.isEditable) { - viewModel.updateMyInfo(uiState.nickname, uiState.clubs) + viewModel.updateMyInfo(uiState.nickname.trim(), uiState.clubs) } viewModel.toggleEditMode() }, From 9028f91e894e0d96b76a511de0822293b03e3103 Mon Sep 17 00:00:00 2001 From: casperjr Date: Sat, 4 Oct 2025 21:47:53 +0900 Subject: [PATCH 18/18] =?UTF-8?q?[FEAT]:=20=EB=82=B4=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EC=84=B1=EA=B3=B5=EC=8B=9C=EC=97=90=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/whosin/client/presentation/mypage/MyPageViewModel.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt index 14bcb80..fe98639 100644 --- a/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/whosin/client/presentation/mypage/MyPageViewModel.kt @@ -81,6 +81,9 @@ class MyPageViewModel( } when (val result = repository.updateMyInfo(newNickName = newNickName, clubList = newClubs)) { is ApiResult.Success -> { + _uiState.update { + it.copy(isEditable = false) + } getMyInfo() println("MyPageViewModel: 내 정보 수정 성공") }