Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 134 additions & 139 deletions src/components/ExerciseSetItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ interface ExerciseSetItemProps {
onPressRemove: () => void;
onWeightChange?: (weight: number) => void;
onRepsChange?: (reps: number) => void;
onOrderChange?: (order: number) => void;
}

const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
Expand All @@ -31,7 +30,6 @@ const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
onPressRemove,
onWeightChange,
onRepsChange,
onOrderChange,
}) => {
const isHighlighted = isActive || isCompleted;

Expand All @@ -49,36 +47,12 @@ const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<View style={styles.deleteButtonCircle}>
<Icon name="remove" size={14} color="#ffffff" />
<Icon name="close" size={16} color="#ffffff" />
</View>
</TouchableOpacity>

{/* 세트 번호 - 편집 가능 */}
{onOrderChange ? (
<View style={styles.orderContainer}>
<TextInput
style={[
styles.orderInput,
isHighlighted ? styles.textActive : styles.textDefault,
]}
value={(order ?? 1).toString()}
onChangeText={(text) => {
const num = parseInt(text) || 1;
onOrderChange(num);
}}
keyboardType="numeric"
editable={!isCompleted}
/>
<Text
style={[
styles.orderUnit,
isHighlighted ? styles.textActive : styles.textDefault,
]}
>
세트
</Text>
</View>
) : (
{/* 세트 번호 */}
<View style={styles.setNumberContainer}>
<Text
style={[
styles.setNumber,
Expand All @@ -87,32 +61,36 @@ const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
>
{order ?? 1}세트
</Text>
)}
</View>

{/* 무게 */}
{onWeightChange ? (
<View style={styles.valueContainer}>
<TextInput
style={[
styles.valueInput,
isHighlighted ? styles.textActive : styles.textDefault,
]}
value={(weight ?? 0).toString()}
onChangeText={(text) => {
const num = parseInt(text) || 0;
onWeightChange(num);
}}
keyboardType="numeric"
editable={!isCompleted}
/>
<Text
style={[
styles.unit,
isHighlighted ? styles.textActive : styles.textDefault,
]}
>
kg
</Text>
<View style={styles.inputWrapper}>
<TextInput
style={[
styles.valueInput,
isHighlighted ? styles.valueInputActive : styles.valueInputDefault,
]}
value={(weight ?? 0).toString()}
onChangeText={(text) => {
const num = parseFloat(text) || 0;
onWeightChange(num);
}}
keyboardType="decimal-pad"
editable={!isCompleted}
placeholder="0"
placeholderTextColor="#999"
/>
<Text
style={[
styles.unit,
isHighlighted ? styles.textActive : styles.textDefault,
]}
>
kg
</Text>
</View>
</View>
) : (
<Text
Expand All @@ -128,27 +106,31 @@ const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
{/* 횟수 */}
{onRepsChange ? (
<View style={styles.valueContainer}>
<TextInput
style={[
styles.valueInput,
isHighlighted ? styles.textActive : styles.textDefault,
]}
value={(reps ?? 0).toString()}
onChangeText={(text) => {
const num = parseInt(text) || 0;
onRepsChange(num);
}}
keyboardType="numeric"
editable={!isCompleted}
/>
<Text
style={[
styles.unit,
isHighlighted ? styles.textActive : styles.textDefault,
]}
>
</Text>
<View style={styles.inputWrapper}>
<TextInput
style={[
styles.valueInput,
isHighlighted ? styles.valueInputActive : styles.valueInputDefault,
]}
value={(reps ?? 0).toString()}
onChangeText={(text) => {
const num = parseInt(text) || 0;
onRepsChange(num);
}}
keyboardType="number-pad"
editable={!isCompleted}
placeholder="0"
placeholderTextColor="#999"
/>
<Text
style={[
styles.unit,
isHighlighted ? styles.textActive : styles.textDefault,
]}
>
</Text>
</View>
</View>
) : (
<Text
Expand All @@ -161,20 +143,19 @@ const ExerciseSetItem: React.FC<ExerciseSetItemProps> = ({
</Text>
)}

{/* 체크박스 */}
{/* 완료 버튼 */}
<TouchableOpacity
style={[
styles.checkbox,
isCompleted ? styles.checkboxCompleted : styles.checkboxDefault,
styles.completeButton,
isCompleted ? styles.completeButtonActive : styles.completeButtonDefault,
]}
onPress={onToggleComplete}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
{isCompleted && (
<Icon name="checkmark" size={18} color="#000000" />
)}
{!isCompleted && (
<Icon name="checkmark" size={18} color="#CCCCCC" />
{isCompleted ? (
<Icon name="checkmark-circle" size={28} color="#4CAF50" />
) : (
<Icon name="ellipse-outline" size={28} color="#CCCCCC" />
)}
</TouchableOpacity>
</View>
Expand All @@ -185,26 +166,32 @@ const styles = StyleSheet.create({
container: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 10,
paddingHorizontal: 18,
marginHorizontal: 12,
marginBottom: 8,
borderRadius: 12,
justifyContent: "space-between",
paddingVertical: 16,
paddingHorizontal: 16,
marginHorizontal: 0,
marginBottom: 12,
borderRadius: 16,
position: "relative",
borderWidth: 1.5,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 1,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 2,
shadowOpacity: 0.08,
shadowRadius: 4,
elevation: 2,
gap: 12,
width: "100%",
},
containerDefault: {
backgroundColor: "#FFFFFF",
borderColor: "#E8E8E8",
},
containerActive: {
backgroundColor: "#E8FF8A",
backgroundColor: "#F0F9F0",
borderColor: "#4CAF50",
},
deleteButton: {
position: "absolute",
Expand All @@ -213,89 +200,97 @@ const styles = StyleSheet.create({
zIndex: 1,
},
deleteButtonCircle: {
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: "#CCCCCC",
width: 28,
height: 28,
borderRadius: 14,
backgroundColor: "#FF5252",
justifyContent: "center",
alignItems: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 3,
elevation: 3,
},
setNumber: {
fontSize: 14,
fontWeight: "400",
minWidth: 50,
marginRight: 12,
},
orderContainer: {
flexDirection: "row",
alignItems: "center",
minWidth: 60,
marginRight: 12,
},
orderInput: {
fontSize: 14,
fontWeight: "400",
minWidth: 30,
textAlign: "right",
padding: 0,
setNumberContainer: {
width: 60,
justifyContent: "center",
alignItems: "flex-start",
},
orderUnit: {
fontSize: 14,
fontWeight: "400",
marginLeft: 4,
setNumber: {
fontSize: 15,
fontWeight: "600",
textAlign: "left",
},
weight: {
fontSize: 14,
fontWeight: "400",
fontSize: 15,
fontWeight: "600",
flex: 1,
marginRight: 12,
maxWidth: "35%",
textAlign: "right",
},
reps: {
fontSize: 14,
fontWeight: "400",
fontSize: 15,
fontWeight: "600",
flex: 1,
marginRight: 12,
maxWidth: "35%",
textAlign: "right",
},
valueContainer: {
flex: 1,
maxWidth: "35%",
},
inputWrapper: {
flexDirection: "row",
alignItems: "center",
marginRight: 12,
justifyContent: "flex-end",
backgroundColor: "#F8F8F8",
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 10,
borderWidth: 1,
borderColor: "#E0E0E0",
width: "100%",
},
valueInput: {
flex: 1,
fontSize: 14,
fontWeight: "400",
fontSize: 16,
fontWeight: "600",
textAlign: "right",
minWidth: 40,
width: 50,
padding: 0,
color: "#000000",
},
valueInputDefault: {
color: "#000000",
},
valueInputActive: {
color: "#4CAF50",
},
unit: {
fontSize: 14,
fontWeight: "400",
marginLeft: 4,
fontWeight: "600",
marginLeft: 6,
color: "#666666",
width: 24,
},
textDefault: {
color: "#000000",
},
textActive: {
color: "#000000",
},
checkbox: {
width: 32,
height: 32,
borderRadius: 8,
borderWidth: 1,
completeButton: {
width: 50,
height: 50,
justifyContent: "center",
alignItems: "center",
flexShrink: 0,
},
checkboxDefault: {
backgroundColor: "#FFFFFF",
borderColor: "#E0E0E0",
completeButtonDefault: {
backgroundColor: "transparent",
},
checkboxCompleted: {
backgroundColor: "#FFFFFF",
borderColor: "#000000",
completeButtonActive: {
backgroundColor: "transparent",
},
});

Choose a reason for hiding this comment

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

코드 리뷰

1. 삭제된 onOrderChange props

  • onOrderChange prop이 삭제되었는데, 이 기능을 사용하는 다른 부분 (예: 부모 컴포넌트)에서 문제가 발생할 수 있습니다. 이 prop을 사용하는 코드가 없다면 삭제해도 괜찮지만, 관련된 부분이 있다면 이 과정을 문서화하고 동작이 어떻게 바뀔 것인지 명시해야 합니다.

2. 데이터 변환

  • parseInt를 사용하여 문자열을 정수로 변환하는 부분이 보입니다. 이 경우 사용자가 유효하지 않은 값을 입력할 경우 0으로 기본값을 설정하고 있습니다. 이는 의도하지 않은 동작을 유발할 수 있습니다. 예를 들어, 비어 있거나 문자를 입력한 경우 명시적으로 에러 처리를 해주는 것이 좋습니다.
  • 예를 들어, onWeightChangeonRepsChange에서 유효성 검사 로직을 추가하여 사용자가 잘못된 값을 입력하지 않도록 해야 합니다.

3. 스타일 및 접근성

  • 스타일링에서 특정 값(색상 등)을 하드코딩하고 있습니다. 이 값은 상수로 정의하거나 테마를 사용하여 처리하면 유지보수가 쉬워질 것입니다.
  • 접근성을 고려하여 접근 가능한 텍스트 및 아이콘에 대한 설명을 추가하는 것이 좋습니다. 예를 들어, TouchableOpacityaccessibleaccessibilityLabel 속성을 추가하면 좋습니다.

4. 반응형 디자인 성능

  • TextInput 및 기타 UI 요소에 대한 최대 너비를 %로 설정하는 것은 좋지만, 너무 많은 너비를 사용할 경우 작은 화면에서 잘리지 않을 수 있습니다. 다양한 해상도에서의 테스트가 필요합니다.

5. 주석

  • 주석을 통해 코드의 함수나 동작에 대한 설명을 제공하는 것은 좋습니다. 그러나 주석은 더 구체적이어야 합니다. 예를 들어, // 완료 버튼의 경우 완료 버튼의 동작이나 사용 사례를 더 명확히 설명해야 합니다.

이와 같은 점을 개선하면 코드를 더 안전하고 유지보수하기 쉬운 상태로 만드는 데 도움이 될 것입니다.

Expand Down
Loading