nostrmarket/static/js/index.js
padreug 0b7639adf5 Improve merchant creation with automatic keypair generation
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>
2025-11-04 00:47:46 +01:00

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)
}
})