import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { inject as service } from '@ember/service'; import { on } from '@ember/modifier'; import { EventFactory } from 'applesauce-core'; import Geohash from 'latlon-geohash'; export default class PlacePhotoUpload extends Component { @service nostrAuth; @service nostrRelay; @tracked photoUrl = ''; @tracked status = ''; @tracked error = ''; get place() { return this.args.place || {}; } get title() { return this.place.title || 'this place'; } @action async uploadPhoto(event) { event.preventDefault(); this.error = ''; this.status = 'Uploading...'; try { // Mock upload await new Promise((resolve) => setTimeout(resolve, 1000)); this.photoUrl = 'https://dummyimage.com/600x400/000/fff.jpg&text=Mock+Place+Photo'; this.status = 'Photo uploaded! Ready to publish.'; } catch (e) { this.error = 'Upload failed: ' + e.message; this.status = ''; } } @action async publish() { if (!this.nostrAuth.isConnected) { this.error = 'You must connect Nostr first.'; return; } if (!this.photoUrl) { this.error = 'Please upload a photo.'; return; } const { osmId, lat, lon } = this.place; const osmType = this.place.osmType || 'node'; if (!osmId) { this.error = 'This place does not have a valid OSM ID.'; return; } this.status = 'Publishing event...'; this.error = ''; try { const factory = new EventFactory({ signer: this.nostrAuth.signer }); const tags = [['i', `osm:${osmType}:${osmId}`]]; if (lat && lon) { tags.push(['g', Geohash.encode(lat, lon, 4)]); tags.push(['g', Geohash.encode(lat, lon, 6)]); tags.push(['g', Geohash.encode(lat, lon, 7)]); tags.push(['g', Geohash.encode(lat, lon, 9)]); } tags.push([ 'imeta', `url ${this.photoUrl}`, 'm image/jpeg', 'dim 600x400', 'alt A photo of a place', ]); // NIP-XX draft Place Photo event const template = { kind: 360, content: '', tags, }; // Ensure created_at is present before signing if (!template.created_at) { template.created_at = Math.floor(Date.now() / 1000); } const event = await factory.sign(template); await this.nostrRelay.publish(event); this.status = 'Published successfully!'; // Reset form this.photoUrl = ''; } catch (e) { this.error = 'Failed to publish: ' + e.message; this.status = ''; } } }