Merged in feat/loy-291-new-claim-points-flow (pull request #3508)
feat(LOY-291): New claim points flow for logged in users * wip new flow * More wip * More wip * Wip styling * wip with a mutation * Actually fetch booking data * More styling wip * Fix toast duration * fix loading a11y maybe * More stuff * Add feature flag * Add invalid state * Clean up * Add fields for missing user info * Restructure files * Add todos * Disable warning * Fix icon and border radius Approved-by: Emma Zettervall Approved-by: Matilda Landström
This commit is contained in:
@@ -85,7 +85,10 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
|
||||
ref={mergeRefs(field.ref, ref)}
|
||||
name={field.name}
|
||||
onBlur={field.onBlur}
|
||||
onChange={field.onChange}
|
||||
onChange={(event) => {
|
||||
field.onChange(event)
|
||||
props.onChange?.(event)
|
||||
}}
|
||||
value={field.value ?? ""}
|
||||
autoComplete={autoComplete}
|
||||
id={id ?? field.name}
|
||||
|
||||
@@ -160,6 +160,8 @@ import EditOutlined from "./generated/EditOutlined"
|
||||
import EditFilled from "./generated/EditFilled"
|
||||
import EditCalendarOutlined from "./generated/EditCalendarOutlined"
|
||||
import EditCalendarFilled from "./generated/EditCalendarFilled"
|
||||
import EditDocumentOutlined from "./generated/EditDocumentOutlined"
|
||||
import EditDocumentFilled from "./generated/EditDocumentFilled"
|
||||
import EditSquareOutlined from "./generated/EditSquareOutlined"
|
||||
import EditSquareFilled from "./generated/EditSquareFilled"
|
||||
import ElectricBikeOutlined from "./generated/ElectricBikeOutlined"
|
||||
@@ -642,6 +644,9 @@ const _materialIcons = {
|
||||
edit_calendar: {
|
||||
rounded: { outlined: EditCalendarOutlined, filled: EditCalendarFilled },
|
||||
},
|
||||
edit_document: {
|
||||
rounded: { outlined: EditDocumentOutlined, filled: EditDocumentFilled },
|
||||
},
|
||||
edit_square: {
|
||||
rounded: { outlined: EditSquareOutlined, filled: EditSquareFilled },
|
||||
},
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/* AUTO-GENERATED — DO NOT EDIT */
|
||||
import type { SVGProps } from "react"
|
||||
|
||||
const EditDocumentFilled = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg viewBox="0 -960 960 960" {...props}>
|
||||
<path d="M220-80q-24 0-42-18t-18-42v-680q0-24 18-42t42-18h315q12 0 23.5 5t19.5 13l204 204q8 8 13 19.5t5 23.5v99q0 8-5 14.5t-13 8.5q-12 5-23 11.5T738-465L518-246q-8 8-13 19.5t-5 23.5v93q0 13-8.5 21.5T470-80zm340-30v-81q0-6 2-11t7-10l212-211q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q9 9 13 20t4 22-4.5 22.5T902-300L692-89q-5 5-10 7t-11 2h-81q-13 0-21.5-8.5T560-110m263-194 37-39-37-37-38 38zM550-600h190L520-820l220 220-220-220v190q0 13 8.5 21.5T550-600" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default EditDocumentFilled
|
||||
@@ -0,0 +1,10 @@
|
||||
/* AUTO-GENERATED — DO NOT EDIT */
|
||||
import type { SVGProps } from "react"
|
||||
|
||||
const EditDocumentOutlined = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg viewBox="0 -960 960 960" {...props}>
|
||||
<path d="M560-110v-81q0-5.57 2-10.78 2-5.22 7-10.22l211.61-210.77q9.11-9.12 20.25-13.18Q812-440 823-440q12 0 23 4.5t20 13.5l37 37q9 9 13 20t4 22-4.5 22.5-13.58 20.62L692-89q-5 5-10.22 7-5.21 2-10.78 2h-81q-12.75 0-21.37-8.63Q560-97.25 560-110m300-233-37-37zM620-140h38l121-122-37-37-122 121zM220-80q-24 0-42-18t-18-42v-680q0-24 18-42t42-18h315q12.44 0 23.72 5T578-862l204 204q8 8 13 19.28t5 23.72v71q0 12.75-8.68 21.37-8.67 8.63-21.5 8.63-12.82 0-21.32-8.63-8.5-8.62-8.5-21.37v-56H550q-12.75 0-21.37-8.63Q520-617.25 520-630v-190H220v680h250q12.75 0 21.38 8.68 8.62 8.67 8.62 21.5 0 12.82-8.62 21.32Q482.75-80 470-80zm0-60v-680zm541-141-19-18 37 37z" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default EditDocumentOutlined
|
||||
@@ -1,4 +1,5 @@
|
||||
import { router } from "../.."
|
||||
import { findBookingForCurrentUserRoute } from "./query/findBookingForCurrentUserRoute"
|
||||
import { findBookingRoute } from "./query/findBookingRoute"
|
||||
import { getBookingRoute } from "./query/getBookingRoute"
|
||||
import { getBookingStatusRoute } from "./query/getBookingStatusRoute"
|
||||
@@ -7,6 +8,7 @@ import { getLinkedReservationsRoute } from "./query/getLinkedReservationsRoute"
|
||||
export const bookingQueryRouter = router({
|
||||
get: getBookingRoute,
|
||||
findBooking: findBookingRoute,
|
||||
findBookingForCurrentUser: findBookingForCurrentUserRoute,
|
||||
linkedReservations: getLinkedReservationsRoute,
|
||||
status: getBookingStatusRoute,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { notFoundError } from "../../../errors"
|
||||
import { safeProtectedServiceProcedure } from "../../../procedures"
|
||||
import { findBooking } from "../../../services/booking/findBooking"
|
||||
import { getHotel } from "../../hotels/services/getHotel"
|
||||
import { findBookingInput } from "../input"
|
||||
|
||||
export const findBookingForCurrentUserRoute = safeProtectedServiceProcedure
|
||||
.input(
|
||||
findBookingInput.omit({ lastName: true, firstName: true, email: true })
|
||||
)
|
||||
.query(async function ({ ctx, input }) {
|
||||
const lang = input.lang ?? ctx.lang
|
||||
const { confirmationNumber } = input
|
||||
const user = await ctx.getScandicUser()
|
||||
const token = await ctx.getScandicUserToken()
|
||||
|
||||
const findBookingCounter = createCounter(
|
||||
"trpc.booking.findBookingForCurrentUser"
|
||||
)
|
||||
const metricsFindBooking = findBookingCounter.init({
|
||||
confirmationNumber,
|
||||
})
|
||||
metricsFindBooking.start()
|
||||
|
||||
if (!user || !token) {
|
||||
metricsFindBooking.dataError(
|
||||
`Fail to find user when finding booking for ${confirmationNumber}`,
|
||||
{ confirmationNumber }
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const booking = await findBooking(
|
||||
{
|
||||
confirmationNumber,
|
||||
lang,
|
||||
lastName: user.lastName,
|
||||
firstName: user.firstName,
|
||||
email: user.email,
|
||||
},
|
||||
token
|
||||
)
|
||||
|
||||
if (!booking) {
|
||||
metricsFindBooking.dataError(
|
||||
`Fail to find booking data for ${confirmationNumber}`,
|
||||
{ confirmationNumber }
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const hotelData = await getHotel(
|
||||
{
|
||||
hotelId: booking.hotelId,
|
||||
isCardOnlyPayment: false,
|
||||
language: lang,
|
||||
},
|
||||
ctx.serviceToken
|
||||
)
|
||||
|
||||
if (!hotelData) {
|
||||
metricsFindBooking.dataError(
|
||||
`Failed to find hotel data for ${booking.hotelId}`,
|
||||
{
|
||||
hotelId: booking.hotelId,
|
||||
}
|
||||
)
|
||||
|
||||
throw notFoundError({
|
||||
message: "Hotel data not found",
|
||||
errorDetails: { hotelId: booking.hotelId },
|
||||
})
|
||||
}
|
||||
|
||||
metricsFindBooking.success()
|
||||
|
||||
return {
|
||||
hotel: {
|
||||
name: hotelData.hotel.name,
|
||||
cityName: hotelData.hotel.cityName,
|
||||
},
|
||||
booking,
|
||||
}
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
import z from "zod"
|
||||
|
||||
import { signupVerify } from "@scandic-hotels/common/constants/routes/signup"
|
||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
@@ -318,4 +320,33 @@ export const userMutationRouter = router({
|
||||
return true
|
||||
}),
|
||||
}),
|
||||
claimPoints: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
from: z.string(),
|
||||
to: z.string(),
|
||||
city: z.string(),
|
||||
hotel: z.string(),
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
email: z.string().email(),
|
||||
phone: z.string(),
|
||||
})
|
||||
)
|
||||
.mutation(async function ({ input, ctx }) {
|
||||
userMutationLogger.info("api.user.claimPoints start")
|
||||
const user = await ctx.getScandicUser()
|
||||
if (!user) {
|
||||
throw "error"
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Claiming points", input, user.membershipNumber)
|
||||
|
||||
// TODO Waiting for API endpoint, simulating delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 2_000))
|
||||
|
||||
userMutationLogger.info("api.user.claimPoints success")
|
||||
return true
|
||||
}),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user