1import { useAtomRefresh } from "@effect/atom-react";
2import { squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
3import type {
4 PullRequestAction,
5 PullRequestDetail,
6 PullRequestUpdateMethod,
7} from "@t3tools/contracts";
8import { useRef, useState } from "react";
9import { Alert } from "react-native";
10import { composerPullRequests } from "../../state/pull-requests";
11import { useAtomCommand } from "../../state/use-atom-command";
12import { canPerformPullRequestAction } from "./pullRequestActions";
13import { pullRequestTarget, type PullRequestParams } from "./usePullRequestDiff";
14import { usePullRequestPermissions } from "./usePullRequestPermissions";
15
16/** Small row actions stay in place, preserving expanded rows and scroll position. */
17export function usePullRequestAction(params: PullRequestParams, pr: PullRequestDetail | null) {
18 const target = pullRequestTarget(params);
19 const permissions = usePullRequestPermissions(params, pr);
20 const run = useAtomCommand(composerPullRequests.runAction, { reportFailure: false });
21 const refreshDetail = useAtomRefresh(composerPullRequests.detail(target));
22 const refreshActivity = useAtomRefresh(composerPullRequests.activity(target));
23 const pending = useRef(false);
24 const [busy, setBusy] = useState(false);
25 const available = (action: PullRequestAction) =>
26 pr !== null && !busy && permissions.canWrite && canPerformPullRequestAction(pr, action);
27 const perform = async (action: PullRequestAction, updateMethod?: PullRequestUpdateMethod) => {
28 if (pending.current || !available(action)) return;
29 pending.current = true;
30 setBusy(true);
31 try {
32 const response = await run({
33 ...target,
34 input: { ...target.input, action, ...(updateMethod ? { updateMethod } : {}) },
35 });
36 if (response._tag === "Failure") throw squashAtomCommandFailure(response);
37 refreshDetail();
38 refreshActivity();
39 } catch (cause) {
40 Alert.alert(
41 "Couldn't update this pull request",
42 cause instanceof Error ? cause.message : "Try again.",
43 );
44 } finally {
45 pending.current = false;
46 setBusy(false);
47 }
48 };
49 const confirm = (action: PullRequestAction, title: string, message: string) =>
50 Alert.alert(title, message, [
51 { text: "Cancel", style: "cancel" },
52 {
53 text: title,
54 style: action === "close" || action === "delete-branch" ? "destructive" : "default",
55 onPress: () => void perform(action),
56 },
57 ]);
58 return { available, perform, confirm, busy };
59}