Merged in feat/SW-104-add-card (pull request #410)

Feat/SW-104 add card

* feat: add api endpoints for adding and removing credit card

* feat(SW-104): Added Sonner toast lib

* feat(SW-104): Add route handlers for add card flow

* feat(SW-104): Added link to route handler and trigger toast when query params from callback is set

* feat(SW-104): Added translations for add card success toast

* feat(SW-104): Refactored to use client request for initiate save card

* fix(SW-104): Return proper status codes when initiating save card fails

* fix(SW-104): remove delete card endpoint because it was added in SW-245

* fix(SW-104): remove console.log

* fix(SW-104): Use api.post for save card request

* fix(SW-104): move function declaration above export

* fix(SW-104): handle response of save card and use Lang enum

* fix(SW-104): added comment for why setTimeout is needed for toast and also removed lang prop

* fix(SW-104): added type for AddCreditCardButton props

* feat: add toasts

* fix(SW-104): start using toasts from ToastHandler and fix problem with duplicate toasts

* fix(SW-104): remove unnecessary wrapping div


Approved-by: Michael Zetterberg
This commit is contained in:
Tobias Johansson
2024-08-20 15:04:02 +00:00
parent aa9e723cb5
commit 84f5e74f00
30 changed files with 537 additions and 15 deletions

View File

@@ -1,6 +1,12 @@
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import * as api from "@/lib/api"
import { internalServerError } from "@/server/errors/next"
import {
badRequestError,
forbiddenError,
unauthorizedError,
} from "@/server/errors/trpc"
import {
protectedProcedure,
router,
@@ -12,13 +18,19 @@ import * as maskValue from "@/utils/maskValue"
import { getMembership, getMembershipCards } from "@/utils/user"
import encryptValue from "../utils/encryptValue"
import { getUserInputSchema, staysInput } from "./input"
import {
getUserInputSchema,
initiateSaveCardInput,
saveCardInput,
staysInput,
} from "./input"
import {
getCreditCardsSchema,
getFriendTransactionsSchema,
getMembershipCardsSchema,
getStaysSchema,
getUserSchema,
initiateSaveCardSchema,
Stay,
} from "./output"
import { benefits, extendedUser, nextLevelPerks } from "./temp"
@@ -517,6 +529,69 @@ export const userQueryRouter = router({
return verifiedData.data.data
}),
initiateSaveCard: protectedProcedure
.input(initiateSaveCardInput)
.mutation(async function ({ ctx, input }) {
const apiResponse = await api.post(api.endpoints.v1.initiateSaveCard, {
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
body: {
language: input.language,
mobileToken: input.mobileToken,
redirectUrl: input.redirectUrl,
},
})
if (!apiResponse.ok) {
switch (apiResponse.status) {
case 400:
throw badRequestError(apiResponse)
case 401:
throw unauthorizedError(apiResponse)
case 403:
throw forbiddenError(apiResponse)
default:
throw internalServerError(apiResponse)
}
}
const apiJson = await apiResponse.json()
const verifiedData = initiateSaveCardSchema.safeParse(apiJson)
if (!verifiedData.success) {
console.error(`Failed to initiate save card data`)
console.error(`User: (${JSON.stringify(ctx.session.user)})`)
console.error(verifiedData.error)
return null
}
return verifiedData.data.data
}),
saveCard: protectedProcedure.input(saveCardInput).mutation(async function ({
ctx,
input,
}) {
const apiResponse = await api.post(
`${api.endpoints.v1.creditCards}/${input.transactionId}`,
{
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
body: {},
}
)
if (!apiResponse.ok) {
console.error(`API Response Failed - Save card`)
console.error(`User: (${JSON.stringify(ctx.session.user)})`)
console.error(apiResponse)
return null
}
return true
}),
membershipCards: protectedProcedure.query(async function ({ ctx }) {
const apiResponse = await api.get(api.endpoints.v1.profile, {
cache: "no-store",