Skip to content

feat: マップ吹き出しに経過時間表示を追加#24

Merged
TinyKitten merged 5 commits intomainfrom
claude/add-time-ago-tooltips-cDPMD
Feb 19, 2026
Merged

feat: マップ吹き出しに経過時間表示を追加#24
TinyKitten merged 5 commits intomainfrom
claude/add-time-ago-tooltips-cDPMD

Conversation

@TinyKitten
Copy link
Copy Markdown
Member

@TinyKitten TinyKitten commented Feb 19, 2026

最新位置の文言の後に中黒(・)をセパレータとして
「〜秒前」「〜分前」「〜時間前」「〜日前」「〜ヶ月前」「〜年前」
の動的な経過時間テキストを表示するように変更

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM

Summary by CodeRabbit

  • 新機能
    • 地図のコールアウト表示を新しいコンポーネント化で改善し、表示内容(路線名、速度、精度、電池等)が整理されました。
    • コールアウトの選択・解除がマップ操作に連動して扱いやすくなりました(アクティブなコールアウト管理)。
    • コールアウト内の時刻表記を日本語の相対表現(例:「5分前」)で表示し、約10秒間隔で自動更新します。
    • 各軌跡データに最新更新時刻が追加され、表示の精度が向上しました。

最新位置の文言の後に中黒(・)をセパレータとして
「〜秒前」「〜分前」「〜時間前」「〜日前」「〜ヶ月前」「〜年前」
の動的な経過時間テキストを表示するように変更

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 19, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

マップのコールアウト表示を内部コンポーネントに差し替え、formatTimeAgoで相対時刻を日本語表示する機能を追加。表示は10秒間隔で自動更新され、軌跡データにlatestTimestampフィールドを追加してそれを利用します。

Changes

Cohort / File(s) Summary
ユーティリティ関数
components/location-card.tsx
新規エクスポート関数 formatTimeAgo(timestamp: number): string を追加。与えられたタイムスタンプを日本語の相対時刻で返すロジックを実装。
データモデル拡張
hooks/use-device-trajectory.ts
DeviceTrajectory に `latestTimestamp: number
マップ表示(UI/ロジック)
app/(tabs)/map.tsx
内部コンポーネント CalloutContent を導入し、コールアウト表示を置換。formatTimeAgo を用いて経過時間を取得し、アクティブなコールアウトで10秒ごとに更新するロジックと、activeCalloutId による表示制御を追加。

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant Map as "Map Screen\napp/(tabs)/map.tsx"
  participant Hook as "useDeviceTrajectory\n(hook with latestTimestamp)"
  participant Callout as "CalloutContent\n(internal)"
  participant Format as "formatTimeAgo\ncomponents/location-card.tsx"

  User->>Map: マーカー選択 / コールアウト要求
  Map->>Hook: 軌跡データ取得要求
  Hook-->>Map: DeviceTrajectory(+latestTimestamp)
  Map->>Callout: trajectory props を渡す
  Callout->>Format: formatTimeAgo(latestTimestamp)
  Format-->>Callout: 日本語の相対時刻文字列
  Callout->>User: コールアウト表示(経過時間)
  loop every 10s
    Callout->>Format: formatTimeAgo(latestTimestamp)
    Format-->>Callout: 更新文字列
    Callout->>User: 表示更新
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 ぴょんと地図の上で時が踊る
秒がささやき、分がこたえるよ
最新の刻(とき)をそっと紡いで
10秒ごとにまた輝く光よ
地図と僕で時間を追いかけるよ

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed プルリクエストのタイトルは「マップ吹き出しに経過時間表示を追加」で、変更内容の主要な目的と完全に一致している。マップ上の吹き出しに経過時間を動的に表示する機能追加という主なポイントを正確に要約している。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/add-time-ago-tooltips-cDPMD

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (1)
components/location-card.tsx (1)

65-66: 経過時間のリアルタイム更新について(参考情報)

Date.now() はレンダリング時の時刻を使用するため、コンポーネントが再レンダリングされない限り表示は更新されません。位置情報の更新時に再レンダリングされる想定であれば問題ありませんが、長時間吹き出しを表示し続ける場合は setInterval による定期更新を検討してもよいかもしれません。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/location-card.tsx` around lines 65 - 66, formatTimeAgo(timestamp:
number) currently calls Date.now() only at render time so the “time ago” text
won't update while the popup stays open; update the component that calls
formatTimeAgo (e.g., the LocationCard component) to trigger periodic re-renders
by adding a useEffect-driven timer (setInterval) that updates a piece of state
(e.g., now or tick) on a suitable cadence (every second or every minute
depending on desired granularity), clear the interval on unmount, and keep using
formatTimeAgo(timestamp) to compute the displayed string; alternatively, modify
formatTimeAgo to accept a second parameter now so callers can pass the ticking
state to produce live updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/location-card.tsx`:
- Around line 65-91: formatTimeAgo currently computes diffMs/diffSec and can
return negative values when timestamp is in the future; add a guard at the start
of formatTimeAgo to clamp negative differences to zero (e.g., if diffMs <= 0 set
diffMs = 0 or return "0秒前"/"たった今"), then continue computing diffSec/diffMin/etc.
Reference the function name formatTimeAgo and the variables
diffMs/diffSec/diffMin to locate where to apply the guard.

---

Nitpick comments:
In `@components/location-card.tsx`:
- Around line 65-66: formatTimeAgo(timestamp: number) currently calls Date.now()
only at render time so the “time ago” text won't update while the popup stays
open; update the component that calls formatTimeAgo (e.g., the LocationCard
component) to trigger periodic re-renders by adding a useEffect-driven timer
(setInterval) that updates a piece of state (e.g., now or tick) on a suitable
cadence (every second or every minute depending on desired granularity), clear
the interval on unmount, and keep using formatTimeAgo(timestamp) to compute the
displayed string; alternatively, modify formatTimeAgo to accept a second
parameter now so callers can pass the ticking state to produce live updates.

diffMsが負の場合に「-N秒前」のような不正な表示になる問題を修正し、
「たった今」を返すようにした

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM
formatTimeAgoがレンダー時のDate.now()のみで計算されるため、
吹き出しが開いたまま時間が経過しても表示が更新されなかった。
CalloutContentコンポーネントを分離し10秒間隔のタイマーで
再レンダーすることで経過時間をライブ更新する。

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM
再レンダーのみが目的であることを明確にするため、
useState+setTickパターンからuseReducer+forceUpdateに変更

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
app/(tabs)/map.tsx (1)

50-110: 吹き出しが閉じていても全マーカーでタイマーが回る可能性があります。
CalloutContent が全マーカーで常時レンダーされる構造(Marker内部で各trajectoryに対してCalloutContentが配置)なので、react-native-maps(v1.26.20)が Callout の showCallout()/hideCallout() で表示制御しても、コンポーネント自体はマウントされたままです。その結果、10秒ごとの interval が台数分発火して無駄な再レンダー/電池消費につながります。isActive を渡して開いている吹き出しだけ更新する形に絞るのが安全です。

♻️ 提案(CalloutContent 側のガード追加)
-function CalloutContent({
+function CalloutContent({
   deviceId,
   stateLabel,
   stateConf,
   borderColor,
   timestamp,
   lineId,
   lineNames,
   latestSpeed,
   latestAccuracy,
   latestBatteryLevel,
+  isActive,
 }: {
   deviceId: string;
   stateLabel: string;
   stateConf: { bgClass: string; textClass: string };
   borderColor: string;
   timestamp: number | null;
   lineId: string | null;
   lineNames: Record<string, string>;
   latestSpeed: number | null | undefined;
   latestAccuracy: number | null | undefined;
   latestBatteryLevel: number | null;
+  isActive: boolean;
 }) {
   const [, setTick] = useState(0);

   useEffect(() => {
-    if (timestamp == null) return;
+    if (!isActive || timestamp == null) return;
     const id = setInterval(() => setTick((t) => t + 1), TIME_AGO_INTERVAL_MS);
     return () => clearInterval(id);
-  }, [timestamp]);
+  }, [isActive, timestamp]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(tabs)/map.tsx around lines 50 - 110, CalloutContent is currently
starting a TIME_AGO_INTERVAL_MS interval for every mounted marker; change its
props to accept an isActive:boolean and update the useEffect in CalloutContent
to only setInterval when isActive === true and timestamp != null, and always
clear the interval in the cleanup; also ensure callers (where CalloutContent is
rendered inside Marker/trajectory) pass isActive based on whether that marker's
Callout is actually shown (e.g., tracked by selectedMarkerId or showCallout
state) so only the open callout runs the timer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/`(tabs)/map.tsx:
- Around line 50-110: CalloutContent is currently starting a
TIME_AGO_INTERVAL_MS interval for every mounted marker; change its props to
accept an isActive:boolean and update the useEffect in CalloutContent to only
setInterval when isActive === true and timestamp != null, and always clear the
interval in the cleanup; also ensure callers (where CalloutContent is rendered
inside Marker/trajectory) pass isActive based on whether that marker's Callout
is actually shown (e.g., tracked by selectedMarkerId or showCallout state) so
only the open callout runs the timer.

CalloutContentにisActive propを追加し、表示中の吹き出しだけが
setIntervalで経過時間を更新するように変更。
activeCalloutId stateを追加しハンドラーで同期させることで
選択中マーカーを追跡する。

https://claude.ai/code/session_015En85PtwwQhrGDwZZGURDM
@TinyKitten TinyKitten merged commit ed8dadc into main Feb 19, 2026
1 check passed
@TinyKitten TinyKitten deleted the claude/add-time-ago-tooltips-cDPMD branch February 19, 2026 10:02
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.

2 participants