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

refactor: Identity - Vue Composition API #3771

Merged
merged 24 commits into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0ca1062
refactor identitypopover
preschian Aug 18, 2022
cacddac
refactor identity to composition api
preschian Aug 18, 2022
a3cb004
fix deepscan
preschian Aug 18, 2022
cdf8759
fix deepscan again
preschian Aug 18, 2022
b40ac57
use provide/inject in IdentityPopover
preschian Aug 19, 2022
872ecb6
rename
preschian Aug 19, 2022
2563841
Merge branch 'main' of github.com:preschian/nft-gallery into refactor…
preschian Aug 19, 2022
4c49049
rename back
preschian Aug 19, 2022
60c3370
identity composables
preschian Aug 20, 2022
7adb86a
fix deepsource
preschian Aug 20, 2022
abf204f
codeclimate useIdentity
preschian Aug 20, 2022
fc2b85d
Merge branch 'main' of github.com:preschian/nft-gallery into refactor…
preschian Aug 20, 2022
f6d8833
codeclimate useIdentityStats
preschian Aug 20, 2022
4f0d094
address required and hide on mobile
preschian Aug 20, 2022
825f4e9
remove unused stats.value
preschian Aug 20, 2022
ff40f52
add emit @change
preschian Aug 21, 2022
dbaaf95
fix review, auto imports composables
preschian Aug 22, 2022
9ca9fe0
remove unused props
preschian Aug 23, 2022
f86c898
Merge branch 'main' into refactor-identity-composition-api
preschian Aug 23, 2022
0eb2a58
Merge branch 'main' of github.com:preschian/nft-gallery into refactor…
preschian Aug 24, 2022
ecc0c84
Merge branch 'main' of github.com:preschian/nft-gallery into refactor…
preschian Aug 25, 2022
12303c4
move folder under components
preschian Aug 25, 2022
293b4b4
rename to queryName for useGraphql
preschian Aug 25, 2022
ea15a54
Merge branch 'main' into refactor-identity-composition-api
yangwao Aug 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion components/rmrk/Profile/ProfileLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
:route="`/${urlPrefix}/u`"
:param="address"
link="u">
<Identity :address="address" :inline="true" :vertical-align="true" />
<Identity
v-if="address"
:address="address"
:inline="true"
:vertical-align="true" />
<template #extra>
<Avatar :size="24" :value="address" class="mr-2" />
</template>
</LinkResolver>
<template v-if="showTwitter">
<Identity
v-if="address"
:address="address"
:show-twitter="showTwitter"
:show-discord="showDiscord"
Expand Down
37 changes: 16 additions & 21 deletions components/shared/identity/IdentityChain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
src="/infinity.svg"
class="ml-1 infinity-loader" />
<template v-else>
<span v-if="identity.display" class="ml-1"
>({{ identity.display }})</span
>
<span v-if="identity?.display" class="ml-1">
({{ identity?.display }})
</span>
</template>
</span>
<template v-else-if="!hideIdentityPopover">
Expand All @@ -27,30 +27,25 @@
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
<script lang="ts" setup>
import { GenericAccountId } from '@polkadot/types/generic/AccountId'

import { emptyObject } from '@/utils/empty'

type IdentityFields = Record<string, string>
type Address = string | GenericAccountId | undefined

const components = {
IdentityPopover: () =>
import('@/components/shared/identity/popover/IdentityPopover.vue'),
}
const IdentityPopover = defineAsyncComponent(
() => import('@/components/shared/identity/popover/IdentityPopover.vue')
)

@Component({ components })
export default class IdentityChain extends Vue {
@Prop() readonly showOnchainIdentity!: boolean
@Prop() readonly hideIdentityPopover!: boolean
@Prop() readonly isFetchingIdentity!: boolean
@Prop({ default: emptyObject<IdentityFields>() }) readonly identity
@Prop() readonly address!: Address
@Prop() readonly shortenedAddress!: Address
@Prop() readonly name!: Address
}
defineProps<{
showOnchainIdentity?: boolean
hideIdentityPopover?: boolean
isFetchingIdentity?: boolean
identity?: IdentityFields
address?: Address
shortenedAddress?: string
name?: string | object
}>()
</script>

<style scoped>
Expand Down
186 changes: 40 additions & 146 deletions components/shared/identity/IdentityIndex.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<template>
<component
:is="is"
<div
vikiival marked this conversation as resolved.
Show resolved Hide resolved
v-if="
((showTwitter && twitter) || !showTwitter) &&
((showDiscord && discord) || !showDiscord)
Expand All @@ -21,154 +20,49 @@
:address="address"
:shortened-address="shortenedAddress"
:name="name" />
</component>
</div>
</template>

<script lang="ts">
import { Component, Emit, Prop, Watch, mixins } from 'nuxt-property-decorator'
import { get, update } from 'idb-keyval'
import { hexToString, isHex } from '@polkadot/util'
import { Data } from '@polkadot/types'
<script lang="ts" setup>
import { GenericAccountId } from '@polkadot/types/generic/AccountId'
import { onApiConnect } from '@kodadot1/sub-api'

import InlineMixin from '@/utils/mixins/inlineMixin'
import UseApiMixin from '@/utils/mixins/useApiMixin'

import { emptyObject } from '@/utils/empty'
import { identityStore } from '@/utils/idbStore'
import shortAddress from '@/utils/shortAddress'
import shouldUpdate from '@/utils/shouldUpdate'
import useIdentity from './useIdentity'

type Address = string | GenericAccountId | undefined
type IdentityFields = Record<string, string>

const components = {
IdentitySocial: () =>
import('@/components/shared/identity/IdentitySocial.vue'),
IdentityChain: () => import('@/components/shared/identity/IdentityChain.vue'),
}

@Component({ components })
export default class Identity extends mixins(InlineMixin, UseApiMixin) {
@Prop() public address!: Address
@Prop(Boolean) public verticalAlign!: boolean
@Prop(Boolean) public noOwerflow!: boolean
@Prop(Boolean) public emit!: boolean
@Prop(Boolean) public showTwitter!: boolean
@Prop(Boolean) public showDiscord!: boolean
@Prop(Boolean) public showOnchainIdentity!: boolean
@Prop(Boolean) public hideIdentityPopover!: boolean
@Prop(String) public customNameOption!: string
public identity: IdentityFields = emptyObject<IdentityFields>()
public isFetchingIdentity = false

get shortenedAddress(): Address {
return shortAddress(this.resolveAddress(this.address))
}

get name(): Address {
if (this.customNameOption) {
return this.customNameOption
}
const name = this.identity.display
if (name?.length > 20) {
return shortAddress(name)
}
return (name as string) || this.shortenedAddress
}

get twitter(): Address {
const twitter = this.identity.twitter
return (twitter as string) || ''
}

get discord(): Address {
return this.identity?.discord
}

@Watch('address', { immediate: true })
async watchAddress(newAddress: Address, oldAddress: Address) {
if (shouldUpdate(newAddress, oldAddress)) {
this.identityOf(newAddress).then((id) => (this.identity = id))
}
}

protected mounted() {
onApiConnect(this.apiUrl, async () => {
this.identity = await this.identityOf(this.resolveAddress(this.address))
})
}

public async identityOf(account: Address): Promise<IdentityFields> {
if (!account) {
return Promise.resolve(emptyObject<IdentityFields>())
}

const address: string = this.resolveAddress(account)
const identity = await get(address, identityStore)

if (!identity) {
return await this.fetchIdentity(address)
}

if (this.emit) {
this.emitIdentityChange(identity)
}

return identity
}

private handleRaw(display: Data): string {
if (display?.isRaw) {
return display.asRaw.toHuman() as string
}

if (isHex((display as any)?.Raw)) {
return hexToString((display as any)?.Raw)
}

return display?.toString()
}

private resolveAddress(account: Address): string {
return account instanceof GenericAccountId
? account.toString()
: account || ''
}

protected async fetchIdentity(address: string): Promise<IdentityFields> {
this.isFetchingIdentity = true
const api = await this.useApi()

const optionIdentity = await api?.query.identity?.identityOf(address)
const identity = optionIdentity?.unwrapOrDefault()

if (!identity?.size) {
this.isFetchingIdentity = false
return emptyObject<IdentityFields>()
}

const final = Array.from(identity.info)
.filter(([, value]) => !Array.isArray(value) && !value.isEmpty)
.reduce((acc, [key, value]) => {
acc[key] = this.handleRaw(value as unknown as Data)
return acc
}, {} as IdentityFields)

update(address, () => final, identityStore)
this.isFetchingIdentity = false

if (this.emit) {
this.emitIdentityChange(final)
}

return final
}

@Emit('change')
emitIdentityChange(final: IdentityFields) {
return final
}
}
const IdentitySocial = defineAsyncComponent(
() => import('@/components/shared/identity/IdentitySocial.vue')
)
const IdentityChain = defineAsyncComponent(
() => import('@/components/shared/identity/IdentityChain.vue')
)

const props = defineProps<{
address?: Address
emit?: boolean
showTwitter?: boolean
showDiscord?: boolean
showOnchainIdentity?: boolean
hideIdentityPopover?: boolean
customNameOption?: string
inline?: boolean
}>()

const {
identity,
isFetchingIdentity,
shortenedAddress,
twitter,
discord,
name,
} = useIdentity({
address: props.address,
customNameOption: props.customNameOption,
})

provide('address', props.address)
provide('shortenedAddress', shortenedAddress.value)
provide(
'identity',
computed(() => identity.value)
)
</script>
17 changes: 7 additions & 10 deletions components/shared/identity/IdentitySocial.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'

@Component
export default class IdentitySocial extends Vue {
@Prop({ required: true, default: false }) readonly twitter
@Prop({ required: true, default: false }) readonly showTwitter
@Prop({ required: true, default: false }) readonly discord
@Prop({ required: true, default: false }) readonly showDiscord
}
<script lang="ts" setup>
defineProps<{
twitter: string
showTwitter: boolean
discord: string
showDiscord: boolean
}>()
</script>
Loading