Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add network filter to top collection #8817

Merged
merged 12 commits into from
Jan 3, 2024
46 changes: 39 additions & 7 deletions components/common/ChainDropdown.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
<template>
<div>
<NeoDropdown>
<NeoDropdown :position="position" :mobile-modal="mobileModal">
<template #trigger="{ active }">
<NeoButton
class="chain-dropdown-text"
:label="isMobile ? selected?.text : `Network: ${selected?.text}`"
:label="
isMobile || !showNetworkLabel
? selected?.text
: `Network: ${selected?.text}`
"
:icon="active ? 'chevron-up' : 'chevron-down'"
:active="active" />
</template>

<NeoDropdownItem
v-for="chain in availableChains"
:key="chain.value"
:active="route.params.prefix === chain.value"
:active="prefix === chain.value"
@click="onSwitchChain(chain.value)">
{{ chain.text }}
</NeoDropdownItem>
Expand All @@ -22,19 +26,47 @@

<script setup lang="ts">
import { NeoButton, NeoDropdown, NeoDropdownItem } from '@kodadot1/brick'
import { type Prefix } from '@kodadot1/static'

const props = withDefaults(
defineProps<{
showNetworkLabel: boolean
position?: 'bottom-left'
redirect?: boolean
mobileModal?: boolean
exclude: Prefix[]
}>(),
{
showNetworkLabel: true,
position: undefined,
redirect: true,
mobileModal: false,
exclude: () => [],
},
)

const route = useRoute()
const { setUrlPrefix } = usePrefix()
const { availableChains } = useChain()
const { setUrlPrefix, urlPrefix } = usePrefix()
const { availableChains: allChains } = useChain()
const { redirectAfterChainChange } = useChainRedirect()
const { isMobile } = useViewport()

const prefix = computed(() => route.params.prefix || urlPrefix.value)

const selected = computed(() =>
availableChains.value.find((chain) => chain.value === route.params.prefix),
allChains.value.find((chain) => chain.value === prefix.value),
)

const availableChains = computed(() =>
allChains.value.filter(
(chain) => !props.exclude.includes(chain.value as Prefix),
),
)

function onSwitchChain(chain) {
setUrlPrefix(chain)
redirectAfterChainChange(chain)
if (props.redirect) {
redirectAfterChainChange(chain)
}
}
</script>
61 changes: 34 additions & 27 deletions components/landing/topCollections/TopCollections.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,46 @@
:label="`${$t(`topCollections.timeFrames.${label}`)}`"
@click="setTimeRange(value)" />
</div>
<div></div>
</div>

<div class="top-collections-grid mb-5">
<div v-for="(collection, index) in data" :key="index">
<TopCollectionsItem
:collection="collection"
:index="index + 1"
:time-range="state.timeRange" />
<div class="pt-2">
<ChainDropdown
position="bottom-left"
:show-network-label="false"
:redirect="false"
:exclude="['ksm']"
mobile-modal />
</div>
</div>

<div v-if="loading" class="top-collections-grid">
<div
v-for="index in limit"
:key="index"
class="top-collections-item py-2 flex items-center justify-between">
<div class="flex items-center">
<div class="p-4 has-text-weight-bold">
{{ index }}
<div class="top-collections-grid my-5">
<template v-if="loading">
<div
v-for="index in limit"
:key="index"
class="top-collections-item py-2 flex items-center justify-between">
<div class="flex items-center">
<div class="p-4 has-text-weight-bold">
{{ index }}
</div>
<div>
<BasicImage custom-class="is-48x48 image-outline" rounded />
</div>
</div>
<div>
<BasicImage custom-class="is-48x48 image-outline" rounded />
<div class="px-2" style="width: 60%">
<NeoSkeleton width="70%" />
<NeoSkeleton width="20%" size="small" />
</div>
<div class="is-pulled-right has-text-right px-4" style="width: 20%">
<NeoSkeleton width="80%" position="right" />
<NeoSkeleton width="70%" size="small" position="right" />
</div>
</div>
<div class="px-2" style="width: 60%">
<NeoSkeleton width="70%" />
<NeoSkeleton width="20%" size="small" />
</div>
<div class="is-pulled-right has-text-right px-4" style="width: 20%">
<NeoSkeleton width="80%" position="right" />
<NeoSkeleton width="70%" size="small" position="right" />
</div>
</template>

<div v-for="(collection, index) in data" v-else :key="collection.id">
<TopCollectionsItem
:collection="collection"
:index="index + 1"
:time-range="state.timeRange" />
</div>
</div>

Expand Down
65 changes: 39 additions & 26 deletions components/landing/topCollections/utils/useTopCollections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,48 +52,61 @@ export const useTopCollections = (limit: number) => {
'topCollectionWithVolumeList',
() => [],
)
const error = ref(null)
// const loading = ref(false)
const loading = ref(true)
const collectionsSalesResults = ref<CollectionsSalesResult>()
const { result: topCollections, loading } = useQuery(
isAssetHub.value ? topCollectionsListAh : topCollectionList,
{ orderBy: 'volume_DESC', limit },
{ clientId: client.value },
)

watch([topCollections, error], () => {
if (error.value) {
loading.value = false
return
}
const {
data: topCollections,
pending: topCollectionLoading,
refresh,
} = useAsyncData('topCollections', async () => {
const { data } = await useAsyncQuery<TopCollectionListResult>({
query: isAssetHub.value ? topCollectionsListAh : topCollectionList,
variables: { orderBy: 'volume_DESC', limit },
clientId: client.value,
})
return data.value
})

watch([topCollections], async () => {
if (topCollections.value) {
const ids = (
topCollections.value as TopCollectionListResult
).collectionEntities.map((c) => c.id)
const ids = topCollections.value.collectionEntities.map((c) => c.id)

const { onResult } = useQuery(
collectionsSales,
{ ids },
{ clientId: client.value },
)
onResult((result) => (collectionsSalesResults.value = result.data))
const { data } = await useAsyncQuery<CollectionsSalesResult>({
query: collectionsSales,
variables: { ids },
clientId: client.value,
})

topCollectionWithVolumeList.value = []
collectionsSalesResults.value = data.value
}
})

watch(collectionsSalesResults, () => {
if (collectionsSalesResults.value) {
const collectionsList = (topCollections.value as TopCollectionListResult)
.collectionEntities
if (
collectionsSalesResults.value &&
topCollections.value?.collectionEntities.length
) {
topCollectionWithVolumeList.value = proccessData(
collectionsList,
topCollections.value.collectionEntities,
collectionsSalesResults.value.collectionsSales,
)

loading.value = false
}
})

watch(topCollectionLoading, (value) => {
if (value) {
loading.value = true
}
})

watch(urlPrefix, () => refresh())

return {
data: topCollectionWithVolumeList,
error,
loading,
}
}