Skip to content

Commit 7166d00

Browse files
authored
Merge pull request #5 from xdevguild/ui-rewrite
Rewrite UI
2 parents da94d1f + 104f4cb commit 7166d00

190 files changed

Lines changed: 9774 additions & 7050 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.prettierrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
"singleQuote": true,
66
"arrowParens": "always",
77
"trailingComma": "es5",
8-
"endOfLine": "auto"
8+
"endOfLine": "auto",
9+
"plugins": [
10+
"prettier-plugin-tailwindcss"
11+
]
912
}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
### [0.14.0](https://github.com/xdevguild/buildo.dev/releases/tag/v0.14.0) (2024-...)
2+
- rebuild the UI. Each operation has separate page now
3+
14
### [0.13.1](https://github.com/xdevguild/buildo.dev/releases/tag/v0.13.1) (2024-02-28)
25
- update useElven and implement required changes in code
36

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
'use client';
2+
3+
import * as z from 'zod';
4+
import {
5+
BytesValue,
6+
TypedValue,
7+
ContractCallPayloadBuilder,
8+
ContractFunction,
9+
BigUIntValue,
10+
} from '@multiversx/sdk-core';
11+
import { useForm } from 'react-hook-form';
12+
import { zodResolver } from '@hookform/resolvers/zod';
13+
import { Form } from '@/components/ui/form';
14+
import { OperationsInputField } from '@/app/(operations)/components/operations-ui/operations-input-field';
15+
import { OperationsSubmitButton } from '@/app/(operations)/components/operations-ui/operations-submit-button';
16+
import { CommonOpertationContentProps } from '@/app/(operations)/components/operations-ui/operations-common-types';
17+
import { OperationsRadioGroup } from '@/app/(operations)/components/operations-ui/operations-radio-group';
18+
import BigNumber from 'bignumber.js';
19+
import { useAccount, useConfig, useTransaction } from '@useelven/core';
20+
import axios from 'axios';
21+
import { specialOpertationsGasLimit } from '@/app/(operations)/components/operations-ui/constants';
22+
import { useTxStatus } from '@/hooks/use-tx-status';
23+
import { OperationInfoBox } from './operations-ui/operation-info-box';
24+
25+
const formSchema = z.object({
26+
tokenId: z.string().min(1, 'The field is required'),
27+
quantity: z
28+
.string()
29+
.refine(
30+
(value) => !new BigNumber(value).isNaN(),
31+
'Required BigNumber string.'
32+
),
33+
type: z.enum(['add', 'burn'], {
34+
required_error: 'Please choose the type of the operation (add/burn)',
35+
}),
36+
});
37+
38+
export const AddBurnQuantity = ({
39+
tokenType,
40+
}: {
41+
tokenType: CommonOpertationContentProps['tokenType'];
42+
}) => {
43+
const { triggerTx, error, txResult, transaction, pending } = useTransaction();
44+
const { address } = useAccount();
45+
const { apiAddress } = useConfig();
46+
47+
const form = useForm<z.infer<typeof formSchema>>({
48+
resolver: zodResolver(formSchema),
49+
defaultValues: {
50+
tokenId: '',
51+
quantity: '',
52+
type: 'add',
53+
},
54+
});
55+
56+
useTxStatus({
57+
successHash: txResult?.hash,
58+
pendingHash: transaction?.getHash()?.toString(),
59+
error,
60+
pending,
61+
});
62+
63+
const onSubmit = async ({
64+
tokenId,
65+
quantity,
66+
type,
67+
}: z.infer<typeof formSchema>) => {
68+
try {
69+
// TODO: replace with useElven useApiCall when ready to handle such cases
70+
const tokenOnNetwork = await axios.get<{
71+
nonce: number;
72+
collection: string;
73+
}>(`${apiAddress}/nfts/${tokenId.trim()}`, {
74+
headers: {
75+
'Content-Type': 'application/json',
76+
Accept: 'application/json',
77+
},
78+
});
79+
80+
const nonce = tokenOnNetwork?.data?.nonce;
81+
const collectionId = tokenOnNetwork?.data?.collection;
82+
83+
// TODO: show the error in the transaction status modal
84+
if (!nonce || !collectionId) {
85+
console.error(
86+
"Can't read the nonce or/and collection id of the token, using MultiversX API!"
87+
);
88+
return;
89+
}
90+
91+
const args: TypedValue[] = [
92+
BytesValue.fromUTF8(collectionId.trim()),
93+
new BigUIntValue(new BigNumber(nonce)),
94+
new BigUIntValue(new BigNumber(quantity.trim())),
95+
];
96+
97+
// TODO: replace ContractCallPayloadBuilder
98+
const data = new ContractCallPayloadBuilder()
99+
.setFunction(
100+
new ContractFunction(
101+
type === 'add' ? 'ESDTNFTAddQuantity' : 'ESDTNFTBurn'
102+
)
103+
)
104+
.setArgs(args)
105+
.build();
106+
107+
triggerTx?.({
108+
address,
109+
gasLimit: specialOpertationsGasLimit,
110+
data,
111+
value: 0,
112+
});
113+
} catch (e) {
114+
console.error(
115+
"Can't read the nonce or/and collection id of the token, using MultiversX API!",
116+
e
117+
);
118+
}
119+
};
120+
121+
return (
122+
<>
123+
<OperationInfoBox error={error} txResult={txResult} />
124+
<Form {...form}>
125+
<form
126+
id="add-burn-form"
127+
onSubmit={form.handleSubmit(onSubmit)}
128+
className="space-y-8"
129+
>
130+
<div className="flex-1 overflow-auto p-1">
131+
<OperationsRadioGroup
132+
items={[
133+
{ name: 'add', description: 'Add the quantity' },
134+
{ name: 'burn', description: 'Reduce the quantity' },
135+
]}
136+
name="type"
137+
label="Operation type"
138+
description="Please choose the type of the operation. Add or Burn."
139+
/>
140+
<OperationsInputField
141+
name="tokenId"
142+
label="Token id"
143+
placeholder="Example: MyToken-23432-01"
144+
description="Please provide your token id"
145+
/>
146+
<OperationsInputField
147+
name="quantity"
148+
label="Quantity"
149+
placeholder="Example: 10000"
150+
description={
151+
tokenType === 'semi-fungible'
152+
? 'Please provide the quantity.'
153+
: 'Please provide the supply (remember to take into consideration the number of decimals. For example 100.5 with 2 decimal places will be 10050).'
154+
}
155+
/>
156+
</div>
157+
<OperationsSubmitButton formId="add-burn-form" />
158+
</form>
159+
</Form>
160+
</>
161+
);
162+
};
Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use client';
2+
13
import * as z from 'zod';
24
import {
35
BytesValue,
@@ -8,27 +10,23 @@ import {
810
import { useForm, useWatch } from 'react-hook-form';
911
import { zodResolver } from '@hookform/resolvers/zod';
1012
import { Form } from '@/components/ui/form';
11-
import {
12-
DialogDescription,
13-
DialogFooter,
14-
DialogHeader,
15-
DialogTitle,
16-
} from '@/components/ui/dialog';
1713
import {
1814
esdtTokenProperties,
1915
sftNftTokenProperties,
2016
commonOpertationsGasLimit,
2117
builtInSC,
2218
TokenPropertyOrRole,
23-
} from '@/components/operations/constants';
24-
import { OperationsCheckboxGroup } from '@/components/operations/operations-checkbox-group';
25-
import { OperationsSubmitButton } from '@/components/operations/operations-submit-button';
26-
import { useContext, useEffect } from 'react';
27-
import { OperationsStateDialogContext } from '@/components/operations/operations-status-dialog';
28-
import { CommonOpertationContentProps } from '@/components/operations/operations-common-types';
29-
import { OperationsSelectField } from '@/components/operations/operations-select-field';
19+
} from '@/app/(operations)/components/operations-ui/constants';
20+
import { OperationsCheckboxGroup } from '@/app/(operations)/components/operations-ui/operations-checkbox-group';
21+
import { OperationsSubmitButton } from '@/app/(operations)/components/operations-ui/operations-submit-button';
22+
import { useEffect } from 'react';
23+
import { CommonOpertationContentProps } from '@/app/(operations)/components/operations-ui/operations-common-types';
24+
import { OperationsSelectField } from '@/app/(operations)/components/operations-ui/operations-select-field';
3025
import { useCreatorTokens } from '@/hooks/use-creator-tokens';
3126
import { getTokenIdKey } from '@/lib/get-token-id';
27+
import { useTransaction } from '@useelven/core';
28+
import { OperationInfoBox } from './operations-ui/operation-info-box';
29+
import { useTxStatus } from '@/hooks/use-tx-status';
3230

3331
const formSchema = z.object({
3432
tokenId: z.string().min(1, 'The field is required'),
@@ -51,13 +49,11 @@ const propertiesMap: Record<
5149
};
5250

5351
export const ChangeProperties = ({
54-
triggerTx,
55-
close,
5652
tokenType,
57-
}: CommonOpertationContentProps) => {
58-
const { setOpen: setTxStatusDialogOpen } = useContext(
59-
OperationsStateDialogContext
60-
);
53+
}: {
54+
tokenType: CommonOpertationContentProps['tokenType'];
55+
}) => {
56+
const { triggerTx, error, txResult, transaction, pending } = useTransaction();
6157

6258
const { tokens } = useCreatorTokens<CreatorTokens>({
6359
tokenType,
@@ -71,6 +67,13 @@ export const ChangeProperties = ({
7167
},
7268
});
7369

70+
useTxStatus({
71+
successHash: txResult?.hash,
72+
pendingHash: transaction?.getHash()?.toString(),
73+
error,
74+
pending,
75+
});
76+
7477
const watchTokenId = useWatch({ control: form.control, name: 'tokenId' });
7578

7679
const onSubmit = ({ tokenId, properties }: z.infer<typeof formSchema>) => {
@@ -87,6 +90,7 @@ export const ChangeProperties = ({
8790
args.push(BytesValue.fromUTF8(propertyEnabled.toString()));
8891
}
8992

93+
// TODO: replace ContractCallPayloadBuilder
9094
const data = new ContractCallPayloadBuilder()
9195
.setFunction(new ContractFunction('controlChanges'))
9296
.setArgs(args)
@@ -98,10 +102,6 @@ export const ChangeProperties = ({
98102
data,
99103
value: 0,
100104
});
101-
102-
setTxStatusDialogOpen(true);
103-
form.reset();
104-
close();
105105
};
106106

107107
useEffect(() => {
@@ -125,48 +125,45 @@ export const ChangeProperties = ({
125125

126126
return (
127127
<>
128-
<DialogHeader className="p-8 pb-0">
129-
<DialogTitle>Change properties of a {tokenType} ESDT</DialogTitle>
130-
<DialogDescription>
131-
The manager of an ESDT token may individually change any of the
132-
properties of the token, or multiple properties at once. The token
133-
should have the canUpgrade property set to true.
134-
</DialogDescription>
135-
</DialogHeader>
136-
<div className="overflow-y-auto py-0 px-8">
137-
<Form {...form}>
138-
<form
139-
id="change-properties-form"
140-
onSubmit={form.handleSubmit(onSubmit)}
141-
className="space-y-8"
142-
>
143-
<div className="flex-1 overflow-auto p-1">
144-
<OperationsSelectField
145-
name="tokenId"
146-
label="Token id"
147-
description="Please provide your token id"
148-
options={
149-
tokens
150-
? tokens?.map((token) => ({
128+
<OperationInfoBox error={error} txResult={txResult} />
129+
<Form {...form}>
130+
<form
131+
id="change-properties-form"
132+
onSubmit={form.handleSubmit(onSubmit)}
133+
className="space-y-8"
134+
>
135+
<div className="flex-1 overflow-auto p-1">
136+
<OperationsSelectField
137+
name="tokenId"
138+
label="Token id"
139+
description="Please provide your token id"
140+
options={
141+
tokens
142+
? tokens
143+
?.sort((a, b) => {
144+
const aTokenId = a[getTokenIdKey(tokenType)];
145+
const bTokenId = b[getTokenIdKey(tokenType)];
146+
if (aTokenId < bTokenId) return -1;
147+
if (aTokenId > bTokenId) return 1;
148+
return 0;
149+
})
150+
.map((token) => ({
151151
value: token[getTokenIdKey(tokenType)],
152152
label: token[getTokenIdKey(tokenType)],
153153
}))
154-
: []
155-
}
156-
/>
157-
<OperationsCheckboxGroup
158-
items={propertiesMap[tokenType]}
159-
name="properties"
160-
label="Token properties"
161-
description="Set new properties set for the ESDT token."
162-
/>
163-
</div>
164-
</form>
165-
</Form>
166-
</div>
167-
<DialogFooter className="py-4 px-8">
168-
<OperationsSubmitButton formId="change-properties-form" />
169-
</DialogFooter>
154+
: []
155+
}
156+
/>
157+
<OperationsCheckboxGroup
158+
items={propertiesMap[tokenType]}
159+
name="properties"
160+
label="Token properties"
161+
description="Set new properties set for the ESDT token."
162+
/>
163+
</div>
164+
<OperationsSubmitButton formId="change-properties-form" />
165+
</form>
166+
</Form>
170167
</>
171168
);
172169
};

0 commit comments

Comments
 (0)