import type { Pilot } from "@deadhead/schema"; import { useEffect, useState } from "react"; import { useNavigate } from "react-router"; import { useApi } from "../api/context"; import { useLoadedPlayer } from "../state/actions"; import { usePreferences } from "../state/preferences"; import { Button, Sheet } from "../ui"; import { useAwayOpen } from "./AwaySummary"; /** The id of the skill point pop-up in dismissed tips (CR-011 one-time tips). */ export const SKILL_POINTS_TIP = "skill-points"; /** "You" for the player's own pilot, else the pilot's first name. */ function callName(pilot: Pilot): string { return pilot.isAvatar ? "You" : (pilot.name.split(" ")[0] ?? pilot.name); } /** "You", "You and Rosa", "You, Rosa and Jin". */ function listNames(names: string[]): string { return names.length < 2 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`; } /** * The skill point nudge (decision 0.5.109): once the business is the player's * and the notification permission prompt has been answered, a one-time tip * listing every pilot with unspent skill points. "Show tips again" brings it * back. */ export function SkillPointPrompt() { const state = useLoadedPlayer(); const awayOpen = useAwayOpen((s) => s.open); const api = useApi(); const navigate = useNavigate(); const dismissed = usePreferences((p) => p.dismissedTips.includes(SKILL_POINTS_TIP)); const dismissTip = usePreferences((p) => p.dismissTip); const owner = state.tutorial === null; // After the deal, wait for the player to answer the permission prompt (decision 0.5.91). const [promptAnswered, setPromptAnswered] = useState(false); useEffect(() => { if (!owner) return; let live = true; void (api.notificationPrompt?.() ?? Promise.resolve()).then(() => { if (live) setPromptAnswered(true); }); return () => { live = false; }; }, [api, owner]); const ready = state.pilots.filter((p) => p.skillPointsAvailable > 0); if (!owner || !promptAnswered || dismissed || ready.length === 0) return null; // Let delivery summaries go first. if (state.summaries.length > 0 || awayOpen) return null; const names = ready.map(callName); const subject = ready.length === 1 ? `${names[0]} ${ready[0]!.isAvatar ? "have" : "has"}` : `${listNames(names)} ${ready.length === 2 ? "both" : "all"} have`; return (

{subject} skill points to spend. Skills unlock better-paying contracts: heavier loads, valuable cargo, longer routes.

{ready.map((pilot, i) => ( {i > 0 && " ยท "} {callName(pilot)}:{" "} {pilot.skillPointsAvailable} {pilot.skillPointsAvailable === 1 ? "point" : "points"} ))}

); }