Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into 1629-cards-wallet-backend-…
Browse files Browse the repository at this point in the history
…view-card-transactions
  • Loading branch information
sanducb committed Oct 1, 2024
2 parents 3b3dee1 + bef2be5 commit d75b614
Show file tree
Hide file tree
Showing 9 changed files with 357 additions and 92 deletions.
2 changes: 2 additions & 0 deletions packages/wallet/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ export class App {
cardController.getCardsByCustomer
)
router.get('/cards/:cardId/details', isAuth, cardController.getCardDetails)
router.put('/cards/:cardId/lock', isAuth, cardController.lock)
router.put('/cards/:cardId/unlock', isAuth, cardController.unlock)
router.get(
'/cards/:cardId/transactions',
isAuth,
Expand Down
43 changes: 41 additions & 2 deletions packages/wallet/backend/src/card/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ import { toSuccessResponse } from '@shared/backend'
import {
ICardDetailsRequest,
ICardDetailsResponse,
ICardLockRequest,
ICardResponse,
IGetTransactionsResponse
ICardUnlockRequest,
IGetTransactionsResponse,
getCardTransactionsSchema
} from './types'
import { validate } from '@/shared/validate'
import {
getCardsByCustomerSchema,
getCardDetailsSchema,
getCardTransactionsSchema
lockCardSchema,
unlockCardSchema
} from './validation'

export interface ICardController {
getCardsByCustomer: Controller<ICardDetailsResponse[]>
getCardDetails: Controller<ICardResponse>
lock: Controller<ICardResponse>
unlock: Controller<ICardResponse>
getCardTransactions: Controller<IGetTransactionsResponse>
}

Expand Down Expand Up @@ -62,6 +68,39 @@ export class CardController implements ICardController {
}
}

public lock = async (req: Request, res: Response, next: NextFunction) => {
try {
const { params, query, body } = await validate(lockCardSchema, req)
const { cardId } = params
const { reasonCode } = query
const requestBody: ICardLockRequest = body

const result = await this.cardService.lock(
cardId,
reasonCode,
requestBody
)

res.status(200).json(toSuccessResponse(result))
} catch (error) {
next(error)
}
}

public unlock = async (req: Request, res: Response, next: NextFunction) => {
try {
const { params, body } = await validate(unlockCardSchema, req)
const { cardId } = params
const requestBody: ICardUnlockRequest = body

const result = await this.cardService.unlock(cardId, requestBody)

res.status(200).json(toSuccessResponse(result))
} catch (error) {
next(error)
}
}

public getCardTransactions = async (
req: Request,
res: Response,
Expand Down
20 changes: 20 additions & 0 deletions packages/wallet/backend/src/card/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { GateHubClient } from '../gatehub/client'
import {
ICardDetailsRequest,
ICardDetailsResponse,
ICardLockRequest,
ICardResponse,
ICardUnlockRequest,
IGetTransactionsResponse
} from './types'
import { LockReasonCode } from '@wallet/shared/src'
import { NotFound } from '@shared/backend'

export class CardService {
Expand Down Expand Up @@ -50,5 +53,22 @@ export class CardService {
if (!walletAddress) {
throw new NotFound('Card not found or not associated with the user.')
}

return this.gateHubClient.getCardDetails(requestBody)
}

async lock(
cardId: string,
reasonCode: LockReasonCode,
requestBody: ICardLockRequest
): Promise<ICardResponse> {
return this.gateHubClient.lockCard(cardId, reasonCode, requestBody)
}

async unlock(
cardId: string,
requestBody: ICardUnlockRequest
): Promise<ICardResponse> {
return this.gateHubClient.unlockCard(cardId, requestBody)
}
}
8 changes: 8 additions & 0 deletions packages/wallet/backend/src/card/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ export interface ICardProductResponse {
cost: string
}

export interface ICardLockRequest {
note: string
}

export interface ICardUnlockRequest {
note: string
}

// Response for fetching card transactions
export interface ITransaction {
id: number
Expand Down
28 changes: 28 additions & 0 deletions packages/wallet/backend/src/card/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ export const getCardDetailsSchema = z.object({
})
})

export const lockCardSchema = z.object({
params: z.object({
cardId: z.string()
}),
query: z.object({
reasonCode: z.enum([
'ClientRequestedLock',
'LostCard',
'StolenCard',
'IssuerRequestGeneral',
'IssuerRequestFraud',
'IssuerRequestLegal'
])
}),
body: z.object({
note: z.string()
})
})

export const unlockCardSchema = z.object({
params: z.object({
cardId: z.string()
}),
body: z.object({
note: z.string()
})
})

export const getCardTransactionsSchema = z.object({
params: z.object({
cardId: z.string()
Expand Down
38 changes: 37 additions & 1 deletion packages/wallet/backend/src/gatehub/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from '@/gatehub/consts'
import axios, { AxiosError } from 'axios'
import { Logger } from 'winston'
import { IFRAME_TYPE } from '@wallet/shared/src'
import { IFRAME_TYPE, LockReasonCode } from '@wallet/shared/src'
import { BadRequest } from '@shared/backend'
import {
ICardDetailsResponse,
Expand All @@ -40,6 +40,8 @@ import {
ICreateCustomerResponse,
ICardProductResponse,
ICardDetailsRequest,
ICardLockRequest,
ICardUnlockRequest,
IGetTransactionsResponse
} from '@/card/types'

Expand Down Expand Up @@ -372,6 +374,40 @@ export class GateHubClient {
return cardDetailsResponse
}

async lockCard(
cardId: string,
reasonCode: LockReasonCode,
requestBody: ICardLockRequest
): Promise<ICardResponse> {
let url = `${this.apiUrl}/v1/cards/${cardId}/lock`
url += `?reasonCode=${encodeURIComponent(reasonCode)}`

return this.request<ICardResponse>(
'PUT',
url,
JSON.stringify(requestBody),
{
cardAppId: this.env.GATEHUB_CARD_APP_ID
}
)
}

async unlockCard(
cardId: string,
requestBody: ICardUnlockRequest
): Promise<ICardResponse> {
const url = `${this.apiUrl}/v1/cards/${cardId}/unlock`

return this.request<ICardResponse>(
'PUT',
url,
JSON.stringify(requestBody),
{
cardAppId: this.env.GATEHUB_CARD_APP_ID
}
)
}

async getCardTransactions(
cardId: string,
pageSize?: number,
Expand Down
Loading

0 comments on commit d75b614

Please sign in to comment.