Skip to content

Commit 8148e56

Browse files
authored
[FEAT/#1612] 솝레터 메인 2차 API 연동 (#1615)
* [CHORE/#1612] EditSopletterFloatingActionButton prefix Write 로 수정 * [FEAT/#1612] 이모지 포함 텍스트 길이 계산을 위한 확장 함수 추가 * [FEAT/#1612] 솝레터 메모 상세 내역 수정 UI 구현 * [FEAT/#1612] 솝레터 메모 수정 시 글자 수 제한 및 유효성 검사 로직 추가 * [FEAT/#1612] 솝레터 메시지 수정 API 연동 - `UpdateSopletterMessageRequestDto` 추가 및 `SopletterService` 내 PATCH API 정의. - `SopletterDataSource`, `SopletterRepository` 및 관련 구현체에 메시지 수정 기능 추가. - `SopletterMainViewModel`에서 메시지 수정 API를 연동하고, 성공 시 UI 상태(메모 목록 및 상세 다이얼로그) 업데이트 로직 구현. - 수정 성공 시 성공 스낵바 노출 및 실패 시 에러 다이얼로그 표시 처리 추가. * [MOD/#1612] TwoButtonDialog 버튼 세로 패딩 커스텀 기능 추가 - `TwoButtonDialog`에 `buttonVerticalPadding` 파라미터 추가 (기본값 11.dp) - `DialogButton`이 고정된 값(11.dp) 대신 전달받은 `verticalPadding`을 사용하도록 수정 * [UI/#1612] 솝레터 삭제 확인 다이얼로그 추가 - `SopletterDeleteDialog` 컴포넌트 신규 생성. * [FEAT/#1612] 솝레터 메시지 삭제 API 연동 * [MOD/#1612] SopletterScaffold 및 메모 상세 다이얼로그 스낵바 노출 로직 수정 - `SopletterScaffold`에서 외부 스낵바 호스트의 가시성을 조절할 수 있는 `isOuterSnackbarHostVisible` 파라미터를 추가하였습니다. - 스낵바 UI 구성을 별도의 `SopletterSnackbarHost` 컴포저블로 분리하고, 텍스트가 길어질 경우를 대비해 `Ellipsis` 처리를 추가하였습니다. - `SopletterMemoDetailDialog` 내부에서 스낵바를 직접 보여줄 수 있도록 `SnackbarHostState`를 주입받아 다이얼로그 전용 스낵바 레이아웃을 구현하였습니다. - `SopletterMainScreen`에서 다이얼로그가 띄워진 경우 외부 스낵바가 보이지 않도록 상태를 연결하였습니다. * [REFACTOR/#1612] SopletterMemoDetailDialog 컴포넌트 리팩터링 및 UI 구조 개선 - `SopletterMemoDetailDialog` 내부의 복잡한 로직을 `MemoDialogHeader`, `MemoDialogContent`, `MemoDialogActionButton` 등의 개별 컴포저블로 분리하여 가독성 개선. - `ColumnScope` 확장 함수를 사용하여 레이아웃 계층 최적화. - 수정 완료 버튼의 활성화/비활성화 상태에 따른 배경색 및 텍스트 색상 로직 정립. * [FIX/#1612] sopletter 다이얼로그 전용 스낵바 추가 및 노출 로직 개선 - `outerSnackbarHostState`와 `dialogSnackbarHostState`를 분리하여 메인 화면과 다이얼로그 각각의 스낵바 호스트를 관리하도록 수정합니다. - `ShowSnackbar` 사이드 이펙트에 `SnackbarTarget` 필드를 추가하여 스낵바 노출 위치를 지정할 수 있도록 개선합니다. - 메모 상세 다이얼로그가 닫힐 때 다이얼로그 전용 스낵바를 dismiss 하는 로직을 추가합니다. - 메모 삭제 완료 시 스낵바가 메인 화면에 노출되도록 `SnackbarTarget.OUTER`를 적용합니다. * [MOD/#1612] Sopletter 에러 발생 시 ErrorDialog 대신 Snackbar를 노출하도록 수정 - `SopletterMainViewModel`의 에러 처리 로직에서 `isShowErrorDialog`를 `false`로 변경하고, 대신 실패 안내 메시지를 담은 Snackbar SideEffect를 호출하도록 수정하였습니다. * [FEAT/#1612] Sopletter 주제 조회 기능 구현 - `SopletterTopic` 도메인 모델 및 관련 DTO(`SopletterTopicsResponseDto`, `SopletterTopicDto`) 추가 - `SopletterRepository` 및 실구현체에 `getTopics` 함수 추가 - `SopletterDataSource` 및 `SopletterService`에 주제 조회 API 연동 - DTO를 도메인 모델로 변환하기 위한 `SopletterMapper` 로직 추가 * [FEAT/#1612] sopletter 토픽 리스트 조회 및 에러 처리 구현 - `SopletterTopicUiModel`을 제거하고 도메인 모델인 `SopletterTopic`을 사용하도록 변경 - `SopletterTopicViewModel`에 `SopletterRepository`를 통한 토픽 조회 및 재시도 로직 추가 - 토픽 조회 실패 시 `NetworkErrorDialog`를 노출하도록 처리 - `topicId`의 타입을 `Int`에서 `Long`으로 변경 - `SopletterMainScreen`에서 토픽 화면으로의 네비게이션 연결 추가 * [MOD/#1612] Sopletter 관련 데이터 모델 및 DTO 명칭 변경 - `SopletterDefaultMessages`를 `SopletterMessages`로 리네임하여 범용성 개선. - `SopletterDefaultMessagesResponseDto`를 `SopletterMessagesResponseDto`로 리네임. - Repository, DataSource, Service, Mapper 내 관련 타입 참조 업데이트. * [FEAT/#1612] 개별 메시지 조회 API 추가 - `SopletterRepository` 및 `SopletterDataSource`에 토픽별 메시지 조회를 위한 `getTopicMessages` 함수 추가 - `SopletterService`에 `GET /sopt-letter/topics/{topicId}/messages` API 연동 - Repository 및 DataSource 구현체에 관련 로직 반영 * [FEAT/#1612] Sopletter 특정 토픽 기반 메시지 조회 기능 추가 - `SopletterMainUiState`에 `selectedTopicId` 필드 추가 - `SavedStateHandle`을 통해 전달받은 `topicId`를 기반으로 토픽별 메시지 또는 기본 메시지를 조회하도록 `fetchMessages` 로직 개선 - 초기 진입 시 토픽 ID 유무에 따른 초기화 로직(`initMessages`) 구현 - `fetchDefaultMessages` 메서드 명칭을 `fetchMessages`로 변경하여 범용성 확보 * [MOD/#1612] SopletterMainTopBar UI 및 뒤로가기 로직 수정 - `ic_btn_arrow_left` 벡터 에셋을 추가하였습니다. - `SopletterMainTopBar`에서 `isTopicDetail` 상태에 따라 닫기 아이콘과 뒤로가기 아이콘이 교체되도록 수정하였습니다. - 상단 바 아이콘들에 `size(32.dp)`를 적용하고, 타이틀 텍스트에 `Ellipsis` 처리를 추가하였습니다. - `SopletterMainRoute` 및 `SopletterMainScreen`의 `onCloseClick` 콜백을 `onBackClick`으로 변경하고 `navigateUp`을 연결하였습니다. - 주제 상세 화면 여부에 따라 토픽 아이콘 클릭 시의 동작을 조정하였습니다. * [FEAT/#1612] Sopletter 메인 및 토픽 화면 네비게이션 구현 - `SopletterMain` 및 `SopletterTopic` 목적지(Route) 정의 - `sopletterGraph` 내 메인 화면과 토픽 화면 컴포저블 추가 - 온보딩 완료 시 메인 화면으로 이동 및 백스택 제거 로직 구현 - `NavController.navigateToSopletter` 확장 함수 추가 * [FEAT/#1612] sopletter 모듈 내비게이션 구조 개선 및 화면 연결 - `SopletterMain` 및 `SopletterTopic` 내비게이션 목적지와 확장 함수를 별도 파일로 분리. - `SopletterNameScreen`에서 메인 화면으로 이동하는 내비게이션 로직 구현. - `sopletterGraph` 내에서 직접 `navigate` 호출 대신 정의된 확장 함수(`navigateToSopletterMain`, `navigateToSopletterTopic`)를 사용하도록 변경. - 이름 설정 완료 후 메인 이동 시 온보딩 화면이 스택에 남지 않도록 `navOptions` 적용. - `popBackStack` 대신 `navigateUp`을 사용하여 일관된 뒤로가기 동작 적용. * [FEAT/#1612] Sopletter 진입 시 온보딩 완료 여부에 따른 라우팅 로직 추가 - `SopletterEntryRoute` 및 `SopletterEntryViewModel`을 생성하여 온보딩 완료 여부에 따라 메인 또는 온보딩 페이지로 분기 처리 로직을 구현했습니다. - `SopletterNavigation`의 시작 목적지(startDestination)를 `SopletterEntry`로 변경했습니다. - `SopletterMainViewModel`에서 `topicId`를 가져오는 방식을 `SavedStateHandle` 직접 참조로 수정했습니다. * [FEAT/#1612] Sopletter 메인 토픽 CTA 추가 및 레이아웃 수정 - 신규 컴포넌트 `SopletterTopicCta` 추가 및 메인 화면(리스트/빈 화면) 상단에 적용 - `EmptySopletterContent` 레이아웃을 `fillMaxWidth`로 수정 및 빈 화면 내 간격 조정 - 빈 화면 상태에서도 글쓰기 플로팅 버튼(FAB)이 표시되도록 수정 - `SopletterPullRefreshContainer` 내 인디케이터 노출 조건 수정 (`isInitialized` 기반) - 메인 리스트 상단에 CTA 컴포넌트 배치를 위해 `StaggeredGridItemSpan.FullLine` 적용 * [MOD/#1612] SopletterMainScreen 내 토픽 CTA 버튼 가시성 로직 수정 - `uiState.selectedTopicId`가 null일 때만 `SopletterTopicCta`가 표시되도록 가시성 조건 추가. * [MOD/#1612] Sopletter 초기화 상태(isInitialized)에 따른 UI 처리 - `SopletterMainScreen`에 `isInitialized` 상태에 따른 분기 처리를 추가하여 초기화 전 빈 배경을 노출하도록 수정했습니다. - `SopletterMainPreviewParameterProvider` 내 프리뷰 데이터에 `isInitialized = true` 기본값을 추가했습니다. * [MOD/#1612] SopletterMemoDetailDialog의 Dialog 컴포넌트를 커스텀 Box 오버레이로 대체 - `Dialog` 컴포넌트를 제거하고 전체 화면 `Box`와 배경 오버레이를 사용하는 구조로 변경 - 키보드 활성화 시 레이아웃 대응을 위해 편집 모드에 `imePadding` 적용 - 다이얼로그 내부 클릭 시 배경의 dismiss 이벤트가 트리거되지 않도록 `consumeClicks` 확장 함수 추가 및 적용 - 편집 상태(`isEditing`)에 따라 `dialogMinHeight`가 유동적으로 변하도록 로직 수정 * [REFACTOR/#1612] Sopletter 개별 스낵바 통합 - `SopletterMemoDetailDialog`에서 `SnackbarHost`를 제거하고 관련 파라미터를 정리하였습니다. - `SopletterMainScreen` 내 개별적으로 관리되던 스낵바 상태(`outerSnackbarHostState`, `dialogSnackbarHostState`)를 단일 `snackbarHostState`로 통합하였습니다. - 스낵바가 화면 최상단에 노출되도록 레이아웃 구조를 `Box`로 감싸고 `SopletterSnackbarHost` 위치를 조정하였습니다. - `SopletterMainSideEffect`에서 더 이상 사용하지 않는 `SnackbarTarget` 옵션을 제거하였습니다. * [MOD/#1612] SopletterEntryRoute 배경색 수정 - Change the background color of `SopletterEntryRoute` from `onSurface950` to `background`. * [MOD/#1612] SopletterScaffold 내 스낵바 가시성 파라미터명 변경 - `SopletterScaffold`의 `isOuterSnackbarHostVisible` 파라미터명을 `isSnackbarHostVisible`로 변경하였습니다. - `SopletterMainScreen`에서 변경된 파라미터명을 반영하였습니다. * [MOD/#1612] SopletterMainViewModel에서 Safe Args를 사용하여 topicId를 가져오도록 수정 * [MOD/#1612] 수정 취소 시 텍스트 상태를 기존 내용으로 초기화하도록 수정 - Reset `editTextState` to the original content and place the cursor at the end when `onEditCancelClick` is triggered in `SopletterMemoDetailDialog`. * [FEAT/#1612] SopletterMemoDetailDialog 내 뒤로가기 핸들링 로직 추가 - `BackHandler`를 추가하여 수정 중일 경우 수정 취소 처리를, 아닐 경우 다이얼로그 닫기 처리를 수행하도록 변경함. * [MOD/#1612] 머지후 꼬인 navigation, innerPadding 수정
1 parent 9486a15 commit 8148e56

38 files changed

Lines changed: 1342 additions & 348 deletions

core/designsystem/src/main/java/org/sopt/official/designsystem/component/dialog/TwoButtonDialog.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import androidx.compose.runtime.Composable
3737
import androidx.compose.ui.Modifier
3838
import androidx.compose.ui.text.style.TextAlign
3939
import androidx.compose.ui.tooling.preview.Preview
40+
import androidx.compose.ui.unit.Dp
4041
import androidx.compose.ui.unit.dp
4142
import androidx.compose.ui.window.DialogProperties
4243
import org.sopt.official.designsystem.SoptTheme
@@ -49,6 +50,7 @@ fun TwoButtonDialog(
4950
onPositiveClick: () -> Unit,
5051
onNegativeClick: () -> Unit,
5152
modifier: Modifier = Modifier,
53+
buttonVerticalPadding: Dp = 11.dp,
5254
properties: DialogProperties = DialogProperties(
5355
usePlatformDefaultWidth = false
5456
),
@@ -77,6 +79,7 @@ fun TwoButtonDialog(
7779
disabledContainerColor = SoptTheme.colors.onSurface600,
7880
disabledContentColor = SoptTheme.colors.primary
7981
),
82+
verticalPadding = buttonVerticalPadding,
8083
modifier = Modifier.weight(1f)
8184
)
8285

@@ -89,6 +92,7 @@ fun TwoButtonDialog(
8992
disabledContainerColor = SoptTheme.colors.primary,
9093
disabledContentColor = SoptTheme.colors.onSurface
9194
),
95+
verticalPadding = buttonVerticalPadding,
9296
modifier = Modifier.weight(1f)
9397
)
9498
}
@@ -101,11 +105,12 @@ private fun DialogButton(
101105
text: String,
102106
onClick: () -> Unit,
103107
colors: ButtonColors,
108+
verticalPadding: Dp,
104109
modifier: Modifier = Modifier
105110
) {
106111
Button(
107112
onClick = onClick,
108-
contentPadding = PaddingValues(vertical = 11.dp),
113+
contentPadding = PaddingValues(vertical = verticalPadding),
109114
colors = colors,
110115
shape = RoundedCornerShape(10.dp),
111116
modifier = modifier

data/sopletter/src/main/java/org/sopt/official/data/sopletter/datasource/SopletterDataSource.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,22 @@
2424
*/
2525
package org.sopt.official.data.sopletter.datasource
2626

27-
import org.sopt.official.data.sopletter.dto.response.SopletterDefaultMessagesResponseDto
27+
import org.sopt.official.data.sopletter.dto.response.SopletterMessagesResponseDto
2828
import org.sopt.official.data.sopletter.dto.response.SopletterMessageDetailResponseDto
2929
import org.sopt.official.data.sopletter.dto.response.SopletterReportFormResponseDto
30+
import org.sopt.official.data.sopletter.dto.response.SopletterTopicsResponseDto
3031

3132
interface SopletterDataSource {
3233
suspend fun getDefaultMessages(
3334
cursor: Long?,
3435
size: Int,
35-
): SopletterDefaultMessagesResponseDto
36+
): SopletterMessagesResponseDto
37+
38+
suspend fun getTopicMessages(
39+
topicId: Long,
40+
cursor: Long?,
41+
size: Int,
42+
): SopletterMessagesResponseDto
3643

3744
suspend fun getReportForm(): SopletterReportFormResponseDto
3845

@@ -50,4 +57,19 @@ interface SopletterDataSource {
5057
topicId: Long,
5158
messageId: Long,
5259
)
60+
61+
suspend fun updateMessage(
62+
topicId: Long,
63+
messageId: Long,
64+
content: String,
65+
): SopletterMessageDetailResponseDto
66+
67+
suspend fun deleteMessage(
68+
topicId: Long,
69+
messageId: Long,
70+
)
71+
72+
suspend fun getTopics(
73+
type: String,
74+
): SopletterTopicsResponseDto
5375
}

data/sopletter/src/main/java/org/sopt/official/data/sopletter/datasourceimpl/SopletterDataSourceImpl.kt

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
package org.sopt.official.data.sopletter.datasourceimpl
2626

2727
import org.sopt.official.data.sopletter.datasource.SopletterDataSource
28-
import org.sopt.official.data.sopletter.dto.response.SopletterDefaultMessagesResponseDto
28+
import org.sopt.official.data.sopletter.dto.request.UpdateSopletterMessageRequestDto
29+
import org.sopt.official.data.sopletter.dto.response.SopletterMessagesResponseDto
2930
import org.sopt.official.data.sopletter.dto.response.SopletterMessageDetailResponseDto
3031
import org.sopt.official.data.sopletter.dto.response.SopletterReportFormResponseDto
32+
import org.sopt.official.data.sopletter.dto.response.SopletterTopicsResponseDto
3133
import org.sopt.official.data.sopletter.service.SopletterService
3234
import javax.inject.Inject
3335
class SopletterDataSourceImpl @Inject constructor(
@@ -36,7 +38,17 @@ class SopletterDataSourceImpl @Inject constructor(
3638
override suspend fun getDefaultMessages(
3739
cursor: Long?,
3840
size: Int,
39-
): SopletterDefaultMessagesResponseDto = sopletterService.getDefaultMessages(
41+
): SopletterMessagesResponseDto = sopletterService.getDefaultMessages(
42+
cursor = cursor,
43+
size = size,
44+
)
45+
46+
override suspend fun getTopicMessages(
47+
topicId: Long,
48+
cursor: Long?,
49+
size: Int,
50+
): SopletterMessagesResponseDto = sopletterService.getTopicMessages(
51+
topicId = topicId,
4052
cursor = cursor,
4153
size = size,
4254
)
@@ -66,4 +78,26 @@ class SopletterDataSourceImpl @Inject constructor(
6678
topicId = topicId,
6779
messageId = messageId,
6880
)
81+
82+
override suspend fun updateMessage(
83+
topicId: Long,
84+
messageId: Long,
85+
content: String,
86+
): SopletterMessageDetailResponseDto = sopletterService.updateMessage(
87+
topicId = topicId,
88+
messageId = messageId,
89+
body = UpdateSopletterMessageRequestDto(content = content),
90+
)
91+
92+
override suspend fun deleteMessage(
93+
topicId: Long,
94+
messageId: Long,
95+
) = sopletterService.deleteMessage(
96+
topicId = topicId,
97+
messageId = messageId,
98+
)
99+
100+
override suspend fun getTopics(
101+
type: String,
102+
): SopletterTopicsResponseDto = sopletterService.getTopics(type = type)
69103
}

data/sopletter/src/main/java/org/sopt/official/data/sopletter/dto/response/SopletterDefaultMessagesResponseDto.kt renamed to data/sopletter/src/main/java/org/sopt/official/data/sopletter/dto/request/UpdateSopletterMessageRequestDto.kt

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,13 @@
2222
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2323
* SOFTWARE.
2424
*/
25-
package org.sopt.official.data.sopletter.dto.response
25+
package org.sopt.official.data.sopletter.dto.request
2626

2727
import kotlinx.serialization.SerialName
2828
import kotlinx.serialization.Serializable
2929

3030
@Serializable
31-
data class SopletterDefaultMessagesResponseDto(
32-
@SerialName("topicId")
33-
val topicId: Long,
34-
@SerialName("title")
35-
val title: String,
36-
@SerialName("totalCount")
37-
val totalCount: Int,
38-
@SerialName("nextCursor")
39-
val nextCursor: Long? = null,
40-
@SerialName("hasNext")
41-
val hasNext: Boolean,
42-
@SerialName("messages")
43-
val messages: List<SopletterMessageDto>,
44-
)
45-
46-
@Serializable
47-
data class SopletterMessageDto(
48-
@SerialName("messageId")
49-
val messageId: Long,
50-
@SerialName("previewContent")
51-
val previewContent: String,
52-
@SerialName("colorCode")
53-
val colorCode: String,
54-
@SerialName("rotationDegree")
55-
val rotationDegree: Double,
56-
@SerialName("shapeType")
57-
val shapeType: String,
58-
)
31+
data class UpdateSopletterMessageRequestDto(
32+
@SerialName("content")
33+
val content: String,
34+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.sopt.official.data.sopletter.dto.response
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class SopletterMessagesResponseDto(
8+
@SerialName("topicId")
9+
val topicId: Long,
10+
@SerialName("title")
11+
val title: String,
12+
@SerialName("totalCount")
13+
val totalCount: Int,
14+
@SerialName("nextCursor")
15+
val nextCursor: Long? = null,
16+
@SerialName("hasNext")
17+
val hasNext: Boolean,
18+
@SerialName("messages")
19+
val messages: List<SopletterMessageDto>,
20+
)
21+
22+
@Serializable
23+
data class SopletterMessageDto(
24+
@SerialName("messageId")
25+
val messageId: Long,
26+
@SerialName("previewContent")
27+
val previewContent: String,
28+
@SerialName("colorCode")
29+
val colorCode: String,
30+
@SerialName("rotationDegree")
31+
val rotationDegree: Double,
32+
@SerialName("shapeType")
33+
val shapeType: String,
34+
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.sopt.official.data.sopletter.dto.response
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class SopletterTopicsResponseDto(
8+
@SerialName("topics")
9+
val topics: List<SopletterTopicDto>,
10+
)
11+
12+
@Serializable
13+
data class SopletterTopicDto(
14+
@SerialName("topicId")
15+
val topicId: Long,
16+
@SerialName("title")
17+
val title: String,
18+
)

data/sopletter/src/main/java/org/sopt/official/data/sopletter/mapper/SopletterMapper.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@
2323
* SOFTWARE.
2424
*/
2525
package org.sopt.official.data.sopletter.mapper
26-
import org.sopt.official.data.sopletter.dto.response.SopletterDefaultMessagesResponseDto
26+
import org.sopt.official.data.sopletter.dto.response.SopletterMessagesResponseDto
2727
import org.sopt.official.data.sopletter.dto.response.SopletterMessageDetailResponseDto
2828
import org.sopt.official.data.sopletter.dto.response.SopletterMessageDto
29-
import org.sopt.official.domain.sopletter.model.SopletterDefaultMessages
29+
import org.sopt.official.data.sopletter.dto.response.SopletterTopicDto
30+
import org.sopt.official.data.sopletter.dto.response.SopletterTopicsResponseDto
31+
import org.sopt.official.domain.sopletter.model.SopletterMessages
3032
import org.sopt.official.domain.sopletter.model.SopletterMessageDetail
3133
import org.sopt.official.domain.sopletter.model.SopletterMessage
3234
import org.sopt.official.domain.sopletter.model.SopletterShapeType
35+
import org.sopt.official.domain.sopletter.model.SopletterTopic
3336

34-
internal fun SopletterDefaultMessagesResponseDto.toDomain(): SopletterDefaultMessages = SopletterDefaultMessages(
37+
internal fun SopletterTopicsResponseDto.toDomain(): List<SopletterTopic> = topics.map(SopletterTopicDto::toDomain)
38+
39+
internal fun SopletterMessagesResponseDto.toDomain(): SopletterMessages = SopletterMessages(
3540
topicId = topicId,
3641
title = title,
3742
totalCount = totalCount,
@@ -58,3 +63,8 @@ internal fun SopletterMessageDetailResponseDto.toDomain(): SopletterMessageDetai
5863
likedByMe = likedByMe,
5964
mine = mine,
6065
)
66+
67+
internal fun SopletterTopicDto.toDomain(): SopletterTopic = SopletterTopic(
68+
topicId = topicId,
69+
title = title,
70+
)

data/sopletter/src/main/java/org/sopt/official/data/sopletter/repository/SopletterRepositoryImpl.kt

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import javax.inject.Inject
2828
import org.sopt.official.common.coroutines.suspendRunCatching
2929
import org.sopt.official.data.sopletter.datasource.SopletterDataSource
3030
import org.sopt.official.data.sopletter.mapper.toDomain
31-
import org.sopt.official.domain.sopletter.model.SopletterDefaultMessages
31+
import org.sopt.official.domain.sopletter.model.SopletterMessages
3232
import org.sopt.official.domain.sopletter.model.SopletterMessageDetail
33+
import org.sopt.official.domain.sopletter.model.SopletterTopic
3334
import org.sopt.official.domain.sopletter.repository.SopletterRepository
3435

3536
internal class SopletterRepositoryImpl @Inject constructor(
@@ -38,13 +39,25 @@ internal class SopletterRepositoryImpl @Inject constructor(
3839
override suspend fun getDefaultMessages(
3940
cursor: Long?,
4041
size: Int,
41-
): Result<SopletterDefaultMessages> = suspendRunCatching {
42+
): Result<SopletterMessages> = suspendRunCatching {
4243
sopletterDataSource.getDefaultMessages(
4344
cursor = cursor,
4445
size = size,
4546
).toDomain()
4647
}
4748

49+
override suspend fun getTopicMessages(
50+
topicId: Long,
51+
cursor: Long?,
52+
size: Int,
53+
): Result<SopletterMessages> = suspendRunCatching {
54+
sopletterDataSource.getTopicMessages(
55+
topicId = topicId,
56+
cursor = cursor,
57+
size = size,
58+
).toDomain()
59+
}
60+
4861
override suspend fun getReportFormUrl(): Result<String> = suspendRunCatching {
4962
sopletterDataSource.getReportForm().reportFormUrl
5063
}
@@ -78,4 +91,30 @@ internal class SopletterRepositoryImpl @Inject constructor(
7891
messageId = messageId,
7992
)
8093
}
94+
95+
override suspend fun updateMessage(
96+
topicId: Long,
97+
messageId: Long,
98+
content: String,
99+
): Result<SopletterMessageDetail> = suspendRunCatching {
100+
sopletterDataSource.updateMessage(
101+
topicId = topicId,
102+
messageId = messageId,
103+
content = content,
104+
).toDomain()
105+
}
106+
107+
override suspend fun deleteMessage(
108+
topicId: Long,
109+
messageId: Long,
110+
): Result<Unit> = suspendRunCatching {
111+
sopletterDataSource.deleteMessage(
112+
topicId = topicId,
113+
messageId = messageId,
114+
)
115+
}
116+
117+
override suspend fun getTopics(): Result<List<SopletterTopic>> = suspendRunCatching {
118+
sopletterDataSource.getTopics(type = SopletterRepository.TOPIC_TYPE_NORMAL).toDomain()
119+
}
81120
}

0 commit comments

Comments
 (0)