feat(SW-245): Delete credit card

This commit is contained in:
Tobias Johansson
2024-08-13 10:20:59 +02:00
committed by Michael Zetterberg
parent 2af17ef4d8
commit e9a6499086
33 changed files with 603 additions and 208 deletions

View File

@@ -1,5 +1,6 @@
import { mergeRouters } from "@/server/trpc"
import { userMutationRouter } from "./mutation"
import { userQueryRouter } from "./query"
export const userRouter = mergeRouters(userQueryRouter)
export const userRouter = mergeRouters(userQueryRouter, userMutationRouter)

View File

@@ -1,5 +1,7 @@
import { z } from "zod"
import { Lang } from "@/constants/languages"
export const getUserInputSchema = z
.object({
mask: z.boolean().default(true),
@@ -19,11 +21,15 @@ export const soonestUpcomingStaysInput = z
})
.default({ limit: 3 })
export const initiateSaveCardInput = z.object({
export const addCreditCardInput = z.object({
language: z.string(),
})
export const saveCardInput = z.object({
export const deleteCreditCardInput = z.object({
creditCardId: z.string(),
})
export const saveCreditCardInput = z.object({
transactionId: z.string(),
merchantId: z.string().optional(),
})

View File

@@ -0,0 +1,85 @@
import * as api from "@/lib/api"
import { initiateSaveCardSchema } from "@/server/routers/user/output"
import { protectedProcedure, router } from "@/server/trpc"
import {
addCreditCardInput,
deleteCreditCardInput,
saveCreditCardInput,
} from "./input"
export const userMutationRouter = router({
creditCard: router({
add: protectedProcedure.input(addCreditCardInput).mutation(async function ({
ctx,
input,
}) {
const apiResponse = await api.post(api.endpoints.v1.intiateSaveCard, {
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
body: {
language: input.language,
mobileToken: false,
redirectUrl: `api/web/add-card-callback/${input.language}`,
},
})
if (!apiResponse.ok) {
console.info(`API Response Failed - Initiating add Creadit Card flow`)
console.error(apiResponse)
return null
}
const apiJson = await apiResponse.json()
const verifiedData = initiateSaveCardSchema.safeParse(apiJson)
if (!verifiedData.success) {
console.error(`Failed to initiate save card data`)
console.error(verifiedData.error)
return null
}
return verifiedData.data.data
}),
save: protectedProcedure
.input(saveCreditCardInput)
.mutation(async function ({ ctx, input }) {
const apiResponse = await api.post(
`${api.endpoints.v1.creditCards}/${input.transactionId}`,
{
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
}
)
if (!apiResponse.ok) {
console.error(`API Response Failed - Save card`)
console.error(apiResponse)
return false
}
return true
}),
delete: protectedProcedure
.input(deleteCreditCardInput)
.mutation(async function ({ ctx, input }) {
const apiResponse = await api.remove(
`${api.endpoints.v1.creditCards}/${input.creditCardId}`,
{
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
}
)
if (!apiResponse.ok) {
console.error(`API Response Failed - Delete credit card`)
console.error(apiResponse)
return false
}
return true
}),
}),
})

View File

@@ -176,20 +176,28 @@ type GetFriendTransactionsData = z.infer<typeof getFriendTransactionsSchema>
export type FriendTransaction = GetFriendTransactionsData["data"][number]
export const getCreditCardsSchema = z.object({
data: z.array(
z.object({
attribute: z.object({
cardName: z.string().optional(),
alias: z.string(),
truncatedNumber: z.string(),
expirationDate: z.string(),
cardType: z.string(),
}),
id: z.string(),
type: z.string(),
})
),
export const creditCardSchema = z
.object({
attribute: z.object({
cardName: z.string().optional(),
alias: z.string(),
truncatedNumber: z.string(),
expirationDate: z.string(),
cardType: z.string(),
}),
id: z.string(),
type: z.string(),
})
.transform((apiResponse) => {
return {
id: apiResponse.id,
type: apiResponse.attribute.cardType,
truncatedNumber: apiResponse.attribute.truncatedNumber,
}
})
export const creditCardsSchema = z.object({
data: z.array(creditCardSchema),
})
export const getMembershipCardsSchema = z.array(

View File

@@ -1,12 +1,6 @@
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,
@@ -21,18 +15,15 @@ import encryptValue from "../utils/encryptValue"
import {
friendTransactionsInput,
getUserInputSchema,
initiateSaveCardInput,
saveCardInput,
staysInput,
} from "./input"
import {
creditCardsSchema,
FriendTransaction,
getCreditCardsSchema,
getFriendTransactionsSchema,
getMembershipCardsSchema,
getStaysSchema,
getUserSchema,
initiateSaveCardSchema,
Stay,
} from "./output"
import { benefits, extendedUser, nextLevelPerks } from "./temp"
@@ -566,7 +557,7 @@ export const userQueryRouter = router({
}
const apiJson = await apiResponse.json()
const verifiedData = getCreditCardsSchema.safeParse(apiJson)
const verifiedData = creditCardsSchema.safeParse(apiJson)
if (!verifiedData.success) {
console.error(`Failed to validate Credit Cards Data`)
console.error(`User: (${JSON.stringify(ctx.session.user)})`)
@@ -577,69 +568,6 @@ 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: false,
redirectUrl: `api/web/add-card-callback/${input.language}`,
},
})
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",