Skip to content

Commit cea8a72

Browse files
Tymmmydragosp1011
andauthored
feat: Interledger Cards (#2147)
* order cards form * add ordering cards form continued * Revert "chore(deps): update actions/labeler action to v6 (#2135)" This reverts commit 8903b44. * new cards continued * Update TerminateCardDialog.tsx * cards for Interledger * feat: add password check for terminate * Add password check * Update card.tsx * Update controller.test.ts --------- Co-authored-by: dragosp1011 <dragosh1011@gmail.com>
1 parent edf0527 commit cea8a72

File tree

15 files changed

+638
-447
lines changed

15 files changed

+638
-447
lines changed

packages/wallet/backend/src/app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ export class App {
424424

425425
router.post('/cards', isAuth, interledgerCardController.create)
426426

427+
router.put(
428+
'/cards/:cardId/activate',
429+
isAuth,
430+
interledgerCardController.activate
431+
)
427432
router.put(
428433
'/cards/:cardId/freeze',
429434
isAuth,

packages/wallet/backend/src/interledgerCard/controller.ts

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import type { NextFunction, Request } from 'express'
22
import { validate } from '@/shared/validate'
33
import { CreateCardResponse, InterledgerCardService } from './service'
4-
import { cardIdSchema, cardSchema } from './validation'
5-
import { Controller, toSuccessResponse } from '@shared/backend'
4+
import { cardIdSchema, cardSchema, terminateCardSchema } from './validation'
5+
import {
6+
BadRequest,
7+
Controller,
8+
NotFound,
9+
toSuccessResponse
10+
} from '@shared/backend'
611
import { Card } from '@/interledgerCard/model'
12+
import { UserService } from '@/user/service'
713

814
interface IInterledgerCardController {
915
create: Controller<CreateCardResponse>
@@ -15,7 +21,10 @@ interface IInterledgerCardController {
1521
}
1622

1723
export class InterledgerCardController implements IInterledgerCardController {
18-
constructor(private interledgerCardService: InterledgerCardService) {}
24+
constructor(
25+
private interledgerCardService: InterledgerCardService,
26+
private userService: UserService
27+
) {}
1928

2029
create = async (
2130
req: Request,
@@ -48,9 +57,8 @@ export class InterledgerCardController implements IInterledgerCardController {
4857
const userId = req.session.user.id
4958

5059
try {
51-
const accounts = await this.interledgerCardService.list(userId)
52-
53-
res.status(200).json(toSuccessResponse(accounts))
60+
const cards = await this.interledgerCardService.list(userId)
61+
res.status(200).json(toSuccessResponse(cards))
5462
} catch (e) {
5563
next(e)
5664
}
@@ -78,6 +86,21 @@ export class InterledgerCardController implements IInterledgerCardController {
7886
}
7987
}
8088

89+
activate = async (req: Request, res: CustomResponse, next: NextFunction) => {
90+
try {
91+
const userId = req.session.user.id
92+
const {
93+
params: { cardId }
94+
} = await validate(cardIdSchema, req)
95+
96+
await this.interledgerCardService.activate(userId, cardId)
97+
98+
res.status(200).json(toSuccessResponse())
99+
} catch (e) {
100+
next(e)
101+
}
102+
}
103+
81104
freeze = async (req: Request, res: CustomResponse, next: NextFunction) => {
82105
try {
83106
const userId = req.session.user.id
@@ -112,8 +135,20 @@ export class InterledgerCardController implements IInterledgerCardController {
112135
try {
113136
const userId = req.session.user.id
114137
const {
115-
params: { cardId }
116-
} = await validate(cardIdSchema, req)
138+
params: { cardId },
139+
body: { password }
140+
} = await validate(terminateCardSchema, req)
141+
142+
const user = await this.userService.getById(userId)
143+
144+
if (!user) {
145+
throw new NotFound()
146+
}
147+
148+
const passwordIsValid = await user?.verifyPassword(password)
149+
if (!passwordIsValid) {
150+
throw new BadRequest('Password is not valid')
151+
}
117152

118153
await this.interledgerCardService.terminate(userId, cardId)
119154

packages/wallet/backend/src/interledgerCard/service.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ export class InterledgerCardService implements IInterledgerCardService {
9999
return card
100100
}
101101

102+
async activate(userId: string, cardId: string) {
103+
const card = await this.getById(userId, cardId)
104+
if (card.status !== 'ORDERED') {
105+
throw new BadRequest('Incorrect status')
106+
}
107+
108+
await card.$query().patch({
109+
status: 'ACTIVE'
110+
})
111+
}
112+
102113
async freeze(userId: string, cardId: string) {
103114
const card = await this.getById(userId, cardId)
104115
if (card.status !== 'ACTIVE') {

packages/wallet/backend/src/interledgerCard/validation.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ export const cardIdSchema = z.object({
1212
cardId: z.string().uuid()
1313
})
1414
})
15+
export const terminateCardSchema = z.object({
16+
params: z.object({
17+
cardId: z.string().uuid()
18+
}),
19+
body: z.object({
20+
password: z.string().min(1)
21+
})
22+
})

packages/wallet/backend/src/reorder.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@ async function reorder() {
7474
card: { productCode: cardProductCode }
7575
})
7676

77-
logger.info(
78-
`Created card with cardId: ${card.id}; customerId: ${card.customerId}`
79-
)
77+
logger.info(`Created card with cardId: ${card.id};`)
8078

8179
await gateHubClient.orderPlasticForCard(
8280
'32c471ae-f7d3-4ca9-ac95-68345013d1d4',

packages/wallet/backend/tests/cards/controller.test.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,14 @@ describe('CardController', () => {
107107

108108
const mockedCards: ICardResponse[] = [
109109
{
110-
sourceId: '3dc96e41-279d-4355-921a-e1946e90e1ff',
111-
nameOnCard: 'Jane Doe',
112110
id: 'test-card-id',
113-
accountId: '469E3666F8914020B6B2604F7D4A10F6',
114-
accountSourceId: 'c44e6bc8-d0ef-491e-b374-6d09b6fa6332',
115-
maskedPan: '528700******9830',
116-
status: 'Active',
117-
statusReasonCode: null,
118-
lockLevel: null,
119-
expiryDate: '0929',
120-
customerId: 'customer-id',
121-
customerSourceId: 'a5aba6c7-b8ad-4cfe-98d5-497366a4ee2c',
122-
productCode: 'VMDTKPREB',
123-
isPinSet: false
111+
status: 'ORDERED',
112+
walletAddress: {
113+
id: 'test-wa-id',
114+
publicName: 'test',
115+
url: 'test-url',
116+
active: false
117+
}
124118
}
125119
]
126120

packages/wallet/frontend/src/components/dialogs/TerminateCardDialog.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { Form } from '@/ui/forms/Form'
1414
import { UserCardFront } from '../userCards/UserCard'
1515
import { cardService, terminateCardSchema } from '@/lib/api/card'
1616
import { useToast } from '@/lib/hooks/useToast'
17-
import { getObjectKeys } from '@/utils/helpers'
1817
import { ICardResponse } from '@wallet/shared'
1918
import { Input } from '@/ui/forms/Input'
2019
import { useRouter } from 'next/router'
@@ -72,7 +71,7 @@ export const TerminateCardDialog = ({
7271
onSubmit={async (data) => {
7372
const response = await cardService.terminate(
7473
card.id,
75-
data
74+
data.password
7675
)
7776

7877
if (response.success) {
@@ -83,14 +82,7 @@ export const TerminateCardDialog = ({
8382
})
8483
router.replace(router.pathname)
8584
} else {
86-
const { errors, message } = response
87-
if (errors) {
88-
getObjectKeys(errors).map((field) =>
89-
terminateCardForm.setError(field, {
90-
message: errors[field]
91-
})
92-
)
93-
}
85+
const { message } = response
9486
if (message) {
9587
terminateCardForm.setError('root', { message })
9688
}
@@ -99,7 +91,7 @@ export const TerminateCardDialog = ({
9991
>
10092
<div className="flex flex-col items-center justify-center gap-2">
10193
<UserCardFront
102-
nameOnCard={`${card.nameOnCard} ${card.walletAddress ? card.walletAddress.replace('https://', '$') : ''}`}
94+
cardWalletAddress={card ? card.walletAddress.url : ''}
10395
isBlocked={false}
10496
/>
10597
<p className="text-center">

packages/wallet/frontend/src/components/dialogs/UserCardPINDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export const UserCardPINDialog = ({
7272
</DialogTitle>
7373
<div className="flex space-x-5">
7474
<UserCardFront
75-
nameOnCard={`${card.nameOnCard} ${card.walletAddress ? card.walletAddress.replace('https://', '$') : ''}`}
75+
cardWalletAddress={card ? card.walletAddress.url : ''}
7676
isBlocked={false}
7777
className="origin-top-left scale-[.3] [margin:0_calc(-20rem*(1-.3))_calc(-13rem*(1-0.3))_0] "
7878
/>

packages/wallet/frontend/src/components/icons/UserCardIcons.tsx

Lines changed: 98 additions & 73 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)