Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit aeefe4e

Browse files
authored
Merge pull request #126 from kodadot/main
oof uff
2 parents 9b8d187 + 49d6b12 commit aeefe4e

File tree

15 files changed

+974
-151
lines changed

15 files changed

+974
-151
lines changed

dashboard/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"file-saver": "^2.0.2",
3737
"ipfs": "^0.52.2",
3838
"js-ipfs-fetch": "^1.4.2",
39+
"markdown-it-vue": "^1.1.6",
3940
"register-service-worker": "^1.7.1",
4041
"serialize-javascript": "^3.1.0",
4142
"setimmediate": "^1.0.5",
@@ -62,8 +63,8 @@
6263
"sass-loader": "^8.0.2",
6364
"tslint": "^6.1.0",
6465
"typescript": "^3.8.3",
65-
"vue-debounce-decorator": "^1.0.1",
6666
"vue-cli-plugin-i18n": "^1.0.1",
67+
"vue-debounce-decorator": "^1.0.1",
6768
"vue-template-compiler": "2.6.11"
6869
}
6970
}

dashboard/src/components/rmrk/Gallery/AvailableActions.vue

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
</option>
1313
</b-select>
1414
</b-field>
15-
<b-field v-if="showMeta" label="Meta">
16-
<b-input v-model="meta"></b-input>
17-
</b-field>
15+
<component v-if="showMeta" :is="showMeta" @input="updateMeta" />
1816
<b-button
1917
v-if="showSubmit"
2018
type="is-primary"
@@ -32,24 +30,34 @@ import Connector from '@vue-polkadot/vue-api';
3230
import exec, { execResultValue } from '@/utils/transactionExecutor';
3331
import { notificationTypes, showNotification } from '@/utils/notification';
3432
import { getInstance, RmrkType } from '../service/RmrkService';
33+
import { unpin } from '@/pinata';
34+
import Consolidator from '../service/Consolidator';
3535
import RmrkVersionMixin from '@/utils/mixins/rmrkVersionMixin';
3636
3737
const ownerActions = ['SEND', 'CONSUME', 'LIST'];
3838
const buyActions = ['BUY'];
3939
40-
const needMeta: Record<string, boolean> = {
41-
SEND: true,
42-
LIST: true
40+
const needMeta: Record<string, string> = {
41+
SEND: 'AddressInput',
42+
LIST: 'BalanceInput'
4343
};
4444
45-
@Component({})
45+
const components = {
46+
BalanceInput: () => import('@/components/shared/BalanceInput.vue'),
47+
AddressInput: () => import('@/components/shared/AddressInput.vue')
48+
}
49+
50+
@Component({ components })
4651
export default class AvailableActions extends Mixins(RmrkVersionMixin) {
4752
@Prop() public currentOwnerId!: string;
4853
@Prop() public accountId!: string;
4954
@Prop() public price!: string;
5055
@Prop() public nftId!: string;
56+
@Prop() public imageHash!: string;
57+
@Prop() public metadataHash!: string;
58+
@Prop() public animationHash!: string;
5159
private selectedAction: string = '';
52-
private meta: string = '';
60+
private meta: string | number = '';
5361
private isLoading: boolean = false;
5462
5563
get actions() {
@@ -90,20 +98,27 @@ export default class AvailableActions extends Mixins(RmrkVersionMixin) {
9098
}`;
9199
}
92100
93-
private async submit() {
101+
protected updateMeta(value: string | number) {
102+
this.meta = value;
103+
}
104+
105+
protected async submit() {
94106
const { api } = Connector.getInstance();
95107
const rmrkService = getInstance();
96108
const rmrk = this.constructRmrk();
97109
try {
98110
showNotification(rmrk)
99111
console.log('submit', rmrk);
100-
const isSend = this.selectedAction === 'SEND';
101-
const cb = isSend ? api.tx.utility.batch : api.tx.system.remark
102-
const arg = isSend ? [api.tx.system.remark(rmrk), api.tx.balances.transfer(this.currentOwnerId, this.price)] : rmrk
112+
const isBuy = this.selectedAction === 'BUY';
113+
const cb = isBuy ? api.tx.utility.batch : api.tx.system.remark
114+
const arg = isBuy ? [api.tx.system.remark(rmrk), api.tx.balances.transfer(this.currentOwnerId, this.price)] : rmrk
103115
const tx = await exec(this.accountId, '', cb, [arg]);
104116
showNotification(execResultValue(tx), notificationTypes.success)
105117
console.warn('TX IN', tx);
106118
const persisted = await rmrkService?.resolve(rmrk, this.accountId);
119+
if (this.selectedAction === 'CONSUME') {
120+
this.unpinNFT()
121+
}
107122
console.log(persisted)
108123
console.log('SAVED', persisted?._id);
109124
showNotification(`[TEXTILE] ${persisted?._id}`, notificationTypes.success)
@@ -112,5 +127,34 @@ export default class AvailableActions extends Mixins(RmrkVersionMixin) {
112127
console.error(e);
113128
}
114129
}
130+
131+
protected unpinNFT() {
132+
[this.imageHash, this.metadataHash, this.animationHash]
133+
.forEach(async hash => {
134+
if (hash) {
135+
try {
136+
await unpin(hash)
137+
} catch (e) {
138+
console.warn(`[ACTIONS] Cannot Unpin ${hash} because: ${e}`)
139+
}
140+
}
141+
})
142+
143+
}
144+
145+
protected async consolidate(): Promise<boolean> {
146+
const rmrkService = getInstance();
147+
await rmrkService?.checkExpiredOrElseRefresh()
148+
149+
if (!rmrkService) {
150+
console.warn('NO RMRK SERVICE, Live your life on the edge')
151+
return true;
152+
}
153+
154+
const nft = await rmrkService?.getNFT(this.nftId)
155+
return Consolidator.consolidate(this.selectedAction, nft, this.currentOwnerId, this.accountId)
156+
}
157+
158+
115159
}
116160
</script>

dashboard/src/components/rmrk/Gallery/GalleryItem.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
</b-tag>
5555
<p v-if="!isLoading"
5656
class="subtitle is-size-5">
57+
<!-- <markdown-it-vue class="md-body" :content="nft.description" /> -->
58+
<!-- <markdown-it-vue-light class="md-body" :content="nft.description" /> -->
5759
{{ nft.description }}
5860
</p>
5961
<b-skeleton :count="3" size="is-large" :active="isLoading"></b-skeleton>
@@ -71,6 +73,9 @@
7173
<script lang="ts" >
7274
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
7375
import { getInstance } from '@/components/rmrk/service/RmrkService';
76+
// import MarkdownItVue from 'markdown-it-vue';
77+
// import MarkdownItVueLight from 'markdown-it-vue/dist/markdown-it-vue-light.umd.min.js';
78+
import 'markdown-it-vue/dist/markdown-it-vue.css'
7479
import { NFTWithMeta, NFT } from '../service/scheme';
7580
import { fetchNFTMetadata, sanitizeIpfsUrl } from '../utils';
7681
import { emptyObject } from '@/utils/empty';
@@ -87,6 +92,7 @@ import api from '@/fetch';
8792
import { resolveMedia } from '../utils';
8893
import { MediaType } from '../types';
8994
import { MetaInfo } from 'vue-meta';
95+
// import { VueConstructor } from 'vue';
9096
9197
type NFTType = NFTWithMeta;
9298
@@ -115,10 +121,11 @@ type NFTType = NFTWithMeta;
115121
components: {
116122
AccountSelect,
117123
AvailableActions,
118-
Money,
119-
Sharing,
120124
Facts,
125+
// MarkdownItVue: MarkdownItVue as VueConstructor<Vue>,
126+
Money,
121127
Name,
128+
Sharing,
122129
Appreciation: () => import('./Appreciation.vue'),
123130
MediaResolver: () => import('../Media/MediaResolver.vue'),
124131
PackSaver: () => import('../Pack/PackSaver.vue')

dashboard/src/components/rmrk/service/Consolidator.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { RmrkType } from './RmrkService';
2-
import { RmrkInteraction } from '../types';
2+
import { RmrkEvent, RmrkInteraction } from '../types';
33
import { Collection, NFT } from './scheme';
44
import { u8aToHex } from '@polkadot/util';
55
import { decodeAddress } from '@polkadot/keyring';
@@ -26,9 +26,30 @@ export default class Consolidator {
2626
}
2727
}
2828

29-
// private static canBuy() {
29+
public static isAvailableForSale(nft: NFT, previousOwner: string) {
30+
return Consolidator.callerEquals(nft.currentOwner, previousOwner)
31+
}
3032

31-
// }
33+
public static consolidate(action: RmrkEvent | string, nft: NFT, previousOwner: string, caller: string): boolean {
34+
switch(action) {
35+
case RmrkEvent.BUY:
36+
return Consolidator.canBuy(nft, previousOwner)
37+
case RmrkEvent.CONSUME:
38+
return Consolidator.canConsume(nft, caller)
39+
default:
40+
console.warn(`[CONSOLIDATOR] NO consolidation for interaction ${action}`)
41+
}
42+
43+
return true
44+
}
45+
46+
private static canBuy(nft: NFT, previousOwner: string) {
47+
return Consolidator.isAvailableForSale(nft, previousOwner);
48+
}
49+
50+
private static canConsume(nft: NFT, caller: string) {
51+
return Consolidator.callerEquals(nft.currentOwner, caller)
52+
}
3253

3354
// private static canMintNft() {
3455

dashboard/src/components/rmrk/service/NftUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { RmrkEvent, RMRK, RmrkInteraction } from '../types';
33
import { SQUARE } from '../utils'
44
import { generateId } from '../service/Consolidator'
55
import { Collection, NFT } from './scheme';
6+
import slugify from 'slugify';
67

78
class NFTUtils {
89
public static decode(value: string) {
@@ -54,7 +55,7 @@ class NFTUtils {
5455
return {
5556
id: generateId(nft.currentOwner, symbol),
5657
_id: '',
57-
symbol,
58+
symbol: slugify(symbol, '_').toUpperCase(),
5859
issuer: nft.currentOwner,
5960
version,
6061
name: nft.name,

dashboard/src/components/rmrk/service/RmrkService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class RmrkService extends TextileService<RmrkType> implements State {
4848
return this._client.context.withKeyInfo(keysToTheKingdom)
4949
}
5050

51-
protected async checkExpiredOrElseRefresh() {
51+
public async checkExpiredOrElseRefresh() {
5252
console.log('checkExpiredOrElseRefresh', this.isAuthExpired)
5353
if (this.isAuthExpired) {
5454
try {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div>
3+
<b-field :label="$t(label)">
4+
<b-input type="is-danger" v-model="value" @input="handleInput" :message="err"></b-input>
5+
</b-field>
6+
</div>
7+
</template>
8+
9+
<script lang="ts">
10+
import { checkAddress } from '@polkadot/util-crypto';
11+
import { Debounce } from 'vue-debounce-decorator';
12+
import { Component, Emit, Prop, Vue } from 'vue-property-decorator';
13+
14+
@Component({})
15+
export default class AddressInput extends Vue {
16+
17+
private value: string = '';
18+
private err: string | null = '';
19+
@Prop({ default: 'insert address' }) public label!: string;
20+
21+
@Debounce(500)
22+
@Emit('input')
23+
protected handleInput(value: string) {
24+
const [valid, err] = checkAddress(value, this.ss58Format);
25+
this.err = err;
26+
27+
if (valid) {
28+
return value
29+
}
30+
31+
return ''
32+
}
33+
34+
get ss58Format(): number {
35+
return this.$store.getters.getChainProperties?.ss58Format
36+
}
37+
}
38+
</script>
Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
<template>
2-
<div>
3-
<Balance
4-
:argument="{ name: 'balance', type: 'balance' }"
5-
@selected="handleValue"
6-
/>
2+
<div class="arguments-wrapper">
3+
<b-field :label="$t('balance')" class="balance">
4+
<b-input v-model="value" @input="handleInput" type="number" step="0.001" min="0"/>
5+
<p class="control balance">
6+
<b-select v-model="selectedUnit" @input="handleInput">
7+
<option v-for="u in units" v-bind:key="u.value" v-bind:value="u.value">
8+
{{ u.name }}
9+
</option>
10+
</b-select>
11+
</p>
12+
</b-field>
713
</div>
814
</template>
915

1016
<script lang="ts" >
1117
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator';
1218
import Balance from '@/params/components/Balance.vue';
19+
import { units as defaultUnits } from '@/params/constants';
20+
import { Unit } from '@/params/types';
21+
import shouldUpdate from '@/utils/shouldUpdate';
22+
import { Debounce } from 'vue-debounce-decorator';
1323
1424
const components = { Balance }
1525
@@ -19,11 +29,55 @@ type BalanceType = {
1929
2030
@Component({ components })
2131
export default class BalanceInput extends Vue {
22-
@Prop() public value!: number;
32+
private value: number = 0;
33+
protected units: Unit[] = defaultUnits;
34+
private selectedUnit: number = 1;
35+
36+
37+
get chainProperties() {
38+
return this.$store.getters.getChainProperties;
39+
}
40+
41+
get decimals(): number {
42+
return this.chainProperties.tokenDecimals
43+
}
44+
45+
get unit(): string {
46+
return this.chainProperties.tokenSymbol
47+
}
48+
49+
get calculatedBalance() {
50+
return this.value * (10**this.decimals) * this.selectedUnit
51+
}
52+
53+
protected mapper(unit: Unit) {
54+
if (unit.name === '-') {
55+
return { ...unit, name: this.unit }
56+
}
57+
return unit
58+
}
59+
60+
public mounted() {
61+
this.units = defaultUnits.map(this.mapper);
62+
}
63+
64+
// @Watch('$store.getters.getChainProperties.tokenSymbol')
65+
// protected updateUnit(val: string, oldVal: string) {
66+
// console.log('@Watch(unit)', val, oldVal)
67+
// if (shouldUpdate(val, oldVal)) {
68+
// this.units = defaultUnits.map(u => {
69+
// if (u.name === '-') {
70+
// return { ...u, name: val }
71+
// }
72+
// return u
73+
// })
74+
// }
75+
// }
2376
77+
@Debounce(200)
2478
@Emit('input')
25-
public handleValue(value: BalanceType) {
26-
return value.balance;
79+
public handleInput() {
80+
return this.calculatedBalance;
2781
}
2882
}
2983
</script>

0 commit comments

Comments
 (0)