Skip to content

Commit

Permalink
[PLA-1677] transfer balance feature (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
zlayine authored Mar 25, 2024
1 parent bfa6bd3 commit 49bc253
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 11 deletions.
15 changes: 15 additions & 0 deletions resources/js/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,19 @@ export class ApiService {

return ApiService.sendPlatformRequest(data);
}

static async transferBalance(transferBalanceData: Record<string, unknown>) {
const data = {
query: mutations.TransferBalance,
variables: {
recipient: transferBalanceData.recipient,
amount: transferBalanceData.amount,
keepAlive: transferBalanceData.keepAlive,
idempotencyKey: transferBalanceData.idempotencyKey,
skipValidation: transferBalanceData.skipValidation,
},
};

return ApiService.sendPlatformRequest(data);
}
}
2 changes: 2 additions & 0 deletions resources/js/api/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import RemoveAllAttributes from '~/graphql/mutation/RemoveAllAttributes';
import Freeze from '~/graphql/mutation/Freeze';
import Thaw from '~/graphql/mutation/Thaw';
import UpdateTransaction from '~/graphql/mutation/UpdateTransaction';
import TransferBalance from '~/graphql/mutation/TransferBalance';

import BatchMint from '~/graphql/mutation/batch/BatchMint';
import BatchTransfer from '~/graphql/mutation/batch/BatchTransfer';
Expand Down Expand Up @@ -87,6 +88,7 @@ export default {
Freeze,
Thaw,
UpdateTransaction,
TransferBalance,

BatchMint,
BatchTransfer,
Expand Down
1 change: 1 addition & 0 deletions resources/js/components/FormInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
`block flex-1 flex-shrink-0 border-0 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary text-sm leading-6 overflow-hidden transition-all disabled:bg-gray-100 ${inputClass}`,
]"
:placeholder="placeholder"
autocomplete="off"
oninput="validity.valid||(value=value.replace(/\D+/g, ''))"
@input="inputChange"
@keyup.enter="emit('submit')"
Expand Down
29 changes: 18 additions & 11 deletions resources/js/components/pages/Wallets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
<div class="px-4 sm:px-6 lg:px-8 bg-white m-4 sm:m-8 shadow rounded-lg overflow-y-auto h-full transition-all">
<div class="mt-4 flow-root">
<div class="md:-mx-6 lg:-mx-8 transition-all">
<div class="sm:py-2 sm:px-6 lg:px-8 mb-2 w-full">
<div class="flex flex-wrap gap-4">
<div class="" v-for="searchInput in searchInputs" :key="searchInput.name">
<FormInput
v-model="searchInput.value"
:name="searchInput.name"
:label="searchInput.label"
:placeholder="searchInput.placeholder"
@input-change="searchChange"
/>
<div class="flex md:flex-row flex-col-reverse justify-between">
<div class="sm:py-2 sm:px-6 lg:px-8 mb-2 w-full flex justify-between">
<div class="flex flex-wrap gap-4">
<div class="" v-for="searchInput in searchInputs" :key="searchInput.name">
<FormInput
v-model="searchInput.value"
:name="searchInput.name"
:label="searchInput.label"
:placeholder="searchInput.placeholder"
@input-change="searchChange"
/>
</div>
</div>
</div>
<div class="flex md:px-6 lg:px-8 py-2 mb-2 items-end">
<Btn primary @click="openModalSlide('TransferBalanceSlideover')"> Transfer Balance </Btn>
</div>
</div>

<LoadingContent
class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"
:is-loading="isLoading"
Expand Down Expand Up @@ -98,6 +104,7 @@ import snackbar, { events } from '~/util/snackbar';
import FormInput from '~/components/FormInput.vue';
import NoItems from '~/components/NoItems.vue';
import { TransactionState } from '~/types/types.enums';
import Btn from '../Btn.vue';
const isLoading = ref(false);
const isPaginationLoading = ref(false);
Expand Down Expand Up @@ -199,7 +206,7 @@ const getWallet = async () => {
}
};
const openModalSlide = (componentName: string, wallet) => {
const openModalSlide = (componentName: string, wallet?: any) => {
let componentPath = 'common';
slideComponent.value = { componentName, componentPath, ...wallet };
modalSlide.value = true;
Expand Down
142 changes: 142 additions & 0 deletions resources/js/components/slideovers/common/TransferBalanceSlideover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<template>
<Form
ref="formRef"
class="flex h-full flex-col divide-y divide-gray-200 bg-white shadow-xl"
:validation-schema="validation"
@submit="transfer"
>
<h3 class="text-xl font-semibold px-4 sm:px-6 py-4 text-gray-900">Transfer Balance</h3>
<div class="h-0 flex-1 overflow-y-auto">
<div class="flex flex-1 flex-col justify-between">
<div class="divide-y divide-gray-200 px-4 sm:px-6">
<div class="space-y-6 pt-6 pb-5">
<FormInput
v-model="recipient"
name="recipient"
label="Recipient"
description="The recipient account who is going to receive the transfer."
required
tooltip="Wallet Address"
/>
<FormInput
v-model="amount"
name="amount"
label="Amount"
description="The amount to transfer."
type="number"
required
:prefix="currencySymbol"
/>
<FormInput
v-if="useAppStore().advanced"
v-model="idempotencyKey"
name="idempotencyKey"
label="Idempotency Key"
description="The idempotency key to set. It is recommended to use a UUID for this."
tooltip="In mathematical and computer science terms, idempotency is a property of certain operations that can be applied repeated times without changing the initial result of the application."
readmore="Idempotency Key"
/>
<FormCheckbox
v-if="useAppStore().advanced"
v-model="keepAlive"
name="keepAlive"
label="Keep Alive"
description="If true, the transaction will fail if the balance drops below the minimum requirement. Defaults to False."
/>
<FormCheckbox
v-if="useAppStore().advanced"
v-model="skipValidation"
name="skipValidation"
label="Skip validation"
description="Skip all validation rules, use with caution. Defaults to false."
/>
</div>
</div>
</div>
</div>
<div class="flex space-x-3 flex-shrink-0 justify-end px-4 py-4">
<Btn @click="closeSlide">Cancel</Btn>
<Btn :loading="isLoading" :disabled="isLoading" primary is-submit>Transfer</Btn>
</div>
</Form>
</template>

<script setup lang="ts">
import { Form } from 'vee-validate';
import * as yup from 'yup';
import { computed, ref } from 'vue';
import FormInput from '~/components/FormInput.vue';
import FormCheckbox from '~/components/FormCheckbox.vue';
import Btn from '~/components/Btn.vue';
import { ApiService } from '~/api';
import snackbar from '~/util/snackbar';
import { currencySymbolByNetwork, formatData, formatPriceToENJ, snackbarErrors } from '~/util';
import { useAppStore } from '~/store';
import {
addressRequiredSchema,
booleanNotRequiredSchema,
numberRequiredSchema,
stringNotRequiredSchema,
} from '~/util/schemas';
const emit = defineEmits(['close']);
const isLoading = ref(false);
const recipient = ref('');
const amount = ref('');
const idempotencyKey = ref('');
const keepAlive = ref(false);
const skipValidation = ref(false);
const formRef = ref();
const currencySymbol = computed(() => currencySymbolByNetwork(useAppStore().config.network));
const validation = yup.object({
recipient: addressRequiredSchema,
amount: numberRequiredSchema.typeError('Amount must be a number').min(0),
idempotencyKey: stringNotRequiredSchema,
keepALive: booleanNotRequiredSchema,
skipValidation: booleanNotRequiredSchema,
});
const transfer = async () => {
await formRef.value?.validate();
if (!formRef.value?.getMeta().valid) return;
try {
isLoading.value = true;
const res = await ApiService.transferBalance(
formatData({
recipient: recipient.value,
amount: formatPriceToENJ(amount.value) ?? null,
keepAlive: keepAlive.value,
idempotencyKey: idempotencyKey.value,
skipValidation: skipValidation.value,
})
);
const id = res.data?.TransferBalance?.id;
if (id) {
snackbar.success({
title: 'Transfer Balance',
text: `Transfer Balance successfully with transaction id: ${id}`,
event: id,
});
closeSlide();
}
} catch (e) {
if (snackbarErrors(e)) return;
snackbar.error({
title: 'Transfer Balance',
text: 'Transfer Balance failed',
});
} finally {
isLoading.value = false;
}
};
const closeSlide = () => {
emit('close');
};
</script>
11 changes: 11 additions & 0 deletions resources/js/graphql/mutation/TransferBalance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default `mutation TransferBalance($recipient: String!, $amount: BigInt!, $keepAlive: Boolean = false, $idempotencyKey: String, $skipValidation: Boolean = false) {
TransferBalance(
recipient: $recipient
amount: $amount
keepAlive: $keepAlive
idempotencyKey: $idempotencyKey
skipValidation: $skipValidation
) {
id
}
}`;

0 comments on commit 49bc253

Please sign in to comment.