chore: audit fixes, designer stats and form FAB handling
This commit is contained in:
parent
dddfe51f86
commit
262eb32e7c
33 changed files with 53 additions and 24 deletions
13
package-lock.json
generated
13
package-lock.json
generated
|
|
@ -2946,12 +2946,6 @@
|
|||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz",
|
||||
"integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
|
|
@ -10926,9 +10920,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.3.tgz",
|
||||
"integrity": "sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==",
|
||||
"version": "7.6.5",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz",
|
||||
"integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
|
|
@ -10938,7 +10932,6 @@
|
|||
"@protobufjs/eventemitter": "^1.1.1",
|
||||
"@protobufjs/fetch": "^1.1.1",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.2",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.1",
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@
|
|||
},
|
||||
"overrides": {
|
||||
"@tanstack/query-core": "$@tanstack/react-query",
|
||||
"protobufjs": "7.6.3",
|
||||
"protobufjs": "7.6.5",
|
||||
"sharp": "0.35.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -522,6 +522,8 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
// The map is full-bleed (it manages its own height), so it gets no bottom
|
||||
// padding even though it shares this one persistent layout with every route.
|
||||
const isFullBleed = noPadding || location.pathname === '/' || location.pathname === '/map';
|
||||
// The floating assistant must not cover form controls on long-form pages.
|
||||
const hideSasquatch = /^\/(become|create|edit|supporters|onboarding)(\/|$)/.test(location.pathname);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [mobileLanguageView, setMobileLanguageView] = useState(false);
|
||||
// One auth dialog for the header + burger menu. Owning it here (not inside
|
||||
|
|
@ -1262,12 +1264,14 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
</Suspense>
|
||||
|
||||
{/* Sasquatch Guide (all screens) — lazy; not needed at first paint */}
|
||||
<Suspense fallback={null}>
|
||||
<LazySasquatchGuide
|
||||
message={currentMessage}
|
||||
onDismiss={dismissCurrentMessage}
|
||||
/>
|
||||
</Suspense>
|
||||
{!hideSasquatch && (
|
||||
<Suspense fallback={null}>
|
||||
<LazySasquatchGuide
|
||||
message={currentMessage}
|
||||
onDismiss={dismissCurrentMessage}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
{/* Set Status Dialog — lazy (on-demand modal) */}
|
||||
<Suspense fallback={null}>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export function useFollowers(pubkey?: string) {
|
|||
|
||||
// Query all kind 3 events that have a p tag with our pubkey
|
||||
const events = await nostr.query(
|
||||
[{ kinds: [3], '#p': [targetPubkey], limit: 100 }],
|
||||
[{ kinds: [3], '#p': [targetPubkey], limit: 500 }],
|
||||
{ signal }
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
SKATE_MUSICIAN_KIND,
|
||||
SKATE_JUDGE_KIND,
|
||||
SKATE_ORGANIZER_KIND,
|
||||
SKATE_BARBER_KIND, SKATE_TRANSPORT_KIND,
|
||||
SKATE_BARBER_KIND, SKATE_TRANSPORT_KIND, SKATE_DESIGNER_KIND,
|
||||
SKATE_TOUR_KIND,
|
||||
SKATE_CREW_KIND,
|
||||
MARKETPLACE_ITEM_KIND,
|
||||
|
|
@ -80,6 +80,7 @@ export interface GrowthStats {
|
|||
totalOrganizers: number;
|
||||
totalBarbers: number;
|
||||
totalTransport: number;
|
||||
totalDesigners: number;
|
||||
totalTours: number;
|
||||
totalCrews: number;
|
||||
/** All unique pubkeys that have published any content */
|
||||
|
|
@ -232,6 +233,7 @@ export function useGrowthStats() { // Community stats read from the CANONICAL c
|
|||
organizerEvents,
|
||||
barberEvents,
|
||||
transportEvents,
|
||||
designerEvents,
|
||||
listingEvents,
|
||||
tradeEvents,
|
||||
] = await Promise.all([
|
||||
|
|
@ -256,6 +258,7 @@ export function useGrowthStats() { // Community stats read from the CANONICAL c
|
|||
querySkateContent([{ kinds: [SKATE_ORGANIZER_KIND], limit: 500 }], { signal }).catch(() => []),
|
||||
querySkateContent([{ kinds: [SKATE_BARBER_KIND], limit: 500 }], { signal }).catch(() => []),
|
||||
querySkateContent([{ kinds: [SKATE_TRANSPORT_KIND], limit: 500 }], { signal }).catch(() => []),
|
||||
querySkateContent([{ kinds: [SKATE_DESIGNER_KIND], limit: 500 }], { signal }).catch(() => []),
|
||||
// Marketplace: live listings + completed-trade attestations.
|
||||
querySkateContent([{ kinds: [MARKETPLACE_ITEM_KIND], '#t': ['skateboarding'], limit: 2000 }], { signal }).catch(() => []),
|
||||
querySkateContent([{ kinds: [TRADE_ATTESTATION_KIND], limit: 1000 }], { signal }).catch(() => []),
|
||||
|
|
@ -299,8 +302,9 @@ export function useGrowthStats() { // Community stats read from the CANONICAL c
|
|||
const organizers = dedup(organizerEvents);
|
||||
const barbers = dedup(barberEvents);
|
||||
const transport = dedup(transportEvents);
|
||||
const designers = dedup(designerEvents);
|
||||
// Aggregate of the "other" crafts for active-mapper / total rollups.
|
||||
const otherLab = [...artists, ...graffiti, ...tattoo, ...trainers, ...musicians, ...judges, ...organizers, ...barbers, ...transport];
|
||||
const otherLab = [...artists, ...graffiti, ...tattoo, ...trainers, ...musicians, ...judges, ...organizers, ...barbers, ...transport, ...designers];
|
||||
|
||||
// ── Marketplace ──────────────────────────────────────────────────────
|
||||
// Showcase-only stash items are public but NOT for sale, so exclude them.
|
||||
|
|
@ -579,6 +583,7 @@ export function useGrowthStats() { // Community stats read from the CANONICAL c
|
|||
totalOrganizers: organizers.length,
|
||||
totalBarbers: barbers.length,
|
||||
totalTransport: transport.length,
|
||||
totalDesigners: designers.length,
|
||||
totalTours: tours.length,
|
||||
totalCrews: crews.length,
|
||||
totalMappers: allPubkeys.size,
|
||||
|
|
|
|||
|
|
@ -714,6 +714,7 @@ const batch6 = {
|
|||
judges: "Jutges",
|
||||
organizers: "Organitzadors",
|
||||
barbers: "Barbers",
|
||||
designers: "Dissenyadors",
|
||||
showFewer: "Mostra'n menys",
|
||||
showAllCrafts: "Mostra els 15 oficis",
|
||||
community: "Comunitat",
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ export const csBatch4 = {
|
|||
judges: "Rozhodčí",
|
||||
organizers: "Organizátoři",
|
||||
barbers: "Barbeři",
|
||||
designers: "Designéři",
|
||||
showFewer: "Zobrazit méně",
|
||||
showAllCrafts: "Zobrazit všech 15 řemesel",
|
||||
community: "Komunita",
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const deBatch4 = {
|
|||
judges: "Juroren",
|
||||
organizers: "Organisatoren",
|
||||
barbers: "Barbiere",
|
||||
designers: "Designer:innen",
|
||||
showFewer: "Weniger anzeigen",
|
||||
showAllCrafts: "Alle 15 Handwerke anzeigen",
|
||||
community: "Community",
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const elBatch4 = {
|
|||
judges: "Κριτές",
|
||||
organizers: "Διοργανωτές",
|
||||
barbers: "Κουρείς",
|
||||
designers: "Σχεδιαστές",
|
||||
showFewer: "Εμφάνιση λιγότερων",
|
||||
showAllCrafts: "Εμφάνιση και των 15 ειδικοτήτων",
|
||||
community: "Κοινότητα",
|
||||
|
|
|
|||
|
|
@ -6521,6 +6521,7 @@ walletUi: {
|
|||
organizers: 'Organizers',
|
||||
barbers: 'Barbers',
|
||||
transport: 'Transport',
|
||||
designers: 'Designers',
|
||||
showFewer: 'Show fewer',
|
||||
showAllCrafts: 'Show all 15 crafts',
|
||||
community: 'Community',
|
||||
|
|
|
|||
|
|
@ -6521,6 +6521,7 @@ walletUi: {
|
|||
organizers: 'Organizadores',
|
||||
barbers: 'Barberos',
|
||||
transport: 'Transporte',
|
||||
designers: 'Diseñadores',
|
||||
showFewer: 'Mostrar menos',
|
||||
showAllCrafts: 'Mostrar los 15 oficios',
|
||||
community: 'Comunidad',
|
||||
|
|
|
|||
|
|
@ -714,6 +714,7 @@ const batch6 = {
|
|||
judges: "Epaileak",
|
||||
organizers: "Antolatzaileak",
|
||||
barbers: "Bizarginak",
|
||||
designers: "Diseinatzaileak",
|
||||
showFewer: "Erakutsi gutxiago",
|
||||
showAllCrafts: "Erakutsi 15 lanbide guztiak",
|
||||
community: "Komunitatea",
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const frBatch4 = {
|
|||
judges: "Juges",
|
||||
organizers: "Organisateurs",
|
||||
barbers: "Coiffeurs",
|
||||
designers: "Concepteurs",
|
||||
showFewer: "Afficher moins",
|
||||
showAllCrafts: "Afficher les 15 disciplines",
|
||||
community: "Communauté",
|
||||
|
|
|
|||
|
|
@ -714,6 +714,7 @@ const batch6 = {
|
|||
"judges": "Xuíces",
|
||||
"organizers": "Organizadores",
|
||||
"barbers": "Barbeiros",
|
||||
"designers": "Deseñadores",
|
||||
"showFewer": "Amosar menos",
|
||||
"showAllCrafts": "Amosar os 15 oficios",
|
||||
"community": "Comunidade",
|
||||
|
|
|
|||
|
|
@ -714,6 +714,7 @@ const batch6 = {
|
|||
"judges": "जज",
|
||||
"organizers": "आयोजक",
|
||||
"barbers": "नाई",
|
||||
"designers": "डिज़ाइनर",
|
||||
"showFewer": "कम दिखाएँ",
|
||||
"showAllCrafts": "सभी 15 क्राफ़्ट दिखाएँ",
|
||||
"community": "समुदाय",
|
||||
|
|
|
|||
|
|
@ -694,6 +694,7 @@ const idBatch4 = {
|
|||
judges: 'Juri',
|
||||
organizers: 'Penyelenggara',
|
||||
barbers: 'Tukang Cukur',
|
||||
designers: 'Desainer',
|
||||
showFewer: 'Tampilkan lebih sedikit',
|
||||
showAllCrafts: 'Tampilkan semua 15 keahlian',
|
||||
community: 'Komunitas',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const itBatch4 = {
|
|||
judges: "Giudici",
|
||||
organizers: "Organizzatori",
|
||||
barbers: "Barbieri",
|
||||
designers: "Progettisti",
|
||||
showFewer: "Mostra meno",
|
||||
showAllCrafts: "Mostra tutti i 15 mestieri",
|
||||
community: "Community",
|
||||
|
|
|
|||
|
|
@ -697,6 +697,7 @@ const jaBatch7 = {
|
|||
judges: 'ジャッジ',
|
||||
organizers: 'オーガナイザー',
|
||||
barbers: 'バーバー',
|
||||
designers: 'デザイナー',
|
||||
showFewer: '表示を減らす',
|
||||
showAllCrafts: '15職種すべて表示',
|
||||
community: 'コミュニティ',
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ const koBatch4 = {
|
|||
judges: '심판',
|
||||
organizers: '주최자',
|
||||
barbers: '바버',
|
||||
designers: '디자이너',
|
||||
showFewer: '접기',
|
||||
showAllCrafts: '15개 분야 모두 보기',
|
||||
community: '커뮤니티',
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ const nlBatch4 = {
|
|||
judges: 'Juryleden',
|
||||
organizers: 'Organisatoren',
|
||||
barbers: 'Barbers',
|
||||
designers: 'Ontwerpers',
|
||||
showFewer: 'Minder tonen',
|
||||
showAllCrafts: 'Alle 15 ambachten tonen',
|
||||
community: 'Community',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const plBatch4 = {
|
|||
judges: "Sędziowie",
|
||||
organizers: "Organizatorzy",
|
||||
barbers: "Barberzy",
|
||||
designers: "Projektanci",
|
||||
showFewer: "Pokaż mniej",
|
||||
showAllCrafts: "Pokaż wszystkie 15 rzemiosł",
|
||||
community: "Społeczność",
|
||||
|
|
|
|||
|
|
@ -775,6 +775,7 @@ const ptBatch4 = {
|
|||
judges: 'Jurados',
|
||||
organizers: 'Organizadores',
|
||||
barbers: 'Barbeiros',
|
||||
designers: 'Projetistas',
|
||||
showFewer: 'Mostrar menos',
|
||||
showAllCrafts: 'Mostrar todos os 15 ofícios',
|
||||
community: 'Comunidade',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const roBatch4 = {
|
|||
judges: 'Juri',
|
||||
organizers: 'Organizatori',
|
||||
barbers: 'Frizeri',
|
||||
designers: 'Designeri',
|
||||
showFewer: 'Arată mai puține',
|
||||
showAllCrafts: 'Arată toate cele 15 meserii',
|
||||
community: 'Comunitate',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const ruBatch4 = {
|
|||
judges: 'Судьи',
|
||||
organizers: 'Организаторы',
|
||||
barbers: 'Барберы',
|
||||
designers: 'Дизайнеры',
|
||||
showFewer: 'Показать меньше',
|
||||
showAllCrafts: 'Показать все 15 ремёсел',
|
||||
community: 'Сообщество',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const svBatch4 = {
|
|||
judges: "Domare",
|
||||
organizers: "Arrangörer",
|
||||
barbers: "Barberare",
|
||||
designers: "Formgivare",
|
||||
showFewer: "Visa färre",
|
||||
showAllCrafts: "Visa alla 15 hantverk",
|
||||
community: "Community",
|
||||
|
|
|
|||
|
|
@ -768,6 +768,7 @@ const thBatch9 = {
|
|||
judges: 'กรรมการ',
|
||||
organizers: 'ผู้จัด',
|
||||
barbers: 'ช่างตัดผม',
|
||||
designers: 'นักออกแบบ',
|
||||
showFewer: 'แสดงน้อยลง',
|
||||
showAllCrafts: 'แสดงทั้ง 15 อาชีพ',
|
||||
community: 'ชุมชน',
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const trBatch4 = {
|
|||
judges: "Jüri üyeleri",
|
||||
organizers: "Organizatörler",
|
||||
barbers: "Berberler",
|
||||
designers: "Tasarımcılar",
|
||||
showFewer: "Daha az göster",
|
||||
showAllCrafts: "15 zanaatın tümünü göster",
|
||||
community: "Topluluk",
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ const ukBatch4 = {
|
|||
judges: "Судді",
|
||||
organizers: "Організатори",
|
||||
barbers: "Барбери",
|
||||
designers: "Дизайнери",
|
||||
showFewer: "Показати менше",
|
||||
showAllCrafts: "Показати всі 15 напрямів",
|
||||
community: "Спільнота",
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ const viBatch4 = {
|
|||
judges: 'Giám khảo',
|
||||
organizers: 'Nhà tổ chức',
|
||||
barbers: 'Thợ cắt tóc',
|
||||
designers: 'Nhà thiết kế',
|
||||
showFewer: 'Hiện ít hơn',
|
||||
showAllCrafts: 'Hiện cả 15 nghề',
|
||||
community: 'Cộng đồng',
|
||||
|
|
|
|||
|
|
@ -693,6 +693,7 @@ const zhCNBatch4 = {
|
|||
judges: "裁判",
|
||||
organizers: "组织者",
|
||||
barbers: "理发师",
|
||||
designers: "设计师",
|
||||
showFewer: "收起",
|
||||
showAllCrafts: "显示全部 15 种手艺",
|
||||
community: "社区",
|
||||
|
|
|
|||
|
|
@ -693,6 +693,7 @@ const zhTWBatch4 = {
|
|||
judges: "裁判",
|
||||
organizers: "組織者",
|
||||
barbers: "理髮師",
|
||||
designers: "設計師",
|
||||
showFewer: "收起",
|
||||
showAllCrafts: "顯示全部 15 種手藝",
|
||||
community: "社群",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { formatAge } from '@/lib/routeCache';
|
|||
const ANGOR_PROJECT_URL = 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z';
|
||||
import { SKATE_RELAY } from '@/lib/types';
|
||||
import { AreaChart, Area, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, Legend } from 'recharts';
|
||||
import { MapPin, Store, Calendar, GraduationCap, Video, Scissors, Route, Users, Users2, Camera, Hammer, TrendingUp, Radio, Zap, ExternalLink, Trophy, FlaskConical, Palette, SprayCan, PenTool, Dumbbell, Music, Gavel, Tent, Sparkles, Truck, ShoppingBag, Tag, Handshake, Globe, RefreshCw } from 'lucide-react';
|
||||
import { MapPin, Store, Calendar, GraduationCap, Video, Scissors, Route, Users, Users2, Camera, Hammer, TrendingUp, Radio, Zap, ExternalLink, Trophy, FlaskConical, Palette, SprayCan, PenTool, Dumbbell, Music, Gavel, Tent, Sparkles, Truck, Shirt, ShoppingBag, Tag, Handshake, Globe, RefreshCw } from 'lucide-react';
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -25,13 +25,13 @@ function labCraftTotal(s: {
|
|||
totalCoaches: number; totalFilmers: number; totalEditors: number;
|
||||
totalPhotographers: number; totalBuilders: number; totalArtists: number;
|
||||
totalGraffiti: number; totalTattoo: number; totalTrainers: number;
|
||||
totalMusicians: number; totalJudges: number; totalOrganizers: number; totalBarbers: number; totalTransport: number;
|
||||
totalMusicians: number; totalJudges: number; totalOrganizers: number; totalBarbers: number; totalTransport: number; totalDesigners: number;
|
||||
}): number {
|
||||
return (
|
||||
s.totalCoaches + s.totalFilmers + s.totalEditors + s.totalPhotographers +
|
||||
s.totalBuilders + s.totalArtists + s.totalGraffiti + s.totalTattoo +
|
||||
s.totalTrainers + s.totalMusicians + s.totalJudges + s.totalOrganizers +
|
||||
s.totalBarbers + (s.totalTransport ?? 0)
|
||||
s.totalBarbers + (s.totalTransport ?? 0) + (s.totalDesigners ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -323,6 +323,7 @@ export default function CommunityStatsPage() {
|
|||
<StatCard icon={Tent} value={stats?.totalOrganizers ?? 0} label={t('walletUi.stats.organizers')} color="#2dd4bf" loading={isLoading} to="/lab?craft=organizing" />
|
||||
<StatCard icon={Sparkles} value={stats?.totalBarbers ?? 0} label={t('walletUi.stats.barbers')} color="#22d3ee" loading={isLoading} to="/lab?craft=barbering" />
|
||||
<StatCard icon={Truck} value={stats?.totalTransport ?? 0} label={t('walletUi.stats.transport')} color="#f59e0b" loading={isLoading} to="/lab?craft=transport" />
|
||||
<StatCard icon={Shirt} value={stats?.totalDesigners ?? 0} label={t('walletUi.stats.designers')} color="#a78bfa" loading={isLoading} to="/lab?craft=clothing" />
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ export default function SupportersPage() {
|
|||
? num(stats.totalCoaches) + num(stats.totalFilmers) + num(stats.totalEditors) + num(stats.totalPhotographers)
|
||||
+ num(stats.totalBuilders) + num(stats.totalArtists) + num(stats.totalGraffiti) + num(stats.totalTattoo)
|
||||
+ num(stats.totalTrainers) + num(stats.totalMusicians) + num(stats.totalJudges) + num(stats.totalOrganizers)
|
||||
+ num(stats.totalBarbers) + num(stats.totalTransport)
|
||||
+ num(stats.totalBarbers) + num(stats.totalTransport) + num(stats.totalDesigners)
|
||||
: 0;
|
||||
|
||||
const impact = stats
|
||||
|
|
|
|||
Loading…
Reference in a new issue