diff --git a/models.py b/models.py
index 73e6687..58842d5 100644
--- a/models.py
+++ b/models.py
@@ -37,6 +37,7 @@ class MerchantProfile(BaseModel):
about: str | None = None
picture: str | None = None
banner: str | None = None
+ website: str | None = None
nip05: str | None = None
lud16: str | None = None
@@ -90,11 +91,23 @@ class Merchant(PartialMerchant, Nostrable):
return merchant
def to_nostr_event(self, pubkey: str) -> NostrEvent:
- content = {
- "name": self.config.name,
- "about": self.config.about,
- "picture": self.config.picture,
- }
+ content: dict[str, str] = {}
+ if self.config.name:
+ content["name"] = self.config.name
+ if self.config.display_name:
+ content["display_name"] = self.config.display_name
+ if self.config.about:
+ content["about"] = self.config.about
+ if self.config.picture:
+ content["picture"] = self.config.picture
+ if self.config.banner:
+ content["banner"] = self.config.banner
+ if self.config.website:
+ content["website"] = self.config.website
+ if self.config.nip05:
+ content["nip05"] = self.config.nip05
+ if self.config.lud16:
+ content["lud16"] = self.config.lud16
event = NostrEvent(
pubkey=pubkey,
created_at=round(time.time()),
diff --git a/services.py b/services.py
index 4039dbb..b978e39 100644
--- a/services.py
+++ b/services.py
@@ -149,9 +149,8 @@ async def update_merchant_to_nostr(
stall.event_id = event.id
stall.event_created_at = event.created_at
await update_stall(merchant.id, stall)
- if delete_merchant:
- # merchant profile updates not supported yet
- event = await sign_and_send_to_nostr(merchant, merchant, delete_merchant)
+ # Always publish merchant profile (kind 0)
+ event = await sign_and_send_to_nostr(merchant, merchant, delete_merchant)
assert event
merchant.config.event_id = event.id
return merchant
diff --git a/static/components/edit-profile-dialog.js b/static/components/edit-profile-dialog.js
new file mode 100644
index 0000000..aacfefc
--- /dev/null
+++ b/static/components/edit-profile-dialog.js
@@ -0,0 +1,85 @@
+window.app.component('edit-profile-dialog', {
+ name: 'edit-profile-dialog',
+ template: '#edit-profile-dialog',
+ delimiters: ['${', '}'],
+ props: ['model-value', 'merchant-id', 'merchant-config', 'adminkey'],
+ emits: ['update:model-value', 'profile-updated'],
+ data: function () {
+ return {
+ saving: false,
+ formData: {
+ name: '',
+ display_name: '',
+ about: '',
+ picture: '',
+ banner: '',
+ website: '',
+ nip05: '',
+ lud16: ''
+ }
+ }
+ },
+ computed: {
+ show: {
+ get() {
+ return this.modelValue
+ },
+ set(value) {
+ this.$emit('update:model-value', value)
+ }
+ }
+ },
+ methods: {
+ saveProfile: async function () {
+ this.saving = true
+ try {
+ const config = {
+ ...this.merchantConfig,
+ name: this.formData.name || null,
+ display_name: this.formData.display_name || null,
+ about: this.formData.about || null,
+ picture: this.formData.picture || null,
+ banner: this.formData.banner || null,
+ website: this.formData.website || null,
+ nip05: this.formData.nip05 || null,
+ lud16: this.formData.lud16 || null
+ }
+ await LNbits.api.request(
+ 'PATCH',
+ `/nostrmarket/api/v1/merchant/${this.merchantId}`,
+ this.adminkey,
+ config
+ )
+ this.show = false
+ this.$q.notify({
+ type: 'positive',
+ message: 'Profile updated!'
+ })
+ this.$emit('profile-updated')
+ } catch (error) {
+ LNbits.utils.notifyApiError(error)
+ } finally {
+ this.saving = false
+ }
+ },
+ loadFormData: function () {
+ if (this.merchantConfig) {
+ this.formData.name = this.merchantConfig.name || ''
+ this.formData.display_name = this.merchantConfig.display_name || ''
+ this.formData.about = this.merchantConfig.about || ''
+ this.formData.picture = this.merchantConfig.picture || ''
+ this.formData.banner = this.merchantConfig.banner || ''
+ this.formData.website = this.merchantConfig.website || ''
+ this.formData.nip05 = this.merchantConfig.nip05 || ''
+ this.formData.lud16 = this.merchantConfig.lud16 || ''
+ }
+ }
+ },
+ watch: {
+ modelValue(newVal) {
+ if (newVal) {
+ this.loadFormData()
+ }
+ }
+ }
+})
diff --git a/static/components/key-pair.js b/static/components/key-pair.js
deleted file mode 100644
index d324bc0..0000000
--- a/static/components/key-pair.js
+++ /dev/null
@@ -1,11 +0,0 @@
-window.app.component('key-pair', {
- name: 'key-pair',
- template: '#key-pair',
- delimiters: ['${', '}'],
- props: ['public-key', 'private-key', 'merchant-config'],
- methods: {
- handleImageError: function (event) {
- event.target.style.display = 'none'
- }
- }
-})
diff --git a/static/components/merchant-tab.js b/static/components/merchant-tab.js
index 3c48281..cd2e2b2 100644
--- a/static/components/merchant-tab.js
+++ b/static/components/merchant-tab.js
@@ -13,12 +13,41 @@ window.app.component('merchant-tab', {
'is-admin',
'merchant-config'
],
+ emits: [
+ 'toggle-show-keys',
+ 'hide-keys',
+ 'merchant-deleted',
+ 'toggle-merchant-state',
+ 'restart-nostr-connection',
+ 'profile-updated'
+ ],
+ data: function () {
+ return {
+ showEditProfileDialog: false,
+ showKeysDialog: false
+ }
+ },
computed: {
marketClientUrl: function () {
return '/nostrmarket/market'
}
},
methods: {
+ publishProfile: async function () {
+ try {
+ await LNbits.api.request(
+ 'PUT',
+ `/nostrmarket/api/v1/merchant/${this.merchantId}/nostr`,
+ this.adminkey
+ )
+ this.$q.notify({
+ type: 'positive',
+ message: 'Profile published to Nostr!'
+ })
+ } catch (error) {
+ LNbits.utils.notifyApiError(error)
+ }
+ },
toggleShowKeys: function () {
this.$emit('toggle-show-keys')
},
@@ -33,6 +62,9 @@ window.app.component('merchant-tab', {
},
restartNostrConnection: function () {
this.$emit('restart-nostr-connection')
+ },
+ handleImageError: function (e) {
+ e.target.style.display = 'none'
}
}
})
diff --git a/static/components/nostr-keys-dialog.js b/static/components/nostr-keys-dialog.js
new file mode 100644
index 0000000..81c451f
--- /dev/null
+++ b/static/components/nostr-keys-dialog.js
@@ -0,0 +1,56 @@
+window.app.component('nostr-keys-dialog', {
+ name: 'nostr-keys-dialog',
+ template: '#nostr-keys-dialog',
+ delimiters: ['${', '}'],
+ props: ['public-key', 'private-key', 'model-value'],
+ emits: ['update:model-value'],
+ data: function () {
+ return {
+ showNsec: false
+ }
+ },
+ computed: {
+ show: {
+ get() {
+ return this.modelValue
+ },
+ set(value) {
+ this.$emit('update:model-value', value)
+ }
+ },
+ npub: function () {
+ if (!this.publicKey) return ''
+ try {
+ return window.NostrTools.nip19.npubEncode(this.publicKey)
+ } catch (e) {
+ return this.publicKey
+ }
+ },
+ nsec: function () {
+ if (!this.privateKey) return ''
+ try {
+ return window.NostrTools.nip19.nsecEncode(this.privateKey)
+ } catch (e) {
+ return this.privateKey
+ }
+ }
+ },
+ methods: {
+ copyText: function (text, message) {
+ var notify = this.$q.notify
+ Quasar.copyToClipboard(text).then(function () {
+ notify({
+ message: message || 'Copied to clipboard!',
+ position: 'bottom'
+ })
+ })
+ }
+ },
+ watch: {
+ modelValue(newVal) {
+ if (!newVal) {
+ this.showNsec = false
+ }
+ }
+ }
+})
diff --git a/templates/nostrmarket/components/edit-profile-dialog.html b/templates/nostrmarket/components/edit-profile-dialog.html
new file mode 100644
index 0000000..27a4b1e
--- /dev/null
+++ b/templates/nostrmarket/components/edit-profile-dialog.html
@@ -0,0 +1,63 @@
+
-