76 lines
2.7 KiB
TypeScript
76 lines
2.7 KiB
TypeScript
import { content } from "@deadhead/content";
|
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useNavigate } from "react-router";
|
|
import { useApi } from "../api/context";
|
|
import { formatCredits } from "../format";
|
|
import { errorMessage, useLoadedPlayer } from "../state/actions";
|
|
import { PLAYER_STATE_KEY } from "../state/player";
|
|
|
|
/**
|
|
* The one-time deal (decision 0.5.30): shown when the server says it is
|
|
* available, after any delivery summary has been dismissed. There is no
|
|
* decline option.
|
|
*/
|
|
export function DealModal() {
|
|
const state = useLoadedPlayer();
|
|
const api = useApi();
|
|
const queryClient = useQueryClient();
|
|
const navigate = useNavigate();
|
|
const accept = useMutation({
|
|
mutationFn: () => api.call("acceptDeal", {}),
|
|
onSuccess: (newState) => {
|
|
queryClient.setQueryData(PLAYER_STATE_KEY, newState);
|
|
void navigate("/");
|
|
},
|
|
});
|
|
|
|
if (!state.tutorial?.dealAvailable || state.summaries.length > 0) return null;
|
|
|
|
const { dealLoanAmount, loanRepaymentShare } = content.config;
|
|
const courier = content.shipModel("courier")!;
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-30 flex items-end justify-center bg-black/70 p-4 sm:items-center">
|
|
<div
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="deal-title"
|
|
className="w-full max-w-md rounded-xl border border-amber-500/50 bg-slate-900 p-4"
|
|
>
|
|
<h2 id="deal-title" className="text-lg font-semibold text-amber-300">
|
|
An offer from Halvorsen
|
|
</h2>
|
|
<p className="mt-2 text-sm text-slate-300">
|
|
Old Halvorsen is retiring. He'll sell you his Courier and his Earth bay. Pay him back
|
|
out of every job.
|
|
</p>
|
|
<dl className="mt-3 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-sm">
|
|
<dt className="text-slate-400">You get</dt>
|
|
<dd>A {courier.name} and a bay at Earth</dd>
|
|
<dt className="text-slate-400">Loan</dt>
|
|
<dd aria-label="Loan amount" className="tabular-nums">
|
|
{formatCredits(dealLoanAmount)}
|
|
</dd>
|
|
<dt className="text-slate-400">Repayment</dt>
|
|
<dd aria-label="Repayment share">
|
|
{Math.round(loanRepaymentShare * 100)}% of every payout until it's paid off
|
|
</dd>
|
|
</dl>
|
|
{accept.isError && (
|
|
<p role="alert" className="mt-3 text-sm text-red-400">
|
|
{errorMessage(accept.error)}
|
|
</p>
|
|
)}
|
|
<button
|
|
type="button"
|
|
onClick={() => accept.mutate()}
|
|
disabled={accept.isPending}
|
|
className="mt-4 w-full rounded-lg bg-amber-500 py-2 font-semibold text-slate-950 disabled:opacity-60"
|
|
>
|
|
Shake on it
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|