feat: gate Amber Cordn notices and refresh Zapstore listing

This commit is contained in:
SkateSpots 2026-10-28 14:02:04 +07:00
parent 0c0917b70b
commit 9b6bdd2b53
3 changed files with 57 additions and 57 deletions

View file

@ -225,7 +225,7 @@ export function NotificationBell({
requests: cordnJoinRequests, requests: cordnJoinRequests,
isLoading: cordnJoinLoading, isLoading: cordnJoinLoading,
dismiss: dismissCordnJoin, dismiss: dismissCordnJoin,
} = useCordnJoinNotifications(); } = useCordnJoinNotifications(open);
const { lastRead, seenAt, markAllRead } = useNotificationsRead(); const { lastRead, seenAt, markAllRead } = useNotificationsRead();
// Buying/selling steps: an offer on your listing, a counter it's your turn to // Buying/selling steps: an offer on your listing, a counter it's your turn to

View file

@ -1,8 +1,10 @@
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useNostrLogin } from '@nostrify/react/login';
import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useLocalStorage } from '@/hooks/useLocalStorage'; import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useSkateRelays } from '@/hooks/useSkateRelays'; import { useSkateRelays } from '@/hooks/useSkateRelays';
import { hasNip44, isInteractiveSigner } from '@/lib/signerCapabilities';
import { APP_DATA_KIND } from '@/lib/types'; import { APP_DATA_KIND } from '@/lib/types';
import { import {
CORDN_JOIN_TAG, CORDN_JOIN_TAG,
@ -17,11 +19,15 @@ const DISMISSED_KEY = 'skatespots:cordn-join-dismissed';
* background watcher as encrypted NIP-78 events. The watcher also sends the * background watcher as encrypted NIP-78 events. The watcher also sends the
* same event as a NIP-17 DM, so the OS push path works while the app is closed. * same event as a NIP-17 DM, so the OS push path works while the app is closed.
*/ */
export function useCordnJoinNotifications() { export function useCordnJoinNotifications(opened = false) {
const { user } = useCurrentUser(); const { user } = useCurrentUser();
const { logins } = useNostrLogin();
const interactive = isInteractiveSigner(user, logins);
const { querySkateContent, getQueryKeySuffix } = useSkateRelays(); const { querySkateContent, getQueryKeySuffix } = useSkateRelays();
const [dismissed, setDismissed] = useLocalStorage<string[]>(DISMISSED_KEY, []); const [dismissed, setDismissed] = useLocalStorage<string[]>(DISMISSED_KEY, []);
const canRead = !!user?.pubkey && !!user.signer.nip44; // Amber prompts once per decrypt. Load these only when the bell is opened;
// passive signers can fetch them quietly in the background.
const canRead = !!user?.pubkey && hasNip44(user, logins) && (!interactive || opened);
const query = useQuery({ const query = useQuery({
queryKey: ['cordn-join-notifications', user?.pubkey, getQueryKeySuffix()], queryKey: ['cordn-join-notifications', user?.pubkey, getQueryKeySuffix()],

View file

@ -1,104 +1,98 @@
# Zapstore publish config for SkateSpots # Zapstore publish config for SkateSpots
# https://zapstore.dev # https://zapstore.dev
# #
# HOW TO PUBLISH # Publish: scripts/release.sh patch --yes (reads ~/.config/skatespots/zsp.env)
# ────────────── # or: SIGN_WITH=... zsp publish --quiet zapstore.yaml
# 1. Build the APK locally:
# npm run android:build
#
# 2. Publish to Zapstore:
# SIGN_WITH=nsec1... zsp publish zapstore.yaml
#
# Or with browser extension (NIP-07):
# SIGN_WITH=browser zsp publish zapstore.yaml
#
# zsp will:
# - Parse the APK (version, cert, permissions, icon)
# - Upload APK + icon to cdn.zapstore.dev (Blossom)
# - Sign and publish events to relay.zapstore.dev
# ═══════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════
# SOURCE CONFIGURATION # SOURCE CONFIGURATION
# ═══════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════
# Source code, shown as the "Source" link in the Zapstore listing. # Source code, shown as the "Source" link in the Zapstore listing.
# This points at the NIP-34 git repository announcement (kind 30617),
# rendered as a browsable web page by nostrhub.io. A plain HTTPS URL is
# used (rather than a bare naddr) so Zapstore renders it as a clickable
# Source link — a bare naddr coordinate was published correctly but not
# surfaced in the UI.
repository: https://nostrhub.io/naddr1qvzqqqrhnypzqg88e9f588nx7wyz4wt0ura23w3yd4hmztqrkr95utwyvgachjepqyd8wumn8ghj7emfwsh8x6rpddjhxur9v9ex2tnyd9uj7qq22d4kzar92dcx7arnhyhdwn repository: https://nostrhub.io/naddr1qvzqqqrhnypzqg88e9f588nx7wyz4wt0ura23w3yd4hmztqrkr95utwyvgachjepqyd8wumn8ghj7emfwsh8x6rpddjhxur9v9ex2tnyd9uj7qq22d4kzar92dcx7arnhyhdwn
# Local APK built by: npm run android:build # Local APK built by: npm run android:build
release_source: ./android/app/build/outputs/apk/release/app-release.apk release_source: ./android/app/build/outputs/apk/release/app-release.apk
# Guard: refuse to publish if the configured signer is not the app identity.
pubkey: npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx
# ═══════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════
# APP METADATA # APP METADATA
# ═══════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════
name: SkateSpots name: SkateSpots
summary: The decentralized skate map & community, built on Nostr summary: The decentralized skate map, crews, private chat and gear — on Nostr.
description: | description: |
Discover skate spots worldwide, start your own Crew, find coaches, Discover skate spots worldwide, start a crew, find coaches, filmers,
photographers, builders and filmers, join events, buy/sell gear, and photographers, builders and editors, join events, trade gear, and connect
connect with the global skateboarding community. with the global skateboarding community.
Built on Nostr — decentralized, censorship-resistant, no ads, no tracking. Built on Nostr: decentralized, censorship-resistant, no ads, no tracking,
Powered by Bitcoin Lightning zaps. no central account. Lightning zaps and Cashu are supported where available.
Features: Features:
- Interactive world map with a "Near Me" locator - Interactive world map with a Near Me locator and spot status reports
- Live spot status reports — active, bust, skate-stopped, closed or gone - Crews with members, roles, events and invites
- Crews: build your local skate community, map-anchored - Private chat: NIP-17 DMs, plus MLS end-to-end encrypted crew rooms
- The Lab: coaches, filmers, photographers, builders & video editors - The Lab: coaches, filmers, photographers, builders and other crafts
- Events calendar - Events calendar, tours and local guides
- Buy/sell used skate gear - Marketplace for used gear, with barter and Lightning payments
- Private encrypted gear stash - Private encrypted gear Stash
- Local tours — guides show you the hidden spots - On-device message translation in 24 languages (text never leaves the phone)
- Lightning zaps to content creators - Weekly newsletter and a public Cordn community room
- Works offline (PWA) - Works offline; web push and local Android notifications
website: https://skate-spots.org website: https://skate-spots.org
license: AGPL-3.0-only license: AGPL-3.0-only
# App icon (local path or URL). YAML config ALWAYS wins over the icon # Launcher / listing icon.
# extracted from the APK or pulled from external metadata sources.
# This is the orange SkateSpots logo used everywhere else.
icon: ./public/images/icon-1024.png icon: ./public/images/icon-1024.png
# Tags for Zapstore discovery # Listing screenshots (uploaded by zsp to the Zapstore CDN).
images:
- ./public/images/screenshots/map.png
- ./public/images/screenshots/spot.png
- ./public/images/screenshots/marketplace.png
# Discovery tags.
tags: tags:
- sports - sports
- social - social
- nostr - nostr
- bitcoin - bitcoin
- maps - maps
- chat
- privacy
- marketplace
# Nostr NIPs supported by this app # Nostr NIPs used by the app.
supported_nips: supported_nips:
- "01" - "01"
- "05"
- "07" - "07"
- "13"
- "17"
- "19"
- "23"
- "25"
- "44"
- "46" - "46"
- "47" - "47"
- "51"
- "55" - "55"
- "56"
- "57" - "57"
- "59"
- "65" - "65"
- "75"
- "78"
- "99" - "99"
# ═══════════════════════════════════════════════════════════════════ # Keep metadata source-free: the YAML is the source of truth for the icon,
# METADATA SOURCES # screenshots and copy.
# ═══════════════════════════════════════════════════════════════════
# Do NOT enrich icon/metadata from external sources — we set everything
# explicitly here so the correct orange logo is always used. Play Store
# enrichment was overriding our icon with the wrong (blue launcher) image.
metadata_sources: [] metadata_sources: []
# ═══════════════════════════════════════════════════════════════════ # Release notes for this version.
# RELEASE NOTES
# ═══════════════════════════════════════════════════════════════════
# Path to a plain-text file with release notes for this version.
# zsp reads this file and publishes its contents to Zapstore.
release_notes: ./release-notes.txt release_notes: ./release-notes.txt