From b4787bbfffbb5a4c5844efed9ae3385173433c37 Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:31:17 +0100 Subject: [PATCH 01/12] feat: edit collectio n permission --- components/collection/EditModal.vue | 69 +++++++++++++++++-- .../collection/HeroButtonEditCollection.vue | 27 ++++++-- .../transactionUpdateCollection.ts | 4 ++ composables/transaction/types.ts | 9 ++- composables/transaction/utils.ts | 2 +- locales/en.json | 6 ++ 6 files changed, 105 insertions(+), 12 deletions(-) diff --git a/components/collection/EditModal.vue b/components/collection/EditModal.vue index da1591778b..382403e5b2 100644 --- a/components/collection/EditModal.vue +++ b/components/collection/EditModal.vue @@ -125,6 +125,47 @@ + + +
+
+

+ {{ $t('mint.mintType') }} +

+ + + +
+ +
+
+

{{ $t('mint.collection.permission.noPriceSet') }}

+ +
+ +
+
+
@@ -142,9 +183,9 @@ diff --git a/components/collection/HeroButtonEditCollection.vue b/components/collection/HeroButtonEditCollection.vue index a0e30fd549..f6032ffc9a 100644 --- a/components/collection/HeroButtonEditCollection.vue +++ b/components/collection/HeroButtonEditCollection.vue @@ -24,7 +24,7 @@ diff --git a/composables/transaction/transactionUpdateCollection.ts b/composables/transaction/transactionUpdateCollection.ts index 9a8ba8487d..3dd48ecc85 100644 --- a/composables/transaction/transactionUpdateCollection.ts +++ b/composables/transaction/transactionUpdateCollection.ts @@ -75,6 +75,10 @@ async function execUpdateCollectionStatmine({ item, api, executeTransaction, isL args.push(api.tx.nfts.setCollectionMaxSupply(item.collectionId, item.collection.max ? item.collection.max : undefined)) } + if (item.update.permission) { + args.push(api.tx.nfts.updateMintSettings(item.collectionId, item.collection.mintingSettings)) + } + executeTransaction({ cb: api.tx.utility.batchAll, arg: [args], diff --git a/composables/transaction/types.ts b/composables/transaction/types.ts index 94a2d8a71e..71424a08cc 100644 --- a/composables/transaction/types.ts +++ b/composables/transaction/types.ts @@ -302,6 +302,12 @@ export interface ActionSetNftMetadata { errorMessage?: string } +export type CollectionMintSettingType = 'Issuer' | 'Public' | 'HolderOf' +export type CollectionMintSetting = { + price: string + mintType: CollectionMintSettingType +} + export type SetNftMetadataParams = BaseUnionMintParams & { api: ApiPromise } export type UpdateCollection = { @@ -311,6 +317,7 @@ export type UpdateCollection = { imageType?: string banner?: File | string | null max: number | null + mintingSettings: CollectionMintSetting } export type UpdateCollectionParams = BaseUnionMintParams & { api: ApiPromise } @@ -319,7 +326,7 @@ export interface ActionUpdateCollection { interaction: Collections.UPDATE_COLLECTION collectionId: string collection: UpdateCollection - update: { max: boolean, metadata: boolean } + update: { max: boolean, metadata: boolean, permission: boolean } urlPrefix: string successMessage?: string | ((blockNumber: string) => string) errorMessage?: string diff --git a/composables/transaction/utils.ts b/composables/transaction/utils.ts index 549f928499..0fab4bc799 100644 --- a/composables/transaction/utils.ts +++ b/composables/transaction/utils.ts @@ -66,7 +66,7 @@ export function isActionValid(action: Actions): boolean { [Collections.DELETE]: (action: ActionDeleteCollection) => Boolean(action.collectionId), [Collections.UPDATE_COLLECTION]: (action: ActionUpdateCollection) => - Boolean(action.collectionId) && (action.update.metadata || action.update.max), + Boolean(action.collectionId) && (action.update.metadata || action.update.max || action.update.permission), [NFTs.BURN_MULTIPLE]: (action: ActionBurnMultipleNFTs) => hasContent(action.nftIds), [NFTs.SET_METADATA]: (action: ActionSetNftMetadata) => diff --git a/locales/en.json b/locales/en.json index ae894a5be4..54daf3786a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1247,6 +1247,11 @@ "message": "Name of your collection. It will be visible in the gallery", "placeholder": "Enter collection name" }, + "permission": { + "label": "Collection Permission", + "noPriceSet": "No specified price set", + "pricePlaceholder": "specify the price of the items" + }, "submit": "Create Collection", "symbol": { "label": "Symbol (short name)", @@ -1283,6 +1288,7 @@ "mass": "NFT mass minter", "mintCollectionSuccess": "Collection {name} Saved in block {block}", "mintNFTSuccess": "NFT {name} Saved in block {block}", + "mintType": "Mint Type", "nfsw": "Explicit content (NSFW)", "nfswMessage": "Set your collection as explicit and sensitive content.", "nft": { From 443280e36dd5563fbc751f0141e7987705a75700 Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:21:56 +0100 Subject: [PATCH 02/12] fix: token input --- components/collection/EditModal.vue | 35 +++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/components/collection/EditModal.vue b/components/collection/EditModal.vue index 382403e5b2..91db577060 100644 --- a/components/collection/EditModal.vue +++ b/components/collection/EditModal.vue @@ -155,14 +155,23 @@ position="left" />
- + class="flex focus-within:!border-border-color border border-k-shade h-12 mt-3" + > + +
+ {{ chainSymbol }} +
+ @@ -207,6 +216,7 @@ const props = defineProps<{ }>() const isModalActive = useVModel(props, 'modelValue') +const { chainSymbol, decimals, withDecimals } = useChain() const name = ref() const description = ref() @@ -225,7 +235,8 @@ const nameChanged = computed(() => props.collection.name !== name.value) const hasImageChanged = computed(() => (!imageUrl.value && Boolean(props.collection.image)) || Boolean(image.value)) const originalLogoImageUrl = computed(() => sanitizeIpfsUrl(props.collection.image)) const mintTypeChanged = computed(() => selectedMintingType.value !== props.collection.mintingSettings.mintType) -const mintPriceChanged = computed(() => mintingPrice.value !== Number(props.collection.mintingSettings.price)) +const mintPriceChanged = computed(() => mintingPrice.value !== originalMintPrice.value) +const originalMintPrice = computed(() => props.collection.mintingSettings.price ? Number(props.collection.mintingSettings.price) / (10 ** decimals.value) : null) const disabled = computed(() => { const hasImage = imageUrl.value @@ -253,7 +264,7 @@ const editCollection = async () => { max: max.value, mintingSettings: { mintType: selectedMintingType.value, - price: mintingPriceUnset.value ? null : String(mintingPrice.value), + price: mintingPriceUnset.value ? null : String(withDecimals(mintingPrice.value || 0)), }, } as UpdateCollection) } @@ -271,17 +282,17 @@ watch(isModalActive, (value) => { // permission selectedMintingType.value = props.collection.mintingSettings.mintType mintingPriceUnset.value = !props.collection.mintingSettings.price - mintingPrice.value = Number(props.collection.mintingSettings.price) || null + mintingPrice.value = originalMintPrice.value || null } }) -watch([banner, unlimited, mintingPriceUnset], ([banner, unlimited, mintingPriceUnset]) => { +watch([banner, unlimited, mintingPriceUnset], ([banner, unlimited, priceUnset]) => { if (banner) { bannerUrl.value = URL.createObjectURL(banner) } max.value = unlimited ? null : max.value || props.collection.max - mintingPrice.value = mintingPriceUnset ? null : mintingPrice.value || Number(props.collection.mintingSettings.price) + mintingPrice.value = priceUnset ? null : originalMintPrice.value }) From bc09014aced79b0d006f810882fbb0e41e9161bb Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:06:31 +0100 Subject: [PATCH 03/12] fix: edit collection --- components/collection/EditModal.vue | 6 +++--- components/collection/HeroButtonEditCollection.vue | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/collection/EditModal.vue b/components/collection/EditModal.vue index 91db577060..69384b7cbd 100644 --- a/components/collection/EditModal.vue +++ b/components/collection/EditModal.vue @@ -148,8 +148,8 @@
-
-

{{ $t('mint.collection.permission.noPriceSet') }}

+
+

{{ $t(mintingPriceUnset ? 'mint.collection.permission.noPriceSet' : 'mint.collection.permission.pricePlaceholder') }}

({ value: type as CollectionMintSettingType, text: type })) +const COLLECTION_MINTING_TYPES_OPTIONS = (['Issuer', 'Public', 'HolderOf'] as CollectionMintSettingType[]).map(type => ({ value: type, text: type })) const emit = defineEmits(['submit']) const props = defineProps<{ diff --git a/components/collection/HeroButtonEditCollection.vue b/components/collection/HeroButtonEditCollection.vue index f6032ffc9a..fc327e40c7 100644 --- a/components/collection/HeroButtonEditCollection.vue +++ b/components/collection/HeroButtonEditCollection.vue @@ -1,5 +1,6 @@ diff --git a/components/collection/SearchInput.vue b/components/collection/SearchInput.vue new file mode 100644 index 0000000000..c9ba9df13c --- /dev/null +++ b/components/collection/SearchInput.vue @@ -0,0 +1,117 @@ + + + diff --git a/components/collection/utils/useCollectionDetails.ts b/components/collection/utils/useCollectionDetails.ts index 0beefe32cf..40a64f5963 100644 --- a/components/collection/utils/useCollectionDetails.ts +++ b/components/collection/utils/useCollectionDetails.ts @@ -104,7 +104,7 @@ export function useCollectionSoldData({ address, collectionId }) { export const useCollectionMinimal = ({ collectionId, }: { - collectionId: Ref + collectionId: Ref }) => { const { urlPrefix, client } = usePrefix() const { isAssetHub } = useIsChain(urlPrefix) diff --git a/components/search/utils/collectionSearch.ts b/components/search/utils/collectionSearch.ts index 9876a5215e..0fcf808e52 100644 --- a/components/search/utils/collectionSearch.ts +++ b/components/search/utils/collectionSearch.ts @@ -1,5 +1,6 @@ import { $fetch } from 'ofetch' import consola from 'consola' +import type { Prefix } from '@kodadot1/static' import { URLS } from '~/utils/constants' const SEARCH_BASE_URL = URLS.koda.search @@ -11,11 +12,12 @@ const api = $fetch.create({ }, credentials: 'omit', }) -export async function fetchCollectionSuggestion(key: string, limit?: number) { +export async function fetchCollectionSuggestion(key: string, limit?: number, chain?: Prefix) { const object = { search: key, table: 'collections', limit, + chain, } try { diff --git a/composables/transaction/transactionUpdateCollection.ts b/composables/transaction/transactionUpdateCollection.ts index 3dd48ecc85..c5e13ccb18 100644 --- a/composables/transaction/transactionUpdateCollection.ts +++ b/composables/transaction/transactionUpdateCollection.ts @@ -76,7 +76,18 @@ async function execUpdateCollectionStatmine({ item, api, executeTransaction, isL } if (item.update.permission) { - args.push(api.tx.nfts.updateMintSettings(item.collectionId, item.collection.mintingSettings)) + if (item.collection.mintingSettings.mintType === 'HolderOf') { + args.push(api.tx.nfts.updateMintSettings(item.collectionId, { + price: item.collection.mintingSettings.price, + mintType: { + HolderOf: item.collection.mintingSettings.holderOf, + }, + })) + } + else { + const { holderOf: _, ...restSettings } = item.collection.mintingSettings + args.push(api.tx.nfts.updateMintSettings(item.collectionId, restSettings)) + } } executeTransaction({ diff --git a/composables/transaction/types.ts b/composables/transaction/types.ts index e299b5720e..4d42bad476 100644 --- a/composables/transaction/types.ts +++ b/composables/transaction/types.ts @@ -295,6 +295,7 @@ export type CollectionMintSettingType = 'Issuer' | 'Public' | 'HolderOf' export type CollectionMintSetting = { price: string mintType: CollectionMintSettingType + holderOf?: string } export type SetNftMetadataParams = BaseUnionMintParams & { api: ApiPromise } diff --git a/locales/en.json b/locales/en.json index 571445eea6..c80b099eee 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1250,10 +1250,15 @@ "placeholder": "Enter collection name" }, "permission": { + "holderOfIdWarning": "You need to set a HolderOf collection", + "holderOfWarning": "Currently HolderOf collection is not supported to mint on Koda", + "issuerWarning": "You should not set a price for Issuer type", "label": "Collection Permission", "noPriceSet": "No specified price set", - "pricePlaceholder": "specify the price of the items" + "pricePlaceholder": "specify the price of the items", + "publicWarning": "You need to set a price so that users can mint on Koda" }, + "search": "Search Collection Name...", "submit": "Create Collection", "symbol": { "label": "Symbol (short name)", From a5137080dd0ce3a6e4ec07e3dfdc1b7ac8a3708b Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:39:14 +0100 Subject: [PATCH 05/12] fix: collection type edit --- components/collection/EditModal.vue | 8 +++++--- locales/en.json | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/collection/EditModal.vue b/components/collection/EditModal.vue index 8fbfec09e5..b261c61e2f 100644 --- a/components/collection/EditModal.vue +++ b/components/collection/EditModal.vue @@ -151,8 +151,8 @@

{{ $t(mintingPriceUnset ? 'mint.collection.permission.noPriceSet' : 'mint.collection.permission.pricePlaceholder') }}

@@ -178,7 +178,7 @@ class="mt-4" >

- Holder of Collection + {{ $t('mint.collection.permission.holderOfCollection') }}

{ const hasBannerChanged = (!bannerUrl.value && Boolean(props.collection.banner)) || Boolean(banner.value) const hasMaxChanged = max.value !== props.collection.max const holderOfCollectionIdChanged = holderOfCollectionId.value !== originalHolderOfCollectionId.value + const invalidPublicCollection = selectedMintingType.value === 'Public' && !mintingPrice.value const invalidHolderOfCollection = selectedMintingType.value === 'HolderOf' && !holderOfCollectionId.value - return !hasImage || !isNameFilled || invalidHolderOfCollection + return !hasImage || !isNameFilled || invalidHolderOfCollection || invalidPublicCollection || (!nameChanged.value && !descriptionChanged && !hasImageChanged.value && !hasBannerChanged && !hasMaxChanged && !mintTypeChanged.value && !mintPriceChanged.value && !holderOfCollectionIdChanged) }) @@ -347,6 +348,7 @@ const permissionSettingCheckingMap = { if (!mintingPrice.value || mintingPrice.value <= 0) { return $i18n.t('mint.collection.permission.publicWarning') } + return $i18n.t('mint.collection.permission.publicWithPriceWarning') }, HolderOf: () => { if (!holderOfCollectionId.value) { diff --git a/locales/en.json b/locales/en.json index c80b099eee..c349a21288 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1250,13 +1250,15 @@ "placeholder": "Enter collection name" }, "permission": { + "holderOfCollection": "Holder of Collection", "holderOfIdWarning": "You need to set a HolderOf collection", "holderOfWarning": "Currently HolderOf collection is not supported to mint on Koda", "issuerWarning": "You should not set a price for Issuer type", "label": "Collection Permission", "noPriceSet": "No specified price set", "pricePlaceholder": "specify the price of the items", - "publicWarning": "You need to set a price so that users can mint on Koda" + "publicWarning": "You need to set a price so that users can mint on Koda", + "publicWithPriceWarning": "You will not be able to mint in Koda. Moreover anyone can mint into your collection" }, "search": "Search Collection Name...", "submit": "Create Collection", From 5fd39a3a4901177a604743ea83371b2b287386ea Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:42:25 +0100 Subject: [PATCH 06/12] fix: dark mode --- components/collection/SearchInput.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/collection/SearchInput.vue b/components/collection/SearchInput.vue index c9ba9df13c..e32d368036 100644 --- a/components/collection/SearchInput.vue +++ b/components/collection/SearchInput.vue @@ -3,18 +3,18 @@
-
+
Date: Tue, 31 Dec 2024 21:02:45 +0100 Subject: [PATCH 07/12] fix: collection permission edit --- components/collection/EditModal.vue | 39 +++++++++++-------- .../collection/HeroButtonEditCollection.vue | 16 ++++++-- components/collection/SearchInput.vue | 31 ++++++++++----- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/components/collection/EditModal.vue b/components/collection/EditModal.vue index b261c61e2f..9e9d64c18d 100644 --- a/components/collection/EditModal.vue +++ b/components/collection/EditModal.vue @@ -127,6 +127,7 @@
@@ -149,15 +150,15 @@
-

{{ $t(mintingPriceUnset ? 'mint.collection.permission.noPriceSet' : 'mint.collection.permission.pricePlaceholder') }}

+

{{ $t(hasMintingPrice ? 'mint.collection.permission.pricePlaceholder' : 'mint.collection.permission.noPriceSet') }}

() const imageUrl = ref() const bannerUrl = ref() const unlimited = ref(true) -const mintingPriceUnset = ref(true) +const hasMintingPrice = ref(false) const mintingPrice = ref(null) + const selectedMintingType = ref(null) const min = computed(() => props.min || 1) const max = ref(null) @@ -304,7 +306,7 @@ const editCollection = async () => { max: max.value, mintingSettings: { mintType: selectedMintingType.value, - price: mintingPriceUnset.value ? null : String(withDecimals(mintingPrice.value || 0)), + price: hasMintingPrice.value ? String(withDecimals(mintingPrice.value || 0)) : null, holderOf: holderOfCollectionId.value || originalHolderOfCollectionId.value, }, } as UpdateCollection) @@ -322,19 +324,26 @@ watch(isModalActive, (value) => { // permission selectedMintingType.value = props.collection.mintingSettings.mintType - mintingPriceUnset.value = !props.collection.mintingSettings.price + hasMintingPrice.value = Boolean(props.collection.mintingSettings.price) mintingPrice.value = originalMintPrice.value || null holderOfCollectionId.value = originalHolderOfCollectionId.value } +}, { + immediate: true, }) - -const priceHandlerMap = { +const mintTypeChangeHandlerMap = { Issuer: () => { + hasMintingPrice.value = false mintingPrice.value = null - mintingPriceUnset.value = true }, Public: () => { - mintingPriceUnset.value = false + hasMintingPrice.value = true + mintingPrice.value = null + }, + HolderOf: () => { + hasMintingPrice.value = false + mintingPrice.value = null + holderOfCollectionId.value = undefined }, } @@ -358,19 +367,17 @@ const permissionSettingCheckingMap = { }, } -watch(selectedMintingType, (type) => { - if (type && priceHandlerMap[type]) { - priceHandlerMap[type as CollectionMintSettingType]() +watch(selectedMintingType, (type, oldType) => { + if (oldType && type && mintTypeChangeHandlerMap[type]) { + mintTypeChangeHandlerMap[type as CollectionMintSettingType]() } }) -watch([banner, unlimited, mintingPriceUnset], ([banner, unlimited, priceUnset]) => { +watch([banner, unlimited], ([banner, unlimited]) => { if (banner) { bannerUrl.value = URL.createObjectURL(banner) } max.value = unlimited ? null : max.value || props.collection.max - - mintingPrice.value = priceUnset ? null : originalMintPrice.value }) diff --git a/components/collection/HeroButtonEditCollection.vue b/components/collection/HeroButtonEditCollection.vue index 50e990ba7a..7509312503 100644 --- a/components/collection/HeroButtonEditCollection.vue +++ b/components/collection/HeroButtonEditCollection.vue @@ -25,7 +25,7 @@ diff --git a/components/collection/SearchInput.vue b/components/collection/SearchInput.vue index e32d368036..5ece8bbd38 100644 --- a/components/collection/SearchInput.vue +++ b/components/collection/SearchInput.vue @@ -17,10 +17,14 @@ class="p-2 flex items-center cursor-pointer hover:bg-k-hover text-text-color" @click="selectCollection(collection)" > - +
+ +
+ {{ collection.name }}
@@ -29,14 +33,18 @@ v-if="selectedCollection" class="mt-2.5" > -
- - {{ selectedCollection.name }} +
+
+ +
+ {{ selectedCollection.name }} { image: newCollection.meta.image, } } +}, { + immediate: true, }) const handleSearch = async () => { From b1d1af808ef0e31a641c1479fd7824561fe9afee Mon Sep 17 00:00:00 2001 From: Jarsen <31397967+Jarsen136@users.noreply.github.com> Date: Wed, 1 Jan 2025 12:22:30 +0100 Subject: [PATCH 08/12] fix: search input --- components/collection/SearchInput.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/components/collection/SearchInput.vue b/components/collection/SearchInput.vue index 5ece8bbd38..15479975db 100644 --- a/components/collection/SearchInput.vue +++ b/components/collection/SearchInput.vue @@ -1,6 +1,7 @@