Remove a period's days along with the period
Deleting a period left every day it had funded behind. The link from a day back to its period was set to null the instant the period was deleted, so the days became untraceable before anything could clean them up, and the next recalculation had no way to know they no longer belonged to anything. Undo had the same fault for the same reason: the period went, the days stayed, and a reload showed them still there. The days are now removed with the period, before the link can be broken. A day pinned by hand goes too — pinning keeps the planner from quietly retyping a day, not from being deleted when you delete the period it belongs to, which is already how an unplanned band behaves.
This commit is contained in:
@@ -847,6 +847,51 @@ describe('Calendar', () => {
|
||||
expect(toast).toHaveTextContent('10')
|
||||
})
|
||||
|
||||
it('reports a calendar-drawn period\'s shortfall in days, not weeks, since it carries an exact targetDays', async () => {
|
||||
// Regression: a drag-created wish sets `targetDays` (an exact day
|
||||
// count); `targetWeeks` on that same wish is just a rough
|
||||
// `Math.ceil(days / 7)` leftover the API still requires — never what
|
||||
// the user actually asked for. The toast must report the days
|
||||
// figure, not `weeksWished`, once `targetDays` is set. `weeksWished`
|
||||
// is deliberately set to a nonsense value here (3) to prove the toast
|
||||
// isn't reading it at all, not just that it happens to agree.
|
||||
const created = makeLeaveWish({ id: 'lw-new', name: 'Ny period', targetDays: 7, targetWeeks: 1 })
|
||||
const add = vi.fn().mockResolvedValue(created)
|
||||
const sync = vi.fn().mockResolvedValue(
|
||||
makePlanSyncResponse({
|
||||
changes: [],
|
||||
proposal: makePlanProposal({
|
||||
outcomes: [
|
||||
makeWindowOutcome({
|
||||
wishId: 'lw-new',
|
||||
startDate: '2026-09-17',
|
||||
endDate: '2026-09-23',
|
||||
weeksWished: 3,
|
||||
weeksFunded: 0,
|
||||
shortfallDays: 5,
|
||||
data: { wish_name: 'Ny period', wish_name_message_key: null },
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
)
|
||||
vi.mocked(useLeaveWishes).mockReturnValue(makeLeaveWishesResult({ add, data: [] }))
|
||||
vi.mocked(usePlanSync).mockReturnValue(makePlanSyncResult({ sync }))
|
||||
|
||||
render(<Calendar />)
|
||||
const calendarDays = screen.getAllByTestId('calendar-day')
|
||||
const currentMonthDays = calendarDays.filter((el) => !el.classList.contains('calendar-day--disabled'))
|
||||
fireEvent.pointerDown(currentMonthDays[0] as HTMLElement)
|
||||
fireEvent.pointerEnter(currentMonthDays[6] as HTMLElement)
|
||||
fireEvent.pointerUp(window)
|
||||
|
||||
const toast = await screen.findByTestId('calendar-toast')
|
||||
expect(toast).toHaveTextContent('7')
|
||||
expect(toast).toHaveTextContent('dagarna')
|
||||
expect(toast).not.toHaveTextContent('3 vecko')
|
||||
expect(toast).not.toHaveTextContent('veckorna')
|
||||
})
|
||||
|
||||
it('shows no toast when a sync with no changes also has no outcome for the touched wish (genuine no-op)', async () => {
|
||||
const created = makeLeaveWish({ id: 'lw-new' })
|
||||
const add = vi.fn().mockResolvedValue(created)
|
||||
@@ -999,7 +1044,7 @@ describe('Calendar', () => {
|
||||
expect(screen.queryByTestId('calendar-toast')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('undo after creating a period from a drag removes the wish and re-syncs', async () => {
|
||||
it('undo after creating a period from a drag deletes the wish and re-syncs, leaving day cleanup to the backend', async () => {
|
||||
const created = makeLeaveWish({ id: 'lw-new' })
|
||||
const add = vi.fn().mockResolvedValue(created)
|
||||
const remove = vi.fn().mockResolvedValue(undefined)
|
||||
@@ -1007,6 +1052,14 @@ describe('Calendar', () => {
|
||||
vi.mocked(useLeaveWishes).mockReturnValue(makeLeaveWishesResult({ add, remove, data: [created] }))
|
||||
vi.mocked(usePlanSync).mockReturnValue(makePlanSyncResult({ sync }))
|
||||
|
||||
// `LeaveWishService.delete()` deletes every `planned_leave_day` row
|
||||
// the wish produced as part of deleting the wish itself — the
|
||||
// frontend no longer snapshots or deletes days individually. The
|
||||
// outcome under test is therefore the delegation: undo removes the
|
||||
// wish and re-syncs, and never touches `plannedDaysHook.remove` at all.
|
||||
const removeDay = vi.fn().mockResolvedValue(undefined)
|
||||
vi.mocked(usePlannedDays).mockReturnValue(makePlannedDaysResult({ remove: removeDay }))
|
||||
|
||||
render(<Calendar />)
|
||||
const calendarDays = screen.getAllByTestId('calendar-day')
|
||||
const currentMonthDays = calendarDays.filter((el) => !el.classList.contains('calendar-day--disabled'))
|
||||
@@ -1020,9 +1073,10 @@ describe('Calendar', () => {
|
||||
|
||||
await waitFor(() => expect(remove).toHaveBeenCalledWith('lw-new'))
|
||||
await waitFor(() => expect(sync.mock.calls.length).toBeGreaterThan(syncCallsBeforeUndo))
|
||||
expect(removeDay).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('undo after selecting a preset removes the wish and re-syncs', async () => {
|
||||
it('undo after selecting a preset deletes the wish and re-syncs, leaving day cleanup to the backend', async () => {
|
||||
const created = makeLeaveWish({ id: 'lw-preset' })
|
||||
const add = vi.fn().mockResolvedValue(created)
|
||||
const remove = vi.fn().mockResolvedValue(undefined)
|
||||
@@ -1030,6 +1084,9 @@ describe('Calendar', () => {
|
||||
vi.mocked(useLeaveWishes).mockReturnValue(makeLeaveWishesResult({ add, remove, data: [created] }))
|
||||
vi.mocked(usePlanSync).mockReturnValue(makePlanSyncResult({ sync }))
|
||||
|
||||
const removeDay = vi.fn().mockResolvedValue(undefined)
|
||||
vi.mocked(usePlannedDays).mockReturnValue(makePlannedDaysResult({ remove: removeDay }))
|
||||
|
||||
render(<Calendar />)
|
||||
fireEvent.click(screen.getByTestId('preset-click'))
|
||||
|
||||
@@ -1039,6 +1096,7 @@ describe('Calendar', () => {
|
||||
|
||||
await waitFor(() => expect(remove).toHaveBeenCalledWith('lw-preset'))
|
||||
await waitFor(() => expect(sync.mock.calls.length).toBeGreaterThan(syncCallsBeforeUndo))
|
||||
expect(removeDay).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('undo after deleting an ad-hoc period recreates the deleted days', async () => {
|
||||
|
||||
Reference in New Issue
Block a user