Skip to content

feat: 걸음 수 화면과 유저 아이콘 연결#188

Merged
surfwithus merged 1 commit intomainfrom
feat/userIcons
Aug 25, 2025
Merged

feat: 걸음 수 화면과 유저 아이콘 연결#188
surfwithus merged 1 commit intomainfrom
feat/userIcons

Conversation

@surfwithus
Copy link
Collaborator

@surfwithus surfwithus commented Aug 25, 2025

Important

Enhances user profile image matching in FamilyStepTrackerScreen using userId, userName, and family data.

  • Behavior:
    • Introduced _getProfileImageForUser in family_step_tracker_screen.dart to enhance user profile image matching.
    • Matches user profiles using userId, userName, and family member data.
    • Falls back to default image if no match is found or on error.
  • UI:
    • Updates _fetchStepsForDate to use new image matching logic for displaying user icons.
    • Adjusts text formatting for step counts in family_step_tracker_screen.dart.

This description was created by Ellipsis for 2560f5a. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • 버그 수정
    • 가족 걸음 추적 화면에서 일부 구성원의 프로필 이미지가 누락되거나 다른 사람으로 표시되던 문제를 개선했습니다. 사용자 고유 식별자와 계정 ID, 이름 등을 종합해 더 정확하게 이미지를 매칭하며, 정보가 불완전한 경우 기본 이미지로 자동 대체합니다. 이로써 빈/깨진 이미지가 줄어들고 아바타 표시의 일관성과 안정성이 향상되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Aug 25, 2025

Walkthrough

가족 걸음 수 화면에서 구성원 프로필 이미지 해상 로직을 교체. 기존 단일 PrefsManager 조회를 제거하고, 사용자 uuid→userId→이름→현재 사용자→기본 이미지(0) 순으로 조회하는 비동기 헬퍼를 추가·호출. 나머지 데이터 바인딩은 동일하며 일부 서식만 변경.

Changes

Cohort / File(s) Change Summary
프로필 이미지 조회 로직 업데이트
frontend/ongi/lib/screens/health/family_step_tracker_screen.dart
단일 PrefsManager.getProfileImagePathByUserId 호출을 폐기하고 _getProfileImageForUser(userId, userName, familyMembers) 헬퍼로 대체. 일치 기준: uuid → userId → 이름 → 현재 사용자 → 기본 이미지(id 0). 오류 시 기본 경로 반환. per-member 처리에서 헬퍼 await 적용. 비기능적 서식 정리 포함.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant S as FamilyStepTrackerScreen
  participant H as _getProfileImageForUser
  participant P as PrefsManager
  participant FM as FamilyMembers
  participant CU as CurrentUser
  participant A as DefaultImage(0)

  U->>S: 화면 로드/리스트 렌더
  loop 각 가족 구성원
    S->>H: getProfileImageForUser(userId, userName, familyMembers)
    H->>FM: uuid로 매칭 시도
    alt uuid 매칭 성공
      H-->>S: 이미지 경로
    else uuid 불일치
      H->>P: userId로 조회 시도
      alt userId 매칭 성공
        H-->>S: 이미지 경로
      else userId 불일치
        H->>FM: 이름으로 매칭 시도
        alt 이름 매칭 성공
          H-->>S: 이미지 경로
        else 이름 불일치
          H->>CU: 현재 사용자 정보 확인
          alt 현재 사용자 매칭 성공
            H-->>S: 이미지 경로
          else 매칭 실패/오류
            H->>A: 기본 이미지 선택
            H-->>S: 기본 이미지 경로
          end
        end
      end
    end
  end
  S-->>U: 프로필 이미지 포함된 리스트 표시
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

작은 발걸음 톡톡, 가족이 줄을 서네
토끼 난 귀를 쫑긋, 사진 길 찾으러 가네 🐰
uuid, userId, 이름도 살펴보고,
길을 잃어도 걱정 마—기본 사진 준비됐지!
오늘도 한 걸음, 더 또렷한 화면으로 뛰지!

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/userIcons

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 2560f5a in 1 minute and 17 seconds. Click for details.
  • Reviewed 143 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. frontend/ongi/lib/screens/health/family_step_tracker_screen.dart:139
  • Draft comment:
    Ensure 'firstOrNull' is available (e.g. via an extension or package import) as it's not standard in Dart.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% 1. firstOrNull is part of Dart's core library since Dart 2.15. 2. Most Flutter projects today use recent Dart versions. 3. If firstOrNull wasn't available, the code wouldn't compile. 4. The comment is asking for verification rather than pointing out a clear issue. 5. The comment violates the rule about not asking for verifications or double-checks. I could be wrong about which version of Dart this project uses - maybe it's using an older version where firstOrNull isn't available. Even if using an older Dart version, the build would fail immediately if firstOrNull wasn't available, making this comment unnecessary. The author would discover this without needing a comment. Delete this comment. It violates the rule about not asking for verifications, and any issues with firstOrNull would be caught by the build system.
2. frontend/ongi/lib/screens/health/family_step_tracker_screen.dart:173
  • Draft comment:
    Consider caching the currentUserInfo to avoid repeated async calls inside a loop.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% The comment has merit since getUserInfo() is an async call that could be expensive if it hits storage. However, this is only called when other matching attempts fail, not on every iteration. The optimization would be minor and the code is already quite complex. The current implementation favors clarity over minor performance gains. The comment identifies a real potential performance issue. Multiple async calls in a loop can be problematic. However, this is a fallback case that likely rarely executes, and the performance impact is probably minimal. The added complexity of caching may not be worth it. While technically correct, this optimization suggestion is likely premature and would add complexity for minimal benefit. The comment should be removed.

Workflow ID: wflow_u7tLqZ3U9oGHjShq

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.


return PrefsManager.getProfileImagePath(0);
} catch (e) {
return PrefsManager.getProfileImagePath(0);
Copy link

Choose a reason for hiding this comment

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

Log the error in the catch block for better debugging instead of silently returning the default image.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
frontend/ongi/lib/screens/health/family_step_tracker_screen.dart (4)

93-99: 루프 내 await로 인한 N회 I/O 발생: 현재 사용자 정보 캐싱 전달 권장

각 멤버마다 _getProfileImageForUser에서 SharedPreferences(추정) 접근이 반복될 수 있습니다. 루프 시작 전에 현재 사용자 정보를 한 번만 조회·캐싱하여 헬퍼에 전달하는 방식이 효율적입니다. 아래처럼 헬퍼에 currentUserInfo를 넘기도록 인터페이스를 확장하세요.

-              String profileImagePath = await _getProfileImageForUser(
+              String profileImagePath = await _getProfileImageForUser(
                 userId,
                 userName,
                 familyMembers,
-              );
+                currentUserInfo: currentUserInfo,
+              );

루프 진입 전 한 번만 가져와 전달(참고용 보조 코드, 파일 다른 위치 수정 필요):

// for (final dynamic item in members) { ... } 바로 위
final Map<String, dynamic>? currentUserInfo = await PrefsManager.getUserInfo();

330-337: 숫자 천 단위 포매팅 중복/정규식 사용 → intl NumberFormat으로 단일 헬퍼화 권장

정규식 포매팅은 가독성이 낮고 중복됩니다. intlNumberFormat.decimalPattern('ko')을 사용해 헬퍼로 치환하면 명확하고 재사용 가능합니다.

-                                          : _totalSteps
-                                                        .toString()
-                                                        .replaceAllMapped(
-                                                          RegExp(
-                                                            r'(\d{1,3})(?=(\d{3})+(?!\d))',
-                                                          ),
-                                                          (m) => '${m[1]},',
-                                                        ) +
-                                                    '걸음',
+                                          : '${_formatDecimal(_totalSteps)}걸음',

보조 코드(파일 다른 위치):

import 'package:intl/intl.dart';

// State 클래스 내부 예: 
final NumberFormat _numberFormat = NumberFormat.decimalPattern('ko');
String _formatDecimal(int n) => _numberFormat.format(n);

512-515: 숫자 포매팅 로직 중복(아래 영역)도 동일 헬퍼로 치환

위에서 제안한 _formatDecimal을 재사용하여 UI 전반의 일관성을 높이세요.

-                      steps.toString().replaceAllMapped(
-                        RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
-                        (m) => '${m[1]},',
-                      ),
+                      _formatDecimal(steps),

132-186: 자동 필드 키/타입 검증 도구 도입 제안 (선택적 권장)

현재 코드베이스에서 아래 네 가지 필드는 모두 일관된 타입으로 사용되고 있음을 확인했습니다.

  • uuid, userId, name → String
  • profileImageId → int

주요 사용처
• 모델: User.fromJson (maum_log.dart) 에서

profileImageId: json['profileImageId'] ?? 0

• 저장소: PrefsManager.saveProfileImageId(int), getProfileImageId()
• 서비스: FamilyService.getFamilyMembers() → 반환된 Map<String, dynamic> 에서
['uuid'], ['userId'], ['name'], ['profileImageId']
• 화면: family_step_tracker_screen.dart 등에서
member['uuid']?.toString(), member['profileImageId'] as int 등으로 안전하게 처리

런타임 예외 가능성은 낮지만, CI 파이프라인이나 빌드 단계에서 아래와 같은 자동 검증 스크립트나 로직을 추가하면 더 높은 안정성을 확보할 수 있습니다.

  • rg/ast-grep 기반 필드 키·타입 스캔
  • json_serializable 등 코드 생성 기반 파서 도입
  • Map 구조 유효성 확인을 위한 유닛 테스트
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8e8e832 and 2560f5a.

📒 Files selected for processing (1)
  • frontend/ongi/lib/screens/health/family_step_tracker_screen.dart (7 hunks)
🔇 Additional comments (1)
frontend/ongi/lib/screens/health/family_step_tracker_screen.dart (1)

413-413: 왕관 표시 조건식 명료하고 안전합니다

최상위이면서 0보다 큰 경우만 왕관을 보여주는 조건은 의도에 부합합니다.

Comment on lines +67 to 71
final Map<String, dynamic>? stepResult =
results[0] as Map<String, dynamic>?;
final List<Map<String, dynamic>> familyMembers =
results[1] as List<Map<String, dynamic>>;

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

비동기 이후 mounted 체크 누락 + Future.wait 결과 캐스팅 안전성 강화 필요

await 이후 위젯이 dispose되면 아래 setState 구간에서 예외가 발생할 수 있습니다. 또한 results[1] 캐스팅은 null/타입 변동 시 런타임 오류 위험이 있습니다. mounted 가드와 안전 캐스팅을 추가하세요.

-      final results = await Future.wait(futures);
-      final Map<String, dynamic>? stepResult =
-          results[0] as Map<String, dynamic>?;
-      final List<Map<String, dynamic>> familyMembers =
-          results[1] as List<Map<String, dynamic>>;
+      final results = await Future.wait<dynamic>(futures);
+      if (!mounted) return;
+      final Map<String, dynamic>? stepResult =
+          results[0] as Map<String, dynamic>?;
+      final List<Map<String, dynamic>> familyMembers =
+          (results[1] as List?)?.cast<Map<String, dynamic>>() ??
+          const <Map<String, dynamic>>[];

추가로, futures도 제네릭을 명시하면 캐스팅이 더 줄어듭니다(권장, 별도 변경):

  • final futures = <Future>[ ... ];
🤖 Prompt for AI Agents
In frontend/ongi/lib/screens/health/family_step_tracker_screen.dart around lines
67 to 71, after awaiting Future.wait you must check mounted before calling
setState and make the Future.wait result casts safe: replace direct casts with
null-aware and type-checked extraction (e.g., verify results[0] is Map<String,
dynamic>? and results[1] is List and map its items to Map<String,dynamic> or
fallback to an empty list) and return early if values are invalid; add an if
(!mounted) return; guard immediately after the await and before any setState
call. Optionally, declare the futures with explicit generics (e.g.,
<Future<dynamic>> or more specific types) to reduce unsafe casts.

Comment on lines +132 to +186
Future<String> _getProfileImageForUser(
String userId,
String userName,
List<Map<String, dynamic>> familyMembers,
) async {
try {
// 1. userId로 매칭 시도 (uuid 필드와 비교)
final memberByUuid = familyMembers
.where((member) => member['uuid']?.toString() == userId)
.firstOrNull;

if (memberByUuid != null && memberByUuid['profileImageId'] != null) {
return PrefsManager.getProfileImagePath(
memberByUuid['profileImageId'] as int,
);
}

// 2. userId 필드와 직접 비교
final memberByUserId = familyMembers
.where((member) => member['userId']?.toString() == userId)
.firstOrNull;

if (memberByUserId != null && memberByUserId['profileImageId'] != null) {
return PrefsManager.getProfileImagePath(
memberByUserId['profileImageId'] as int,
);
}

// 3. userName으로 매칭 시도
if (userName.isNotEmpty) {
final memberByName = familyMembers
.where((member) => member['name']?.toString() == userName)
.firstOrNull;

if (memberByName != null && memberByName['profileImageId'] != null) {
return PrefsManager.getProfileImagePath(
memberByName['profileImageId'] as int,
);
}
}

final currentUserInfo = await PrefsManager.getUserInfo();
final currentUserUuid = currentUserInfo['uuid'];
final currentUserName = currentUserInfo['name'];

if (userId == currentUserUuid || userName == currentUserName) {
final profileImageId = currentUserInfo['profileImageId'] ?? 0;
return PrefsManager.getProfileImagePath(profileImageId);
}

return PrefsManager.getProfileImagePath(0);
} catch (e) {
return PrefsManager.getProfileImagePath(0);
}
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

firstOrNull 사용으로 컴파일 실패 가능 + null/타입 안전성 및 비교 로직 보완 필요

  • Dart SDK 기본 Iterable에는 firstOrNull이 없으며(프로젝트에 package:collection 의존/임포트 없으면 컴파일 오류), 안전하게는 firstWhereOrNull(+ import)이 필요합니다.
  • profileImageId as int는 API가 문자열을 반환하면 런타임 예외가 납니다. 안전 파싱으로 교체하세요.
  • PrefsManager.getUserInfo()가 null/비맵인 경우를 가드해야 합니다.
  • 이름 비교는 공백/대소문자 차이를 최소화하도록 trim 비교 권장.
  • 현재 사용자 조회를 매 호출마다 하지 않도록, 선택 인자로 전달 가능하게 인터페이스 확장 권장(위 93-99 코멘트와 연계).

아래처럼 보완을 제안합니다.

-  Future<String> _getProfileImageForUser(
-    String userId,
-    String userName,
-    List<Map<String, dynamic>> familyMembers,
-  ) async {
+  Future<String> _getProfileImageForUser(
+    String userId,
+    String userName,
+    List<Map<String, dynamic>> familyMembers, {
+    Map<String, dynamic>? currentUserInfo,
+  }) async {
     try {
-      // 1. userId로 매칭 시도 (uuid 필드와 비교)
-      final memberByUuid = familyMembers
-          .where((member) => member['uuid']?.toString() == userId)
-          .firstOrNull;
+      // 안전 파싱 헬퍼
+      int? _toInt(dynamic v) {
+        if (v is int) return v;
+        return int.tryParse(v?.toString() ?? '');
+      }
+
+      // 1. userId로 매칭 시도 (uuid 필드와 비교)
+      final memberByUuid = familyMembers.firstWhereOrNull(
+        (member) => member['uuid']?.toString() == userId,
+      );
 
-      if (memberByUuid != null && memberByUuid['profileImageId'] != null) {
-        return PrefsManager.getProfileImagePath(
-          memberByUuid['profileImageId'] as int,
-        );
+      final uuidImgId = _toInt(memberByUuid?['profileImageId']);
+      if (uuidImgId != null) {
+        return PrefsManager.getProfileImagePath(uuidImgId);
       }
 
-      // 2. userId 필드와 직접 비교
-      final memberByUserId = familyMembers
-          .where((member) => member['userId']?.toString() == userId)
-          .firstOrNull;
+      // 2. userId 필드와 직접 비교
+      final memberByUserId = familyMembers.firstWhereOrNull(
+        (member) => member['userId']?.toString() == userId,
+      );
 
-      if (memberByUserId != null && memberByUserId['profileImageId'] != null) {
-        return PrefsManager.getProfileImagePath(
-          memberByUserId['profileImageId'] as int,
-        );
+      final userIdImgId = _toInt(memberByUserId?['profileImageId']);
+      if (userIdImgId != null) {
+        return PrefsManager.getProfileImagePath(userIdImgId);
       }
 
       // 3. userName으로 매칭 시도
       if (userName.isNotEmpty) {
-        final memberByName = familyMembers
-            .where((member) => member['name']?.toString() == userName)
-            .firstOrNull;
+        final nameTrim = userName.trim();
+        final memberByName = familyMembers.firstWhereOrNull(
+          (member) => member['name']?.toString().trim() == nameTrim,
+        );
 
-        if (memberByName != null && memberByName['profileImageId'] != null) {
-          return PrefsManager.getProfileImagePath(
-            memberByName['profileImageId'] as int,
-          );
+        final nameImgId = _toInt(memberByName?['profileImageId']);
+        if (nameImgId != null) {
+          return PrefsManager.getProfileImagePath(nameImgId);
         }
       }
 
-      final currentUserInfo = await PrefsManager.getUserInfo();
-      final currentUserUuid = currentUserInfo['uuid'];
-      final currentUserName = currentUserInfo['name'];
+      final info = currentUserInfo ?? await PrefsManager.getUserInfo();
+      if (info is Map<String, dynamic>) {
+        final currentUserUuid = info['uuid']?.toString();
+        final currentUserName = info['name']?.toString();
 
-      if (userId == currentUserUuid || userName == currentUserName) {
-        final profileImageId = currentUserInfo['profileImageId'] ?? 0;
-        return PrefsManager.getProfileImagePath(profileImageId);
+        if (userId == currentUserUuid ||
+            (userName.isNotEmpty &&
+             userName.trim() == currentUserName?.trim())) {
+          final profileImageId = _toInt(info['profileImageId']) ?? 0;
+          return PrefsManager.getProfileImagePath(profileImageId);
+        }
       }
 
       return PrefsManager.getProfileImagePath(0);
     } catch (e) {
       return PrefsManager.getProfileImagePath(0);
     }
   }

보조 변경(파일 다른 위치, 임포트 추가 필요):

// 파일 상단 임포트 목록에 추가
import 'package:collection/collection.dart';

스키마 확인 요청: FamilyService.getFamilyMembers()가 실제로 uuid, userId, name, profileImageId 키를 반환하는지, 그리고 타입(int/str) 일관성이 있는지 점검 부탁드립니다.


다음 스크립트를 실행하여 firstOrNull 사용 여부, collection 임포트, PrefsManager.getUserInfo 시그니처 등을 확인해주세요:

이 결과를 바탕으로 리뷰 코멘트의 타당성을 최종 검증하고, 필요한 경우 수정 제안을 반영하겠습니다.


🏁 Script executed:

#!/bin/bash
# 1. collection 패키지 임포트 확인
rg -n "import .*collection" frontend/ongi/lib/screens/health/family_step_tracker_screen.dart

# 2. firstOrNull 사용 위치 확인
rg -n "firstOrNull" frontend/ongi/lib/screens/health/family_step_tracker_screen.dart

# 3. firstWhereOrNull 사용 여부 확인
rg -n "firstWhereOrNull" frontend/ongi/lib/screens/health/family_step_tracker_screen.dart

# 4. getUserInfo 호출 위치 확인
rg -n "getUserInfo" frontend/ongi/lib/screens/health/family_step_tracker_screen.dart

# 5. PrefsManager 클래스 정의 및 getUserInfo 시그니처 확인
rg -n "class PrefsManager" -n .
rg -n "getUserInfo" -n .

Length of output: 2859


다음 스크립트를 실행하여 PrefsManager.getUserInfo의 구현을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# getUserInfo 구현 확인 (75~115행)
sed -n '75,115p' frontend/ongi/lib/utils/prefs_manager.dart

Length of output: 1496


다음 스크립트를 실행하여 FamilyService.getFamilyMembers()의 반환 스키마와 타입 일관성을 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# 1. getFamilyMembers가 정의된 파일 경로 찾기
family_file=$(rg -l "getFamilyMembers" -n frontend/ongi/lib/services | head -n 1)
echo "Found file: $family_file"

# 2. 함수 정의 및 반환부 확인 (앞뒤 컨텍스트 포함)
sed -n '1,200p' "$family_file" | sed -n '/getFamilyMembers/,/}/p'

Length of output: 579


다음 스크립트를 실행하여 FamilyService.getFamilyMembers()의 전체 구현 및 반환 스키마를 확인해주세요:


🏁 Script executed:

#!/bin/bash
# 전체 라인 수 확인
wc -l frontend/ongi/lib/services/family_service.dart

# 파일 앞부분 확인 (1~200행)
sed -n '1,200p' frontend/ongi/lib/services/family_service.dart

# 구현부 뒷부분 확인 (200~400행)
sed -n '200,400p' frontend/ongi/lib/services/family_service.dart

Length of output: 2107


firstOrNull 미사용으로 인한 컴파일 오류 및 타입·안전성 보강 필요

아래 항목을 우선적으로 적용해 주세요:

  • firstOrNull 호출은 Dart 기본 Iterable에 없으므로
    package:collection을 임포트하거나
    Iterable.firstWhereOrNull로 교체
    (파일: frontend/ongi/lib/screens/health/family_step_tracker_screen.dart, 141·152·164행)
  • member['profileImageId'] as int 캐스팅은 API가 문자열을 반환할 경우 런타임 예외 발생 우려
    int.tryParse(v?.toString() ?? '') 기반 안전 파싱 헬퍼 사용 권장
  • PrefsManager.getUserInfo()는 항상 Map<String,dynamic>을 반환하지만 내부 값(name, uuid, profileImageId)이 null일 수 있으니
    • 값이 null일 때 기본값 또는 예외 처리를 추가
  • userName 비교 시 불필요한 공백·대소문자 차이 방지를 위해
    userName.trim() (필요 시 toLowerCase()) 사용
  • 매 호출마다 사용자 정보를 다시 조회하지 않도록
    currentUserInfo를 선택적 파라미터로 받아 재사용하도록 인터페이스 확장 검토
  • API 응답 스키마(uuid, userId, name, profileImageId)의 키 존재 여부 및 타입(int vs. String) 일관성 확인 요청
🤖 Prompt for AI Agents
In frontend/ongi/lib/screens/health/family_step_tracker_screen.dart around lines
132 to 186, the code uses Iterable.firstOrNull (not in Dart core), unsafely
casts profileImageId with `as int`, re-fetches user info each call, and does raw
userName comparisons; replace firstOrNull by importing package:collection or use
firstWhere((c) => ..., orElse: () => null)/firstWhereOrNull, parse
profileImageId robustly via int.tryParse(member['profileImageId']?.toString() ??
'') with a safe fallback (0), guard currentUserInfo fields with defaults before
using them (e.g., uuid/name/profileImageId), normalize userName using trim()
(and toLowerCase() if case-insensitive), and consider changing the function
signature to accept an optional currentUserInfo to avoid repeated
PrefsManager.getUserInfo() calls; finally, validate the API response keys/types
(uuid, userId, name, profileImageId) and handle missing or string-typed ids
consistently.

@surfwithus surfwithus merged commit a49715f into main Aug 25, 2025
4 checks passed
@surfwithus surfwithus deleted the feat/userIcons branch August 25, 2025 10:02
Neibce pushed a commit to 2025-PNU-SW-Hackathon/PNUSW-2025-OnGi-10 that referenced this pull request Aug 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant