Skip to content

Commit 236c691

Browse files
authored
Merge pull request #581 from klever-io/staging
Deploy 10/02/26
2 parents 1cd5b03 + 16419d7 commit 236c691

File tree

7 files changed

+158
-26
lines changed

7 files changed

+158
-26
lines changed

src/components/TransactionForms/CustomForms/AssetTrigger.tsx

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
parseStaking,
2828
parseURIs,
2929
} from './utils';
30+
import { getKDAFeePoolHelperText } from './utils/kdaFeePool';
3031
import { assetTriggerTooltips as tooltip } from './utils/tooltips';
3132

3233
export interface IMetadataOptions {
@@ -348,30 +349,7 @@ const getAssetTriggerForm = (
348349
);
349350
case 15:
350351
return (
351-
<FormSection>
352-
<FormInput
353-
name="kdaPool.adminAddress"
354-
title="Admin Address"
355-
dynamicInitialValue={walletAddress}
356-
required
357-
/>
358-
<FormInput
359-
name="kdaPool.quotient"
360-
title="KDA/KLV Quotient"
361-
type="number"
362-
required
363-
tooltip={tooltip.updateKdaPool.quotient}
364-
/>
365-
<FormInput
366-
name="kdaPool.active"
367-
title="Active"
368-
type="checkbox"
369-
toggleOptions={['No', 'Yes']}
370-
dynamicInitialValue={true}
371-
bool
372-
tooltip={tooltip.updateKdaPool.active}
373-
/>
374-
</FormSection>
352+
<KDAFeePoolForm collection={collection} walletAddress={walletAddress} />
375353
);
376354
case 16:
377355
return null;
@@ -382,6 +360,46 @@ const getAssetTriggerForm = (
382360
}
383361
};
384362

363+
const KDAFeePoolForm: React.FC<{
364+
collection: ICollectionList;
365+
walletAddress: string;
366+
}> = ({ collection, walletAddress }) => {
367+
const { watch } = useFormContext();
368+
const quotient = watch('kdaPool.quotient');
369+
370+
const assetName = collection.label || collection.value || 'KDA';
371+
372+
const helperText = getKDAFeePoolHelperText(quotient, assetName);
373+
374+
return (
375+
<FormSection>
376+
<FormInput
377+
name="kdaPool.adminAddress"
378+
title="Admin Address"
379+
dynamicInitialValue={walletAddress}
380+
required
381+
/>
382+
<FormInput
383+
name="kdaPool.quotient"
384+
title="KDA per KLV Rate"
385+
type="number"
386+
required
387+
tooltip={tooltip.updateKdaPool.quotient}
388+
helperText={helperText}
389+
/>
390+
<FormInput
391+
name="kdaPool.active"
392+
title="Active"
393+
type="checkbox"
394+
toggleOptions={['No', 'Yes']}
395+
dynamicInitialValue={true}
396+
bool
397+
tooltip={tooltip.updateKdaPool.active}
398+
/>
399+
</FormSection>
400+
);
401+
};
402+
385403
export const AddRoleSection: React.FC<PropsWithChildren> = () => {
386404
const network = getNetwork();
387405

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { getKDAFeePoolHelperText } from './kdaFeePool';
2+
3+
describe('getKDAFeePoolHelperText', () => {
4+
it('should return helper text for a positive integer quotient', () => {
5+
const result = getKDAFeePoolHelperText(2, 'TIKTOK-TSE0');
6+
expect(result).toBe(
7+
'If a fee costs 10 KLV, users will pay 20 TIKTOK-TSE0',
8+
);
9+
});
10+
11+
it('should return helper text for a decimal quotient', () => {
12+
const result = getKDAFeePoolHelperText(0.5, 'USDT-23V8');
13+
expect(result).toBe('If a fee costs 10 KLV, users will pay 5 USDT-23V8');
14+
});
15+
16+
it('should return helper text for a string quotient', () => {
17+
const result = getKDAFeePoolHelperText('3', 'KDA');
18+
expect(result).toBe('If a fee costs 10 KLV, users will pay 30 KDA');
19+
});
20+
21+
it('should return undefined for zero quotient', () => {
22+
expect(getKDAFeePoolHelperText(0, 'KDA')).toBeUndefined();
23+
});
24+
25+
it('should return undefined for negative quotient', () => {
26+
expect(getKDAFeePoolHelperText(-1, 'KDA')).toBeUndefined();
27+
});
28+
29+
it('should return undefined for empty string', () => {
30+
expect(getKDAFeePoolHelperText('', 'KDA')).toBeUndefined();
31+
});
32+
33+
it('should return undefined for null', () => {
34+
expect(getKDAFeePoolHelperText(null, 'KDA')).toBeUndefined();
35+
});
36+
37+
it('should return undefined for undefined', () => {
38+
expect(getKDAFeePoolHelperText(undefined, 'KDA')).toBeUndefined();
39+
});
40+
41+
it('should return undefined for NaN input', () => {
42+
expect(getKDAFeePoolHelperText('abc', 'KDA')).toBeUndefined();
43+
});
44+
45+
it('should return undefined for Infinity', () => {
46+
expect(getKDAFeePoolHelperText(Infinity, 'KDA')).toBeUndefined();
47+
});
48+
49+
it('should handle small decimal quotients without floating point artifacts', () => {
50+
const result = getKDAFeePoolHelperText(0.02, 'TIKTOK-TSE0');
51+
expect(result).toContain('If a fee costs 10 KLV, users will pay');
52+
expect(result).toContain('TIKTOK-TSE0');
53+
expect(result).not.toContain('0.20000000000000001');
54+
});
55+
56+
it('should show less-than text for extremely small quotients', () => {
57+
const result = getKDAFeePoolHelperText(1e-10, 'TINY-ABC1');
58+
expect(result).toBe(
59+
'If a fee costs 10 KLV, users will pay < 0.00000001 TINY-ABC1',
60+
);
61+
});
62+
63+
it('should format normally when amount equals MIN_DISPLAYABLE_AMOUNT', () => {
64+
const result = getKDAFeePoolHelperText(1e-9, 'KDA');
65+
expect(result).toBe('If a fee costs 10 KLV, users will pay 0.00000001 KDA');
66+
});
67+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const MIN_DISPLAYABLE_AMOUNT = 1e-8;
2+
3+
export const getKDAFeePoolHelperText = (
4+
quotient: unknown,
5+
assetName: string,
6+
): string | undefined => {
7+
const numericQuotient = Number(quotient);
8+
const amount = 10 * numericQuotient;
9+
10+
if (!Number.isFinite(amount) || numericQuotient <= 0) {
11+
return undefined;
12+
}
13+
14+
if (amount > 0 && amount < MIN_DISPLAYABLE_AMOUNT) {
15+
return `If a fee costs 10 KLV, users will pay < 0.00000001 ${assetName}`;
16+
}
17+
18+
const formattedAmount = amount.toLocaleString(undefined, {
19+
maximumFractionDigits: 8,
20+
});
21+
22+
return `If a fee costs 10 KLV, users will pay ${formattedAmount} ${assetName}`;
23+
};

src/components/TransactionForms/CustomForms/utils/tooltips.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const assetTriggerTooltips = {
9393
},
9494
updateKdaPool: {
9595
quotient:
96-
'KDA ratio for each KLV E.g.: when KLV the quotient is 2, the cost is 2 KDA per 1 KLV',
96+
'How many units of your token equal 1 KLV for fee payment. Example: if set to 2, users pay 2 of your token for every 1 KLV in fees.',
9797
active: '"Yes" if the pooling should be active',
9898
},
9999
role: {

src/components/TransactionForms/FormInput/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
DropdownCustomLabelSelectStyles,
2525
ErrorMessage,
2626
FileInput,
27+
HelperText,
2728
InfoIcon,
2829
InputLabel,
2930
RequiredSpan,
@@ -79,6 +80,7 @@ export interface IBaseFormInputProps
7980
loading?: boolean;
8081
warning?: boolean;
8182
propsValidate?: () => any;
83+
helperText?: string | React.ReactNode;
8284
}
8385

8486
export interface IFormInputProps extends IBaseFormInputProps {
@@ -190,6 +192,7 @@ const FormInput: React.FC<
190192
loading = false,
191193
warning,
192194
propsValidate,
195+
helperText,
193196
...rest
194197
}) => {
195198
const areaRef = useRef<HTMLTextAreaElement | null>(null);
@@ -534,6 +537,9 @@ const FormInput: React.FC<
534537
{logoError && (
535538
<ErrorMessage warning={!!logoError}>{logoError}</ErrorMessage>
536539
)}
540+
{helperText && !error && !apiError && !logoError && (
541+
<HelperText>{helperText}</HelperText>
542+
)}
537543
</Container>
538544
);
539545
};

src/components/TransactionForms/FormInput/styles.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,18 @@ export const ErrorMessage = styled.span<{ warning?: boolean }>`
407407
`}
408408
`;
409409

410+
export const HelperText = styled.span`
411+
&& {
412+
color: ${({ theme }) => theme.darkText};
413+
opacity: 0.6;
414+
font-size: 0.8rem;
415+
font-weight: 400;
416+
position: absolute;
417+
bottom: -1.1rem;
418+
left: 0;
419+
}
420+
`;
421+
410422
export const MarginRightAutoLabel = styled.span`
411423
width: 100%;
412424
margin-right: auto;

src/pages/smart-contract-transaction/[hash].tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
2020
import { smartContractTransactionDetailsCall } from '@/services/requests/smartContracts';
2121
import dynamic from 'next/dynamic';
2222
import { isKVMAvailable } from '@/utils/kvm';
23+
import nextI18nextConfig from '../../../next-i18next.config';
2324

2425
const SmartContractTransaction: React.FC = () => {
2526
const router = useRouter();
@@ -87,7 +88,12 @@ export const getServerSideProps: GetServerSideProps = async ({
8788
notFound: true,
8889
};
8990
}
90-
const props = await serverSideTranslations(locale, ['en']);
91+
const props = await serverSideTranslations(
92+
locale,
93+
['common'],
94+
nextI18nextConfig,
95+
['en'],
96+
);
9197
return { props };
9298
};
9399

0 commit comments

Comments
 (0)