diff --git a/apps/scandic-web/components/Dialog/dialog.module.css b/apps/scandic-web/components/Dialog/dialog.module.css index 986bc9b66..d74a86d83 100644 --- a/apps/scandic-web/components/Dialog/dialog.module.css +++ b/apps/scandic-web/components/Dialog/dialog.module.css @@ -29,6 +29,10 @@ } } +.dialog { + outline: none; +} + .modal { background-color: var(--Base-Surface-Primary-light-Normal); border-radius: var(--Corner-radius-Medium); diff --git a/apps/scandic-web/components/Dialog/index.tsx b/apps/scandic-web/components/Dialog/index.tsx index ca18d3516..4e8f286d6 100644 --- a/apps/scandic-web/components/Dialog/index.tsx +++ b/apps/scandic-web/components/Dialog/index.tsx @@ -31,7 +31,7 @@ export default function Dialog({ {trigger} - + {({ close }) => (
diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx new file mode 100644 index 000000000..eb4903646 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx @@ -0,0 +1,65 @@ +import { useIntl } from "react-intl" + +import { trpc } from "@/lib/trpc/client" + +import Dialog from "@/components/Dialog" +import { DeleteIcon } from "@/components/Icons" +import Button from "@/components/TempDesignSystem/Button" +import { toast } from "@/components/TempDesignSystem/Toasts" +import useLang from "@/hooks/useLang" + +export default function RemoveButton({ + confirmationNumber, + code, + title, + onSuccess, +}: { + confirmationNumber: string + code: string + title?: string + onSuccess: () => void +}) { + const lang = useLang() + const intl = useIntl() + const removePackage = trpc.booking.removePackage.useMutation() + + return ( + + + {intl.formatMessage({ id: "Remove" })} + + } + proceedOnClick={(close) => { + removePackage.mutate( + { + language: lang, + confirmationNumber, + codes: [code], + }, + { + onSuccess: (data) => { + if (!data) { + throw new Error() + } + + close() + onSuccess() + }, + onError: () => { + toast.error(intl.formatMessage({ id: "Something went wrong!" })) + }, + } + ) + }} + /> + ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx index 50db70051..e5427a81a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx @@ -1,6 +1,7 @@ +import { useRouter } from "next/navigation" import { useIntl } from "react-intl" -import { CheckCircleIcon, DeleteIcon, EditIcon } from "@/components/Icons" +import { CheckCircleIcon, EditIcon } from "@/components/Icons" import Accordion from "@/components/TempDesignSystem/Accordion" import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem" import Button from "@/components/TempDesignSystem/Button" @@ -8,6 +9,8 @@ import Divider from "@/components/TempDesignSystem/Divider" import Body from "@/components/TempDesignSystem/Text/Body" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" +import RemoveButton from "./RemoveButton" + import styles from "./addedAncillaries.module.css" import type { AddedAncillariesProps } from "@/types/components/myPages/myStay/ancillaries" @@ -17,6 +20,7 @@ export function AddedAncillaries({ booking, }: AddedAncillariesProps) { const intl = useIntl() + const router = useRouter() return (
@@ -76,30 +80,29 @@ export function AddedAncillaries({
-
- - - -
+ {booking.confirmationNumber && ancillary.code ? ( +
+ + + router.refresh()} + /> +
+ ) : null}
@@ -135,27 +138,29 @@ export function AddedAncillaries({ )} -
- - - -
+ {booking.confirmationNumber && ancillary.code ? ( +
+ + + router.refresh()} + /> +
+ ) : null} diff --git a/apps/scandic-web/i18n/dictionaries/da.json b/apps/scandic-web/i18n/dictionaries/da.json index 968033c88..eec7700f8 100644 --- a/apps/scandic-web/i18n/dictionaries/da.json +++ b/apps/scandic-web/i18n/dictionaries/da.json @@ -1,5 +1,6 @@ { "+46 8 517 517 00": "+46 8 517 517 00", + "Are you sure you want to remove this product?": "Er du sikker på, at du vil fjerne dette produkt?", "/night per adult": "/nat per voksen", "Included (based on availability)": "Inkluderet (baseret på tilgængelighed)", "Total price (incl VAT)": "Samlet pris (inkl. moms)", diff --git a/apps/scandic-web/i18n/dictionaries/de.json b/apps/scandic-web/i18n/dictionaries/de.json index ac44afab5..68463762d 100644 --- a/apps/scandic-web/i18n/dictionaries/de.json +++ b/apps/scandic-web/i18n/dictionaries/de.json @@ -1,5 +1,6 @@ { "+46 8 517 517 00": "+46 8 517 517 00", + "Are you sure you want to remove this product?": "Möchten Sie dieses Produkt wirklich entfernen?", "/night per adult": "/Nacht pro Erwachsenem", "Included (based on availability)": "Inbegriffen (je nach Verfügbarkeit)", "Total price (incl VAT)": "Gesamtpreis (inkl. MwSt.)", diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index 94bf2ecf7..fbeab5b8d 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -1,4 +1,5 @@ { + "Are you sure you want to remove this product?": "Are you sure you want to remove this product?", "+46 8 517 517 00": "+46 8 517 517 00", "/night per adult": "/night per adult", "Included (based on availability)": "Included (based on availability)", diff --git a/apps/scandic-web/i18n/dictionaries/fi.json b/apps/scandic-web/i18n/dictionaries/fi.json index cf7e54cc7..2db4ad9bc 100644 --- a/apps/scandic-web/i18n/dictionaries/fi.json +++ b/apps/scandic-web/i18n/dictionaries/fi.json @@ -1,5 +1,6 @@ { "+46 8 517 517 00": "+46 8 517 517 00", + "Are you sure you want to remove this product?": "Haluatko varmasti poistaa tämän tuotteen?", "/night per adult": "/yötä aikuista kohti", "Included (based on availability)": "Sisältyy (saatavuuden mukaan)", "Total price (incl VAT)": "Kokonaishinta (sis. ALV)", diff --git a/apps/scandic-web/i18n/dictionaries/no.json b/apps/scandic-web/i18n/dictionaries/no.json index 0d04bad6a..d13262da2 100644 --- a/apps/scandic-web/i18n/dictionaries/no.json +++ b/apps/scandic-web/i18n/dictionaries/no.json @@ -1,5 +1,6 @@ { "+46 8 517 517 00": "+46 8 517 517 00", + "Are you sure you want to remove this product?": "Er du sikker på at du vil fjerne dette produktet?", "/night per adult": "/natt per voksen", "Included (based on availability)": "Inkludert (basert på tilgjengelighet)", "Total price (incl VAT)": "Totalpris (inkl. mva)", diff --git a/apps/scandic-web/i18n/dictionaries/sv.json b/apps/scandic-web/i18n/dictionaries/sv.json index ecff7a787..67ce4a9b5 100644 --- a/apps/scandic-web/i18n/dictionaries/sv.json +++ b/apps/scandic-web/i18n/dictionaries/sv.json @@ -1,5 +1,6 @@ { "+46 8 517 517 00": "+46 8 517 517 00", + "Are you sure you want to remove this product?": "Är du säker på att du vill ta bort den här produkten?", "/night per adult": "/natt per vuxen", "Included (based on availability)": "Ingår (baserat på tillgänglighet)", "Total price (incl VAT)": "Totalpris (inkl moms)", diff --git a/apps/scandic-web/server/routers/booking/input.ts b/apps/scandic-web/server/routers/booking/input.ts index 2490e7dfa..930333f29 100644 --- a/apps/scandic-web/server/routers/booking/input.ts +++ b/apps/scandic-web/server/routers/booking/input.ts @@ -96,6 +96,12 @@ export const addPackageInput = z.object({ language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]), }) +export const removePackageInput = z.object({ + confirmationNumber: z.string(), + codes: z.array(z.string()), + language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]), +}) + export const priceChangeInput = z.object({ confirmationNumber: z.string(), }) diff --git a/apps/scandic-web/server/routers/booking/mutation.ts b/apps/scandic-web/server/routers/booking/mutation.ts index ae9231299..73e82348e 100644 --- a/apps/scandic-web/server/routers/booking/mutation.ts +++ b/apps/scandic-web/server/routers/booking/mutation.ts @@ -7,10 +7,11 @@ import { router, safeProtectedServiceProcedure } from "@/server/trpc" import { getMembership } from "@/utils/user" import { - cancelBookingInput, addPackageInput, + cancelBookingInput, createBookingInput, priceChangeInput, + removePackageInput, } from "./input" import { createBookingSchema } from "./output" @@ -48,6 +49,14 @@ const addPackageFailCounter = meter.createCounter( "trpc.bookings.add-package-fail" ) +const removePackageCounter = meter.createCounter("trpc.bookings.remove-package") +const removePackageSuccessCounter = meter.createCounter( + "trpc.bookings.remove-package-success" +) +const removePackageFailCounter = meter.createCounter( + "trpc.bookings.remove-package-fail" +) + async function getMembershipNumber( session: Session | null ): Promise { @@ -379,4 +388,72 @@ export const bookingMutationRouter = router({ return verifiedData.data }), + removePackage: safeProtectedServiceProcedure + .input(removePackageInput) + .mutation(async function ({ ctx, input }) { + const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken + const { confirmationNumber, codes, language } = input + + const headers = { + Authorization: `Bearer ${accessToken}`, + } + + const loggingAttributes = { + confirmationNumber, + codes, + language, + } + + removePackageCounter.add(1, loggingAttributes) + + console.info( + "api.booking.remove-package start", + JSON.stringify({ + request: loggingAttributes, + headers, + }) + ) + + const apiResponse = await api.remove( + api.endpoints.v1.Booking.packages(confirmationNumber), + { + headers, + } as RequestInit, + { language, codes } + ) + + if (!apiResponse.ok) { + const text = await apiResponse.text() + removePackageFailCounter.add(1, { + confirmationNumber, + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + }), + }) + console.error( + "api.booking.remove-package error", + JSON.stringify({ + error: { + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }, + query: loggingAttributes, + }) + ) + return false + } + + removePackageSuccessCounter.add(1, loggingAttributes) + + console.info( + "api.booking.remove-package success", + JSON.stringify({ + query: loggingAttributes, + }) + ) + + return true + }), })