Skip to content

Open shifts: fold into Roster and add more ways to find, share and fill shifts - #3483

Merged
gitar-bot[bot] merged 31 commits into
mainfrom
claude/open-shifts-expansion-hj3sp1
Oct 12, 2026
Merged

gitar-bot[bot] merged 31 commits into
mainfrom
claude/open-shifts-expansion-hj3sp1

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

User description

Requested by Josh · project thread

Summary

Before: Open shifts was its own area with its own Browse, Requests and Alerts tabs and a "Shifts" slot in the desktop rail. On a phone, a tall calendar came first. The list looked 14 days ahead.

After: Open shifts is Roster's second tab (Month, Open shifts, Swaps; Team moves to More, and Month's top card still opens "Who is on"). The page opens with your requests and fortnight hours in one strip, then "Fits your roster", the next shifts with no clash and no roster flag, each with a Request button that opens the confirm sheet. Phones get a day-by-day list with the calendar one tap away. From 1024 px the list and calendar sit side by side, and tapping a day scrolls the list. The window is four weeks. The desktop rail loses its Shifts slot.

Also added, with no database change:

  • Share with a colleague on a shift's page: plain text with the shift, day, times, hours, site and team. No patient details and no pay.
  • Add to calendar on a booked shift: a calendar file made on the device.
  • A Roster Month row: "N open shifts fit your roster", loaded lazily.
  • Managers can post one shift on several dates (sequential posts with an honest partial-failure report), use Post again, and see "Who could do this": team members at or above the level with nothing on their team roster at that time. It shows names and levels only and never messages anyone.
  • The header pill on Open shifts pages shows Roster's badge, and the help text matches the new layout.

How: src/lib/work-frame/areas.ts makes the open-shifts mode draw Roster's frame with an Open shifts tab whose paths cover all doctor-facing Open shifts pages. Manager pages sit in Roster's More. The old open area stays only as an id for help, example data and AI Search. New helpers live in src/lib/open-shifts/share.ts, post-plan.ts and who-could.ts, all unit tested.

Areas touched: Personal practice, App experience, Answer engine

Not in this PR: "Take back your own request" needs a database change and is in its own draft PR, #3485.

Screenshots (example data, phone 390 and 320 px, desktop 1440 px) are in the project files under work-mode-plan-2026-10-12/open-shifts-mockup/.

Verification

  • Checks run:
    • npx tsc --noEmit -p .: clean after merging latest main
    • eslint on changed src/components/open-shifts, src/lib/open-shifts and src/lib/work-frame: clean
    • npm run test:focused over every changed file after merging main: 162 of 163 files passed first time; the one failure (a help link label reading "Open Open shifts") is fixed in the last commit and its test file passes
    • Local Chromium screenshots of every changed page against the dev server
  • Browser suite (verify:ui) is left to CI.

Risk and rollout

  • Risk: navigation change for Roster and Open shifts. Old Open shifts addresses all still open the same pages.
  • Rollback: revert this PR.
  • Provider or production effects: None. No migration, no service worker change, no pay or award figures.

Notes

  • Josh saw the screenshots and chose to send this live on 12 Oct 2026.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY

Generated by Claude Code


CodeAnt-AI Description

Move Open shifts into Roster and expand shift discovery and posting

What Changed

  • Open shifts is now a Roster tab instead of a separate area. Browse covers four weeks, with a day-by-day list and a calendar view on phones, and both views side by side on larger screens.
  • The page highlights your requests and hours, then shows shifts that fit your roster with a direct Request option.
  • You can share an upcoming shift with a colleague or add an approved shift to your calendar.
  • Managers can post the same shift on several dates, copy details from a previous post, and see which team members may be available. Partial posting failures identify which dates succeeded; retries skip those dates.

Impact

✅ Open shifts alongside Roster
✅ Faster discovery of shifts that fit your roster
✅ Fewer duplicate posts after an uncertain response

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

…ter and list view

Open shifts becomes Roster's second tab (Team moves to More), the desktop
rail loses its Shifts slot, and the page leads with your requests and hours,
then the next shifts that fit your roster with a Request button. Phones get a
day-by-day list with the calendar one tap away; from 1024px they sit side by
side. The browse window widens to four weeks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
…ated tests

Adds Share with a colleague and Add to calendar on a shift's page, a row on
Roster's Month page counting open shifts that fit your roster, posting one
shift on several dates, Post again, and Who could do this for managers.
Navigation, side-menu, search and back-trail tests follow the fold into Roster.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
@BigSimmo BigSimmo self-assigned this Oct 12, 2026
@supabase

supabase Bot commented Oct 12, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: a8bc1edf-71a3-46d4-a805-c8581c937998

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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

@codeant-ai

codeant-ai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🏁 CodeAnt Quality Gate Results

Commit: 65773d58
Scan Time: 2026-10-12 13:40:32 UTC

✅ Overall Status: PASSED

Quality Gate Details

Quality Gate Status Details
Secrets ✅ PASSED 0 secrets found
Duplicate Code ✅ PASSED 0.1% duplicated
SAST ✅ PASSED No security issues
Bugs ✅ PASSED Rating S: No bugs
IAC ✅ PASSED No IAC issues

View Full Results

@codspeed

codspeed Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 63.54%

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

ℹ️ 1 benchmark has no flame graph

The flamegraph could not be generated because too much time was spent in runtime internals, making the visualization not useful for performance analysis.

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 7 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ ⚠️ medication-entities: medicationEntityMatchesInText 4.2 ms 11.6 ms -63.54%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/open-shifts-expansion-hj3sp1 (65773d5) with main (7346bbe)

Open in CodSpeed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

Announce share and posting progress through screen-reader-only live regions,
keep the Request pill on one type step, and stop a class name reading as a
result count in the roster-failed branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

Copy link
Copy Markdown
Owner Author

CodSpeed Performance Analysis reports one regressed benchmark on 0aad6cd. That isn't caused by this PR. The benchmarks cover clinical search, ranking and chunking code, and this PR changes none of it (only Open shifts and Roster UI, navigation and tests). On the previous commit (0c2e9cc) the same benchmarks showed a 29% improvement. CodSpeed also warns that the comparison ran in different runtime environments, so this looks like measurement noise. There is no fix to port. I can't re-run the check from here, so I'm leaving it as is and still watching the PR.


Generated by Claude Code

@BigSimmo
BigSimmo marked this pull request as ready for review October 12, 2026 10:27

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

BigSimmo has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codeant-ai

codeant-ai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 2bb9c46 Oct 12, 2026 · 13:15 13:15
✅ Incremental review completed 9d26452 Oct 12, 2026 · 11:40 11:41
✅ Reviewed your PR e335f40 Oct 12, 2026 · 10:27 10:35

@codeant-ai

codeant-ai Bot commented Oct 12, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-12T10:32:38.811580Z e335f40 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@gitar-bot
gitar-bot Bot enabled auto-merge (squash) October 12, 2026 10:27
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Oct 12, 2026
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Integrate Open shifts into Roster and expand shift workflows

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Make Open shifts a Roster tab with a four-week, list-first browse experience.
Diagram

graph TD
  R["Roster frame"] --> B["Open shifts browse"] --> D["Shift details"] --> H["Share and calendar"]
  R --> M["Roster Month"] --> B
  R --> P["Manager posting"] --> A["Roster actions"]
  B --> A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Atomic batch-post endpoint
  • ➕ Could provide one transaction and simpler all-or-nothing results.
  • ➖ Requires a new server contract and changes the intended partial-success behavior.

Recommendation: Reuse the existing single-shift action for now: sequential posts, per-date results, and retrying only missing dates deliver the feature without a backend change. Consider a batch endpoint if posting volume or a requirement for atomicity grows.

Files changed (27) +1630 / -332

Enhancement (14) +1310 / -281
page.tsxPass the request shortcut to the advert +4/-3

Pass the request shortcut to the advert

• Reads 'request=1' from the route query and passes it to the advert so a fitting shift can open its confirmation sheet.

src/app/(search-app)/open-shifts/shift/[serviceId]/[openShiftId]/page.tsx

master-search-header.tsxShow the Roster badge for Open shifts +1/-1

Show the Roster badge for Open shifts

• Uses the route work area's identity when selecting the header icon.

src/components/clinical-dashboard/master-search-header.tsx

open-shifts-advert-actions.tsxAdd share and calendar actions +77/-0

Add share and calendar actions

• Offers native sharing or clipboard copying for open adverts and a locally generated calendar download for booked shifts.

src/components/open-shifts/open-shifts-advert-actions.tsx

open-shifts-advert-page.tsxSupport direct request confirmation and advert actions +30/-1

Support direct request confirmation and advert actions

• Opens the confirmation sheet for an eligible 'request=1' visit without sending a request. Adds sharing and booked-shift calendar actions to the advert.

src/components/open-shifts/open-shifts-advert-page.tsx

open-shifts-browse-page.tsxMake browsing list-first and roster-focused +347/-240

Make browsing list-first and roster-focused

• Adds the requests strip and fitting shifts ahead of a day-by-day list. Phones can switch to a calendar; wider screens show both side by side, with calendar selections scrolling the list.

src/components/open-shifts/open-shifts-browse-page.tsx

open-shifts-fit-line.tsxShow fitting shifts on Roster Month +44/-0

Show fitting shifts on Roster Month

• Counts matching shifts using the existing browse and roster checks and links to Open shifts when the count is nonzero.

src/components/open-shifts/open-shifts-fit-line.tsx

open-shifts-for-you.tsxIntroduce requests and Fits your roster sections +152/-0

Introduce requests and Fits your roster sections

• Summarizes requests and fortnight hours, then presents the next shifts with a clear roster check. Request links lead to the advert's confirmation sheet.

src/components/open-shifts/open-shifts-for-you.tsx

open-shifts-post-page.tsxPost across dates and prefill Post again +209/-31

Post across dates and prefill Post again

• Lets managers post the same shift on up to 14 dates through sequential existing actions. Reports partial failures, avoids resending successful dates during the visit, and accepts validated shift details for Post again.

src/components/open-shifts/open-shifts-post-page.tsx

open-shifts-posted-shift-page.tsxShow possible cover and a Post again shortcut +142/-3

Show possible cover and a Post again shortcut

• Reads team members, assignments, and unavailability to show who could do an open shift, with limitations stated on the page. Adds a link that copies shift details into a new post.

src/components/open-shifts/open-shifts-posted-shift-page.tsx

roster-month-page.tsxLoad the Open shifts count on Month +8/-0

Load the Open shifts count on Month

• Dynamically loads the fitting-shifts row so the cross-team Open shifts read is not part of Month's initial render.

src/components/roster/roster-month-page.tsx

model.tsExtend browsing to four weeks +2/-2

Extend browsing to four weeks

• Changes the shared browse window from 14 to 28 Perth dates.

src/lib/open-shifts/model.ts

post-plan.tsDefine multi-date and Post again planning +142/-0

Define multi-date and Post again planning

• Adds date-set validation, attempt-result splitting, and validated query-string encoding and parsing for a copied shift.

src/lib/open-shifts/post-plan.ts

share.tsBuild shift share text and calendar events +54/-0

Build shift share text and calendar events

• Formats advert facts for sharing and creates a stable, timed Perth calendar event without patient or pay details.

src/lib/open-shifts/share.ts

who-could.tsFind potential cover from the team roster +98/-0

Find potential cover from the team roster

• Filters members by level, overlapping team assignments, and stated unavailability, and defines a read window that includes earlier-starting shifts.

src/lib/open-shifts/who-could.ts

Refactor (3) +46 / -16
areas.tsFold Open shifts into Roster navigation +45/-14

Fold Open shifts into Roster navigation

• Makes Open shifts Roster's second tab, moves Team into More, and adds manager links there. Retains the old area identifier for non-frame uses.

src/lib/work-frame/areas.ts

side-nav.tsRemove the separate Open shifts rail entry +0/-1

Remove the separate Open shifts rail entry

• Leaves Roster as the top-level work area for Open shifts.

src/lib/work-frame/side-nav.ts

pages.tsIndex Open shifts under Roster +1/-1

Index Open shifts under Roster

• Moves browse-related search keywords to the new Roster tab's page identifier.

src/lib/work-search/pages.ts

Tests (9) +269 / -30
clinical-menu-drawer.dom.test.tsxUpdate phone-menu expectations +1/-9

Update phone-menu expectations

• Expects six work areas after the separate Open shifts menu entry is removed.

tests/clinical-menu-drawer.dom.test.tsx

open-shifts-logic.test.tsAdjust browse coverage for the four-week window +1/-1

Adjust browse coverage for the four-week window

• Moves the out-of-window fixture beyond the new 28-day limit.

tests/open-shifts-logic.test.ts

open-shifts-post-plan.test.tsTest posting plans and potential-cover rules +186/-0

Test posting plans and potential-cover rules

• Covers date validation, partial results, Post again query handling, level checks, assignment clashes, unavailability, and the roster read window.

tests/open-shifts-post-plan.test.ts

open-shifts-share.test.tsTest sharing and calendar export data +48/-0

Test sharing and calendar export data

• Checks share text and link placement, overnight event timing, stable calendar IDs, and absence of calendar alarms.

tests/open-shifts-share.test.ts

roster-month-page.dom.test.tsxIsolate the Month page's lazy shift row +2/-0

Isolate the Month page's lazy shift row

• Mocks the Open shifts count component in existing Month DOM tests.

tests/roster-month-page.dom.test.tsx

work-frame-back-trail.dom.test.tsxUpdate inner-area back-trail scenarios +13/-8

Update inner-area back-trail scenarios

• Uses Notifications in scenarios that previously treated Open shifts as an inner area.

tests/work-frame-back-trail.dom.test.tsx

work-frame-navigation.test.tsAssert Roster-tab routing and search indexing +13/-7

Assert Roster-tab routing and search indexing

• Checks the new tab order and path matching, Team's placement in More, and Open shifts' Roster search identifier.

tests/work-frame-navigation.test.ts

work-frame-route.test.tsExpect Roster framing on Open shifts routes +1/-1

Expect Roster framing on Open shifts routes

• Updates the route expectation to name Roster and its Open shifts tab.

tests/work-frame-route.test.ts

work-side-nav.test.tsVerify Open shifts no longer has a rail slot +4/-4

Verify Open shifts no longer has a rail slot

• Expects six side-nav areas and maps Open shifts browse and posting paths to Roster.

tests/work-side-nav.test.ts

Documentation (1) +5 / -5
open-shifts.tsAlign help with the new shift workflows +5/-5

Align help with the new shift workflows

• Explains Roster-tab discovery, direct requests, calendar export, multi-date posting, potential cover, and Post again.

src/lib/work-help/topics/open-shifts.ts

Copy link
Copy Markdown
Owner Author

CodSpeed's medication-entities: medicationEntityMatchesInText regression on 346c161 isn't caused by this PR. The PR doesn't touch that code or anything it imports; it changes only Open shifts, Roster and help text. CodSpeed itself flags this run for system-call time and for comparing different runtime environments, and the same benchmark showed no change on f72cdb5. No fix to port; CodSpeed is not a required check.


Generated by Claude Code

gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit b752fb4

Keeps both sides of the Roster month page: main's trimmed first page
and this branch's Open shifts row.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

…g matches

The none-match message now sits above the day sections instead of
replacing them, so hidden shifts can be shown in place without
changing filters.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 94b2c73

A second unanswered post kept the first attempt's time and shift list, so a
quick third tap could send a duplicate before the team was read again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZwGiwt7eXkD4fwyFM83gY

@gitar-bot gitar-bot Bot left a comment

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.

Gitar has auto-approved this PR (configure)

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 49a075c

Copy link
Copy Markdown
Owner Author

CodSpeed on 49a075c flags medication-entities: medicationEntityMatchesInText. That isn't from this PR. The only change since 2bb9c46 is in open-shifts-post-page.tsx and its test. Neither touches the medication matcher, and CodSpeed reported no performance change on 2bb9c46. CodSpeed also warns that this benchmark spends significant time in system calls, which it can't measure consistently. This is measurement noise, so I'm not changing code for it, and I have no way to re-run the check from here.


Generated by Claude Code

@qodo-code-review

qodo-code-review Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

No code changes since the last review — review skipped

Qodo Logo

@gitar-bot

gitar-bot Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor
Code Review ✅ Approved 4 closed / 4 findings

🟡 Medium risk · Manager multi-date posting issues up to 14 separate shift requests; partial failures could leave an incomplete set of live openings.

Moves Open shifts into Roster as a tab with a four-week browse view, a fits-your-roster list, share and add-to-calendar actions, and manager multi-date posting with a who-could-do-this helper. Resolved the undefined sample prop, the duplicate-post risk on retry before re-read, and the unanswered-post guard blocking deliberate posts to other teams. The liveMatch blocking of identical or filled shift posts was closed without a fix in this PR.

Auto-approved: No blocking issues found.
Please see Auto-approve Docs for details on setting custom approval criteria.

✅ 4 closed
✅ Bug: sample prop declared but never destructured; it is an undefined name

📄 src/components/open-shifts/open-shifts-advert-actions.tsx:21-31 📄 src/components/open-shifts/open-shifts-advert-page.tsx:374-378
The type now includes sample?: boolean, but the destructuring pattern still only takes listing and booked. So if (sample) return null; refers to a name that doesn't exist. tsc fails with "Cannot find name 'sample'", and at runtime every advert page throws a ReferenceError when OpenShiftsAdvertActions renders. Even with the name fixed, putting the early return before useState breaks the rules of hooks: the hook count changes when sample flips while the data loads. Destructure sample and move the sample check after useState, next to the existing shareable/booked return.

✅ Bug: Retry before the re-read lands can still post a duplicate shift

📄 src/components/open-shifts/open-shifts-post-page.tsx:167-181 📄 src/components/open-shifts/open-shifts-post-page.tsx:240-251
When a post gets roster_unavailable, the page saves the current shift ids and calls state.reload(). But usePostedShifts keeps returning the old loaded.shifts with status ready until the new read arrives, and keeps returning them if that read fails (refreshFailed: true). The confirm sheet stays open and "Yes, post it" can be tapped at once. If the manager taps it before the re-read lands, or after the re-read failed, lostAnswerMatch compares the old list with the saved ids, finds nothing new and sends open.post again. If the first post did go live, the team now has two copies of the shift, which is the case this commit is meant to stop. The test only covers the case where the new list is already there when Yes is tapped. Fix: save the time of the failed attempt (or the readAt at that moment). For a date with no answer, do not post again until state.readAt is later than that time and !state.refreshFailed. Until then, return a "Checking whether it went live, try again in a moment" message, or disable Yes.

✅ Edge Case: Unanswered-post guard blocks deliberate posts to other teams

📄 src/components/open-shifts/open-shifts-post-page.tsx:148 📄 src/components/open-shifts/open-shifts-post-page.tsx:219-224 📄 src/components/open-shifts/open-shifts-post-page.tsx:268-279
The new check at line 221 refuses every post while any unanswered entry's team is missing from state.teams. It doesn't consider whether the manager picked the current team themselves or whether that entry has since been settled. Entries are never removed from unanswered, because setUnanswered only ever merges into a copy. Example: a post to team A gets no answer, and A then keeps failing to load (it lands in failedTeams, or the manager loses posting rights there). Every post for the rest of the visit is then refused with "Still checking…" and triggers a reload, even when the manager has chosen team B on purpose for an unrelated shift. The worry about falling back to another team only applies when team came from the ?? state.teams[0] fallback. A fix: pin serviceId to team.serviceId when recording an unanswered entry, block only when team.serviceId !== serviceId, and skip entries whose signature is already in done.

Closed: Bug: liveMatch blocks posting a second identical or filled shift

📄 src/components/open-shifts/open-shifts-post-page.tsx:163-177 📄 src/components/open-shifts/open-shifts-post-page.tsx:205-210
liveMatch runs on every post, including the first one, not only on a retry after a lost answer. It treats any shift the team already has as "already posted" when the code, start and end match, even if the site, level, kind or urgency differ, and even if that shift is already claimed or approved. So a manager who needs two registrars for the same 08:00–16:30 D shift, or needs to re-advertise a slot next to one already filled, has nothing sent. They get "posted" and land on the old shift. Fix: only dedupe dates that failed or were unanswered earlier in this visit (for example, keep a set of attempted signatures and use liveMatch only for those). Also match on the full signature (site, level, kind, urgent) and only on status === "open" shifts posted after the attempt.

Review coverage

🤖 Auto-approval Approved

📋 Rules No rules evaluated

🧪 Functional validation Not enabled · Set up

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔴 Large blast radius size:XXL This PR changes 1000+ lines, ignoring generated files 🕐 40+ Minutes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants