Skip to content

Commit

Permalink
feature/dashboard page (#59)
Browse files Browse the repository at this point in the history
* feature dashboard page

* wallet balance fix

* Update yarn.lock

* fixes after review
  • Loading branch information
Sorizen committed Aug 16, 2024
1 parent 0f68a0f commit 7491060
Show file tree
Hide file tree
Showing 29 changed files with 3,427 additions and 209 deletions.
855 changes: 855 additions & 0 deletions src/abi/MOR1967.json

Large diffs are not rendered by default.

128 changes: 69 additions & 59 deletions src/common/InfoDashboard/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,57 @@
<div class="info-dashboard" :class="{ 'info-dashboard--loading': isLoading }">
<transition name="fade" mode="out-in">
<div v-if="web3ProvidersStore.isConnected" class="info-dashboard__wrp">
<div class="info-dashboard__header">
<div class="info-dashboard__header-title-wrp">
<h5 class="info-dashboard__header-title">
{{ chartTitle }}
</h5>
<app-icon
v-tooltip="$t('info-dashboard.header-note')"
class="info-dashboard__header-title-icon"
:name="$icons.exclamationCircle"
/>
</div>
<div class="info-dashboard__header-buttons">
<app-button
class="info-dashboard__header-button"
scheme="filled"
color="secondary"
size="none"
:disabled="chartType === CHART_TYPE.circulingSupply"
:icon-left="$icons.arrowLeft"
@click="changeChartType(CHART_TYPE.circulingSupply)"
/>
<app-button
class="info-dashboard__header-button"
scheme="filled"
color="secondary"
size="none"
:disabled="chartType === CHART_TYPE.earnedMor"
:icon-left="$icons.arrowLeft"
@click="changeChartType(CHART_TYPE.earnedMor)"
/>
<template v-if="isChartShown">
<div class="info-dashboard__header">
<div class="info-dashboard__header-title-wrp">
<h5 class="info-dashboard__header-title">
{{ chartTitle }}
</h5>
<app-icon
v-tooltip="$t('info-dashboard.header-note')"
class="info-dashboard__header-title-icon"
:name="$icons.exclamationCircle"
/>
</div>
<div class="info-dashboard__header-buttons">
<app-button
class="info-dashboard__header-button"
scheme="filled"
color="secondary"
size="none"
:disabled="chartType === CHART_TYPE.circulingSupply"
:icon-left="$icons.arrowLeft"
@click="changeChartType(CHART_TYPE.circulingSupply)"
/>
<app-button
class="info-dashboard__header-button"
scheme="filled"
color="secondary"
size="none"
:disabled="chartType === CHART_TYPE.earnedMor"
:icon-left="$icons.arrowLeft"
@click="changeChartType(CHART_TYPE.earnedMor)"
/>
</div>
</div>
</div>
<div class="info-dashboard__app-chart-wrp">
<div class="info-dashboard__app-chart-desc">
<p class="info-dashboard__header-subtitle">
{{ chartSubtitle }}
</p>
<select-field
v-model="selectedMonth"
scheme="secondary"
:value-options="monthOptions"
<div class="info-dashboard__app-chart-wrp">
<div class="info-dashboard__app-chart-desc">
<p class="info-dashboard__header-subtitle">
{{ chartSubtitle }}
</p>
<select-field
v-model="selectedMonth"
scheme="secondary"
:value-options="monthOptions"
/>
</div>
<app-chart
class="info-dashboard__app-chart"
:config="chartConfig"
:is-loading="isLoading || isChartDataUpdating"
/>
</div>
<app-chart
class="info-dashboard__app-chart"
:config="chartConfig"
:is-loading="isLoading || isChartDataUpdating"
/>
</div>
</template>
<ul v-if="indicators?.length" class="info-dashboard__indicators">
<li
v-for="(indicator, idx) in indicators"
Expand Down Expand Up @@ -116,6 +118,9 @@ import AppIcon from '../AppIcon.vue'
import AppChart from '../AppChart.vue'
import ConnectWalletButton from '../ConnectWalletButton.vue'
import { AppButton } from '@/common'
import { ROUTE_NAMES } from '@/enums'
import { useRoute } from 'vue-router'
import { errors } from '@/errors'
enum CHART_TYPE {
circulingSupply = 'circulating-supply',
Expand All @@ -141,22 +146,15 @@ const props = withDefaults(
)
const { t } = useI18n()
const route = useRoute()
const web3ProvidersStore = useWeb3ProvidersStore()
const chartType = ref(CHART_TYPE.circulingSupply)
const chartTitle = computed(() =>
chartType.value === CHART_TYPE.circulingSupply
? t('info-dashboard.header-supply-title')
: t('info-dashboard.header-earned-title'),
)
const isChartDataUpdating = ref(false)
const chartSubtitle = computed(() =>
chartType.value === CHART_TYPE.circulingSupply
? t('info-dashboard.header-supply-subtitle')
: t('info-dashboard.header-earned-subtitle'),
)
const chartConfig = reactive<ChartConfig>({ ...CHART_CONFIG })
const monthOptions = computed<FieldOption<number>[]>(() => {
const allMonthOptions = Array.from({ length: 12 }).map((_, idx) => ({
Expand All @@ -172,9 +170,21 @@ const monthOptions = computed<FieldOption<number>[]>(() => {
const selectedMonth = ref(monthOptions.value[monthOptions.value.length - 1])
const isChartDataUpdating = ref(false)
const chartTitle = computed(() =>
chartType.value === CHART_TYPE.circulingSupply
? t('info-dashboard.header-supply-title')
: t('info-dashboard.header-earned-title'),
)
const chartConfig = reactive<ChartConfig>({ ...CHART_CONFIG })
const chartSubtitle = computed(() =>
chartType.value === CHART_TYPE.circulingSupply
? t('info-dashboard.header-supply-subtitle')
: t('info-dashboard.header-earned-subtitle'),
)
const isChartShown = computed(
() => route.name !== ROUTE_NAMES.appDashboardCapital,
)
const updateSupplyChartData = async (month: number) => {
const chartData = await getChartData(
Expand Down Expand Up @@ -221,7 +231,7 @@ const updateChartData = async (month: number) => {
isChartDataUpdating.value = true
try {
if (!props.poolData) throw new Error('poolData unavailable')
if (!props.poolData) throw new errors.PoolDataNotFoundError()
chartType.value === CHART_TYPE.circulingSupply
? await updateSupplyChartData(month)
Expand Down
39 changes: 22 additions & 17 deletions src/common/WalletBalances.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ import { useWeb3ProvidersStore } from '@/store'
import { formatEther } from '@/utils'
import { onClickOutside } from '@vueuse/core'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { errors } from '@/errors'
import AppIcon from './AppIcon.vue'
type Balance = {
logoIconName: ICON_NAMES
value: string
tokenIconName: ICON_NAMES
}
let _morUpdateIntervalId: Parameters<typeof clearInterval>[0]
let _morUpdateIntervalId: NodeJS.Timeout
const rootElement = ref<HTMLDivElement | null>(null)
const isDropMenuShown = ref(false)
Expand All @@ -80,15 +80,19 @@ const web3ProvidersStore = useWeb3ProvidersStore()
const balances = computed<Balance[]>(() => [
{
logoIconName: ICON_NAMES.steth,
value: web3ProvidersStore.balances.stEth
? `${formatEther(web3ProvidersStore.balances.stEth)} stETH`
value: web3ProvidersStore.balances.depositToken
? `${formatEther(web3ProvidersStore.balances.depositToken)} ${
web3ProvidersStore.depositTokenSymbol
}`
: '',
tokenIconName: ICON_NAMES.ethereum,
},
{
logoIconName: ICON_NAMES.morpheus,
value: web3ProvidersStore.balances.mor
? `${formatEther(web3ProvidersStore.balances.mor)} MOR`
value: web3ProvidersStore.balances.rewardsToken
? `${formatEther(web3ProvidersStore.balances.rewardsToken)} ${
web3ProvidersStore.rewardsTokenSymbol
}`
: '',
tokenIconName: ICON_NAMES.arbitrum,
},
Expand All @@ -104,19 +108,21 @@ const onSelectBtnClick = (balanceIdx: number) => {
isDropMenuShown.value = false
}
const updateBalances = async (): Promise<void> => {
const updateBalances = async () => {
if (!web3ProvidersStore.provider.selectedAddress)
throw new Error('user address unavailable')
const address = web3ProvidersStore.provider.selectedAddress
throw new errors.UserAddressError()
const [stEthValue, morValue] = await Promise.all([
web3ProvidersStore.stEthContract.providerBased.value.balanceOf(address),
web3ProvidersStore.morContract.providerBased.value.balanceOf(address),
web3ProvidersStore.depositContract.providerBased.value.balanceOf(
web3ProvidersStore.provider.selectedAddress,
),
web3ProvidersStore.rewardsContract.providerBased.value.balanceOf(
web3ProvidersStore.provider.selectedAddress,
),
])
web3ProvidersStore.balances.stEth = stEthValue
web3ProvidersStore.balances.mor = morValue
web3ProvidersStore.balances.depositToken = stEthValue
web3ProvidersStore.balances.rewardsToken = morValue
}
const init = async (): Promise<void> => {
Expand Down Expand Up @@ -164,8 +170,8 @@ onMounted(() => {
const address = web3ProvidersStore.provider.selectedAddress
try {
web3ProvidersStore.balances.mor =
await web3ProvidersStore.morContract.providerBased.value.balanceOf(
web3ProvidersStore.balances.rewardsToken =
await web3ProvidersStore.rewardsContract.providerBased.value.balanceOf(
address,
)
} catch (error) {
Expand All @@ -181,7 +187,6 @@ onBeforeUnmount(() => {
clearInterval(_morUpdateIntervalId)
})
watch(() => web3ProvidersStore.provider.selectedAddress, onChangeBalances)
watch(() => web3ProvidersStore.networkId, init)
</script>
Expand Down
6 changes: 3 additions & 3 deletions src/common/modals/compositions/ChangeLockModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<script lang="ts" setup>
import BasicModal from '../BasicModal.vue'
import { DatetimeField } from '@/fields'
import { computed, reactive, ref, watch } from 'vue'
import { computed, reactive, ref, toRef, watch } from 'vue'
import { minValue } from '@/validators'
import { Time } from '@/utils'
import { useFormValidation, useI18n, usePool } from '@/composables'
Expand Down Expand Up @@ -84,7 +84,7 @@ const {
expectedRewardsMultiplier,
userPoolData,
fetchExpectedMultiplier,
} = usePool(props.poolId)
} = usePool(toRef(props.poolId))
const web3ProvidersStore = useWeb3ProvidersStore()
Expand Down Expand Up @@ -187,7 +187,7 @@ watch(
watch(
() => [props.isShown, userPoolData.value?.claimLockEnd],
() => {
form.lockPeriod = String(userPoolData.value?.claimLockEnd.toNumber() || '')
form.lockPeriod = String(userPoolData.value?.claimLockEnd?.toNumber() || '')
},
)
</script>
Expand Down
3 changes: 2 additions & 1 deletion src/composables/use-contract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { factories, type Provider } from '@/types'
import { providers } from 'ethers'
import { computed, unref, type ComputedRef, type MaybeRef } from 'vue'
import { errors } from '@/errors'

type ContractFactoryKey = keyof typeof factories
type ContractFactoryClass<K extends ContractFactoryKey = ContractFactoryKey> =
Expand Down Expand Up @@ -50,7 +51,7 @@ export function useContract<K extends ContractFactoryKey = ContractFactoryKey>(
{},
{
get: () => {
throw new Error('FallbackProvider does not have a signer')
throw new errors.FallbackProviderError()
},
},
) as Contract<K>
Expand Down
5 changes: 2 additions & 3 deletions src/composables/use-form-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import useVuelidate, {
} from '@vuelidate/core'
import get from 'lodash/get'
import { ComputedRef, UnwrapNestedRefs, computed, unref } from 'vue'
import { errors } from '@/errors'

export interface FormValidation {
getFieldErrorMessage: (fieldPath: string) => string
Expand Down Expand Up @@ -46,9 +47,7 @@ export const useFormValidation = (
const field = get(validationController.value, fieldPath)

if (!field || !Object.keys(field).length) {
throw new Error(
`getFieldErrorMessage: Cannot find vuelidate field by '${fieldPath}'`,
)
throw new errors.FieldNotFoundError()
}

if (!field.$dirty) errorMessage = ''
Expand Down
Loading

0 comments on commit 7491060

Please sign in to comment.