Skip to content

Commit 1a8d62c

Browse files
authored
feat: require additional data for TX request support issue (#1016)
1 parent c05830a commit 1a8d62c

2 files changed

Lines changed: 103 additions & 92 deletions

File tree

src/screens/support-issue.screen.tsx

Lines changed: 99 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Limit,
99
SupportIssueReason,
1010
SupportIssueType,
11+
TransactionState,
1112
Utils,
1213
Validations,
1314
useBank,
@@ -76,7 +77,7 @@ interface FormData {
7677
receiverIban: string;
7778
date: string;
7879
name: string;
79-
transaction: SelectTransactionFormData;
80+
transaction?: SelectTransactionFormData;
8081
reason: SupportIssueReason;
8182
message: string;
8283
limit: Limit;
@@ -130,7 +131,7 @@ export default function SupportIssueScreen(): JSX.Element {
130131
const [selectTransaction, setSelectTransaction] = useState(false);
131132
const [isKycComplete, setIsKycComplete] = useState<boolean>();
132133
const [banks, setBanks] = useState<Bank[]>();
133-
const [supportIssue, setSupportIssue] = useState<Partial<CreateSupportIssue>>();
134+
const [selectedTxState, setSelectedTxState] = useState<TransactionState>();
134135

135136
const {
136137
control,
@@ -147,6 +148,7 @@ export default function SupportIssueScreen(): JSX.Element {
147148

148149
const issues = Object.values(SupportIssueType);
149150
const reasons = IssueReasons[selectedType] ?? [];
151+
const isRequestOnly = selectedTxState === TransactionState.WAITING_FOR_PAYMENT;
150152

151153
const orderParam = urlParams.get('quote') ?? urlParams.get('order');
152154
const issueTypeParam = urlParams.get('issue-type');
@@ -165,16 +167,14 @@ export default function SupportIssueScreen(): JSX.Element {
165167
useEffect(() => {
166168
const issueType = issueTypeParam && issues.find((t) => t === issueTypeParam);
167169
if (issueType) {
168-
setSupportIssue((prev) => ({ ...prev, type: issueType }));
169170
setValue('type', issueType);
170171
}
171172

172173
const reasonEnum = issueType && reasonParam && IssueReasons[issueType].find((r) => r === reasonParam);
173174
if (reasonEnum) {
174-
setSupportIssue((prev) => ({ ...prev, reason: reasonEnum }));
175175
setValue('reason', reasonEnum);
176176
}
177-
}, [issueTypeParam, reasonParam, issues]);
177+
}, [issueTypeParam, reasonParam]);
178178

179179
useUserGuard('/login', !orderParam);
180180
useKycLevelGuard(KycLevel.Link, '/contact');
@@ -183,11 +183,6 @@ export default function SupportIssueScreen(): JSX.Element {
183183
navigate({ pathname: `/support/chat/${issueUid}` });
184184
}
185185

186-
useEffect(() => {
187-
getBanks()
188-
.then(setBanks)
189-
.catch((error: ApiError) => setError(error.message ?? 'Unknown error'));
190-
}, []);
191186

192187
useEffect(() => {
193188
const kycCompleted = user && user.kyc.level >= KycLevel.Completed;
@@ -203,7 +198,6 @@ export default function SupportIssueScreen(): JSX.Element {
203198
useEffect(() => {
204199
if (orderParam) {
205200
const issueType = SupportIssueType.TRANSACTION_ISSUE;
206-
setSupportIssue((prev) => ({ ...prev, type: issueType }));
207201
setValue('type', issueType);
208202

209203
loadSupportIssue(orderParam).catch(() => undefined); // ignore error
@@ -221,29 +215,28 @@ export default function SupportIssueScreen(): JSX.Element {
221215
}, [isIssueLoading, existingIssue]);
222216

223217
useEffect(() => {
224-
if (selectedTransaction?.uid === selectTxButtonLabel) setSelectTransaction(true);
225-
}, [selectedTransaction]);
218+
if (selectedTransaction?.uid === selectTxButtonLabel) {
219+
setSelectTransaction(true);
220+
}
221+
}, [selectedTransaction?.uid]);
226222

227223
useEffect(() => {
228-
if (selectedReason && selectedReason !== supportIssue?.reason) {
229-
setSupportIssue((prev) => ({ ...prev, reason: selectedReason }));
230-
reset({ ...formDefaultValues, type: selectedType, reason: selectedReason });
224+
if (selectTransaction && selectedReason === SupportIssueReason.TRANSACTION_MISSING) {
225+
setSelectTransaction(false);
231226
}
232-
}, [selectedReason, supportIssue]);
227+
}, [selectedReason, selectTransaction]);
233228

234229
useEffect(() => {
235-
if (selectedType && selectedType !== supportIssue?.type) {
236-
setSupportIssue((prev) => ({ ...prev, type: selectedType }));
237-
reset({ ...formDefaultValues, type: selectedType });
238-
}
239-
}, [selectedType, supportIssue]);
230+
setSelectedTxState(undefined);
231+
setValue('transaction', undefined);
232+
}, [selectedReason]);
233+
240234

241235
useEffect(() => {
242-
if (isLoggedIn)
243-
getBanks()
244-
.then(setBanks)
245-
.catch((error: ApiError) => setError(error.message ?? 'Unknown error'));
246-
}, [isLoggedIn]);
236+
getBanks()
237+
.then(setBanks)
238+
.catch((error: ApiError) => setError(error.message ?? 'Unknown error'));
239+
}, []);
247240

248241
async function onSubmit(data: FormData) {
249242
setIsLoading(true);
@@ -259,14 +252,20 @@ export default function SupportIssueScreen(): JSX.Element {
259252
};
260253

261254
if (data.type === SupportIssueType.TRANSACTION_ISSUE) {
262-
if (data.reason !== SupportIssueReason.TRANSACTION_MISSING) {
263-
request.transaction = { uid: data.transaction?.uid };
264-
} else {
255+
if (data.reason === SupportIssueReason.TRANSACTION_MISSING) {
265256
request.transaction = {
266257
senderIban: data.senderIban,
267258
receiverIban: data.receiverIban,
268259
date: new Date(data.date),
269260
};
261+
} else if (data.reason === SupportIssueReason.FUNDS_NOT_RECEIVED && isRequestOnly) {
262+
request.transaction = {
263+
uid: data.transaction?.uid,
264+
senderIban: data.senderIban,
265+
date: new Date(data.date),
266+
};
267+
} else {
268+
request.transaction = { uid: data.transaction?.uid };
270269
}
271270
orderParam && (request.transaction.orderUid = orderParam);
272271
}
@@ -290,16 +289,26 @@ export default function SupportIssueScreen(): JSX.Element {
290289
}
291290
}
292291

293-
function onSelectTransaction(uid: string) {
292+
function onSelectTransaction(uid: string, state: TransactionState) {
294293
setValue('transaction', { uid, description: 'Transaction ID' });
294+
setSelectedTxState(state);
295295
setSelectTransaction(false);
296296
}
297297

298+
const isFundsNotReceivedRequest =
299+
selectedReason === SupportIssueReason.FUNDS_NOT_RECEIVED && isRequestOnly === true;
300+
298301
const rules = Utils.createRules({
299302
type: Validations.Required,
300-
senderIban: [Validations.Required, !!orderParam && Validations.Iban(allowedCountries)],
301-
receiverIban: Validations.Required,
302-
date: [Validations.Required, Validations.Custom((date) => (/\d{4}-\d{2}-\d{2}/g.test(date) ? true : 'pattern'))],
303+
senderIban: [
304+
(selectedReason === SupportIssueReason.TRANSACTION_MISSING || isFundsNotReceivedRequest) && Validations.Required,
305+
!!orderParam && Validations.Iban(allowedCountries),
306+
],
307+
receiverIban: selectedReason === SupportIssueReason.TRANSACTION_MISSING && Validations.Required,
308+
date: [
309+
(selectedReason === SupportIssueReason.TRANSACTION_MISSING || isFundsNotReceivedRequest) && Validations.Required,
310+
Validations.Custom((date) => (!date || /\d{4}-\d{2}-\d{2}/g.test(date) ? true : 'pattern')),
311+
],
303312
name: Validations.Required,
304313
transaction: Validations.Required,
305314
reason: Validations.Required,
@@ -338,7 +347,6 @@ export default function SupportIssueScreen(): JSX.Element {
338347
<AddBankAccount
339348
onSubmit={(account) => {
340349
setValue('senderIban', account.iban);
341-
setSupportIssue((prev) => ({ ...prev, senderIban: account.iban }));
342350
}}
343351
confirmationText={translate(
344352
'screens/iban',
@@ -387,10 +395,9 @@ export default function SupportIssueScreen(): JSX.Element {
387395
</StyledVerticalStack>
388396
)}
389397

390-
{selectedType === SupportIssueType.TRANSACTION_ISSUE &&
391-
selectedReason &&
392-
(selectedReason !== SupportIssueReason.TRANSACTION_MISSING ? (
393-
!orderParam && (
398+
{selectedType === SupportIssueType.TRANSACTION_ISSUE && selectedReason && (
399+
<>
400+
{selectedReason !== SupportIssueReason.TRANSACTION_MISSING && !orderParam && (
394401
<StyledVerticalStack gap={3.5} full center>
395402
<p className="w-full text-left text-dfxBlue-800 text-base font-semibold pl-3.5 -mb-1">
396403
{translate('screens/payment', 'Transaction')}
@@ -405,59 +412,62 @@ export default function SupportIssueScreen(): JSX.Element {
405412
forceEnable
406413
/>
407414
</StyledVerticalStack>
408-
)
409-
) : (
410-
<>
411-
{bankAccounts && isLoggedIn ? (
412-
<StyledDropdown<string>
413-
rootRef={rootRef}
414-
label={translate('screens/support', 'Sender IBAN')}
415-
items={[...bankAccounts.map((a) => a.iban), AddAccount, NoIban]}
416-
labelFunc={(item) =>
417-
blankedAddress(
418-
item === AddAccount
419-
? translate('general/actions', item)
420-
: item === NoIban
421-
? translate('screens/iban', item)
422-
: (Utils.formatIban(item) ?? ''),
423-
{ displayLength: 30 },
424-
)
425-
}
426-
descriptionFunc={(item) => bankAccounts.find((a) => a.iban === item)?.label ?? ''}
427-
name="senderIban"
428-
placeholder={translate('general/actions', 'Select') + '...'}
429-
full
430-
/>
431-
) : (
432-
<StyledInput
433-
name="senderIban"
434-
autocomplete="iban"
435-
label={translate('screens/support', 'Sender IBAN')}
436-
placeholder="XX XXXX XXXX XXXX XXXX X"
437-
full
438-
/>
439-
)}
415+
)}
440416

441-
{banks && (
442-
<StyledDropdown<string>
443-
rootRef={rootRef}
444-
label={translate('screens/support', 'Receiver IBAN')}
445-
items={banks.map((b) => b.iban)}
446-
labelFunc={(item) => blankedAddress(Utils.formatIban(item) ?? '', { displayLength: 30 })}
447-
name="receiverIban"
448-
placeholder={translate('general/actions', 'Select') + '...'}
417+
{(selectedReason === SupportIssueReason.TRANSACTION_MISSING || isFundsNotReceivedRequest) && (
418+
<>
419+
{bankAccounts && isLoggedIn ? (
420+
<StyledDropdown<string>
421+
rootRef={rootRef}
422+
label={translate('screens/support', 'Sender IBAN')}
423+
items={[...bankAccounts.map((a) => a.iban), AddAccount, NoIban]}
424+
labelFunc={(item) =>
425+
blankedAddress(
426+
item === AddAccount
427+
? translate('general/actions', item)
428+
: item === NoIban
429+
? translate('screens/iban', item)
430+
: (Utils.formatIban(item) ?? ''),
431+
{ displayLength: 30 },
432+
)
433+
}
434+
descriptionFunc={(item) => bankAccounts.find((a) => a.iban === item)?.label ?? ''}
435+
name="senderIban"
436+
placeholder={translate('general/actions', 'Select') + '...'}
437+
full
438+
/>
439+
) : (
440+
<StyledInput
441+
name="senderIban"
442+
autocomplete="iban"
443+
label={translate('screens/support', 'Sender IBAN')}
444+
placeholder="XX XXXX XXXX XXXX XXXX X"
445+
full
446+
/>
447+
)}
448+
449+
{selectedReason === SupportIssueReason.TRANSACTION_MISSING && banks && (
450+
<StyledDropdown<string>
451+
rootRef={rootRef}
452+
label={translate('screens/support', 'Receiver IBAN')}
453+
items={banks.map((b) => b.iban)}
454+
labelFunc={(item) => blankedAddress(Utils.formatIban(item) ?? '', { displayLength: 30 })}
455+
name="receiverIban"
456+
placeholder={translate('general/actions', 'Select') + '...'}
457+
full
458+
/>
459+
)}
460+
461+
<StyledInput
462+
name="date"
463+
label={translate('screens/support', 'Date of the transaction')}
464+
placeholder={new Date().toISOString().split('T')[0]}
449465
full
450466
/>
451-
)}
452-
453-
<StyledInput
454-
name="date"
455-
label={translate('screens/support', 'Date of the transaction')}
456-
placeholder={new Date().toISOString().split('T')[0]}
457-
full
458-
/>
459-
</>
460-
))}
467+
</>
468+
)}
469+
</>
470+
)}
461471

462472
<StyledInput
463473
name="name"

src/screens/transaction.screen.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ function TransactionRefund({ setError }: TransactionRefundProps): JSX.Element {
634634

635635
interface TransactionListProps extends TransactionStatusProps {
636636
isSupport: boolean;
637-
onSelectTransaction?: (txUid: string) => void;
637+
onSelectTransaction?: (txUid: string, state: TransactionState) => void;
638638
}
639639

640640
export function TransactionList({ isSupport, setError, onSelectTransaction }: TransactionListProps): JSX.Element {
@@ -880,6 +880,7 @@ export function TransactionList({ isSupport, setError, onSelectTransaction }: Tr
880880
}}
881881
isLoading={isInvoiceLoading === tx.uid}
882882
color={StyledButtonColor.STURDY_WHITE}
883+
hidden={isSupport}
883884
/>
884885
<StyledButton
885886
label={translate('general/actions', 'Open receipt')}
@@ -893,7 +894,7 @@ export function TransactionList({ isSupport, setError, onSelectTransaction }: Tr
893894
})
894895
.finally(() => setIsReceiptLoading(undefined));
895896
}}
896-
hidden={tx.state !== TransactionState.COMPLETED}
897+
hidden={isSupport || tx.state !== TransactionState.COMPLETED}
897898
isLoading={isReceiptLoading === tx.id}
898899
color={StyledButtonColor.STURDY_WHITE}
899900
/>
@@ -936,7 +937,7 @@ export function TransactionList({ isSupport, setError, onSelectTransaction }: Tr
936937
<StyledButton
937938
color={StyledButtonColor.STURDY_WHITE}
938939
label={translate('general/actions', 'Select')}
939-
onClick={() => onSelectTransaction && onSelectTransaction(tx.uid)}
940+
onClick={() => onSelectTransaction && onSelectTransaction(tx.uid, tx.state)}
940941
/>
941942
)}
942943
</StyledVerticalStack>

0 commit comments

Comments
 (0)