mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-12 23:31:02 +00:00
1e674f040a
In the desktop booking and transport dialogs, clicking "Create expense"
(or editing a linked expense) before the booking had a title saved
nothing, which is right, but the wish was kept. The next ordinary save
then opened the expense editor out of nowhere. The same happened after a
save that threw.
useBookingExpenseIntent stored the wish in a ref and only cleared it when
the form read it, which the desktop forms do after a successful save. The
hook now clears the wish once the save its click started has settled,
unless a newer click replaced it in the meantime. The phone sheets read
it at the start of the save and are unaffected.
Red tests:
- FE-PLANNER-RESMODAL-107 in ReservationModal.test.tsx: "expected
"vi.fn()" to not be called at all, but actually been called 1 times".
- FE-PLANNER-BOOKINGEXPENSE-005 in useBookingExpenseIntent.test.ts:
"expected { create: true } to be null".
- FE-PLANNER-BOOKINGEXPENSE-006: "expected { editItem: { id: 9, ... } }
to be null".
No existing assertions changed.
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { useRef } from 'react';
|
|
|
|
import type { BudgetItem } from '../../types';
|
|
import type { BookingExpenseIntent } from './bookingFormModel';
|
|
|
|
export interface BookingExpenseRemoval {
|
|
/** Deletes the expense linked to the booking. */
|
|
remove: (item: BudgetItem) => Promise<unknown>;
|
|
/** Called when the delete fails. */
|
|
onError: () => void;
|
|
}
|
|
|
|
/**
|
|
* The expense the user asked for from a booking form, held in a ref (not state) so
|
|
* the save started by the same click reads it. Behind the desktop booking and
|
|
* transport dialogs and the phone's booking and transport sheets: `create` (and on
|
|
* the desktop `edit`) note the wish and save; the form reads it with `take` at the
|
|
* point it always did and opens the editor for the saved booking.
|
|
*/
|
|
export function useBookingExpenseIntent(submit: () => Promise<unknown>, removal?: BookingExpenseRemoval) {
|
|
const intentRef = useRef<BookingExpenseIntent | null>(null);
|
|
|
|
// The wish belongs to the save its click starts. A save that returns early
|
|
// (no title) or throws never reads it, and it must not open the editor on
|
|
// the next, unrelated save. A newer click's wish is left alone.
|
|
const saveWith = (intent: BookingExpenseIntent) => {
|
|
intentRef.current = intent;
|
|
void submit().finally(() => {
|
|
if (intentRef.current === intent) intentRef.current = null;
|
|
});
|
|
};
|
|
|
|
return {
|
|
/** Forgets a wish left from an earlier opening. */
|
|
reset: () => {
|
|
intentRef.current = null;
|
|
},
|
|
/** Reads the wish and clears it. */
|
|
take: (): BookingExpenseIntent | null => {
|
|
const intent = intentRef.current;
|
|
intentRef.current = null;
|
|
return intent;
|
|
},
|
|
create: () => saveWith({ create: true }),
|
|
/** Saves the booking first, then opens the linked expense. */
|
|
edit: (item: BudgetItem) => saveWith({ editItem: item }),
|
|
remove: async (item: BudgetItem) => {
|
|
if (!removal) return;
|
|
try {
|
|
await removal.remove(item);
|
|
} catch {
|
|
removal.onError();
|
|
}
|
|
},
|
|
};
|
|
}
|