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: Create Collection Atomic Offer #11412

Merged
merged 2 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 13 additions & 2 deletions components/collection/CollectionTrades.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,18 @@
:query="tradeQuery"
:type="tradeType"
>
<template #action>
<CreateCollectionSwapButton v-if="isTradeSwap(tradeType)" />
<template
v-if="collectionId"
#action
>
<CreateCollectionSwapButton
v-if="isTradeSwap(tradeType)"
:collection-id="collectionId"
/>
<CreateCollectionOfferButton
v-else-if="isTradeOffer(tradeType)"
:collection-id="collectionId"
/>
</template>
</TradeActivityTable>
</div>
Expand All @@ -26,6 +36,7 @@ import { type TradeTableQuery } from '@/components/trade/TradeActivityTable.vue'
import type { TradeType } from '@/components/trade/types'
import { isTradeSwap } from '@/composables/useTradeType'
import CreateCollectionSwapButton from '@/components/swap/CreateCollectionSwapButton.vue'
import CreateCollectionOfferButton from '@/components/trade/makeOffer/CreateCollectionOfferButton.vue'

defineProps<{
tradeType: TradeType
Expand Down
12 changes: 6 additions & 6 deletions components/swap/CreateCollectionSwapButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
import { NeoButton } from '@kodadot1/brick'
import { useCollectionMinimal } from '@/components/collection/utils/useCollectionDetails'

const route = useRoute()
const props = defineProps<{
collectionId: string
}>()

const { $i18n } = useNuxtApp()

const collectionId = computed(() => route.params.id.toString())
const collectionId = computed(() => props.collectionId)
const swapStore = useAtomicSwapStore()
const { isCurrentAccount } = useAuth()

const isCollectionOwner = computed(() => isCurrentAccount(collection.value.currentOwner))

const { collection } = useCollectionMinimal({
collectionId: collectionId,
})
const { onTradeActionClick } = useTradeActionClick(isCollectionOwner)
const { onTradeActionClick } = useTradeActionClick()

const onCreateCollectionSwapClick = () => {
onTradeActionClick(() => {
Expand Down
66 changes: 66 additions & 0 deletions components/trade/makeOffer/CreateCollectionOfferButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<template>
<div>
<NeoButton
variant="secondary"
@click="onCreateCollectionOfferClick"
>
{{ $t('offer.createCollectionOffer') }}
</NeoButton>
<TradeMakeOfferModal />
</div>
</template>

<script lang="ts" setup>
import { NeoButton } from '@kodadot1/brick'
import { useCollectionMinimal } from '@/components/collection/utils/useCollectionDetails'
import { useMakingOfferStore } from '@/stores/makeOffer'
import type { MakingOfferItem } from '@/components/trade/types'

const { $i18n } = useNuxtApp()

const props = defineProps<{
collectionId: string
}>()
const preferencesStore = usePreferencesStore()
const collectionId = computed(() => props.collectionId)
const makeOfferStore = useMakingOfferStore()

const { data: collectionOfferData } = useGraphql<{ offers: NFTOffer[] }>({
queryName: 'highestOfferByCollectionId',
variables: {
id: collectionId.value,
},
})

const { collection } = useCollectionMinimal({
collectionId: collectionId,
})

const { onTradeActionClick } = useTradeActionClick()
const { urlPrefix } = usePrefix()
const highestOfferPrice = computed(() => (collectionOfferData.value)?.offers[0]?.price)

const openOfferModal = () => {
makeOfferStore.clear()
const item = {
id: null,
name: $i18n.t('offer.anyNftFromCollection'),
highestOffer: highestOfferPrice.value,
urlPrefix: urlPrefix.value,
collection: collection.value,
metadata: collection.value?.metadata,
meta: {
image: collection.value?.meta?.image,
},
sn: null,
currentOwner: collection.value?.currentOwner,
}
makeOfferStore.setItem(item as MakingOfferItem)

preferencesStore.setMakeOfferModalOpen(true)
}

const onCreateCollectionOfferClick = () => {
onTradeActionClick(openOfferModal)
}
</script>
5 changes: 4 additions & 1 deletion components/trade/makeOffer/MakeOfferModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
<div class="px-6 max-h-[50vh] overflow-y-auto">
<ModalIdentityItem />

<MakeOfferSingleItem v-if="offerStore.items.length === 1" />
<MakeOfferSingleItem
v-if="offerStore.items.length === 1"
:show-price="Boolean(offerStore.items[0]?.price)"
/>
</div>

<div class="border-t pt-5 pb-4 px-6">
Expand Down
6 changes: 5 additions & 1 deletion components/trade/makeOffer/MakeOfferSingleItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<div class="py-5">
<CartItemDetails :nft="item">
<template #right>
<div class="flex items-end">
<div
v-if="showPrice"
class="flex items-end"
>
{{ itemPrice }}
</div>
</template>
Expand Down Expand Up @@ -61,6 +64,7 @@ const emit = defineEmits([

const props = defineProps<{
offerPrice?: number
showPrice?: boolean
}>()

const offerPrice = useVModel(props, 'offerPrice')
Expand Down
4 changes: 2 additions & 2 deletions components/trade/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ export type MakingOfferItem = {
highestOffer?: string
offerPrice?: string
offerExpiration?: number
id: string
id: string | null
name: string
currentOwner: string
collection: EntityWithId & CollectionFloorPrice
meta?: NFTMetadata
metadata: string
sn: string
sn: string | null
}

export enum TradeStatus {
Expand Down
4 changes: 2 additions & 2 deletions composables/useTradeActionClick.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useIdentityStore } from '@/stores/identity'
import { doAfterCheckCurrentChainVM } from '@/components/common/ConnectWallet/openReconnectWalletModal'

export default function (isOwner: ComputedRef<boolean>) {
export default function (disabled?: ComputedRef<boolean>) {
const identityStore = useIdentityStore()
const { doAfterLogin } = useDoAfterlogin()

const isLogIn = computed(() => Boolean(identityStore.getAuthAddress))

const onTradeActionClick = (cb: () => void) => {
const fn = () => {
if (!isOwner.value) {
if (!disabled?.value) {
cb()
}
}
Expand Down
2 changes: 2 additions & 0 deletions i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1522,9 +1522,11 @@
"notifications": "Notifications"
},
"offer": {
"anyNftFromCollection": "Any NFT",
"bestOffer": "Best Offer",
"cancelOffer": "Cancel Offer",
"collectionFloorPrice": "Collection Floor",
"createCollectionOffer": "Create Collection Offer",
"emptyInput": "Please enter your offer",
"expiration": "Offer Expiration",
"floorDifference": "Floor Difference",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ query collectionByIdMinimalWithRoyalty($id: String!) {
name
currentOwner
createdAt
floorPrice: nfts(
where: { burned_eq: false, price_not_eq: "0" }
orderBy: price_ASC
limit: 1
) {
price
}
}
}
8 changes: 8 additions & 0 deletions queries/subsquid/general/highestOfferByCollectionId.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
query highestOfferByCollectionId($id: String!) {
offers(where: {status_eq: ACTIVE, desired: {collectionId_eq: $id}}, orderBy: price_DESC, limit: 1) {
expiration
status
price
id
}
}