Skip to content

Commit

Permalink
[idea] 1100 release (#1478)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitayutanov authored Jan 30, 2024
1 parent 6282c62 commit 83434bc
Show file tree
Hide file tree
Showing 106 changed files with 1,769 additions and 699 deletions.
11 changes: 6 additions & 5 deletions idea/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
"version": "0.1.2",
"private": true,
"scripts": {
"start": "vite --open",
"start": "vite --open --port 3000",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@gear-js/api": "0.35.2",
"@gear-js/api": "0.36.2",
"@gear-js/react-hooks": "workspace:^",
"@gear-js/ui": "workspace:^",
"@hcaptcha/react-hcaptcha": "1.8.1",
"@hookform/resolvers": "3.3.2",
"@polkadot/api": "10.10.1",
"@polkadot/api": "10.11.2",
"@polkadot/extension-dapp": "0.46.5",
"@polkadot/react-identicon": "3.6.3",
"@polkadot/types": "10.10.1",
"@polkadot/types": "10.11.2",
"@polkadot/util": "12.5.1",
"@react-aria/utils": "3.21.0",
"bignumber.js": "9.1.2",
Expand All @@ -38,7 +38,8 @@
"react-router-dom": "6.16.0",
"react-transition-group": "4.4.5",
"simplebar-react": "3.2.4",
"yup": "1.3.2"
"yup": "1.3.2",
"zod": "3.22.4"
},
"devDependencies": {
"@types/lodash.isequal": "4.5.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FormProvider, useForm } from 'react-hook-form';
import * as yup from 'yup';

import CloseSVG from '@/shared/assets/images/actions/close.svg?react';
import { FormInput, ValueField } from '@/shared/ui/form';
import { Input, ValueField } from '@/shared/ui/form';
import { isAccountAddressValid } from '@/shared/helpers';
import { useBalanceTransfer } from '@/hooks';

Expand Down Expand Up @@ -53,7 +53,7 @@ const TransferBalanceModal = ({ close }: Props) => {
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(handleSubmit)}>
<div className={styles.inputs}>
<FormInput name="address" label="Address" direction="y" block />
<Input name="address" label="Address" direction="y" block />
<ValueField name="value" label="Value:" direction="y" block />
<Checkbox label="Keep Alive" {...register('keepAlive')} />
</div>
Expand Down
16 changes: 14 additions & 2 deletions idea/frontend/src/features/formPayload/ui/FormPayload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@ type Props = {
values?: FormPayloadValues;
};

// TODO: temp solution to unregister manual payload on unmount,
// since on metadata change it's messing with default payload values
function ManualPayloadTextarea({ name }: { name: string }) {
const { register, unregister } = useFormContext();

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => () => unregister(name), []);

return <Textarea id={name} rows={15} placeholder="// Enter your payload here" block {...register(name)} />;
}

const FormPayload = ({ name, label, values, direction = 'x', gap }: Props) => {
const alert = useAlert();
const { setValue, register } = useFormContext();
const { setValue } = useFormContext();

const jsonManualPayload = useRef<string>();

Expand Down Expand Up @@ -101,7 +112,8 @@ const FormPayload = ({ name, label, values, direction = 'x', gap }: Props) => {
<PayloadStructure levelName={name} typeStructure={values.typeStructure} />
) : (
<>
<Textarea id={name} rows={15} placeholder="// Enter your payload here" block {...register(name)} />
<ManualPayloadTextarea name={name} />

{values && (
<FileInput
value={manualPayloadFile}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import styles from './program-card.module.scss';

type Props = {
program: IProgram | LocalProgram;
vertical?: Boolean;
vertical?: boolean;
};

const ProgramCard = memo(({ program, vertical }: Props) => {
Expand Down
19 changes: 19 additions & 0 deletions idea/frontend/src/features/voucher/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { isAccountAddressValid } from '@/shared/helpers';
import { decodeAddress } from '@gear-js/api';
import { z } from 'zod';

const DEFAULT_VALUES = {
address: '',
value: '',
duration: '',
isCodeUploadEnabled: false,
};

const ADDRESS_SCHEMA = z
.string()
.trim()
.min(0)
.refine((value) => isAccountAddressValid(value), 'Invalid address')
.transform((value) => decodeAddress(value));

export { DEFAULT_VALUES, ADDRESS_SCHEMA };
4 changes: 3 additions & 1 deletion idea/frontend/src/features/voucher/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useIssueVoucher } from './use-issue-voucher';
import { useBalanceSchema } from './use-balance-schema';
import { useDurationSchema } from './use-duration-schema';

export { useIssueVoucher };
export { useIssueVoucher, useBalanceSchema, useDurationSchema };
28 changes: 28 additions & 0 deletions idea/frontend/src/features/voucher/hooks/use-balance-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useApi, useBalanceFormat } from '@gear-js/react-hooks';
import { z } from 'zod';

function useBalanceSchema() {
const { api } = useApi();
const { getChainBalanceValue, getFormattedBalanceValue } = useBalanceFormat();

const getBalanceSchema = () => {
if (!api) throw new Error('API is not initialized');

const decimals = api.registry.chainDecimals.toString();
const existentialDeposit = api.existentialDeposit.toString();

const minValueMessage = `Minimum value is ${getFormattedBalanceValue(existentialDeposit).toFixed()}`;
const integerMessage = `Maximum amount of decimal places is ${decimals}`;

return z
.string()
.transform((value) => getChainBalanceValue(value))
.refine((value) => value.isGreaterThanOrEqualTo(existentialDeposit), minValueMessage)
.refine((value) => value.isInteger(), integerMessage)
.transform((value) => value.toFixed());
};

return getBalanceSchema();
}

export { useBalanceSchema };
18 changes: 18 additions & 0 deletions idea/frontend/src/features/voucher/hooks/use-duration-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useApi } from '@gear-js/react-hooks';
import { z } from 'zod';

function useDurationSchema() {
const { api } = useApi();

const getDurationSchema = () => {
if (!api) throw new Error('API is not initialized');

const { minDuration, maxDuration } = api.voucher;

return z.coerce.number().min(minDuration).max(maxDuration).int();
};

return getDurationSchema();
}

export { useDurationSchema };
34 changes: 31 additions & 3 deletions idea/frontend/src/features/voucher/hooks/use-issue-voucher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,39 @@ function useIssueVoucher() {
if (status.isInvalid) alert.error(PROGRAM_ERRORS.INVALID_TRANSACTION);
};

const issueVoucher = async (address: HexString, programId: HexString, value: string, onSuccess: () => void) => {
const issueVoucher = async (
address: HexString,
programId: HexString,
value: string,
duration: number,
isCodeUploadEnabled: boolean,
onSuccess: () => void,
) => {
if (!isApiReady || !account) return;

try {
const { extrinsic } = api.voucher.issue(address, programId, value);
const programs = [programId];

const { extrinsic } = await api.voucher.issue(address, value, duration, programs, isCodeUploadEnabled);

const { signer } = await web3FromSource(account.meta.source);

extrinsic.signAndSend(account.address, { signer }, (events) => handleEvents(events, onSuccess));
} catch (error) {
if (error instanceof Error) alert.error(error.message);
}
};

const issueVoucherDeprecated = async (
address: HexString,
programId: HexString,
value: string,
onSuccess: () => void,
) => {
if (!isApiReady || !account) return;

try {
const { extrinsic } = api.voucher.issueDeprecated(address, programId, value);

const { signer } = await web3FromSource(account.meta.source);

Expand All @@ -49,7 +77,7 @@ function useIssueVoucher() {
}
};

return issueVoucher;
return { issueVoucher, issueVoucherDeprecated };
}

export { useIssueVoucher };
18 changes: 16 additions & 2 deletions idea/frontend/src/features/voucher/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
import { IssueVoucher, UseVoucherCheckbox, VoucherTable, VoucherBadge } from './ui';
import {
IssueVoucher,
VoucherSelect,
VoucherTable,
VoucherBadge,
UseVoucherCheckboxDeprecated,
VoucherTableDeprecated,
} from './ui';

export { IssueVoucher, UseVoucherCheckbox, VoucherTable, VoucherBadge };
export {
IssueVoucher,
VoucherSelect,
VoucherTable,
VoucherBadge,
UseVoucherCheckboxDeprecated,
VoucherTableDeprecated,
};
14 changes: 11 additions & 3 deletions idea/frontend/src/features/voucher/ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { IssueVoucher } from './issue-voucher';
import { UseVoucherCheckbox } from './use-voucher-checkbox';
import { VoucherTable } from './voucher-table';
import { VoucherSelect } from './voucher-select';
import { VoucherTable, VoucherTableDeprecated } from './voucher-table';
import { VoucherBadge } from './voucher-badge';
import { UseVoucherCheckboxDeprecated } from './use-voucher-checkbox-deprecated';

export { IssueVoucher, UseVoucherCheckbox, VoucherTable, VoucherBadge };
export {
IssueVoucher,
VoucherSelect,
VoucherTable,
VoucherBadge,
UseVoucherCheckboxDeprecated,
VoucherTableDeprecated,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Button, Modal } from '@gear-js/ui';
import { HexString, decodeAddress } from '@gear-js/api';
import { useBalanceFormat } from '@gear-js/react-hooks';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form';
import * as yup from 'yup';

import ApplySVG from '@/shared/assets/images/actions/apply.svg?react';
import CloseSVG from '@/shared/assets/images/actions/close.svg?react';
import { isAccountAddressValid } from '@/shared/helpers';
import { Input, ValueField } from '@/shared/ui/form';

import { useIssueVoucher } from '../../hooks';
import styles from './issue-voucher-modal.module.scss';

type Props = {
programId: HexString;
close: () => void;
};

const defaultValues = { address: '', value: '' };

const schema = yup.object().shape({
address: yup
.string()
.test('is-address-valid', 'Invalid address', isAccountAddressValid)
.required('This field is required'),
value: yup.string().required('This field is required'),
});

const resolver = yupResolver(schema);

const IssueVoucherModalDeprecated = ({ programId, close }: Props) => {
const { getChainBalanceValue } = useBalanceFormat();
const { issueVoucherDeprecated } = useIssueVoucher();

const methods = useForm({ defaultValues, resolver });

const handleSubmit = ({ address, value }: typeof defaultValues) => {
const decodedAddress = decodeAddress(address);
const chainValue = getChainBalanceValue(value).toFixed();

issueVoucherDeprecated(decodedAddress, programId, chainValue, close);
};

return (
<Modal heading="Create Voucher" size="large" close={close}>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(handleSubmit)} className={styles.form}>
<Input name="address" label="Account address" direction="y" block />
<ValueField name="value" label="Tokens amount:" direction="y" block />

<div className={styles.buttons}>
<Button type="submit" icon={ApplySVG} size="large" text="Create" />
<Button icon={CloseSVG} color="light" size="large" text="Close" onClick={close} />
</div>
</form>
</FormProvider>
</Modal>
);
};

export { IssueVoucherModalDeprecated };
Loading

0 comments on commit 83434bc

Please sign in to comment.