mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(bookings): the delete question for a booking with a linked expense says the expense is deleted too
Deleting a booking also deletes the expenses linked to it, but the question only said the booking would be deleted. A booking with a linked expense now says so in every place that asks: the bookings list and detail, the transport and transit dialogs, and the phone's booking cards. The MCP delete_reservation description names the linked expenses and the stay a hotel booking created as well. Refs #2604
This commit is contained in:
@@ -10,8 +10,10 @@ import { Segmented, TEXTAREA } from '../shared/dialogParts'
|
||||
import { Tooltip } from '../shared/Tooltip'
|
||||
import { BookingDialogHeader, TypePill } from './bookings/BookingDialogShell'
|
||||
import { TransitLegs } from './bookings/transitParts'
|
||||
import { deleteBodyKey } from './bookings/bookingsModel'
|
||||
import { useTranslation } from '../../i18n'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { useTripStore } from '../../store/tripStore'
|
||||
import { splitReservationDateTime, formatTime } from '../../utils/formatters'
|
||||
import { TransitTitle, TransitMetaBadges, TransitWalkDivider, fmtTransitDuration } from './transitDisplay'
|
||||
import type { Reservation } from '../../types'
|
||||
@@ -55,6 +57,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
|
||||
const { t, locale } = useTranslation()
|
||||
const isMobile = useIsPhone()
|
||||
const timeFormat = useSettingsStore(st => st.settings.time_format) || '24h'
|
||||
const budgetItems = useTripStore(st => st.budgetItems)
|
||||
const res = reservation
|
||||
const meta = typeof res.metadata === 'string' ? (() => { try { return JSON.parse(res.metadata || '{}') } catch { return {} } })() : (res.metadata || {})
|
||||
const transit = meta.transit && Array.isArray(meta.transit.legs) ? meta.transit : null
|
||||
@@ -252,7 +255,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
|
||||
onClose={() => setConfirmDelete(false)}
|
||||
onConfirm={async () => { setConfirmDelete(false); await onDelete(); onClose() }}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t('reservations.confirm.deleteBody', { name: res.title })}
|
||||
message={t(deleteBodyKey(res.id, budgetItems), { name: res.title })}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
@@ -530,7 +533,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
|
||||
onClose={() => setConfirmDelete(false)}
|
||||
onConfirm={async () => { setConfirmDelete(false); await onDelete(); onClose() }}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t('reservations.confirm.deleteBody', { name: res.title })}
|
||||
message={t(deleteBodyKey(res.id, budgetItems), { name: res.title })}
|
||||
/>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ import { BookingDialogHeader, StatusPill } from './bookings/BookingDialogShell'
|
||||
import { DialogShell, DialogSection, DialogFooter, FooterSpacer, DialogButton, DeleteButton } from '../shared/DialogShell'
|
||||
import { INPUT, READONLY_BOX, GRID_2, GRID_3, PANEL, SEARCH_ON_PANEL, EditorField, Segmented, PillSelect, AddRowButton } from '../shared/dialogParts'
|
||||
import { fs, Eyebrow, type StatusTone } from './bookings/bookingParts'
|
||||
import { typeInfo } from './bookings/bookingsModel'
|
||||
import { deleteBodyKey, typeInfo } from './bookings/bookingsModel'
|
||||
import {
|
||||
EMPTY_TRANSPORT_FIELDS, TRANSPORT_TYPE_OPTIONS as TYPE_OPTIONS, emptyCarStop, emptyStationWaypoint, emptyWaypoint,
|
||||
transportDayOptions, type StationWaypointForm, type WaypointForm,
|
||||
@@ -565,7 +565,7 @@ export function TransportModal({ isOpen, onClose, onSave, reservation, days, sel
|
||||
isOpen={showDeleteConfirm}
|
||||
onClose={() => setShowDeleteConfirm(false)}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t('reservations.confirm.deleteBody', { name: reservation?.title ?? '' })}
|
||||
message={t(deleteBodyKey(reservation?.id, budgetItems), { name: reservation?.title ?? '' })}
|
||||
confirmLabel={t('common.delete')}
|
||||
cancelLabel={t('common.cancel')}
|
||||
onConfirm={async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-PLANNER-BOOKINGHOST-001 to FE-PLANNER-BOOKINGHOST-017
|
||||
// FE-PLANNER-BOOKINGHOST-001 to FE-PLANNER-BOOKINGHOST-018
|
||||
import { render, screen, fireEvent, waitFor, within } from '../../../../tests/helpers/render';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
@@ -111,6 +111,15 @@ describe('BookingDetailHost', () => {
|
||||
expect(calls).toEqual(['close', 'delete']);
|
||||
});
|
||||
|
||||
it('FE-PLANNER-BOOKINGHOST-018: the delete question says a linked expense goes with the booking (#2604)', async () => {
|
||||
const r = buildReservation({ title: 'Dinner' });
|
||||
useTripStore.setState({ budgetItems: [buildBudgetItem({ name: 'Dinner bill', reservation_id: r.id } as never)] });
|
||||
renderHost(r, { onDelete: vi.fn() });
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Delete' }));
|
||||
expect(screen.getByText('"Dinner" will be permanently deleted, along with its linked costs.')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-BOOKINGHOST-007: a failed delete says so', async () => {
|
||||
renderHost(buildReservation({ title: 'Dinner' }), { onDelete: vi.fn(async () => { throw new Error('nope'); }) });
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-PLANNER-BKMODEL-001 to FE-PLANNER-BKMODEL-043
|
||||
// FE-PLANNER-BKMODEL-001 to FE-PLANNER-BKMODEL-044
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { Plane, TramFront, FileText, Hotel } from 'lucide-react';
|
||||
import { buildAssignment, buildDay, buildPlace, buildReservation } from '../../../../tests/helpers/factories';
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
applyFilters,
|
||||
buildAssignmentLookup,
|
||||
costsFor,
|
||||
deleteBodyKey,
|
||||
daySpan,
|
||||
displayTitle,
|
||||
groupReservations,
|
||||
@@ -337,6 +338,13 @@ describe('costsFor', () => {
|
||||
expect(costsFor(3, [{ reservation_id: 3, total_price: 4 }], '')).toEqual([{ currency: 'EUR', amount: 4 }]);
|
||||
expect(costsFor(4, [{ reservation_id: 3, total_price: 4 }], 'EUR')).toEqual([]);
|
||||
});
|
||||
|
||||
it('FE-PLANNER-BKMODEL-044: the delete question names the linked expense only when there is one (#2604)', () => {
|
||||
const items = [{ reservation_id: 3 }, { reservation_id: null }];
|
||||
expect(deleteBodyKey(3, items)).toBe('reservations.confirm.deleteBodyWithExpense');
|
||||
expect(deleteBodyKey(4, items)).toBe('reservations.confirm.deleteBody');
|
||||
expect(deleteBodyKey(undefined, items)).toBe('reservations.confirm.deleteBody');
|
||||
});
|
||||
});
|
||||
|
||||
describe('displayTitle', () => {
|
||||
|
||||
@@ -317,6 +317,16 @@ export function costsFor(reservationId: number, items: { reservation_id?: number
|
||||
return [...sums.entries()].map(([currency, amount]) => ({ currency, amount }))
|
||||
}
|
||||
|
||||
/**
|
||||
* The delete question's text. The server deletes a booking's linked expenses with it,
|
||||
* so a booking that has one says so instead of only naming the booking (#2604).
|
||||
*/
|
||||
export function deleteBodyKey(reservationId: number | undefined, items: { reservation_id?: number | null }[]): string {
|
||||
return reservationId != null && items.some(it => it.reservation_id === reservationId)
|
||||
? 'reservations.confirm.deleteBodyWithExpense'
|
||||
: 'reservations.confirm.deleteBody'
|
||||
}
|
||||
|
||||
/** A title for an entry saved without one: its route, else its place, else nothing. */
|
||||
export function displayTitle(r: Reservation): string {
|
||||
if (r.title?.trim()) return r.title
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTripStore } from '../../../store/tripStore'
|
||||
import { useToast } from '../../shared/Toast'
|
||||
import ConfirmDialog from '../../shared/ConfirmDialog'
|
||||
import { useReservationDelete } from './useReservationDelete'
|
||||
import { deleteBodyKey } from './bookingsModel'
|
||||
|
||||
/**
|
||||
* The two things a booking can have done to it without its editor: switching
|
||||
@@ -17,6 +18,7 @@ export function useBookingActions(tripId: number, onDelete: (id: number) => unkn
|
||||
const { t } = useTranslation()
|
||||
const toast = useToast()
|
||||
const toggleReservationStatus = useTripStore(s => s.toggleReservationStatus)
|
||||
const budgetItems = useTripStore(s => s.budgetItems)
|
||||
const { pendingDelete, requestDelete, cancelDelete, confirmDelete } =
|
||||
useReservationDelete(onDelete, () => toast.error(t('reservations.toast.deleteError')), beforeDelete)
|
||||
|
||||
@@ -30,7 +32,7 @@ export function useBookingActions(tripId: number, onDelete: (id: number) => unkn
|
||||
onClose={cancelDelete}
|
||||
onConfirm={confirmDelete}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t('reservations.confirm.deleteBody', { name: pendingDelete?.title ?? '' })}
|
||||
message={t(deleteBodyKey(pendingDelete?.id, budgetItems), { name: pendingDelete?.title ?? '' })}
|
||||
confirmLabel={t('common.delete')}
|
||||
cancelLabel={t('common.cancel')}
|
||||
/>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// FE-PLANNER-RESLISTFILTER-005 to -008: what one card of the phone's bookings
|
||||
// FE-PLANNER-RESLISTFILTER-005 to -009: what one card of the phone's bookings
|
||||
// and transports tabs does.
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { KeyboardEvent, MouseEvent } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { buildReservation } from '../../../../tests/helpers/factories';
|
||||
import { buildBudgetItem, buildReservation } from '../../../../tests/helpers/factories';
|
||||
import { resetAllStores, seedStore } from '../../../../tests/helpers/store';
|
||||
import { useTripStore } from '../../../store/tripStore';
|
||||
import type { Reservation } from '../../../types';
|
||||
import { openFile } from '../../../utils/fileDownload';
|
||||
import { useReservationCard } from './useReservationCard';
|
||||
@@ -88,4 +90,11 @@ describe('useReservationCard', () => {
|
||||
expect(openFile).toHaveBeenCalledTimes(3);
|
||||
expect(openFile).toHaveBeenCalledWith('/uploads/f/1', 'voucher.pdf');
|
||||
});
|
||||
|
||||
it('FE-PLANNER-RESLISTFILTER-009: the card knows whether deleting it takes a linked expense along (#2604)', () => {
|
||||
resetAllStores();
|
||||
seedStore(useTripStore, { budgetItems: [buildBudgetItem({ id: 1, reservation_id: 10 } as never)] });
|
||||
expect(renderHook(() => useReservationCard(ann, host())).result.current.deleteTakesExpense).toBe(true);
|
||||
expect(renderHook(() => useReservationCard(bob, host())).result.current.deleteTakesExpense).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState, type KeyboardEvent, type MouseEvent } from 'react';
|
||||
|
||||
import { useTripStore } from '../../../store/tripStore';
|
||||
import type { Reservation } from '../../../types';
|
||||
import { deleteBodyKey } from './bookingsModel';
|
||||
import { openAttachment } from './openAttachment';
|
||||
import { useReservationDelete } from './useReservationDelete';
|
||||
|
||||
@@ -19,7 +21,8 @@ export interface ReservationCardHost {
|
||||
* behind a question with a toast when it fails, and its attached files, which
|
||||
* open from a chip inside the card's own button (so a click or Enter/Space on
|
||||
* the chip stops there). A file that cannot be opened stays silent here; the
|
||||
* desktop panel toasts it.
|
||||
* desktop panel toasts it. The delete question names a linked expense, which
|
||||
* goes with the booking.
|
||||
*/
|
||||
export function useReservationCard(res: Reservation, host: ReservationCardHost) {
|
||||
const blurCodes = host.settings.blur_booking_codes;
|
||||
@@ -28,11 +31,15 @@ export function useReservationCard(res: Reservation, host: ReservationCardHost)
|
||||
() => host.toast.error(host.t('reservations.toast.deleteError'))
|
||||
);
|
||||
const [codeRevealed, setCodeRevealed] = useState(false);
|
||||
const deleteTakesExpense = useTripStore(
|
||||
(s) => deleteBodyKey(res.id, s.budgetItems) === 'reservations.confirm.deleteBodyWithExpense'
|
||||
);
|
||||
|
||||
return {
|
||||
codeBlurred: !!blurCodes && !codeRevealed,
|
||||
toggleCode: blurCodes ? () => setCodeRevealed((v) => !v) : undefined,
|
||||
confirmingDelete: pendingDelete != null,
|
||||
deleteTakesExpense,
|
||||
askDelete: () => requestDelete(res),
|
||||
cancelDelete,
|
||||
confirmDelete: () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-COMP-MRESCARD-001 to FE-COMP-MRESCARD-008
|
||||
// FE-COMP-MRESCARD-001 to FE-COMP-MRESCARD-009
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { Hotel, Plane } from 'lucide-react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
@@ -120,6 +120,12 @@ describe('MReservationCardParts', () => {
|
||||
expect(card.confirmDelete).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('FE-COMP-MRESCARD-009: a booking with a linked expense says the expense is deleted with it (#2604)', () => {
|
||||
render(<CardDeleteSheet title="LH 400" card={cardState({ confirmingDelete: true, deleteTakesExpense: true })} t={t} />);
|
||||
|
||||
expect(screen.getByText('reservations.confirm.deleteBodyWithExpense:LH 400')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-COMP-MRESCARD-008: the date sits beside the day title and never shrinks, a range stacks the time under it (#2590)', () => {
|
||||
const { container } = render(
|
||||
<CardWhenAndCode
|
||||
|
||||
@@ -161,7 +161,7 @@ export function CardDeleteSheet({ title, card, t }: { title: string; card: CardS
|
||||
open={card.confirmingDelete}
|
||||
onClose={card.cancelDelete}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t('reservations.confirm.deleteBody', { name: title })}
|
||||
message={t(card.deleteTakesExpense ? 'reservations.confirm.deleteBodyWithExpense' : 'reservations.confirm.deleteBody', { name: title })}
|
||||
confirmLabel={t('common.delete')}
|
||||
cancelLabel={t('common.cancel')}
|
||||
danger
|
||||
|
||||
@@ -460,7 +460,7 @@ export class ReservationsMcp {
|
||||
|
||||
@Tool({
|
||||
name: 'delete_reservation',
|
||||
description: 'Delete a reservation from a trip.',
|
||||
description: 'Delete a reservation from a trip. Expenses linked to it are deleted with it, and so is the stay a hotel booking created.',
|
||||
inputSchema: {
|
||||
tripId: idSchema,
|
||||
reservationId: idSchema,
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'هل تريد حذف الحجز "{name}"؟',
|
||||
'reservations.confirm.deleteTitle': 'حذف الحجز؟',
|
||||
'reservations.confirm.deleteBody': 'سيتم حذف "{name}" نهائيًا.',
|
||||
'reservations.confirm.deleteBodyWithExpense': 'سيتم حذف "{name}" نهائيًا، مع التكاليف المرتبطة به.',
|
||||
'reservations.toast.updated': 'تم تحديث الحجز',
|
||||
'reservations.toast.removed': 'تم حذف الحجز',
|
||||
'reservations.toast.fileUploaded': 'تم رفع الملف',
|
||||
|
||||
@@ -87,6 +87,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '“{name}” rezervasiyasını silmək istədiyinizə əminsiniz?',
|
||||
'reservations.confirm.deleteTitle': 'Rezervasiya silinsin?',
|
||||
'reservations.confirm.deleteBody': '“{name}” həmişəlik silinəcək.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '“{name}” və ona bağlı xərclər həmişəlik silinəcək.',
|
||||
|
||||
'reservations.toast.updated': 'Rezervasiya yeniləndi',
|
||||
'reservations.toast.removed': 'Rezervasiya silindi',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Tem certeza de que deseja excluir a reserva "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Excluir reserva?',
|
||||
'reservations.confirm.deleteBody': '"{name}" será excluído permanentemente.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" e os custos vinculados serão excluídos permanentemente.',
|
||||
'reservations.toast.updated': 'Reserva atualizada',
|
||||
'reservations.toast.removed': 'Reserva excluída',
|
||||
'reservations.toast.fileUploaded': 'Arquivo enviado',
|
||||
|
||||
@@ -43,6 +43,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Segur que vols eliminar la reserva "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Vols eliminar la reserva?',
|
||||
'reservations.confirm.deleteBody': "« {name} » s'eliminarà permanentment.",
|
||||
'reservations.confirm.deleteBodyWithExpense': "« {name} » i els costos vinculats s'eliminaran permanentment.",
|
||||
'reservations.toast.updated': 'Reserva actualitzada',
|
||||
'reservations.toast.removed': 'Reserva eliminada',
|
||||
'reservations.toast.fileUploaded': 'Fitxer pujat',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Opravdu chcete smazat rezervaci „{name}”?',
|
||||
'reservations.confirm.deleteTitle': 'Smazat rezervaci?',
|
||||
'reservations.confirm.deleteBody': '„{name}” bude trvale smazána.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '„{name}” bude trvale smazána i s propojenými náklady.',
|
||||
'reservations.toast.updated': 'Rezervace aktualizována',
|
||||
'reservations.toast.removed': 'Rezervace smazána',
|
||||
'reservations.toast.fileUploaded': 'Soubor byl nahrán',
|
||||
|
||||
@@ -77,6 +77,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Möchtest du die Reservierung "{name}" wirklich löschen?',
|
||||
'reservations.confirm.deleteTitle': 'Buchung löschen?',
|
||||
'reservations.confirm.deleteBody': '"{name}" wird unwiderruflich gelöscht.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" wird zusammen mit den verknüpften Kosten unwiderruflich gelöscht.',
|
||||
'reservations.toast.updated': 'Reservierung aktualisiert',
|
||||
'reservations.toast.removed': 'Reservierung gelöscht',
|
||||
'reservations.toast.saveError': 'Fehler beim Speichern',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Are you sure you want to delete the reservation "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Delete booking?',
|
||||
'reservations.confirm.deleteBody': '"{name}" will be permanently deleted.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" will be permanently deleted, along with its linked costs.',
|
||||
'reservations.toast.updated': 'Reservation updated',
|
||||
'reservations.toast.removed': 'Reservation deleted',
|
||||
'reservations.toast.fileUploaded': 'File uploaded',
|
||||
|
||||
@@ -43,6 +43,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '¿Seguro que quieres eliminar la reserva "{name}"?',
|
||||
'reservations.confirm.deleteTitle': '¿Eliminar reserva?',
|
||||
'reservations.confirm.deleteBody': '« {name} » se eliminará permanentemente.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '« {name} » y sus costes vinculados se eliminarán permanentemente.',
|
||||
'reservations.toast.updated': 'Reserva actualizada',
|
||||
'reservations.toast.removed': 'Reserva eliminada',
|
||||
'reservations.toast.fileUploaded': 'Archivo subido',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Kas soovid kindlasti kustutada broneeringu "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Kas kustutada broneering?',
|
||||
'reservations.confirm.deleteBody': '"{name}" kustutatakse jäädavalt.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" kustutatakse jäädavalt koos sellega seotud kuludega.',
|
||||
'reservations.toast.updated': 'Broneering uuendatud',
|
||||
'reservations.toast.removed': 'Broneering kustutatud',
|
||||
'reservations.toast.fileUploaded': 'Fail üles laaditud',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Voulez-vous vraiment supprimer la réservation « {name} » ?',
|
||||
'reservations.confirm.deleteTitle': 'Supprimer la réservation ?',
|
||||
'reservations.confirm.deleteBody': '« {name} » sera définitivement supprimé.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '« {name} » et ses coûts liés seront définitivement supprimés.',
|
||||
'reservations.toast.updated': 'Réservation mise à jour',
|
||||
'reservations.toast.removed': 'Réservation supprimée',
|
||||
'reservations.toast.fileUploaded': 'Fichier importé',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Είστε σίγουροι ότι θέλετε να διαγράψετε την κράτηση "{name}";',
|
||||
'reservations.confirm.deleteTitle': 'Διαγραφή κράτησης;',
|
||||
'reservations.confirm.deleteBody': 'Η κράτηση "{name}" θα διαγραφεί οριστικά.',
|
||||
'reservations.confirm.deleteBodyWithExpense': 'Η κράτηση "{name}" θα διαγραφεί οριστικά μαζί με τα συνδεδεμένα έξοδα.',
|
||||
'reservations.toast.updated': 'Η κράτηση ενημερώθηκε',
|
||||
'reservations.toast.removed': 'Η κράτηση διαγράφηκε',
|
||||
'reservations.toast.fileUploaded': 'Το αρχείο μεταφορτώθηκε',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Biztosan törölni szeretnéd a(z) "{name}" foglalást?',
|
||||
'reservations.confirm.deleteTitle': 'Foglalás törlése?',
|
||||
'reservations.confirm.deleteBody': '"{name}" véglegesen törlődik.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" a hozzá kapcsolt költségekkel együtt véglegesen törlődik.',
|
||||
'reservations.toast.updated': 'Foglalás frissítve',
|
||||
'reservations.toast.removed': 'Foglalás törölve',
|
||||
'reservations.toast.fileUploaded': 'Fájl feltöltve',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Yakin ingin menghapus reservasi "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Hapus pemesanan?',
|
||||
'reservations.confirm.deleteBody': '"{name}" akan dihapus permanen.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" beserta biaya yang terkait akan dihapus permanen.',
|
||||
'reservations.toast.updated': 'Reservasi diperbarui',
|
||||
'reservations.toast.removed': 'Reservasi dihapus',
|
||||
'reservations.toast.fileUploaded': 'File diunggah',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Sei sicuro di voler eliminare la prenotazione "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Eliminare la prenotazione?',
|
||||
'reservations.confirm.deleteBody': '"{name}" verrà eliminato in modo permanente.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" e i costi collegati verranno eliminati in modo permanente.',
|
||||
'reservations.toast.updated': 'Prenotazione aggiornata',
|
||||
'reservations.toast.removed': 'Prenotazione eliminata',
|
||||
'reservations.toast.fileUploaded': 'File caricato',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '予約「{name}」を削除しますか?',
|
||||
'reservations.confirm.deleteTitle': '予約を削除しますか?',
|
||||
'reservations.confirm.deleteBody': '「{name}」は完全に削除されます。',
|
||||
'reservations.confirm.deleteBodyWithExpense': '「{name}」と紐づいた費用は完全に削除されます。',
|
||||
'reservations.toast.updated': '予約を更新しました',
|
||||
'reservations.toast.removed': '予約を削除しました',
|
||||
'reservations.toast.fileUploaded': 'ファイルをアップロードしました',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '예약 "{name}"을(를) 삭제할까요?',
|
||||
'reservations.confirm.deleteTitle': '예약을 삭제할까요?',
|
||||
'reservations.confirm.deleteBody': '"{name}"이(가) 영구 삭제됩니다.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}"과(와) 연결된 비용이 영구 삭제됩니다.',
|
||||
'reservations.toast.updated': '예약이 업데이트되었습니다',
|
||||
'reservations.toast.removed': '예약이 삭제되었습니다',
|
||||
'reservations.toast.fileUploaded': '파일이 업로드되었습니다',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Weet je zeker dat je de reservering "{name}" wilt verwijderen?',
|
||||
'reservations.confirm.deleteTitle': 'Boeking verwijderen?',
|
||||
'reservations.confirm.deleteBody': '"{name}" wordt permanent verwijderd.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" en de gekoppelde kosten worden permanent verwijderd.',
|
||||
'reservations.toast.updated': 'Reservering bijgewerkt',
|
||||
'reservations.toast.removed': 'Reservering verwijderd',
|
||||
'reservations.toast.fileUploaded': 'Bestand geüpload',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Czy na pewno chcesz usunąć rezerwację "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Usunąć rezerwację?',
|
||||
'reservations.confirm.deleteBody': 'Rezerwacja "{name}" zostanie trwale usunięta.',
|
||||
'reservations.confirm.deleteBodyWithExpense': 'Rezerwacja "{name}" zostanie trwale usunięta wraz z powiązanymi kosztami.',
|
||||
'reservations.toast.updated': 'Rezerwacja została zaktualizowana',
|
||||
'reservations.toast.removed': 'Rezerwacja została usunięta',
|
||||
'reservations.toast.fileUploaded': 'Plik został przesłany',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Вы уверены, что хотите удалить бронирование «{name}»?',
|
||||
'reservations.confirm.deleteTitle': 'Удалить бронирование?',
|
||||
'reservations.confirm.deleteBody': '«{name}» будет удалено навсегда.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '«{name}» и связанные с ним расходы будут удалены навсегда.',
|
||||
'reservations.toast.updated': 'Бронирование обновлено',
|
||||
'reservations.toast.removed': 'Бронирование удалено',
|
||||
'reservations.toast.fileUploaded': 'Файл загружен',
|
||||
|
||||
@@ -77,6 +77,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Naozaj chcete odstrániť rezerváciu „{name}“?',
|
||||
'reservations.confirm.deleteTitle': 'Odstrániť rezerváciu?',
|
||||
'reservations.confirm.deleteBody': '„{name}“ bude natrvalo odstránená.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '„{name}“ bude natrvalo odstránená spolu s prepojenými nákladmi.',
|
||||
'reservations.toast.updated': 'Rezervácia aktualizovaná',
|
||||
'reservations.toast.removed': 'Rezervácia odstránená',
|
||||
'reservations.toast.fileUploaded': 'Súbor bol nahraný',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Är du säker på att du vill ta bort bokningen "{name}"?',
|
||||
'reservations.confirm.deleteTitle': 'Ta bort bokningen?',
|
||||
'reservations.confirm.deleteBody': '"{name}" kommer att raderas permanent.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" och de kopplade kostnaderna kommer att raderas permanent.',
|
||||
'reservations.toast.updated': 'Bokning uppdaterad',
|
||||
'reservations.toast.removed': 'Bokning borttagen',
|
||||
'reservations.toast.fileUploaded': 'Fil uppladdad',
|
||||
|
||||
@@ -76,6 +76,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'คุณแน่ใจหรือไม่ว่าต้องการลบการจอง "{name}"',
|
||||
'reservations.confirm.deleteTitle': 'ลบการจองใช่ไหม',
|
||||
'reservations.confirm.deleteBody': '"{name}" จะถูกลบอย่างถาวร',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" และค่าใช้จ่ายที่เชื่อมโยงไว้จะถูกลบอย่างถาวร',
|
||||
'reservations.toast.updated': 'อัพเดตการจองแล้ว',
|
||||
'reservations.toast.removed': 'ลบการจองแล้ว',
|
||||
'reservations.toast.fileUploaded': 'อัปโหลดไฟล์แล้ว',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '"{name}" rezervasyonunu silmek istediğinizden emin misiniz?',
|
||||
'reservations.confirm.deleteTitle': 'Rezervasyon silinsin mi?',
|
||||
'reservations.confirm.deleteBody': '"{name}" kalıcı olarak silinecek.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" ve bağlı maliyetleri kalıcı olarak silinecek.',
|
||||
'reservations.toast.updated': 'Rezervasyon güncellendi',
|
||||
'reservations.toast.removed': 'Rezervasyon silindi',
|
||||
'reservations.toast.fileUploaded': 'Dosya yüklendi',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Ви впевнені, що хочете видалити бронювання «{name}»?',
|
||||
'reservations.confirm.deleteTitle': 'Видалити бронювання?',
|
||||
'reservations.confirm.deleteBody': '«{name}» буде видалено назавжди.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '«{name}» і пов’язані з ним витрати буде видалено назавжди.',
|
||||
'reservations.toast.updated': 'Бронювання оновлено',
|
||||
'reservations.toast.removed': 'Бронювання видалено',
|
||||
'reservations.toast.fileUploaded': 'Файл завантажено',
|
||||
|
||||
@@ -75,6 +75,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': 'Bạn có chắc chắn muốn xóa đặt chỗ "{name}" không?',
|
||||
'reservations.confirm.deleteTitle': 'Xóa đặt chỗ?',
|
||||
'reservations.confirm.deleteBody': '"{name}" sẽ bị xóa vĩnh viễn.',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" và các chi phí liên kết sẽ bị xóa vĩnh viễn.',
|
||||
'reservations.toast.updated': 'Đã cập nhật đặt chỗ',
|
||||
'reservations.toast.removed': 'Đã xóa đặt chỗ',
|
||||
'reservations.toast.fileUploaded': 'Tệp đã được tải lên',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '確定要刪除預訂「{name}」嗎?',
|
||||
'reservations.confirm.deleteTitle': '刪除預訂?',
|
||||
'reservations.confirm.deleteBody': '"{name}" 將被永久刪除。',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" 及其關聯的費用將被永久刪除。',
|
||||
'reservations.toast.updated': '預訂已更新',
|
||||
'reservations.toast.removed': '預訂已刪除',
|
||||
'reservations.toast.fileUploaded': '檔案已上傳',
|
||||
|
||||
@@ -74,6 +74,7 @@ const reservations: TranslationStrings = {
|
||||
'reservations.confirm.delete': '确定要删除预订「{name}」吗?',
|
||||
'reservations.confirm.deleteTitle': '删除预订?',
|
||||
'reservations.confirm.deleteBody': '"{name}" 将被永久删除。',
|
||||
'reservations.confirm.deleteBodyWithExpense': '"{name}" 及其关联的费用将被永久删除。',
|
||||
'reservations.toast.updated': '预订已更新',
|
||||
'reservations.toast.removed': '预订已删除',
|
||||
'reservations.toast.fileUploaded': '文件已上传',
|
||||
|
||||
Reference in New Issue
Block a user