Skip to content

Commit

Permalink
feat: Collaterals popup (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
fegbert authored Apr 28, 2022
1 parent b0970c5 commit 7145a89
Show file tree
Hide file tree
Showing 14 changed files with 505 additions and 16 deletions.
10 changes: 10 additions & 0 deletions core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,13 @@ export declare interface WalletBalances {
walletVatDAI: BigNumber;
walletLastUpdatedDate: Date;
}

export declare interface CollateralStatus {
type: string;
symbol: string;
isAuthorized: boolean;
isAuthorizing: boolean;
isDepositingOrWithdrawing: boolean;
address?: string | null;
balance?: BigNumber;
}
38 changes: 38 additions & 0 deletions frontend/components/ManageCollateralTable.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { storiesOf } from '@storybook/vue';
import BigNumber from 'bignumber.js';
import ManageCollateralTable from './ManageCollateralTable';
import { generateFakeCollateralStatuses } from '~/helpers/generateFakeCollateral';

const common = {
components: { ManageCollateralTable },
data: () => ({
collateralStatuses: generateFakeCollateralStatuses(),
}),
methods: {
authorize(collateralType) {
const collateralStatus = this.collateralStatuses.find(c => c.type === collateralType);
collateralStatus.isAuthorizing = true;
setTimeout(() => {
collateralStatus.isAuthorized = true;
collateralStatus.isAuthorizing = false;
}, 1000);
},
withdraw(collateralType) {
const collateralStatus = this.collateralStatuses.find(c => c.type === collateralType);
collateralStatus.isDepositingOrWithdrawing = true;
setTimeout(() => {
collateralStatus.balance = new BigNumber(0);
collateralStatus.isDepositingOrWithdrawing = false;
}, 1000);
},
},
};

storiesOf('ManageCollateralTable', module).add('Default', () => ({
...common,
template: `<ManageCollateralTable
:collateralStatuses="collateralStatuses"
@authorizeCollateral="authorize"
@withdrawCollateral="withdraw"
/>`,
}));
132 changes: 132 additions & 0 deletions frontend/components/ManageCollateralTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<template>
<TextBlock>
<TextBlock v-if="isExplanationsShown" class="mb-2">
This is a list of collaterals supported by the Maker Protocol. Each row provides the possibility to
withdraw collateral from the VAT (if there is any) and to pre-authorize VAT transactions.
</TextBlock>
<table class="Table">
<tr class="Heading">
<th>Collateral</th>
<th>Token</th>
<th>Authorization</th>
<th>Balance</th>
</tr>
<tbody>
<tr v-for="collateralStatus of sortedCollaterals" :key="collateralStatus.type" class="Body">
<td>
<div class="flex items-center gap-2">
<CurrencyIcon :currency-symbol="collateralStatus.symbol" />
{{ collateralStatus.type }}
</div>
</td>
<td>
<span v-if="collateralStatus.address === undefined" class="opacity-50">Fetching</span>
<span v-else-if="collateralStatus.address === null" class="opacity-50">Not found</span>
<format-address v-else :value="collateralStatus.address" shorten type="address" />
</td>
<td>
<template v-if="collateralStatus.address">
<span v-if="collateralStatus.isAuthorized">Authorized</span>
<BaseButton
v-else
class="w-full"
:is-loading="collateralStatus.isAuthorizing"
@click="$emit('authorizeCollateral', collateralStatus.type)"
>
Authorize
</BaseButton>
</template>
</td>
<td>
<template v-if="collateralStatus.address">
<Tooltip :title="generateWithdrawalErrorMessage(collateralStatus)" placement="top">
<div>
<BaseButton
class="w-full"
:disabled="!canWithdrawCollateral(collateralStatus)"
:is-loading="collateralStatus.isDepositingOrWithdrawing"
@click="$emit('withdrawCollateral', collateralStatus.type)"
>
<span class="mr-1">Withdraw</span
><format-currency :value="collateralStatus.balance" />
</BaseButton>
</div>
</Tooltip>
</template>
</td>
</tr>
</tbody>
</table>
</TextBlock>
</template>

<script lang="ts">
import type { CollateralStatus } from 'auction-core/src/types';
import Vue from 'vue';
import { Tooltip } from 'ant-design-vue';
import TextBlock from '~/components/common/TextBlock.vue';
import FormatAddress from '~/components/utils/FormatAddress.vue';
import FormatCurrency from '~/components/utils/FormatCurrency.vue';
import CurrencyIcon from '~/components/common/CurrencyIcon.vue';
import BaseButton from '~/components/common/BaseButton.vue';
export default Vue.extend({
components: {
Tooltip,
TextBlock,
FormatAddress,
FormatCurrency,
CurrencyIcon,
BaseButton,
},
props: {
collateralStatuses: {
type: Array as Vue.PropType<CollateralStatus[]>,
default: () => [],
},
isExplanationsShown: {
type: Boolean,
default: true,
},
},
computed: {
sortedCollaterals() {
const statuses = this.collateralStatuses;
return statuses.sort((firstCollateral: CollateralStatus, secondCollateral: CollateralStatus) =>
firstCollateral.type.localeCompare(secondCollateral.type)
);
},
},
methods: {
canWithdrawCollateral(collateral: CollateralStatus): boolean {
return collateral.balance?.isGreaterThan(0) && collateral.isAuthorized;
},
generateWithdrawalErrorMessage(collateral: CollateralStatus): string | undefined {
if (!collateral.balance?.isGreaterThan(0)) {
return `There is no ${collateral.type} collateral to withdraw`;
}
if (!collateral.isAuthorized) {
return `The ${collateral.type} collateral needs to be authorized first`;
}
},
},
});
</script>

<style scoped>
.Table {
@apply w-full border-2 border-gray-300 dark:border-gray-600 bg-transparent;
}
.Element {
@apply p-2 h-12 border-r-2 border-b-2 border-gray-300 dark:border-gray-600;
}
.Heading > th {
@apply Element text-gray-700 dark:text-gray-100;
}
.Body > td {
@apply Element text-gray-500 dark:text-gray-300;
}
</style>
1 change: 1 addition & 0 deletions frontend/components/layout/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
@changeWalletType="$emit('changeWalletType', $event)"
@openWalletModal="$emit('openWalletModal')"
@openTermsModal="$emit('openTermsModal')"
@openManageCollateralModal="$emit('openManageCollateralModal')"
/>

<ThemeSwitcher :dark-mode="darkMode" @update="$emit('update:darkMode', $event)" />
Expand Down
49 changes: 49 additions & 0 deletions frontend/components/modals/ManageCollateralModal.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { storiesOf } from '@storybook/vue';
import BigNumber from 'bignumber.js';
import ManageCollateralModal from './ManageCollateralModal';
import { generateFakeCollateralStatuses } from '~/helpers/generateFakeCollateral';

const common = {
components: { ManageCollateralModal },
data: () => ({
isShown: true,
isExplanationsShown: true,
collateralStatuses: generateFakeCollateralStatuses(),
}),
methods: {
authorize(collateralType) {
const collateralStatus = this.collateralStatuses.find(c => c.type === collateralType);
collateralStatus.isAuthorizing = true;
setTimeout(() => {
collateralStatus.isAuthorized = true;
collateralStatus.isAuthorizing = false;
}, 1000);
},
withdraw(collateralType) {
const collateralStatus = this.collateralStatuses.find(c => c.type === collateralType);
collateralStatus.isDepositingOrWithdrawing = true;
setTimeout(() => {
collateralStatus.balance = new BigNumber(0);
collateralStatus.isDepositingOrWithdrawing = false;
}, 1000);
},
},
template: `<ManageCollateralModal
:isShown="isShown"
:collateralStatuses="collateralStatuses"
@authorizeCollateral="authorize"
@withdrawCollateral="withdraw"
/>`,
};

storiesOf('Modals/ManageCollateralModal', module)
.add('Default', () => ({
...common,
}))
.add('Expert Mode', () => ({
...common,
data: () => ({
...common.data(),
isExplanationsShown: false,
}),
}));
51 changes: 51 additions & 0 deletions frontend/components/modals/ManageCollateralModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<modal
:visible="isShown"
:footer="null"
:class="{ dark: isDarkMode }"
title="Collaterals in VAT"
:dialog-style="{ top: '60px' }"
:width="620"
destroy-on-close
@cancel="$emit('cancel')"
>
<ManageCollateralTable
class="p-4"
:is-explanations-shown="isExplanationsShown"
:collateral-statuses="collateralStatuses"
@authorizeCollateral="$emit('authorizeCollateral', $event)"
@withdrawCollateral="$emit('withdrawCollateral', $event)"
/>
</modal>
</template>

<script lang="ts">
import Vue from 'vue';
import { Modal } from 'ant-design-vue';
import ManageCollateralTable from '../ManageCollateralTable.vue';
export default Vue.extend({
components: {
Modal,
ManageCollateralTable,
},
props: {
isShown: {
type: Boolean,
default: false,
},
isDarkMode: {
type: Boolean,
default: false,
},
isExplanationsShown: {
type: Boolean,
default: true,
},
collateralStatuses: {
type: Array as Vue.PropType<CollateralStatus[]>,
default: () => [],
},
},
});
</script>
1 change: 1 addition & 0 deletions frontend/components/utils/WalletSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export default Vue.extend({
menuOptions(): SelectOption[] {
return [
{ label: 'Manage Wallet', value: 'openWalletModal' },
{ label: 'Manage Collaterals', value: 'openManageCollateralModal' },
{ label: 'Disconnect', value: 'changeWalletType' },
];
},
Expand Down
68 changes: 68 additions & 0 deletions frontend/containers/ManageCollateralModalContainer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<ManageCollateralModal
:is-shown="isManageCollateralModalShown"
:is-dark-mode="isDarkMode"
:is-explanations-shown="isExplanationsShown"
:collateral-statuses="collateralStatuses"
@authorizeCollateral="authorize"
@withdrawCollateral="withdraw"
@cancel="setManageCollateralModal(false)"
/>
</template>

<script lang="ts">
import Vue from 'vue';
import { mapActions, mapGetters } from 'vuex';
import ManageCollateralModal from '~/components/modals/ManageCollateralModal.vue';
export default Vue.extend({
name: 'ManageCollateralModalContainer',
components: { ManageCollateralModal },
computed: {
...mapGetters('collaterals', {
collateralStatuses: 'collateralStatuses',
}),
...mapGetters('modals', {
isManageCollateralModalShown: 'getManageCollateralModal',
}),
isExplanationsShown: {
get() {
return this.$store.getters['preferences/getIsExplanationsShown'];
},
set(newIsExplanationsShown) {
this.$store.dispatch('preferences/setExplanationsAction', newIsExplanationsShown);
},
},
isDarkMode: {
get(): Boolean {
return this.$store.getters['preferences/getIsDarkMode'];
},
set(newIsDarkMode) {
this.$store.dispatch('preferences/setIsDarkMode', newIsDarkMode);
},
},
},
watch: {
isManageCollateralModalShown: {
immediate: true,
handler(isShown) {
if (isShown) {
this.$store.dispatch('collaterals/fetchCollateralStatuses');
}
},
},
},
methods: {
...mapActions('wallet', ['withdrawAllCollateralFromVat']),
setManageCollateralModal(open: boolean): void {
this.$store.commit('modals/setManageCollateralModal', open);
},
async authorize(collateralType: string) {
await this.$store.dispatch('authorizations/authorizeCollateral', collateralType);
},
async withdraw(collateralType: string) {
await this.$store.dispatch('wallet/withdrawAllCollateralFromVat', collateralType);
},
},
});
</script>
Loading

0 comments on commit 7145a89

Please sign in to comment.