initial drafting of nostr global search fro products

This commit is contained in:
Tiago Vasconcelos 2023-03-10 16:14:23 +00:00
parent b10531763e
commit 469aabc10a
4 changed files with 128 additions and 10 deletions

View file

@ -1,4 +1,42 @@
<div>
<div v-if="searchNostr" class="row q-col-gutter-md">
<div class="col-12 col-md-7 q-gutter-y-md">
<q-card>
<q-card-section>
<div class="row items-center no-wrap q-mb-md">
<div class="col">
<h5 class="text-subtitle1 q-my-none">Search Globally</h5>
<p>Search for products on Nostr</p>
</div>
</div>
</q-card-section>
<q-card-section>
<q-input
class="q-ml-md"
standout
square
dense
outlined
clearable
v-model.trim="search"
label="Search products"
hint="Enter search terms separated by spaces"
>
<template v-slot:after>
<q-btn
dense
flat
icon="search"
label="Search"
@click="searchProducts"
@keydown.enter="searchProducts"
/>
</template>
</q-input>
</q-card-section>
</q-card>
</div>
</div>
<q-toolbar>
<q-breadcrumbs>
<q-breadcrumbs-el label="Market" icon="home"></q-breadcrumbs-el>

View file

@ -4,13 +4,47 @@ async function customerMarket(path) {
name: 'customer-market',
template,
props: ['products', 'change-page'],
props: [
'products',
'change-page',
'search-nostr',
'relays',
'update-products',
'update-stalls'
],
data: function () {
return {}
return {
search: null
}
},
methods: {
changePageM(page, opts) {
this.$emit('change-page', page, opts)
},
async searchProducts() {
this.$q.loading.show()
let searchTags = this.search.split(' ')
const pool = new NostrTools.SimplePool()
let relays = Array.from(this.relays)
let merchants = new Set()
let productEvents = await pool.list(relays, [
{
kinds: [30018],
'#t': searchTags,
search: this.search, // NIP50, not very well supported
limit: 100
}
])
productEvents.map(e => merchants.add(e.pubkey))
let stallEvents = await pool.list(relays, [
{
kinds: [30017],
authors: Array.from(merchants)
}
])
await this.$emit('update-data', [...stallEvents, ...productEvents])
this.$q.loading.hide()
}
},
created() {}

View file

@ -10,7 +10,8 @@ const market = async () => {
'wss://nostr.zebedee.cloud'
]
const eventToObj = event => {
event.content = JSON.parse(event.content)
console.log(event.content)
event.content = JSON.parse(event.content) || null
return {
...event,
...Object.values(event.tags).reduce((acc, tag) => {
@ -41,6 +42,7 @@ const market = async () => {
key: null
}
},
searchNostr: false,
drawer: false,
pubkeys: new Set(),
relays: new Set(),
@ -62,13 +64,15 @@ const market = async () => {
if (this.activeStall) {
products = products.filter(p => p.stall_id == this.activeStall)
}
if (!this.searchText || this.searchText.length < 2) return products
const searchText = this.searchText.toLowerCase()
if (!searchText || searchText.length < 2) return products
return products.filter(p => {
return (
p.name.toLowerCase().includes(searchText) ||
p.description.toLowerCase().includes(searchText) ||
p.categories.toLowerCase().includes(searchText)
(p.description &&
p.description.toLowerCase().includes(searchText)) ||
(p.categories &&
p.categories.toString().toLowerCase().includes(searchText))
)
})
},
@ -191,6 +195,36 @@ const market = async () => {
this.accountDialog.data.watchOnly = true
return
},
async updateData(events) {
let products = new Map()
let stalls = new Map()
this.stalls.forEach(s => stalls.set(s.id, s))
this.products.forEach(p => products.set(p.id, p))
events.map(eventToObj).map(e => {
if (e.kind == 30018) {
//it's a product `d` is the prod. id
products.set(e.d, {...e.content, id: e.d[0], categories: e.t})
} else if (e.kind == 30017) {
// it's a stall `d` is the stall id
stalls.set(e.d, {...e.content, id: e.d[0], pubkey: e.pubkey})
return
}
})
this.stalls = await Array.from(stalls.values())
this.products = Array.from(products.values()).map(obj => {
let stall = this.stalls.find(s => s.id == obj.stall_id)
obj.stallName = stall.name
obj.images = [obj.image]
if (obj.currency != 'sat') {
obj.formatedPrice = this.getAmountFormated(obj.price, obj.currency)
}
return obj
})
},
async initNostr() {
this.$q.loading.show()
const pool = new NostrTools.SimplePool()
@ -205,8 +239,8 @@ const market = async () => {
authors: Array.from(this.pubkeys)
}
])
.then(events => {
console.log(events)
.then(async events => {
// ;[stalls, products] = await this.updateData(events)
this.events = events || []
this.events.map(eventToObj).map(e => {
if (e.kind == 0) {

View file

@ -148,15 +148,24 @@
{{ activePage }}
</q-toolbar-title>
{%endraw%}
<q-space></q-space>
<q-btn
v-if="!activeStall"
color="primary"
label="Search"
icon="travel_explore"
@click="searchNostr = !searchNostr"
><q-tooltip>Search for products on Nostr</q-tooltip></q-btn
>
<q-input
class="float-left q-ml-md"
class="q-ml-md"
standout
square
dense
outlined
clearable
v-model.trim="searchText"
label="Search for products"
label="Filter products"
>
<template v-slot:append>
<q-icon v-if="!searchText" name="search" />
@ -176,8 +185,11 @@
></customer-stall>
<customer-market
v-else
:search-nostr="searchNostr"
:relays="relays"
:products="filterProducts"
@change-page="navigateTo"
@update-data="updateData"
></customer-market>
</q-page-container>
<!-- ACCOUNT DIALOG -->