Skip to content

feat: #72 — feat: Replace Data nav icon with map marker; extract Alerts into dedicated screen#107

Closed
luandro wants to merge 1 commit into
mainfrom
agent/comapeo-cloud-app/issue-72
Closed

feat: #72 — feat: Replace Data nav icon with map marker; extract Alerts into dedicated screen#107
luandro wants to merge 1 commit into
mainfrom
agent/comapeo-cloud-app/issue-72

Conversation

@luandro

@luandro luandro commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Automated implementation of #72.

Closes #72


Implemented by the agent implementation worker.

Greptile Summary

This PR extracts the Alerts tab from DataScreen into a dedicated /alerts route with its own AlertsScreen, and replaces the Data nav icon with a map-marker SVG. All three i18n locale files are updated and the router/nav are wired up correctly.

  • New /alerts route: AlertsScreen mirrors DataScreen's no-project guard, skeleton loading, error, and empty states, and links alert cards to the existing /data/alerts/$alertId detail route.
  • DataScreen cleanup: Alerts tab, useAlerts hook call, activeTab state, the Tabs import, and all associated messages are removed; the observations flow is unchanged.
  • Nav update: A new Alerts nav item (bell icon) is inserted between Data and Settings; the Data icon path is updated to a map-marker shape.

Confidence Score: 4/5

Safe to merge; the refactor is well-contained and the routing, nav, and i18n wiring are all correct.

The main screen logic, routing, and locale JSON updates are solid. Two small issues in the new AlertsScreen: an unused messages.loading definition that leaked into all three i18n files, and intl missing from a useMemo dependency array (suppressed with an eslint comment). Neither affects current behavior in a meaningful way, but both are worth cleaning up before the next locale-change scenario.

src/screens/AlertsScreen.tsx and the three i18n JSON files (the unused alerts.loading key).

Important Files Changed

Filename Overview
src/screens/AlertsScreen.tsx New dedicated alerts screen. Correctly guards against no-project state and shows skeleton/error/empty states. Two minor issues: unused messages.loading definition and intl missing from useMemo deps.
src/screens/DataScreen.tsx Alerts tab and related hooks/state removed cleanly; observations flow is unchanged and toolbar is correctly gated behind existing no-project guards.
src/app/router.tsx New /alerts route added and exported correctly; alert detail and create-alert routes remain at /data/alerts/* as before.
src/components/layout/authenticated-layout.tsx Data icon path updated to map-marker SVG; new Alerts icon and nav item added in the correct position between Data and Settings.
src/i18n/messages/en.json New alerts.* keys added and obsolete data.tabs.*/data.noAlerts/data.addAlert/data.alertsError keys removed. alerts.loading is added but never referenced in the component.
tests/unit/screens/AlertsScreen.test.tsx New test file with good coverage of loading/error/empty/list states; params substitution in the Link mock is not verified, so the alert-detail href assertion only checks the template string.
tests/unit/screens/DataScreen.test.tsx Alerts-related mocks, fixtures, and tab tests removed cleanly; remaining observation tests are intact and the tab mock boilerplate is gone.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    NAV[AuthenticatedLayout nav]
    NAV -->|/| HOME[HomeScreen]
    NAV -->|/data| DATA[DataScreen\nobservations only]
    NAV -->|/alerts| ALERTS[AlertsScreen\nnew]
    NAV -->|/settings| SETTINGS[SettingsScreen]

    ALERTS -->|Add Alert| CREATE[CreateAlertScreen\n/data/alerts/new]
    ALERTS -->|card click| DETAIL[AlertDetailScreen\n/data/alerts/:id]

    DATA -->|obs row| OBSDETAIL[ObservationDetailScreen\n/data/observations/:id]
Loading

Comments Outside Diff (1)

  1. tests/unit/screens/AlertsScreen.test.tsx, line 1024-1033 (link)

    P2 The mock renders <a href={to}> using the raw to template string, so href is always '/data/alerts/$alertId' regardless of what is passed in params. The test does not verify that the alertId param is wired to alert.localId. Consider extending the mock to substitute params into the path so the assertion can confirm the resolved href.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: tests/unit/screens/AlertsScreen.test.tsx
    Line: 1024-1033
    
    Comment:
    The mock renders `<a href={to}>` using the raw `to` template string, so `href` is always `'/data/alerts/$alertId'` regardless of what is passed in `params`. The test does not verify that the `alertId` param is wired to `alert.localId`. Consider extending the mock to substitute `params` into the path so the assertion can confirm the resolved href.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/screens/AlertsScreen.tsx:35-39
The `messages.loading` definition is never consumed in this component — `alertsQuery.isPending` renders `<Skeleton>` nodes directly, not an `intl.formatMessage(messages.loading)` call. The dead key also propagated unnecessary additions to all three i18n JSON files.

```suggestion
  alertsError: {
```

### Issue 2 of 3
src/screens/AlertsScreen.tsx:61-68
`intl` is used inside the `useMemo` callback (`intl.formatMessage(messages.title)`) but is excluded from the dependency array. If the active locale changes, `topbarModeLabel` will stay stale until `selectedProjectId` or `topbarWorkspaceName` also changes. Adding `intl` to the array removes the need for the suppression comment and keeps the label reactive to locale switches.

```suggestion
  const shellSlot = useMemo(
    () => ({
      topbarWorkspaceName: selectedProjectId ? topbarWorkspaceName : undefined,
      topbarModeLabel: intl.formatMessage(messages.title),
    }),
    [selectedProjectId, topbarWorkspaceName, intl],
  );
```

### Issue 3 of 3
tests/unit/screens/AlertsScreen.test.tsx:1024-1033
The mock renders `<a href={to}>` using the raw `to` template string, so `href` is always `'/data/alerts/$alertId'` regardless of what is passed in `params`. The test does not verify that the `alertId` param is wired to `alert.localId`. Consider extending the mock to substitute `params` into the path so the assertion can confirm the resolved href.

Reviews (1): Last reviewed commit: "feat: implement #72 — feat: Replace Data..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedplaywright@​1.60.01001001009980
Addedtypescript@​6.0.3100100909590
Addedprettier@​3.8.3981009793100

View full report

@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm seroval is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ?npm/@storybook/tanstack-react@10.4.2npm/@tanstack/react-router@1.170.11npm/seroval@1.5.4

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/seroval@1.5.4. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Comment on lines +35 to +39
loading: {
id: 'alerts.loading',
defaultMessage: 'Loading...',
},
alertsError: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 The messages.loading definition is never consumed in this component — alertsQuery.isPending renders <Skeleton> nodes directly, not an intl.formatMessage(messages.loading) call. The dead key also propagated unnecessary additions to all three i18n JSON files.

Suggested change
loading: {
id: 'alerts.loading',
defaultMessage: 'Loading...',
},
alertsError: {
alertsError: {
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/screens/AlertsScreen.tsx
Line: 35-39

Comment:
The `messages.loading` definition is never consumed in this component — `alertsQuery.isPending` renders `<Skeleton>` nodes directly, not an `intl.formatMessage(messages.loading)` call. The dead key also propagated unnecessary additions to all three i18n JSON files.

```suggestion
  alertsError: {
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +61 to +68
const shellSlot = useMemo(
() => ({
topbarWorkspaceName: selectedProjectId ? topbarWorkspaceName : undefined,
topbarModeLabel: intl.formatMessage(messages.title),
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectedProjectId, topbarWorkspaceName],
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 intl is used inside the useMemo callback (intl.formatMessage(messages.title)) but is excluded from the dependency array. If the active locale changes, topbarModeLabel will stay stale until selectedProjectId or topbarWorkspaceName also changes. Adding intl to the array removes the need for the suppression comment and keeps the label reactive to locale switches.

Suggested change
const shellSlot = useMemo(
() => ({
topbarWorkspaceName: selectedProjectId ? topbarWorkspaceName : undefined,
topbarModeLabel: intl.formatMessage(messages.title),
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectedProjectId, topbarWorkspaceName],
);
const shellSlot = useMemo(
() => ({
topbarWorkspaceName: selectedProjectId ? topbarWorkspaceName : undefined,
topbarModeLabel: intl.formatMessage(messages.title),
}),
[selectedProjectId, topbarWorkspaceName, intl],
);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/screens/AlertsScreen.tsx
Line: 61-68

Comment:
`intl` is used inside the `useMemo` callback (`intl.formatMessage(messages.title)`) but is excluded from the dependency array. If the active locale changes, `topbarModeLabel` will stay stale until `selectedProjectId` or `topbarWorkspaceName` also changes. Adding `intl` to the array removes the need for the suppression comment and keeps the label reactive to locale switches.

```suggestion
  const shellSlot = useMemo(
    () => ({
      topbarWorkspaceName: selectedProjectId ? topbarWorkspaceName : undefined,
      topbarModeLabel: intl.formatMessage(messages.title),
    }),
    [selectedProjectId, topbarWorkspaceName, intl],
  );
```

How can I resolve this? If you propose a fix, please make it concise.

@luandro luandro closed this Jun 9, 2026
@luandro luandro deleted the agent/comapeo-cloud-app/issue-72 branch June 9, 2026 02:30
@luandro luandro restored the agent/comapeo-cloud-app/issue-72 branch June 9, 2026 02:33
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.

feat: Replace Data nav icon with map marker; extract Alerts into dedicated screen

1 participant