mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-07 08:27:12 +00:00
Share SSE subscription management, reuse query key builders, and remove duplicate route mapping/error helpers from the SWR refactor.
127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import useSWRMutation from "swr/mutation";
|
|
import { useSWRConfig } from "swr";
|
|
import type {
|
|
PreviewUrlResponse,
|
|
RunStatusResponse,
|
|
} from "@qltysh/fabro-api-client";
|
|
|
|
import { apiJsonMutation } from "./api-client";
|
|
import { queryKeys } from "./query-keys";
|
|
import type { LifecycleAction, LifecycleActionError } from "./run-actions";
|
|
import {
|
|
archiveRun,
|
|
cancelRun,
|
|
isLifecycleActionError,
|
|
unarchiveRun,
|
|
} from "./run-actions";
|
|
|
|
export type PreviewRunArg = {
|
|
port: number;
|
|
expires_in_secs: number;
|
|
};
|
|
|
|
export type PreviewMutationResult = {
|
|
intent: "preview";
|
|
url: string;
|
|
};
|
|
|
|
export type LifecycleMutationResult =
|
|
| {
|
|
intent: LifecycleAction;
|
|
ok: true;
|
|
run: RunStatusResponse;
|
|
}
|
|
| {
|
|
intent: LifecycleAction;
|
|
ok: false;
|
|
error: LifecycleActionError | null;
|
|
};
|
|
|
|
export function usePreviewRun(id: string | undefined) {
|
|
return useSWRMutation(
|
|
id ? queryKeys.runs.preview(id) : null,
|
|
async (key: string, { arg }: { arg: PreviewRunArg }): Promise<PreviewMutationResult> => {
|
|
const result = await apiJsonMutation<PreviewUrlResponse, PreviewRunArg>(key, { arg });
|
|
return { intent: "preview", url: result.url };
|
|
},
|
|
);
|
|
}
|
|
|
|
export function useCancelRun(id: string | undefined) {
|
|
return useLifecycleMutation(id, "cancel", cancelRun);
|
|
}
|
|
|
|
export function useArchiveRun(id: string | undefined) {
|
|
return useLifecycleMutation(id, "archive", archiveRun);
|
|
}
|
|
|
|
export function useUnarchiveRun(id: string | undefined) {
|
|
return useLifecycleMutation(id, "unarchive", unarchiveRun);
|
|
}
|
|
|
|
function useLifecycleMutation(
|
|
id: string | undefined,
|
|
intent: LifecycleAction,
|
|
action: (id: string) => Promise<RunStatusResponse>,
|
|
) {
|
|
const { mutate } = useSWRConfig();
|
|
const key = id ? queryKeys.runs[intent](id) : null;
|
|
return useSWRMutation(
|
|
key,
|
|
async (): Promise<LifecycleMutationResult> => {
|
|
if (!id) {
|
|
return { intent, ok: false, error: null };
|
|
}
|
|
try {
|
|
return { intent, ok: true, run: await action(id) };
|
|
} catch (error) {
|
|
return {
|
|
intent,
|
|
ok: false,
|
|
error: isLifecycleActionError(error) ? error : null,
|
|
};
|
|
}
|
|
},
|
|
{
|
|
onSuccess: (result) => {
|
|
if (!id || !result.ok) return;
|
|
void mutate(queryKeys.runs.detail(id));
|
|
void mutate(queryKeys.boards.runs());
|
|
void mutate(queryKeys.runs.billing(id));
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
export function useToggleDemoMode() {
|
|
const { mutate } = useSWRConfig();
|
|
return useSWRMutation(
|
|
queryKeys.demo.toggle(),
|
|
async (key: string, { arg }: { arg: { enabled: boolean } }) => {
|
|
await apiJsonMutation<void, { enabled: boolean }>(key, { arg });
|
|
},
|
|
{
|
|
onSuccess: () => {
|
|
void mutate(queryKeys.auth.me());
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
export function useLoginDevToken() {
|
|
return useSWRMutation(
|
|
"/auth/login/dev-token",
|
|
async (key: string, { arg }: { arg: { token: string } }) => {
|
|
const response = await fetch(key, {
|
|
method: "POST",
|
|
credentials: "include",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(arg),
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(response.statusText || `HTTP ${response.status}`);
|
|
}
|
|
return response.json() as Promise<{ ok: boolean }>;
|
|
},
|
|
);
|
|
}
|