Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TNT-181] 트레이니 홈 화면 일별 기록 출력 API 연동 #100

Merged
merged 9 commits into from
Feb 13, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import co.kr.tnt.core.designsystem.R
Expand All @@ -47,7 +44,7 @@ fun TnTRecordCard(
modifier: Modifier = Modifier,
image: Painter? = null,
leadingEmoji: String? = null,
feedbackCount: Int? = null,
showFeedback: Boolean = false,
) {
val maxLines = if (image == null) 3 else 2

Expand All @@ -69,7 +66,7 @@ fun TnTRecordCard(
.size(140.dp)
.clip(RoundedCornerShape(16.dp)),
)
if (feedbackCount != null) {
if (showFeedback) {
Spacer(modifier = Modifier.height(12.dp))
}
}
Expand Down Expand Up @@ -122,7 +119,7 @@ fun TnTRecordCard(
}
}
}
feedbackCount?.let {
if (showFeedback) {
// 사진이 없고 피드백이 있으면 기록과 피드백 사이에 20.dp 간격
// 20 - 8(위의 기록 아래 간격) = 12.dp
if (image == null) {
Expand All @@ -137,21 +134,10 @@ fun TnTRecordCard(
)
Spacer(Modifier.width(2.dp))
Text(
text = buildAnnotatedString {
withStyle(
style = TnTTheme.typography.label2Medium.toSpanStyle(),
) {
append(stringResource(R.string.received_feedback))
}
append(" ")
withStyle(
style = TnTTheme.typography.label2Bold.toSpanStyle(),
) {
append(it.toString())
}
},
text = stringResource(R.string.see_received_feedback),
style = TnTTheme.typography.label2Medium,
color = TnTTheme.colors.neutralColors.Neutral500,
modifier = Modifier.alignBy(LastBaseline),
textAlign = TextAlign.Center,
)
}
}
Expand Down Expand Up @@ -402,7 +388,7 @@ private fun TnTRecordCardWithFeedbackPreview() {
tagText = "상체 운동",
time = "오전 7:30",
modifier = Modifier.padding(10.dp),
feedbackCount = 1,
showFeedback = true,
)
}
}
Expand Down Expand Up @@ -435,7 +421,7 @@ private fun TnTRecordCardWithImageAndFeedbackPreview() {
modifier = Modifier.padding(10.dp),
image = ColorPainter(Color.Gray),
leadingEmoji = "\uD83C\uDF1E",
feedbackCount = 2,
showFeedback = true,
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/designsystem/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<string name="placeholder_content_input">내용을 입력해주세요</string>

<!-- Card -->
<string name="received_feedback">받은 피드백</string>
<string name="see_received_feedback">받은 피드백 보기</string>
<string name="make_pt_session_record">PT 수업 기록 남기기</string>
<string name="see_pt_session_record">수업 기록 보기</string>
<string name="lesson_count">%s회차 수업</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,66 @@ import co.kr.tnt.domain.model.trainee.TraineeDailyRecord
import co.kr.tnt.domain.model.trainee.TraineePtSession
import co.kr.tnt.domain.utils.DateFormatter
import kotlinx.serialization.Serializable
import java.time.LocalDateTime

@Serializable
data class DailyRecordsResponse(
val date: String,
val lessons: PtSessionResponse?,
val records: List<RecordResponse>,
val ptInfo: PtSessionResponse?,
val diets: List<DietRecordResponse>?,
)

@Serializable
data class PtSessionResponse(
val ptSessionId: String,
val trainerName: String,
val trainerImage: String?,
val session: Int,
val startTime: String,
val endTime: String,
val hasRecord: Boolean,
val trainerName: String?,
val trainerProfileImage: String?,
val session: Int?,
val lessonStart: String?,
val lessonEnd: String?,
Comment on lines +22 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오잉 이건 왜 다 nullable 이 됐나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버 response 따라가다보니 nullable로 됐습니당.. 배포하고 다시 수정해야 할 것 같습니다!!!

)

@Serializable
data class RecordResponse(
val recordId: Long,
val recordType: String,
val recordTime: String,
val recordImage: String?,
val recordContents: String,
val feedbackCount: Int,
data class DietRecordResponse(
val dietId: Long,
val date: String,
val dietImageUrl: String?,
val dietType: String,
val memo: String,
)

fun DailyRecordsResponse.toDomain(dateFormatter: DateFormatter) =
TraineeDailyRecord(
date = dateFormatter.parse(date),
ptSession = lessons?.toDomain(dateFormatter),
record = records.map { it.toDomain(dateFormatter) },
ptSession = ptInfo?.takeIf { it.hasValidData() }?.toDomain(dateFormatter),
record = diets?.map { it.toDomain(dateFormatter) } ?: emptyList(),
)

fun PtSessionResponse.hasValidData(): Boolean {
return session != null || lessonStart != null || lessonEnd != null
}

fun PtSessionResponse.toDomain(dateFormatter: DateFormatter) = TraineePtSession(
ptSessionId = ptSessionId,
trainerName = trainerName,
trainerImage = trainerImage,
session = session,
startTime = dateFormatter.parseDateTime(startTime),
endTime = dateFormatter.parseDateTime(endTime),
hasRecord = hasRecord,
// TODO : pt 수업 id
ptSessionId = 0L,
trainerName = trainerName ?: "",
trainerImage = trainerProfileImage,
session = session ?: 0,
startTime = lessonStart?.let { dateFormatter.parseDateTime(it) } ?: LocalDateTime.MIN,
endTime = lessonEnd?.let { dateFormatter.parseDateTime(it) } ?: LocalDateTime.MIN,
// TODO : 수업 기록 존재 여부 반영
hasRecord = false,
)

fun RecordResponse.toDomain(dateFormatter: DateFormatter) = DailyRecord(
recordId = recordId,
recordType = recordType.toRecordType() ?: MealType.BREAKFAST,
recordTime = dateFormatter.parseDateTime(recordTime),
recordImage = recordImage,
recordContents = recordContents,
feedbackCount = feedbackCount,
fun DietRecordResponse.toDomain(dateFormatter: DateFormatter) = DailyRecord(
recordId = dietId,
recordType = dietType.toRecordType() ?: MealType.BREAKFAST,
recordTime = dateFormatter.parseDateTime(date),
recordImage = dietImageUrl,
recordContents = memo,
// TODO 피드백 존재 여부 반영
hasFeedback = false,
)

// TODO : 수정
fun String.toRecordType(): RecordType? {
return when (this.uppercase()) {
"BREAKFAST" -> MealType.BREAKFAST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import co.kr.data.network.model.LoginResponse
import co.kr.data.network.model.SignUpResponse
import co.kr.data.network.model.UserResponse
import co.kr.data.network.model.VerifyCodeResponse
import co.kr.data.network.model.trainee.DailyRecordsResponse
import co.kr.data.network.model.trainee.MealRecordDetailResponse
import co.kr.data.network.model.trainee.WeeklyRecordedDatesResponse
import co.kr.data.network.model.trainer.ActiveTraineesResponse
Expand Down Expand Up @@ -113,6 +114,11 @@ interface ApiService {
@Query("endDate") endDate: String,
): WeeklyRecordedDatesResponse

@GET("/trainees/calendar/{date}")
suspend fun getDailyRecord(
@Path("date") date: String,
): DailyRecordsResponse

@GET("/trainees/diets/{dietId}")
suspend fun getMealRecord(
@Path("dietId") dietId: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ class TraineeRemoteDataSource @Inject constructor(
apiService.getWeeklyRecordedDates(startDate, endDate)
}

suspend fun getDailyRecord(
date: String,
) = networkHandler {
apiService.getDailyRecord(date)
}

suspend fun getMealRecord(dietId: Long) = networkHandler {
apiService.getMealRecord(dietId)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package co.kr.data.repository

import co.kr.data.network.model.toDomain
import co.kr.data.network.model.trainee.DailyRecordsResponse
import co.kr.data.network.model.trainee.MealRecordRequest
import co.kr.data.network.model.trainee.PtSessionResponse
import co.kr.data.network.model.trainee.RecordResponse
import co.kr.data.network.model.trainee.toDomain
import co.kr.data.network.source.TraineeRemoteDataSource
import co.kr.data.network.source.UserRemoteDataSource
Expand Down Expand Up @@ -45,140 +42,14 @@ internal class TraineeRepositoryImpl @Inject constructor(
endDate: String,
): TraineeDailyRecordStatus {
val response = traineeRemoteDataSource.getWeeklyRecordedDates(startDate, endDate)

return response.toDomain(dateFormatter)
}

// TODO : API에 맞춰 수정
override suspend fun getTraineeDailyRecord(day: LocalDate): TraineeDailyRecord {
val result = listOf(
DailyRecordsResponse(
date = "2025-02-03",
lessons = PtSessionResponse(
ptSessionId = "CDE35K32",
trainerName = "김헬스",
trainerImage = "https://buly.kr/44x6xFN",
session = 12,
startTime = "2025-02-03T08:00:00",
endTime = "2025-02-03T09:00:00",
hasRecord = true,
),
records = listOf(
RecordResponse(
recordId = 0L,
recordType = "BREAKFAST",
recordTime = "2025-02-03T08:00:00",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "아침으로 계란 2개 먹었습니다.",
feedbackCount = 1,
),
RecordResponse(
recordId = 0L,
recordType = "LUNCH",
recordTime = "2025-02-03T13:00:00",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "점심으로 계란 5개 먹었습니다.",
feedbackCount = 0,
),
),
),
DailyRecordsResponse(
date = "2025-02-08",
lessons = null,
records = listOf(
RecordResponse(
recordId = 0L,
recordType = "BREAKFAST",
recordTime = "2025-02-08T13:00:00",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 2개 먹었습니다.",
feedbackCount = 1,
),
RecordResponse(
recordId = 0L,
recordType = "SNACK",
recordTime = "2025-02-08T15:00:00",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 반개 먹었습니다.",
feedbackCount = 0,
),
RecordResponse(
recordId = 0L,
recordType = "DINNER",
recordTime = "2025-02-08T18:40:00",
recordImage = null,
recordContents = "저녁으로 소고기 먹었습니다.",
feedbackCount = 2,
),
),
),
DailyRecordsResponse(
date = "2025-02-15",
lessons = PtSessionResponse(
ptSessionId = "OSI93DG1",
trainerName = "이강사",
trainerImage = null,
session = 15,
startTime = "2025-02-15T18:00:00",
endTime = "2025-02-15T19:00:00",
hasRecord = true,
),
records = listOf(
RecordResponse(
recordId = 0L,
recordType = "LUNCH",
recordTime = "2025-02-15T13:00:00",
recordImage = null,
recordContents = "비빔밥, 바나나 1개",
feedbackCount = 1,
),
RecordResponse(
recordId = 0L,
recordType = "DINNER",
recordTime = "2025-02-03T20:00:00",
recordImage = "https://buly.kr/BpESNP5",
recordContents = "계란 5개 먹었습니다.",
feedbackCount = 0,
),
),
),
DailyRecordsResponse(
date = "2025-02-10",
lessons = PtSessionResponse(
ptSessionId = "CDK392DF",
trainerName = "박트레이너",
trainerImage = null,
session = 10,
startTime = "2025-02-10T14:30:00",
endTime = "2025-02-10T15:30:00",
hasRecord = false,
),
records = emptyList(),
),
DailyRecordsResponse(
date = "2025-02-23",
lessons = PtSessionResponse(
ptSessionId = "CDE35K32",
trainerName = "정트레이너",
trainerImage = "https://buly.kr/44x6xFN",
session = 25,
startTime = "2025-02-23T06:00:00",
endTime = "2025-02-23T06:50:00",
hasRecord = true,
),
records = emptyList(),
),
).map { response ->
response.toDomain(dateFormatter)
}.firstOrNull { it.date == day }

val noData = TraineeDailyRecord(
date = day,
ptSession = null,
record = emptyList(),
)
override suspend fun getDailyRecord(date: LocalDate): TraineeDailyRecord {
val selectedDate = dateFormatter.format(date, "yyyy-MM-dd")
val response = traineeRemoteDataSource.getDailyRecord(selectedDate)

return result ?: noData
return response.toDomain(dateFormatter)
}

override suspend fun postMealRecord(
Expand Down
2 changes: 1 addition & 1 deletion domain/src/main/java/co/kr/tnt/domain/model/DailyRecord.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ data class DailyRecord(
val recordTime: LocalDateTime,
val recordImage: String?,
val recordContents: String,
val feedbackCount: Int,
val hasFeedback: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ data class TraineeDailyRecord(
)

data class TraineePtSession(
val ptSessionId: String,
val ptSessionId: Long,
val trainerName: String,
val trainerImage: String?,
val session: Int,
Expand Down
Loading