Skip to content

feat: add offline indicator#429

Open
arian81 wants to merge 2 commits intomainfrom
arian/offline-indicator
Open

feat: add offline indicator#429
arian81 wants to merge 2 commits intomainfrom
arian/offline-indicator

Conversation

@arian81
Copy link
Copy Markdown
Member

@arian81 arian81 commented Jan 10, 2026

No description provided.

@vercel
Copy link
Copy Markdown

vercel Bot commented Jan 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
portal Ready Ready Preview, Comment Jan 10, 2026 1:04pm

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 10, 2026

Greptile Overview

Greptile Summary

This PR adds visual indicators to the scanner page to show connection status and pending mutations:

What Changed:

  • Implemented useOnlineStatus() hook using React's useSyncExternalStore to track browser online/offline status
  • Added useIsMutating() from React Query to display count of pending mutations
  • Added two status badges in the UI: an online/offline indicator (green/red) and a pending mutations counter (yellow, only shown when >0)
  • Restructured the mode toggle layout from centered to left-aligned with indicators on the right

How It Works:
The useOnlineStatus hook subscribes to browser online/offline events and checks navigator.onLine. The pendingMutations count comes from React Query's global mutation tracking. Both indicators update reactively and provide visual feedback about the scanner's operational state, which is especially valuable given the existing offline queue functionality.

Issues Found:

  • ⚠️ Hardcoded Tailwind color values (bg-green-100, bg-red-500, etc.) instead of using CSS variables as required by custom rules
  • ⚠️ Missing accessibility attributes (ARIA labels, roles, live regions) for status indicators
  • ⚠️ Layout change from centered to left-aligned toggle buttons may be unintentional
  • ⚠️ Using w-1.5 h-1.5 instead of more concise size-1.5 utility
  • ⚠️ PR description doesn't include "resolves #issue-id" as required by custom rules

The implementation is solid from a functionality perspective and correctly uses React patterns, but needs style improvements to meet project standards.

Confidence Score: 3/5

  • This PR is safe to merge with minor style improvements needed
  • Score reflects that the core functionality is well-implemented (proper use of useSyncExternalStore, React Query integration works correctly, SSR-safe via getServerSideProps), but there are multiple style/best-practice violations including hardcoded colors, missing accessibility attributes, and custom rule violations. No logic bugs or security issues were found.
  • src/pages/scanner.tsx requires style improvements: replace hardcoded colors with Tailwind variables, add ARIA attributes, and use size-* utilities

Important Files Changed

File Analysis

Filename Score Overview
src/pages/scanner.tsx 3/5 Added online/offline indicator and pending mutations counter. Changes are functional but have style issues: hardcoded colors violate custom rules, missing accessibility attributes, and layout change needs verification.

Sequence Diagram

sequenceDiagram
    participant User
    participant Browser
    participant ScannerUI
    participant useOnlineStatus
    participant useIsMutating
    participant scannerMutation
    participant OfflineQueue
    participant Backend

    Note over Browser,useOnlineStatus: Online Status Tracking
    Browser->>useOnlineStatus: navigator.onLine (initial)
    useOnlineStatus->>ScannerUI: isOnline = true/false
    Browser->>useOnlineStatus: "online" event
    useOnlineStatus->>ScannerUI: Update isOnline = true
    Browser->>useOnlineStatus: "offline" event
    useOnlineStatus->>ScannerUI: Update isOnline = false

    Note over ScannerUI,useIsMutating: Pending Mutations Tracking
    useIsMutating->>ScannerUI: pendingMutations count
    
    Note over User,Backend: Scan Flow with Status Indicators
    User->>ScannerUI: Scan QR code
    ScannerUI->>OfflineQueue: addToQueue(userId, stationId)
    ScannerUI->>scannerMutation: mutate(userId, stationId)
    scannerMutation->>useIsMutating: Increment pending count
    useIsMutating->>ScannerUI: Update pendingMutations + 1
    ScannerUI->>User: Show yellow badge with count
    
    alt Online
        scannerMutation->>Backend: POST /scanner/scan
        Backend-->>scannerMutation: Success response
        scannerMutation->>OfflineQueue: removeFromQueue(userId)
        scannerMutation->>useIsMutating: Decrement pending count
        useIsMutating->>ScannerUI: Update pendingMutations - 1
        ScannerUI->>User: Hide badge if count = 0
    else Offline
        Note over scannerMutation,Backend: Mutation queued, will retry
        scannerMutation->>useIsMutating: Keep pending count
        ScannerUI->>User: Show offline (red) indicator
    end

    Note over ScannerUI: Visual Status Updates
    ScannerUI->>User: Online indicator (green/red)
    ScannerUI->>User: Pending mutations badge (yellow, if >0)
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment thread src/pages/scanner.tsx
Comment on lines +388 to +391
? "bg-primary text-white"
: "text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-100",
)}
>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hardcoded color values (bg-yellow-100, bg-yellow-900/30, text-yellow-700, text-yellow-400, bg-yellow-500) violate the custom instruction rule that states: "Use Tailwind CSS variables for colors instead of hardcoded color values."

Consider defining these colors in the Tailwind config as semantic tokens (e.g., --color-warning-light, --color-warning-dark) and using them via CSS variables for better maintainability and theme consistency.

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 With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 388:391

Comment:
The hardcoded color values (`bg-yellow-100`, `bg-yellow-900/30`, `text-yellow-700`, `text-yellow-400`, `bg-yellow-500`) violate the custom instruction rule that states: "Use Tailwind CSS variables for colors instead of hardcoded color values."

Consider defining these colors in the Tailwind config as semantic tokens (e.g., `--color-warning-light`, `--color-warning-dark`) and using them via CSS variables for better maintainability and theme consistency.

<sub>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!</sub>

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

Comment thread src/pages/scanner.tsx
Comment on lines +393 to +408
</button>
</div>
<div className="flex items-center gap-1.5">
{pendingMutations > 0 && (
<div className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400">
<span className="w-1.5 h-1.5 rounded-full bg-yellow-500 animate-pulse" />
{pendingMutations}
</div>
)}
>
Manual
</button>
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400"
: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hardcoded color values (bg-green-100, bg-green-900/30, text-green-700, text-green-400, bg-green-500, bg-red-100, bg-red-900/30, text-red-700, text-red-400, bg-red-500) violate the custom instruction rule that states: "Use Tailwind CSS variables for colors instead of hardcoded color values."

Consider defining semantic color tokens in the Tailwind config (e.g., --color-success, --color-error, --color-online, --color-offline) for better maintainability and theme consistency across the application.

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 With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 393:408

Comment:
The hardcoded color values (`bg-green-100`, `bg-green-900/30`, `text-green-700`, `text-green-400`, `bg-green-500`, `bg-red-100`, `bg-red-900/30`, `text-red-700`, `text-red-400`, `bg-red-500`) violate the custom instruction rule that states: "Use Tailwind CSS variables for colors instead of hardcoded color values."

Consider defining semantic color tokens in the Tailwind config (e.g., `--color-success`, `--color-error`, `--color-online`, `--color-offline`) for better maintainability and theme consistency across the application.

<sub>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!</sub>

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

Comment thread src/pages/scanner.tsx
Comment on lines +386 to +409
"px-3 py-2 rounded text-sm font-medium transition-colors",
mode === "manual"
? "bg-primary text-white"
: "text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-100",
)}
>
Manual
</button>
</div>
<div className="flex items-center gap-1.5">
{pendingMutations > 0 && (
<div className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400">
<span className="w-1.5 h-1.5 rounded-full bg-yellow-500 animate-pulse" />
{pendingMutations}
</div>
)}
>
Manual
</button>
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400"
: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
)}
>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The status indicators are missing accessibility attributes. For users relying on screen readers, the visual status information (online/offline, pending mutations) is not properly conveyed.

Consider adding ARIA attributes:

  • Add role="status" to both status indicators
  • Add aria-live="polite" to announce status changes
  • Add descriptive aria-label attributes (e.g., aria-label="Connection status: Online" or aria-label="Pending operations: 3")

Example improvement:

Suggested change
"px-3 py-2 rounded text-sm font-medium transition-colors",
mode === "manual"
? "bg-primary text-white"
: "text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-100",
)}
>
Manual
</button>
</div>
<div className="flex items-center gap-1.5">
{pendingMutations > 0 && (
<div className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400">
<span className="w-1.5 h-1.5 rounded-full bg-yellow-500 animate-pulse" />
{pendingMutations}
</div>
)}
>
Manual
</button>
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400"
: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
)}
>
<div className="flex items-center gap-1.5">
{pendingMutations > 0 && (
<div
className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400"
role="status"
aria-live="polite"
aria-label={`${pendingMutations} pending operation${pendingMutations !== 1 ? 's' : ''}`}
>
<span className="w-1.5 h-1.5 rounded-full bg-yellow-500 animate-pulse" aria-hidden="true" />
{pendingMutations}
</div>
)}
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400"
: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
)}
role="status"
aria-live="polite"
aria-label={`Connection status: ${isOnline ? 'Online' : 'Offline'}`}
>
<span
className={clsx(
"w-1.5 h-1.5 rounded-full",
isOnline ? "bg-green-500" : "bg-red-500",
)}
aria-hidden="true"
/>
{isOnline ? "Online" : "Offline"}
</div>
</div>
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 386:409

Comment:
The status indicators are missing accessibility attributes. For users relying on screen readers, the visual status information (online/offline, pending mutations) is not properly conveyed.

Consider adding ARIA attributes:
- Add `role="status"` to both status indicators
- Add `aria-live="polite"` to announce status changes
- Add descriptive `aria-label` attributes (e.g., `aria-label="Connection status: Online"` or `aria-label="Pending operations: 3"`)

Example improvement:
```suggestion
          <div className="flex items-center gap-1.5">
            {pendingMutations > 0 && (
              <div 
                className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400"
                role="status"
                aria-live="polite"
                aria-label={`${pendingMutations} pending operation${pendingMutations !== 1 ? 's' : ''}`}
              >
                <span className="w-1.5 h-1.5 rounded-full bg-yellow-500 animate-pulse" aria-hidden="true" />
                {pendingMutations}
              </div>
            )}
            <div
              className={clsx(
                "flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
                isOnline
                  ? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400"
                  : "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
              )}
              role="status"
              aria-live="polite"
              aria-label={`Connection status: ${isOnline ? 'Online' : 'Offline'}`}
            >
              <span
                className={clsx(
                  "w-1.5 h-1.5 rounded-full",
                  isOnline ? "bg-green-500" : "bg-red-500",
                )}
                aria-hidden="true"
              />
              {isOnline ? "Online" : "Offline"}
            </div>
          </div>
```

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

Comment thread src/pages/scanner.tsx
"px-3 py-2 rounded text-sm font-medium transition-colors",
mode === "manual"
? "bg-primary text-white"
: "text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-100",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider using the size-1.5 utility class instead of w-1.5 h-1.5 for more concise code. Tailwind v3.4+ supports the size-* shorthand for setting both width and height.

Suggested change
: "text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-100",
<span className="size-1.5 rounded-full bg-yellow-500 animate-pulse" />

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 With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 389:389

Comment:
Consider using the `size-1.5` utility class instead of `w-1.5 h-1.5` for more concise code. Tailwind v3.4+ supports the `size-*` shorthand for setting both width and height.

```suggestion
                <span className="size-1.5 rounded-full bg-yellow-500 animate-pulse" />
```

<sub>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!</sub>

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

Comment thread src/pages/scanner.tsx
Comment on lines 401 to +405
)}
>
Manual
</button>
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider using the size-1.5 utility class instead of w-1.5 h-1.5 for more concise code. Tailwind v3.4+ supports the size-* shorthand for setting both width and height.

Suggested change
)}
>
Manual
</button>
<div
className={clsx(
"flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
isOnline
<span
className={clsx(
"size-1.5 rounded-full",
isOnline ? "bg-green-500" : "bg-red-500",
)}
/>

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 With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 401:405

Comment:
Consider using the `size-1.5` utility class instead of `w-1.5 h-1.5` for more concise code. Tailwind v3.4+ supports the `size-*` shorthand for setting both width and height.

```suggestion
              <span
                className={clsx(
                  "size-1.5 rounded-full",
                  isOnline ? "bg-green-500" : "bg-red-500",
                )}
              />
```

<sub>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!</sub>

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

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 10, 2026

Additional Comments (1)

src/pages/scanner.tsx
The removal of mx-auto from the mode toggle buttons causes a layout change. The toggle was previously centered, but now it's left-aligned. This changes the visual hierarchy of the page.

If the intent is to align it to the left to make room for the status indicators on the right, this is acceptable. However, please verify this was intentional and not an accidental removal.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/pages/scanner.tsx
Line: 362:362

Comment:
The removal of `mx-auto` from the mode toggle buttons causes a layout change. The toggle was previously centered, but now it's left-aligned. This changes the visual hierarchy of the page.

If the intent is to align it to the left to make room for the status indicators on the right, this is acceptable. However, please verify this was intentional and not an accidental removal.

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

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