1import { useAtomRefresh } from "@effect/atom-react";
2import {
3 maintainerEditsChoiceInForce,
4 type MaintainerEditsChoice,
5} from "@t3tools/client-runtime/pull-request-editing";
6import { squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
7import type { PullRequestDetail } from "@t3tools/contracts";
8import { AsyncResult } from "effect/reactivity";
9import { useRef, useState } from "react";
10import * as Dialog from "../../components/ui/Dialog";
11import { composerPullRequests } from "../../state/pull-requests";
12import { useAtomCommand } from "../../state/use-atom-command";
13import { pullRequestTarget, type PullRequestParams } from "./usePullRequestDiff";
14
15export function usePullRequestMaintainerEdits(
16 params: PullRequestParams,
17 pr: PullRequestDetail | null,
18 canEdit: boolean,
19) {
20 const target = pullRequestTarget(params);
21 const update = useAtomCommand(composerPullRequests.update, { reportFailure: false });
22 const refreshDetail = useAtomRefresh(composerPullRequests.detail(target));
23 const pending = useRef(false);
24 const [saving, setSaving] = useState(false);
25 const [choice, setChoice] = useState<MaintainerEditsChoice | null>(null);
26 const kept = maintainerEditsChoiceInForce(choice, pr?.url ?? "", pr?.observedAt, saving);
27 if (kept !== choice) {
28 setChoice(kept);
29 }
30 const value = kept?.value ?? pr?.maintainerCanModify === true;
31 const save = async (next: boolean) => {
32 if (pending.current || pr === null || !canEdit) return;
33 pending.current = true;
34 const previousChoice = choice;
35 setSaving(true);
36 setChoice({ key: pr.url, observedAt: pr.observedAt, value: next });
37 const response = await update({
38 ...target,
39 input: { ...target.input, maintainerCanModify: next },
40 });
41 pending.current = false;
42 setSaving(false);
43 if (AsyncResult.isFailure(response)) {
44 setChoice(previousChoice);
45 const cause = squashAtomCommandFailure(response);
46 Dialog.alert(
47 "Could not save maintainer access",
48 cause instanceof Error ? cause.message : "Try again.",
49 );
50 return;
51 }
52 refreshDetail();
53 };
54 return {
55 visible: canEdit,
56 value,
57 saving,
58 subtitle: saving
59 ? "Saving…"
60 : "Maintainers can push to this branch. If your fork has workflows, this can also give access to its secrets.",
61 toggle: () => void save(!value),
62 };
63}