From c93d7e4e410497ce667f8a4c140cf608d5e49cf8 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Sat, 3 Oct 2026 17:41:13 +0700 Subject: [PATCH] feat(crew): add a coordinator "Check status" button to the crew form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a coordinator addressed by pubkey, the form now probes it on demand (the same useCoordinatorHealth the Settings → Coordinator card uses) and shows Connected / Quiet / Not seen / Unreachable. Reuses the existing socialUi .coordinator status copy; no new keys. --- src/components/CrewForm.tsx | 56 ++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/components/CrewForm.tsx b/src/components/CrewForm.tsx index 9ace413..8f067c1 100644 --- a/src/components/CrewForm.tsx +++ b/src/components/CrewForm.tsx @@ -24,7 +24,7 @@ import { NofferField } from '@/components/NofferField'; import { SKATE_CREW_KIND, SKATE_SPOT_KIND, SKATE_SHOP_KIND, parseAddrCoord, ZAP_GOAL_KIND, CREW_VIBE_LABELS, CREW_FOCUS_LABELS, CREW_FOCUS_DESCRIPTIONS, CREW_FOCUS_TAG, CREW_LOOKING_FOR_OPTIONS, CREW_ROLE_META, CREW_ROLE_ORDER, SHOW_CREW_TREASURY, isValidNoffer, type SkateCrew, type CrewFocus, type CrewRole } from '@/lib/types'; import { CREW_VIBE_KEYS, CREW_FOCUS_KEYS, CREW_FOCUS_DESC_KEYS, CREW_LOOKING_FOR_KEYS, CREW_ROLE_KEYS } from '@/lib/labelKeys'; import { useCrewGoal } from '@/hooks/useCrewGoal'; -import { useCoordinator } from '@/hooks/useCoordinator'; +import { useCoordinator, useCoordinatorHealth } from '@/hooks/useCoordinator'; import { Nip05HandlesEditor } from '@/components/Nip05HandlesEditor'; import { coordinatorAddUrl, crewCoordinatorInputValue, parseCrewCoordinatorInput, shortNpub } from '@/lib/coordinator'; import { useRelays } from '@/lib/relays'; @@ -191,6 +191,16 @@ interface CrewFormProps { existing?: SkateCrew | null; } +/** Static map for coordinator health status → i18n key (no dynamic keys). */ +const HEALTH_LABEL: Record = { + idle: 'socialUi.coordinator.statusIdle', + checking: 'socialUi.coordinator.statusChecking', + online: 'socialUi.coordinator.statusOnline', + stale: 'socialUi.coordinator.statusStale', + offline: 'socialUi.coordinator.statusOffline', + error: 'socialUi.coordinator.statusError', +}; + export function CrewForm({ existing }: CrewFormProps) { const { t } = useTranslation(); const navigate = useNavigate(); @@ -295,6 +305,17 @@ export function CrewForm({ existing }: CrewFormProps) { const { coordinator: myCoordinator } = useCoordinator(); // Live parse so the founder gets feedback (and the publish path reuses it). const parsedCoordinator = parseCrewCoordinatorInput(coordinatorInput); + // On-demand health probe (the "Check" button) for a coordinator addressed by + // pubkey — mirrors the Settings → Coordinator card. + const coordinatorHealth = useCoordinatorHealth( + parsedCoordinator?.pubkey + ? { + pubkey: parsedCoordinator.pubkey, + relays: /^wss?:\/\//i.test(parsedCoordinator.url) ? [parsedCoordinator.url] : [], + addedAt: 0, + } + : null, + ); // Crew video / montage — YouTube or Instagram URL ("The Part"). const [videoUrl, setVideoUrl] = useState(existing?.videoUrl ?? ''); @@ -1154,6 +1175,39 @@ export function CrewForm({ existing }: CrewFormProps) { {t('socialUi.coordinator.useMine')} )} + {parsedCoordinator?.pubkey && ( +
+ + + {t(HEALTH_LABEL[coordinatorHealth.status] ?? 'socialUi.coordinator.statusIdle')} + +
+ )}

{t('socialUi.coordinator.pointerNote')}

);