diff --git a/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchCourseDetailContainerPreview.kt b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchCourseDetailContainerPreview.kt
new file mode 100644
index 00000000..6061c99f
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchCourseDetailContainerPreview.kt
@@ -0,0 +1,34 @@
+package com.chukchukhaksa.mobile.preview.component.home
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.model.academic.CourseDetail
+import com.chukchukhaksa.mobile.presentation.home.component.CchCourseDetailContainer
+import com.chukchukhaksa.mobile.presentation.home.component.CchTotalGradeContainer
+
+@Preview
+@Composable
+fun CchCourseDetailContainerPreview() {
+ val course = CourseDetail(
+ areaType = "전공선택",
+ courseCode = "09643",
+ courseName = "모바일프로그래밍",
+ credits = 3,
+ grade = "B+",
+ id = "0",
+ isOnline = false,
+ isRetake = false,
+ isRetakeDelete = true,
+ originalScore = 40,
+ professor = "정원용",
+ score = 94,
+ semester = 10,
+ year = 2023,
+ )
+ CchTheme {
+ CchCourseDetailContainer(
+ course = course
+ )
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationProgressContainerPreview.kt b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationProgressContainerPreview.kt
new file mode 100644
index 00000000..ad114f60
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationProgressContainerPreview.kt
@@ -0,0 +1,60 @@
+package com.chukchukhaksa.mobile.preview.component.home
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.model.graduation.GraduationProcessCourse
+import com.chukchukhaksa.mobile.presentation.home.component.CchGraduationProgressContainer
+import com.chukchukhaksa.mobile.presentation.home.component.CchGraduationRequirementsContainer
+
+//@Preview(heightDp = 131)
+@Preview
+@Composable
+fun CchGraduationProgressContainerPreview() {
+ val courses = listOf(
+ GraduationProcessCourse(
+ courseName = "회로이론",
+ credits = 2,
+ grade = "A+",
+ semester = 10,
+ year = 2023,
+ ),
+ GraduationProcessCourse(
+ courseName = "회로이론",
+ credits = 2,
+ grade = "B+",
+ semester = 10,
+ year = 2023,
+ ),
+ GraduationProcessCourse(
+ courseName = "회로이론",
+ credits = 2,
+ grade = "C+",
+ semester = 10,
+ year = 2023,
+ ),
+ GraduationProcessCourse(
+ courseName = "회로이론",
+ credits = 2,
+ grade = "D+",
+ semester = 10,
+ year = 2023,
+ ),
+ GraduationProcessCourse(
+ courseName = "회로이론",
+ credits = 2,
+ grade = "F",
+ semester = 10,
+ year = 2023,
+ ),
+ )
+ CchTheme {
+ CchGraduationProgressContainer(
+ requirementStatus = true,
+ areaType = "중요핵심",
+ earnedCredits = 5,
+ requiredCredits = 6,
+ courses = courses,
+ )
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationRequirementsContainerPreview.kt b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationRequirementsContainerPreview.kt
new file mode 100644
index 00000000..d411f4b6
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchGraduationRequirementsContainerPreview.kt
@@ -0,0 +1,21 @@
+package com.chukchukhaksa.mobile.preview.component.home
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.presentation.home.component.CchGraduationRequirementsContainer
+
+//@Preview(heightDp = 131)
+@Preview
+@Composable
+fun CchGraduationRequirementsContainerPreview() {
+ CchTheme {
+ CchGraduationRequirementsContainer(
+ major = "정보통신학부",
+ gradeLevel = 18,
+ totalEarnedCredits = 109,
+ requiredCredits = 130,
+ onClickGraduationProgress = {},
+ )
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchSemesterGradeButtonPreview.kt b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchSemesterGradeButtonPreview.kt
new file mode 100644
index 00000000..21f30ab2
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchSemesterGradeButtonPreview.kt
@@ -0,0 +1,19 @@
+package com.chukchukhaksa.mobile.preview.component.home
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.presentation.home.component.CchGraduationRequirementsContainer
+import com.chukchukhaksa.mobile.presentation.home.component.CchSemesterGradeButton
+
+@Preview
+@Composable
+fun CchSemesterGradeButtonPreview() {
+ CchTheme {
+ CchSemesterGradeButton(
+ startSemester = "1학년 1학기",
+ endSemester = "3학년 1학기",
+ onClick = {}
+ )
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchTotalGradeContainerPreview.kt b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchTotalGradeContainerPreview.kt
new file mode 100644
index 00000000..a70c939f
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/chukchukhaksa/mobile/preview/component/home/CchTotalGradeContainerPreview.kt
@@ -0,0 +1,18 @@
+package com.chukchukhaksa.mobile.preview.component.home
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.presentation.home.component.CchTotalGradeContainer
+
+@Preview
+@Composable
+fun CchTotalGradeContainerPreview() {
+ CchTheme {
+ CchTotalGradeContainer(
+ totalEarnedCredits = 109,
+ cumulativeGpa = 3.03,
+ percentile = 83.2,
+ )
+ }
+}
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_appbar_arrow_right_chukchuk.xml b/composeApp/src/commonMain/composeResources/drawable/ic_appbar_arrow_right_chukchuk.xml
new file mode 100644
index 00000000..06f32032
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_appbar_arrow_right_chukchuk.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_black.xml b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_black.xml
new file mode 100644
index 00000000..45ac141d
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_black.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_white.xml b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_white.xml
new file mode 100644
index 00000000..20e5544e
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_down_white.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_black.xml b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_black.xml
new file mode 100644
index 00000000..a18707b4
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_black.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_white.xml b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_white.xml
new file mode 100644
index 00000000..e4073e08
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_arrow_up_white.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_check_box.xml b/composeApp/src/commonMain/composeResources/drawable/ic_check_box.xml
new file mode 100644
index 00000000..8e99ecfc
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_check_box.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt
index 51f4478c..52f59dd9 100644
--- a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt
@@ -6,8 +6,8 @@ data class AcademicRecord(
)
data class AcademicRecordCourses(
- val liberal: List,
- val major: List
+ val liberal: List,
+ val major: List
)
data class SemesterGrade(
@@ -21,24 +21,7 @@ data class SemesterGrade(
val year: Int
)
-data class Major(
- val areaType: String,
- val courseCode: String,
- val courseName: String,
- val credits: Int,
- val grade: String,
- val id: String,
- val isOnline: Boolean,
- val isRetake: Boolean,
- val isRetakeDelete: Boolean,
- val originalScore: Int,
- val professor: String,
- val score: Int,
- val semester: Int,
- val year: Int
-)
-
-data class Liberal(
+data class CourseDetail(
val areaType: String,
val courseCode: String,
val courseName: String,
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt
index 590c6e65..cd0934ef 100644
--- a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt
@@ -2,8 +2,7 @@ package com.chukchukhaksa.mobile.common.model.response.academic
import com.chukchukhaksa.mobile.common.model.academic.AcademicRecord
import com.chukchukhaksa.mobile.common.model.academic.AcademicRecordCourses
-import com.chukchukhaksa.mobile.common.model.academic.Liberal
-import com.chukchukhaksa.mobile.common.model.academic.Major
+import com.chukchukhaksa.mobile.common.model.academic.CourseDetail
import com.chukchukhaksa.mobile.common.model.academic.SemesterGrade
data class AcademicRecordResponse(
@@ -71,7 +70,7 @@ data class MajorData(
val semester: Int,
val year: Int
) {
- fun toMajor() = Major(
+ fun toMajor() = CourseDetail(
areaType = areaType,
courseCode = courseCode,
courseName = courseName,
@@ -105,7 +104,7 @@ data class LiberalData(
val semester: Int,
val year: Int
) {
- fun toLiberal() = Liberal(
+ fun toLiberal() = CourseDetail(
areaType = areaType,
courseCode = courseCode,
courseName = courseName,
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/ui/GradeColor.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/ui/GradeColor.kt
new file mode 100644
index 00000000..96441b3e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/ui/GradeColor.kt
@@ -0,0 +1,20 @@
+package com.chukchukhaksa.mobile.common.ui
+
+import androidx.compose.ui.graphics.Color
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray500
+import com.chukchukhaksa.mobile.common.designsystem.theme.Green200
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple600
+import com.chukchukhaksa.mobile.common.designsystem.theme.Red400
+import com.chukchukhaksa.mobile.common.designsystem.theme.Yellow200
+
+fun String.gradeColor(): Color {
+ return when(this) {
+ "A+", "A0" -> return Red400
+ "B+", "B0" -> return Yellow200
+ "C+", "C0" -> return Green200
+ "D+", "D0", "F" -> return Gray500
+ "P" -> return Purple600
+ else -> Black100
+ }
+}
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchCourseDetailContainer.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchCourseDetailContainer.kt
new file mode 100644
index 00000000..8ac5ba04
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchCourseDetailContainer.kt
@@ -0,0 +1,93 @@
+package com.chukchukhaksa.mobile.presentation.home.component
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.unit.dp
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray200
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray400
+import com.chukchukhaksa.mobile.common.designsystem.theme.Red400
+import com.chukchukhaksa.mobile.common.designsystem.theme.White100
+import com.chukchukhaksa.mobile.common.model.academic.CourseDetail
+import com.chukchukhaksa.mobile.common.ui.gradeColor
+
+@Composable
+fun CchCourseDetailContainer(
+ course: CourseDetail
+) {
+ Column(
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .background(White100)
+ .border(1.dp, Gray200, RoundedCornerShape(16.dp))
+ .padding(top = 18.dp, bottom = 20.dp, start = 18.dp, end = 18.dp)
+ .wrapContentHeight(),
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 17.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = "${course.courseCode} | ${course.areaType} | ${course.credits}학점",
+ color = Gray400,
+ style = CchTheme.typography.bodySm,
+ )
+ Text(
+ text = "${course.professor} 교수",
+ color = Gray400,
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 8.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = course.courseName,
+ color = Black100,
+ style = CchTheme.typography.bodyLgStrong,
+ )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(6.dp),
+ ) {
+ Text(
+ text = course.grade,
+ color = course.grade.gradeColor(),
+ style = CchTheme.typography.bodyLgStrong,
+ )
+ Text(
+ text = "${course.score}",
+ color = Black100,
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ }
+ if(course.isRetakeDelete) {
+ Text(
+ text = "재수강삭제",
+ color = Red400,
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ }
+}
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationProgressContainer.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationProgressContainer.kt
new file mode 100644
index 00000000..0b4142b8
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationProgressContainer.kt
@@ -0,0 +1,157 @@
+package com.chukchukhaksa.mobile.presentation.home.component
+
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.Image
+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.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+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.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.unit.dp
+import chukchukhaksa.composeapp.generated.resources.Res
+import chukchukhaksa.composeapp.generated.resources.ic_arrow_down_black
+import chukchukhaksa.composeapp.generated.resources.ic_arrow_down_white
+import chukchukhaksa.composeapp.generated.resources.ic_check_box
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray400
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple300
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple500
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple600
+import com.chukchukhaksa.mobile.common.designsystem.theme.White100
+import com.chukchukhaksa.mobile.common.model.graduation.GraduationProcessCourse
+import com.chukchukhaksa.mobile.common.ui.cchClickable
+import com.chukchukhaksa.mobile.common.ui.gradeColor
+import org.jetbrains.compose.resources.DrawableResource
+import org.jetbrains.compose.resources.painterResource
+
+@Composable
+fun CchGraduationProgressContainer(
+ requirementStatus: Boolean,
+ areaType: String,
+ earnedCredits: Int,
+ requiredCredits: Int,
+ courses: List,
+) {
+ val isExpanded = remember { mutableStateOf(false) }
+ val backgroundColor = if (requirementStatus) Black100 else White100
+ val areaTypeTextColor = if (requirementStatus) Purple500 else Black100
+ val creditTextColor = if (requirementStatus) White100 else Gray400
+ val courseTextColor = if (requirementStatus) White100 else Black100
+ val courseCreditTextColor = if (requirementStatus) Purple300 else Purple600
+ val arrowIcon: DrawableResource = if (requirementStatus) Res.drawable.ic_arrow_down_white else Res.drawable.ic_arrow_down_black
+
+ val rotationAngle by animateFloatAsState(
+ targetValue = if (isExpanded.value) 180f else 0f,
+ label = "Rotation"
+ )
+
+ Column(
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .background(backgroundColor)
+ .animateContentSize(
+ animationSpec = spring(
+ dampingRatio = Spring.DampingRatioLowBouncy,
+ stiffness = Spring.StiffnessLow
+ )
+ )
+ .wrapContentHeight(),
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .cchClickable(onClick = { isExpanded.value = !isExpanded.value })
+ .padding(start = 18.dp, end = 18.dp, top = 20.dp, bottom = if(isExpanded.value) 14.dp else 20.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Text(
+ text = areaType,
+ color = areaTypeTextColor,
+ style = CchTheme.typography.bodyLgStrong,
+ )
+ Text(
+ text = "$earnedCredits / $requiredCredits",
+ color = creditTextColor,
+ style = CchTheme.typography.bodyMdStrong,
+ )
+ if (requirementStatus) {
+ Image(
+ painter = painterResource(resource = Res.drawable.ic_check_box),
+ contentDescription = "",
+ )
+ }
+ }
+ Image(
+ modifier = Modifier.rotate(rotationAngle),
+ painter = painterResource(resource = arrowIcon),
+ contentDescription = "",
+ )
+ }
+ if (isExpanded.value) {
+ Column(
+ modifier = Modifier.padding(bottom = 18.dp, start = 20.dp, end = 20.dp),
+ verticalArrangement = Arrangement.spacedBy(14.dp),
+ ) {
+ courses.forEach {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Text(
+ text = it.courseName,
+ color = courseTextColor,
+ style = CchTheme.typography.bodyMdStrong,
+ )
+ Text(
+ text = "${it.year}-${it.semester}",
+ color = Gray400,
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Text(
+ text = "${it.credits}학점",
+ color = courseCreditTextColor,
+ style = CchTheme.typography.bodySm,
+ )
+ Text(
+ text = it.grade,
+ color = it.grade.gradeColor(),
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationRequirementsContainer.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationRequirementsContainer.kt
new file mode 100644
index 00000000..7e2fb93d
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchGraduationRequirementsContainer.kt
@@ -0,0 +1,120 @@
+package com.chukchukhaksa.mobile.presentation.home.component
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import chukchukhaksa.composeapp.generated.resources.Res
+import chukchukhaksa.composeapp.generated.resources.ic_appbar_arrow_right_chukchuk
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray200
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray400
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple600
+import com.chukchukhaksa.mobile.common.designsystem.theme.White100
+import com.chukchukhaksa.mobile.common.ui.cchClickable
+import org.jetbrains.compose.resources.painterResource
+
+@Composable
+fun CchGraduationRequirementsContainer(
+ major: String,
+ gradeLevel: Int,
+ totalEarnedCredits: Int,
+ requiredCredits: Int,
+ onClickGraduationProgress: () -> Unit
+) {
+ Column(
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .background(White100)
+ .border(1.dp, Gray200, RoundedCornerShape(16.dp))
+ .padding(18.dp)
+ .wrapContentHeight(),
+ ) {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 8.dp),
+ text = major,
+ color = Gray400,
+ style = CchTheme.typography.bodySm,
+ textAlign = TextAlign.Start
+ )
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 18.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = "${gradeLevel}학번 ${major} 졸업요건",
+ color = Black100,
+ style = CchTheme.typography.bodyLgStrong,
+ )
+ Image(
+ modifier = Modifier
+ .clip(CircleShape)
+ .cchClickable(onClick = onClickGraduationProgress),
+ painter = painterResource(resource = Res.drawable.ic_appbar_arrow_right_chukchuk),
+ contentDescription = "",
+ )
+ }
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ CreaditStatusText(value = totalEarnedCredits)
+ Text(
+ text = "$totalEarnedCredits / $requiredCredits",
+ color = Gray400,
+ style = CchTheme.typography.bodySm,
+ )
+ }
+ }
+}
+
+@Composable
+fun CreaditStatusText(value: Int) {
+ val annotatedString = buildAnnotatedString {
+ append("총 ")
+
+ withStyle(
+ style = SpanStyle(
+ color = Purple600,
+ fontWeight = FontWeight.ExtraBold,
+ fontSize = 14.sp
+ )
+ ) {
+ append(value.toString())
+ }
+
+ append(" 학점을 이수했어요 \uD83C\uDF89")
+ }
+
+ Text(
+ text = annotatedString,
+ color = Black100,
+ style = CchTheme.typography.bodySm
+ )
+}
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchSemesterGradeButton.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchSemesterGradeButton.kt
new file mode 100644
index 00000000..ba172db4
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchSemesterGradeButton.kt
@@ -0,0 +1,69 @@
+package com.chukchukhaksa.mobile.presentation.home.component
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.unit.dp
+import chukchukhaksa.composeapp.generated.resources.Res
+import chukchukhaksa.composeapp.generated.resources.ic_appbar_arrow_right_chukchuk
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray200
+import com.chukchukhaksa.mobile.common.designsystem.theme.Gray400
+import com.chukchukhaksa.mobile.common.designsystem.theme.White100
+import com.chukchukhaksa.mobile.common.ui.cchClickable
+import org.jetbrains.compose.resources.painterResource
+
+@Composable
+fun CchSemesterGradeButton(
+ startSemester: String,
+ endSemester: String,
+ onClick: () -> Unit
+) {
+ Column(
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .background(White100)
+ .border(1.dp, Gray200, RoundedCornerShape(16.dp))
+ .padding(18.dp)
+ .wrapContentHeight(),
+ verticalArrangement = Arrangement.spacedBy(18.dp)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = "학기별 세부 성적 확인하기",
+ color = Black100,
+ style = CchTheme.typography.bodyLgStrong,
+ )
+ Image(
+ modifier = Modifier
+ .clip(CircleShape)
+ .cchClickable(onClick = onClick),
+ painter = painterResource(resource = Res.drawable.ic_appbar_arrow_right_chukchuk),
+ contentDescription = "",
+ )
+ }
+ Text(
+ text = "$startSemester - $endSemester",
+ color = Gray400,
+ style = CchTheme.typography.bodySm
+ )
+ }
+}
diff --git a/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchTotalGradeContainer.kt b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchTotalGradeContainer.kt
new file mode 100644
index 00000000..ada7e1b1
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/presentation/home/component/CchTotalGradeContainer.kt
@@ -0,0 +1,90 @@
+package com.chukchukhaksa.mobile.presentation.home.component
+
+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.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.material3.VerticalDivider
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import com.chukchukhaksa.mobile.common.designsystem.theme.Black100
+import com.chukchukhaksa.mobile.common.designsystem.theme.CchTheme
+import com.chukchukhaksa.mobile.common.designsystem.theme.Purple500
+import com.chukchukhaksa.mobile.common.designsystem.theme.White100
+
+@Composable
+fun CchTotalGradeContainer(
+ totalEarnedCredits: Int,
+ cumulativeGpa: Double,
+ percentile: Double,
+) {
+ Row(
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .background(Black100)
+ .padding(vertical = 16.dp, horizontal = 29.dp)
+ .fillMaxWidth()
+ .wrapContentHeight(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceEvenly
+ ) {
+ CchTotalGradeContainerItem(
+ title = "취득학점",
+ value = totalEarnedCredits.toString()
+ )
+ CchTotalGradeContainerDivider()
+ CchTotalGradeContainerItem(
+ title = "평점 평균",
+ value = cumulativeGpa.toString()
+ )
+ CchTotalGradeContainerDivider()
+ CchTotalGradeContainerItem(
+ title = "백분위",
+ value = percentile.toString()
+ )
+ }
+}
+
+@Composable
+fun CchTotalGradeContainerItem(
+ title: String,
+ value: String,
+) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(4.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ text = title,
+ color = White100,
+ style = CchTheme.typography.bodySm
+ )
+ Text(
+ text = value,
+ color = Purple500,
+ style = CchTheme.typography.bodyExlg
+ )
+ }
+}
+
+@Composable
+fun CchTotalGradeContainerDivider() {
+ VerticalDivider(
+ modifier = Modifier
+ .padding(vertical = 17.dp)
+ .height(27.dp),
+ thickness = 1.dp,
+ color = Color(0xFF505050)
+ )
+}