Skip to content

Commit 6979449

Browse files
fix: prevent rejecting verified transactions (#224)
fix: prevent rejecting verified transactions
2 parents 21a9d54 + aff8197 commit 6979449

6 files changed

Lines changed: 109 additions & 5 deletions

File tree

app/models/enum.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ export const TRANSACTION_STATUS = {
2727
SUBMITTED: 'SUBMITTED',
2828
VERIFIED: 'VERIFIED',
2929
REJECTED: 'REJECTED',
30-
}
30+
} as const
3131

32-
export type TransactionStatus = 'SUBMITTED' | 'VERIFIED' | 'REJECTED'
32+
export type TransactionStatus =
33+
typeof TRANSACTION_STATUS[keyof typeof TRANSACTION_STATUS]
3334

3435
export const TRANSACTION_METHOD = {
3536
BANK_TRANSFER: 'BANK_TRANSFER',

app/routes/dashboard.transactions.$transactionId.$action.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
TransactionWithUser,
1616
updateTransactionStatus,
1717
} from '~/models/transaction'
18+
import { canUpdateTransactionStatus } from '~/utils/transaction-status'
1819
import { printLocaleDateTimeString, printRupiah } from '~/utils/format'
1920
import { TransactionStatus, TRANSACTION_STATUS } from '~/models/enum'
2021
import { requireUser } from '~/services/auth.server'
@@ -75,6 +76,26 @@ export const action: ActionFunction = async ({ request, params }) => {
7576
}
7677
}
7778

79+
const existingTransaction = await getTransactionById(transactionId)
80+
if (!existingTransaction) {
81+
return redirect('/dashboard/transactions')
82+
}
83+
84+
if (
85+
!canUpdateTransactionStatus(
86+
existingTransaction.status as TransactionStatus,
87+
status as TransactionStatus
88+
)
89+
) {
90+
throw json(
91+
{
92+
formError:
93+
'Transaksi yang sudah diverifikasi tidak dapat diubah menjadi ditolak.',
94+
},
95+
{ status: 400 }
96+
)
97+
}
98+
7899
const transaction = await updateTransactionStatus(
79100
transactionId,
80101
notes,

app/routes/dashboard.transactions.$transactionId.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ export default function TransactionDetailsPage() {
4949
<SingleColumnLayout>
5050
<div className="min-h-full">
5151
<TransactionDetails transaction={transaction} user={transaction.user}>
52-
{/* TODO: Disable rejecting a verified transaction */}
5352
<TertiaryButtonLink
5453
to={`reject?${searchParams.toString()}`}
5554
replace
56-
disabled={transaction.status === TRANSACTION_STATUS.REJECTED}
55+
disabled={
56+
transaction.status === TRANSACTION_STATUS.REJECTED ||
57+
transaction.status === TRANSACTION_STATUS.VERIFIED
58+
}
5759
>
5860
Tolak Transaksi
5961
</TertiaryButtonLink>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { canUpdateTransactionStatus } from '../transaction-status'
2+
import { TRANSACTION_STATUS } from '~/models/enum'
3+
4+
describe('canUpdateTransactionStatus', () => {
5+
it('allows submitted to verified', () => {
6+
expect(
7+
canUpdateTransactionStatus(
8+
TRANSACTION_STATUS.SUBMITTED,
9+
TRANSACTION_STATUS.VERIFIED
10+
)
11+
).toBe(true)
12+
})
13+
14+
it('allows submitted to rejected', () => {
15+
expect(
16+
canUpdateTransactionStatus(
17+
TRANSACTION_STATUS.SUBMITTED,
18+
TRANSACTION_STATUS.REJECTED
19+
)
20+
).toBe(true)
21+
})
22+
23+
it('prevents verified from being rejected', () => {
24+
expect(
25+
canUpdateTransactionStatus(
26+
TRANSACTION_STATUS.VERIFIED,
27+
TRANSACTION_STATUS.REJECTED
28+
)
29+
).toBe(false)
30+
})
31+
32+
it('allows verified to remain verified', () => {
33+
expect(
34+
canUpdateTransactionStatus(
35+
TRANSACTION_STATUS.VERIFIED,
36+
TRANSACTION_STATUS.VERIFIED
37+
)
38+
).toBe(true)
39+
})
40+
41+
it('allows rejected to be re-verified', () => {
42+
expect(
43+
canUpdateTransactionStatus(
44+
TRANSACTION_STATUS.REJECTED,
45+
TRANSACTION_STATUS.VERIFIED
46+
)
47+
).toBe(true)
48+
})
49+
50+
it('allows rejected to remain rejected', () => {
51+
expect(
52+
canUpdateTransactionStatus(
53+
TRANSACTION_STATUS.REJECTED,
54+
TRANSACTION_STATUS.REJECTED
55+
)
56+
).toBe(true)
57+
})
58+
})

app/utils/transaction-status.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { TransactionStatus, TRANSACTION_STATUS } from '~/models/enum'
2+
3+
export function canUpdateTransactionStatus(
4+
currentStatus: TransactionStatus,
5+
destinationStatus: TransactionStatus
6+
) {
7+
if (
8+
currentStatus === TRANSACTION_STATUS.VERIFIED &&
9+
destinationStatus === TRANSACTION_STATUS.REJECTED
10+
) {
11+
return false
12+
}
13+
14+
return true
15+
}

test/test-utils.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ export function createRemixStubWrapper(
2222
Component: () => ui,
2323
},
2424
])
25-
return <RemixStub initialEntries={initialEntries} />
25+
return (
26+
<RemixStub
27+
initialEntries={initialEntries}
28+
future={{
29+
v3_relativeSplatPath: true,
30+
}}
31+
/>
32+
)
2633
}
2734

2835
/**

0 commit comments

Comments
 (0)