Skip to content

feat: Add ability to edit existing shifts#125

Merged
panteLx merged 2 commits intopanteLx:mainfrom
Belgilias:feature/edit-shift-functionality
Jan 17, 2026
Merged

feat: Add ability to edit existing shifts#125
panteLx merged 2 commits intopanteLx:mainfrom
Belgilias:feature/edit-shift-functionality

Conversation

@Belgilias
Copy link
Contributor

@Belgilias Belgilias commented Jan 17, 2026

feat: Add shift edit functionality

Add the ability to edit existing shifts by clicking on them throughout the application.

Features

  • Click on any shift in the calendar to open edit dialog
  • Click on shifts in the "+X shifts" overflow popup to edit
  • Click on shifts in the Shifts list section at the bottom
  • Pencil icon button added next to delete button for explicit edit action
  • Hover effects on clickable shifts for better UX
  • Edit functionality is disabled when a preset is selected (quick-add mode)

Backend

  • Add PUT endpoint for updating shifts with permission checks

Frontend

  • Add updateShift mutation with optimistic updates
  • Pass editingShift state through component hierarchy
  • Externally synced shifts remain read-only (cannot be edited)

Files Changed

  • app/api/shifts/[id]/route.ts - Added PUT endpoint
  • hooks/useShifts.ts - Added updateShift mutation
  • components/calendar-shift-card.tsx - Added onClick and hover styles
  • components/calendar-grid.tsx - Pass onEditShift to shift cards
  • components/shift-card.tsx - Added pencil icon and click handler
  • components/shifts-list.tsx - Pass onEditShift to shift cards
  • components/shifts-overview-dialog.tsx - Added edit buttons and click handlers
  • components/dialog-manager.tsx - Added editingShift prop
  • components/calendar-content.tsx - Pass onEditShift through hierarchy
  • app/page.tsx - Added edit state management and handlers

Testing

  • npm test passed successfully (lint, build, i18n checks all passing)

Summary by CodeRabbit

  • New Features
    • Edit existing shifts from day overview, shift cards, lists, and dialogs with dedicated edit buttons and clickable cards.
    • Server-side shift update available; edits respect permissions and external-sync (read-only) status and provide user-facing error handling.
    • Updates apply immediately with optimistic caching and automatic refresh after submit.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

Adds end-to-end shift editing: a new PUT API for updating shifts with permission and external-sync checks, an update mutation with optimistic cache updates, and UI wiring across page and components to initiate and submit edit flows from dialogs, cards, and lists.

Changes

Cohort / File(s) Summary
API Shift Update Handler
app/api/shifts/[id]/route.ts
Added PUT handler to update a shift: fetches target, verifies canEditCalendar, blocks externally-synced shifts, updates fields (falling back to existing values), updates updatedAt, and returns errors (404/403/500) as appropriate.
Shift Data Management (hook + API client)
hooks/useShifts.ts
Added updateShiftApi (PUT /api/shifts/{id}), UpdateShiftContext type, an update mutation with optimistic cache update, rollback on error, toasts on result, query invalidation, and exported updateShift(shiftId, formData) method.
Page-level orchestration
app/page.tsx
Introduced editingShift state and handlers (handleEditShiftFromDayDialog, handleShiftDialogChange, handleShiftSubmit) to open edit flows, call updateShift or create path conditionally, clear editing state on close, and refetch shifts after submit.
Calendar composition & grid
components/calendar-content.tsx, components/calendar-grid.tsx, components/calendar-shift-card.tsx
Added onEditShift prop through calendar hierarchy; CalendarShiftCard now conditionally enables click-to-edit (cursor/hover styles) when onEditShift provided and shift is not externally synced.
Cards & lists
components/shift-card.tsx, components/shifts-list.tsx
Added onEdit/onEditShift props; cards gain editability (card click and pencil button) when editable, conditional rendering of edit vs delete buttons based on external-sync state; ShiftsList passes edit handler to ShiftCard.
Dialogs & dialog manager
components/dialog-manager.tsx, components/shifts-overview-dialog.tsx
DialogManager accepts editingShift and onEditShiftFromDayDialog and forwards editingShift into ShiftSheet; ShiftsOverviewDialog added edit button/row click to close dialog and invoke edit callback for non-externally-synced shifts.

Sequence Diagram(s)

sequenceDiagram
    participant User as User (UI)
    participant Page as Home Page
    participant Dialog as Dialog Manager / ShiftSheet
    participant Hook as useShifts (mutation + cache)
    participant API as API Endpoint
    participant DB as Database

    User->>Page: Click edit on shift card / overview
    Page->>Page: set editingShift
    Page->>Dialog: open dialog with editingShift
    User->>Dialog: Submit edited shift
    Dialog->>Page: handleShiftSubmit(formData)
    Page->>Hook: updateShift(shiftId, formData) (optimistic)
    Hook->>Hook: onMutate - snapshot & update cache
    Hook->>API: PUT /api/shifts/{id}
    API->>API: verify canEditCalendar & externalSync
    API->>DB: update shift record
    DB-->>API: updated shift
    API-->>Hook: 200 + updated shift
    Hook->>Hook: onSuccess/onSettled - toast & invalidate/refetch
    Hook-->>Page: mutation settled
    Page->>Dialog: close dialog, clear editingShift
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I nudged a pencil, light and spry,
Edited shifts as hours flew by.
Optimistic hops, then server cheer,
Permissions guarding every ear.
A calendar blossom—soft and nigh. 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% 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 The title 'feat: Add ability to edit existing shifts' directly and clearly summarizes the main objective of the pull request, which is to implement shift editing functionality across the application.

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

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/page.tsx (1)

697-763: Add shift edit functionality to compare mode dialogs.

The DialogManager in compare mode (lines 697-763) is missing the editingShift and onEditShiftFromDayDialog props, while normal mode provides both. This prevents shifts from being edited when opened from the day shifts dialog in compare mode. All other dialog infrastructure is present, and the comment indicates dialogs should be fully functional in this mode—pass these props through to maintain feature parity.

🤖 Fix all issues with AI agents
In `@app/api/shifts/`[id]/route.ts:
- Around line 111-125: The PUT handler currently checks write permission via
canEditCalendar but does not prevent edits to externally managed shifts; after
fetching existingShift from shifts (existingShift variable) add a guard that
reads existingShift.syncedFromExternal and, if true, return a 403/appropriate
error JSON indicating the shift is read-only to external syncs; keep this check
before any mutation or permission-dependent logic so externally synced shifts
cannot be edited even by authorized users.

In `@components/shifts-overview-dialog.tsx`:
- Around line 74-77: The styling conditional currently uses
!shift.externalSyncId but the click handler was changed to use
shift.syncedFromExternal; update both the className condition and the edit
button rendering to use the same check (onEditShift &&
!shift.syncedFromExternal) so hover/cursor styles and the edit-button visibility
match the click-handler logic; specifically modify the className template string
and the edit button render block (the code that references onEditShift and
shift.externalSyncId) to reference shift.syncedFromExternal instead.
- Around line 45-50: The click handler handleShiftClick currently only blocks
edits when shift.externalSyncId exists; update it to also check
shift.syncedFromExternal so it matches the guard used in CalendarShiftCard and
prevents editing externally synced shifts—i.e., change the conditional in
handleShiftClick to require both !shift.externalSyncId &&
!shift.syncedFromExternal before calling onOpenChange/onEditShift.
🧹 Nitpick comments (1)
components/shift-card.tsx (1)

77-89: Consider consistent read-only check for delete button.

The delete button only checks !shift.externalSyncId but the edit button checks both externalSyncId and syncedFromExternal. For consistency and to align with the learnings about enforcing read-only access for synced shifts, the delete condition should also check syncedFromExternal.

♻️ Suggested fix
-            {!shift.externalSyncId && onDelete && (
+            {!shift.externalSyncId && !shift.syncedFromExternal && onDelete && (

@github-project-automation github-project-automation bot moved this to Backlog in BetterShift Jan 17, 2026
@panteLx panteLx merged commit 5fcdc1b into panteLx:main Jan 17, 2026
2 of 3 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in BetterShift Jan 17, 2026
@panteLx
Copy link
Owner

panteLx commented Jan 17, 2026

Great feature! Will be available in the next dev docker image within the next 30 mins!

@Belgilias Belgilias deleted the feature/edit-shift-functionality branch January 18, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants