Enhance the merchant creation process by automatically generating Nostr keypairs for users who don't have them, and streamline the API interface. Changes: - Add CreateMerchantRequest model to simplify merchant creation API - Auto-generate Nostr keypairs for users without existing keys - Update merchant creation endpoint to use user account keypairs - Improve error handling and validation in merchant creation flow - Clean up frontend JavaScript for merchant creation This ensures all merchants have proper Nostr keypairs for marketplace functionality without requiring manual key management from users. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
217 lines
6.4 KiB
JavaScript
217 lines
6.4 KiB
JavaScript
const nostr = window.NostrTools
|
|
|
|
window.app = Vue.createApp({
|
|
el: '#vue',
|
|
mixins: [window.windowMixin],
|
|
data: function () {
|
|
return {
|
|
merchant: {},
|
|
shippingZones: [],
|
|
activeChatCustomer: '',
|
|
orderPubkey: null,
|
|
showKeys: false,
|
|
importKeyDialog: {
|
|
show: false,
|
|
data: {
|
|
privateKey: null
|
|
}
|
|
},
|
|
wsConnection: null
|
|
}
|
|
},
|
|
methods: {
|
|
generateKeys: async function () {
|
|
// No longer need to generate keys here - the backend will use user's existing keypairs
|
|
await this.createMerchant()
|
|
},
|
|
importKeys: async function () {
|
|
this.importKeyDialog.show = false
|
|
// Import keys functionality removed since we use user's native keypairs
|
|
// Show a message that this is no longer needed
|
|
this.$q.notify({
|
|
type: 'info',
|
|
message: 'Merchants now use your account Nostr keys automatically. Key import is no longer needed.',
|
|
timeout: 3000
|
|
})
|
|
},
|
|
showImportKeysDialog: async function () {
|
|
this.importKeyDialog.show = true
|
|
},
|
|
toggleShowKeys: function () {
|
|
this.showKeys = !this.showKeys
|
|
},
|
|
toggleMerchantState: async function () {
|
|
const merchant = await this.getMerchant()
|
|
if (!merchant) {
|
|
this.$q.notify({
|
|
timeout: 5000,
|
|
type: 'warning',
|
|
message: 'Cannot fetch merchant!'
|
|
})
|
|
return
|
|
}
|
|
const message = merchant.config.active
|
|
? 'New orders will not be processed. Are you sure you want to deactivate?'
|
|
: merchant.config.restore_in_progress
|
|
? 'Merchant restore from nostr in progress. Please wait!! ' +
|
|
'Activating now can lead to duplicate order processing. Click "OK" if you want to activate anyway?'
|
|
: 'Are you sure you want activate this merchant?'
|
|
|
|
LNbits.utils.confirmDialog(message).onOk(async () => {
|
|
await this.toggleMerchant()
|
|
})
|
|
},
|
|
toggleMerchant: async function () {
|
|
try {
|
|
const {data} = await LNbits.api.request(
|
|
'PUT',
|
|
`/nostrmarket/api/v1/merchant/${this.merchant.id}/toggle`,
|
|
this.g.user.wallets[0].adminkey
|
|
)
|
|
const state = data.config.active ? 'activated' : 'disabled'
|
|
this.merchant = data
|
|
this.$q.notify({
|
|
type: 'positive',
|
|
message: `'Merchant ${state}`,
|
|
timeout: 5000
|
|
})
|
|
} catch (error) {
|
|
console.warn(error)
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
},
|
|
handleMerchantDeleted: function () {
|
|
this.merchant = null
|
|
this.shippingZones = []
|
|
this.activeChatCustomer = ''
|
|
this.showKeys = false
|
|
},
|
|
createMerchant: async function () {
|
|
try {
|
|
const payload = {
|
|
config: {}
|
|
}
|
|
const {data} = await LNbits.api.request(
|
|
'POST',
|
|
'/nostrmarket/api/v1/merchant',
|
|
this.g.user.wallets[0].adminkey,
|
|
payload
|
|
)
|
|
this.merchant = data
|
|
this.$q.notify({
|
|
type: 'positive',
|
|
message: 'Merchant Created!'
|
|
})
|
|
this.waitForNotifications()
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
},
|
|
getMerchant: async function () {
|
|
try {
|
|
const {data} = await LNbits.api.request(
|
|
'GET',
|
|
'/nostrmarket/api/v1/merchant',
|
|
this.g.user.wallets[0].inkey
|
|
)
|
|
this.merchant = data
|
|
return data
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
},
|
|
customerSelectedForOrder: function (customerPubkey) {
|
|
this.activeChatCustomer = customerPubkey
|
|
},
|
|
filterOrdersForCustomer: function (customerPubkey) {
|
|
this.orderPubkey = customerPubkey
|
|
},
|
|
showOrderDetails: async function (orderData) {
|
|
await this.$refs.orderListRef.orderSelected(
|
|
orderData.orderId,
|
|
orderData.eventId
|
|
)
|
|
},
|
|
waitForNotifications: async function () {
|
|
if (!this.merchant) return
|
|
try {
|
|
const scheme = location.protocol === 'http:' ? 'ws' : 'wss'
|
|
const port = location.port ? `:${location.port}` : ''
|
|
const wsUrl = `${scheme}://${document.domain}${port}/api/v1/ws/${this.merchant.id}`
|
|
console.log('Reconnecting to websocket: ', wsUrl)
|
|
this.wsConnection = new WebSocket(wsUrl)
|
|
this.wsConnection.onmessage = async e => {
|
|
const data = JSON.parse(e.data)
|
|
if (data.type === 'dm:0') {
|
|
this.$q.notify({
|
|
timeout: 5000,
|
|
type: 'positive',
|
|
message: 'New Order'
|
|
})
|
|
|
|
await this.$refs.directMessagesRef.handleNewMessage(data)
|
|
return
|
|
}
|
|
if (data.type === 'dm:1') {
|
|
await this.$refs.directMessagesRef.handleNewMessage(data)
|
|
await this.$refs.orderListRef.addOrder(data)
|
|
return
|
|
}
|
|
if (data.type === 'dm:2') {
|
|
const orderStatus = JSON.parse(data.dm.message)
|
|
this.$q.notify({
|
|
timeout: 5000,
|
|
type: 'positive',
|
|
message: orderStatus.message
|
|
})
|
|
if (orderStatus.paid) {
|
|
await this.$refs.orderListRef.orderPaid(orderStatus.id)
|
|
}
|
|
await this.$refs.directMessagesRef.handleNewMessage(data)
|
|
return
|
|
}
|
|
if (data.type === 'dm:-1') {
|
|
await this.$refs.directMessagesRef.handleNewMessage(data)
|
|
}
|
|
// order paid
|
|
// order shipped
|
|
}
|
|
} catch (error) {
|
|
this.$q.notify({
|
|
timeout: 5000,
|
|
type: 'warning',
|
|
message: 'Failed to watch for updates',
|
|
caption: `${error}`
|
|
})
|
|
}
|
|
},
|
|
restartNostrConnection: async function () {
|
|
LNbits.utils
|
|
.confirmDialog(
|
|
'Are you sure you want to reconnect to the nostrcient extension?'
|
|
)
|
|
.onOk(async () => {
|
|
try {
|
|
await LNbits.api.request(
|
|
'PUT',
|
|
'/nostrmarket/api/v1/restart',
|
|
this.g.user.wallets[0].adminkey
|
|
)
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
})
|
|
}
|
|
},
|
|
created: async function () {
|
|
await this.getMerchant()
|
|
setInterval(async () => {
|
|
if (
|
|
!this.wsConnection ||
|
|
this.wsConnection.readyState !== WebSocket.OPEN
|
|
) {
|
|
await this.waitForNotifications()
|
|
}
|
|
}, 1000)
|
|
}
|
|
})
|