2022-04-25 13:58:16 +08:00

434 lines
10 KiB
Vue

<template>
<div>
<top-menu class="desk-top" :current-tab="currentTab"></top-menu>
<section class="mynft">
<div class="container">
<div class="wrapper">
<nft-type-bar :select-idx="nftType" @nft-type-changed="onNftTypeClicked" class="left-bar"></nft-type-bar>
<sort-select
:filters="filters"
:selected-index="nftState"
@filter-change="filterChange"
></sort-select>
</div>
<nft-list :nft-datas="nftList" v-if="nftList.length > 0" @activate-clicked="onActivateClick"></nft-list>
<result-no
v-if="nftList.length === 0"
title="No Record."
desc=""
></result-no>
<pagination
v-if="totalPage>1"
:total="totalPage"
:current="currentPage"
@to-page="toPage"
class="page-comp"
></pagination>
</div>
<div class="order-status" v-show="showOrderStatus">
<el-tooltip class="item" effect="light" content="Transaction in progress" placement="right">
<time-loader></time-loader>
</el-tooltip>
</div>
</section>
<base-footer :auto-size="true">></base-footer>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'
import SearchPanel from '@/components/market/SearchPanel.vue'
import Pagination from '@/components/market/Pagination.vue'
import SearchResult from '@/components/market/SearchResult.vue'
import TopMenu from '@/components/market/TopMenu.vue'
import NftList from '@/components/market/NftList.vue'
import { getNftList } from '@/api/Mall'
import { AppModule } from '@/store/modules/app'
import BaseFooter from '@/components/layout/BaseFooter.vue'
import NftTypeBar from '@/components/market/NftTypeBar.vue'
import SortSelect from '@/components/market/SortSelect.vue'
import ResultNo from '@/components/market/ResultNo.vue'
import { INftData, parseNftData } from '@/types/Nft'
import TimeLoader from '@/components/main/TimeLoader.vue'
import { preActivateNFT, preOpenBox, queryActivateNFTState, queryBoxOpenState } from '@/api/Market'
import { createModal, ZModal } from '@/utils/modal.util'
import RewardModal from '@/components/core/RewardModal.vue'
import { ElLoadingComponent } from 'element-ui/types/loading'
import { UserModule } from '@/store/modules/user'
import ChainManager from '@/chain/ChainManager'
import { CONTRACT_ADDRESS } from '@/configs/config_chain'
const MYSTERY_BOX_CACHE = 'activate_nft_cache'
@Component({
components: {
TimeLoader,
ResultNo,
SortSelect,
NftTypeBar,
BaseFooter,
NftList,
SearchResult,
SearchPanel,
Pagination,
TopMenu
}
})
export default class MyNft extends Vue {
mobileFilterShow = false
currentTab = 'mynft'
nftList: INftData[] = []
nftType = 1
nftState = 0
showOrderStatus = false
private filters = ['All Items', 'Normal', 'Selling', 'Renting']
private totalPage = 1
private currentPage = 1
private dataCache: Map<any, INftData[]> = new Map()
private isProcess = false
private rewardModal: ZModal
orderTimer: any = null
loadingInstance: ElLoadingComponent
chainManager = new ChainManager()
get accountId() {
return AppModule.accountId
}
get isLogin() {
return !!UserModule.token && !!AppModule.step
}
get boxProxyAddress() {
return CONTRACT_ADDRESS[AppModule.chainId].nftProxy
}
onNftTypeClicked(typeId: number) {
console.log('nft type clicked: ', typeId)
if (this.nftType !== typeId) {
this.nftType = typeId
this.fetchDatas(1)
}
}
filterChange(id: number) {
console.log('filter change: ', id)
if (this.nftState !== id) {
this.nftState = id
this.fetchDatas(1)
}
}
@Watch('isLogin')
private accountChange() {
console.log('account change: ', AppModule.accountId)
if (this.accountId) {
this.fetchDatas(this.currentPage)
this.checkOrderHistory()
}
}
showFilter(val: boolean) {
this.mobileFilterShow = val
}
async fetchDatas(pageNo: number) {
if (!AppModule.accountId) {
return
}
const reqData: any = {
account: AppModule.accountId,
page: pageNo,
type: this.nftType
}
if (this.nftState > 0) {
reqData.state = this.nftState - 1
}
if (this.dataCache.has(reqData)) {
this.nftList = this.dataCache.get(reqData)!
} else {
this.nftList.length = 0
}
const res: any = await getNftList(reqData)
if (res.nfts) {
this.nftList.length = 0
for (const data of res.nfts) {
const nftData = parseNftData(data)
this.nftList.push(nftData)
}
this.dataCache.set(reqData, this.nftList)
}
if (res.page) {
const page = res.page
this.totalPage = page.total_pages || 1
this.currentPage = page.current_page || 1
}
console.log(res)
}
toPage(pageNo: number) {
console.log('to page: ', pageNo)
this.fetchDatas(pageNo)
}
showLoading() {
this.loadingInstance = this.$loading({ background: 'rgba(0, 0, 0, 0.8)' })
}
hideLoading() {
this.loadingInstance?.close()
}
async onActivateClick({ tokenId, type }: {tokenId: string, type: number}) {
console.log('onActivateClick: ', tokenId, type)
if (!this.isLogin) {
this.$message({
message: 'You should login first',
type: 'warning',
duration: 5 * 1000
})
return
}
if (this.isProcess) {
this.$message({
message: 'Box open in process',
type: 'warning',
duration: 5 * 1000
})
}
this.isProcess = true
const reqData = {
token_id: tokenId
}
this.showLoading()
let nonce, signature, nftNew
try {
const res: any = await preActivateNFT(reqData)
nonce = res.nonce
signature = res.signature
nftNew = res.new_token_id
} catch (err) {
console.log('pre activate err', err)
this.$message.error('activate nft with pre request error')
this.hideLoading()
this.isProcess = false
return false
}
try {
const result = await this.chainManager.activateOneNft(
this.boxProxyAddress, tokenId, nftNew, type, nonce, signature)
console.log('activate nft result: ', result)
const stateData = { token_id: tokenId, txhash: result.transactionHash }
localStorage.setItem(MYSTERY_BOX_CACHE, JSON.stringify(stateData))
this.hideLoading()
this.beginTraceOrderStatus(stateData)
} catch (err) {
console.log(err)
this.hideLoading()
this.isProcess = false
this.$message.error('activate nft with error: ' + err)
}
}
checkOrderHistory() {
const historyOrderId = localStorage.getItem(MYSTERY_BOX_CACHE)
if (historyOrderId && this.accountId) {
try {
const data = JSON.parse(historyOrderId)
this.beginTraceOrderStatus(data)
} catch (err) {
localStorage.removeItem(MYSTERY_BOX_CACHE)
}
}
}
beginTraceOrderStatus(cacheData: any) {
this.showOrderStatus = true
this.isProcess = true
this.loadingInstance?.close()
this.orderTimer = setInterval(() => {
this.getOrderStatus(cacheData)
}, 1000)
}
async getOrderStatus(data: any) {
console.log('getOrderStatus: ', data)
try {
const res: any = await queryActivateNFTState(data)
if (res.state === 1) {
// success
this.onOpenSuccess(res.nft)
}
} catch (err) {
console.log('query order status error', err)
}
}
resetTmpOrderId() {
if (this.orderTimer !== null) {
clearInterval(this.orderTimer)
this.orderTimer = null
}
this.isProcess = false
localStorage.removeItem(MYSTERY_BOX_CACHE)
this.loadingInstance?.close()
}
async onOpenSuccess(data: any) {
console.log('open success')
if (!this.isProcess) {
return
}
this.resetTmpOrderId()
this.showOrderStatus = false
const cardList: INftData[] = []
const nftData = parseNftData(data)
cardList.push(nftData)
this.showRewardModal({
title: 'NFT activate Success',
cardList
})
this.fetchDatas(this.currentPage)
// this.$alert('Congratulations', 'Open Success', { type: 'success', confirmButtonText: 'OK' })
}
showRewardModal(data: any) {
console.log('show reward modal with data: ', data)
this.rewardModal = createModal(RewardModal, data)
this.rewardModal.show()
}
}
</script>
<style lang="scss" scoped>
@import '../../scss/breakpoints.scss';
.mynft {
display: flex;
flex-direction: column;
align-items: center;
.container {
display: flex;
flex-direction: column;
width: 1440px;
max-width: 100%;
box-sizing: border-box;
.wrapper{
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
padding: 0 4%;
.left-bar{
width: 40%;
}
}
}
}
.mobile-top {
display: none;
}
.page-comp{
width: 100%;
}
.order-status {
transform: scale(0.3);
width: 220px;
height: 220px;
border-radius: 110px;
background: white;
display: flex;
justify-content: center;
align-items: center;
transform-origin: top;
position: fixed;
left: 100px;
top: 100px;
}
@include media('<desktop') {
.container {
flex-direction: column;
.wrapper{
margin-top: 80px;
margin-bottom: -76px;
padding: 0;
.left-bar{
flex-grow: 1;
width: 50%!important;
padding: 0 15px;
}
}
}
.searchPanel {
width: 100%;
}
.filterTablet {
padding-top: 40px;
width: 100%;
-webkit-transition: all 0.3s;
transition: all 0.3s;
height: auto;
}
.filterTablet.collapsed {
padding-top: 0;
opacity: 0;
height: 0;
z-index: -1;
overflow: hidden;
}
.searchResult {
padding: 2.5em 4em;
}
.searchResult .wrapper .btnFilter {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-transform: uppercase;
}
}
@media (min-width: 1024px) and (max-width: 1439px) {
.mynft {
font-size: 11px;
}
.mynft .container {
width: 1024px;
max-width: 100%;
}
}
@media (min-width: 768px) and (max-width: 1023px) {
.mynft {
font-size: 20px;
}
.container {
width: 768px;
}
}
@media (max-width: 767px) {
.mynft {
font-size: 11px;
}
}
@media (max-width: 767px) and (max-width: 320px) {
.mynft {
font-size: 9px;
}
}
@media (max-width: 767px) {
.container {
width: 375px;
}
.searchResult {
padding: 26px 20px;
}
.show{
display: flex!important;
}
}
</style>