Files
tolaria/src/hooks/useGitSetupState.ts
2026-05-16 12:28:56 +02:00

134 lines
4.0 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import { invoke } from '@tauri-apps/api/core'
import { isTauri, mockInvoke } from '../mock-tauri'
import type { GitSetupPreference } from '../types'
export type { GitSetupPreference } from '../types'
export type GitRepoState = 'checking' | 'missing' | 'ready'
type GitRepoStatus = { path: string; state: GitRepoState }
interface GitSetupStateConfig {
gitSetupPreference?: GitSetupPreference | null
onGitSetupPreferenceChange?: (preference: GitSetupPreference) => void
onToast: (message: string | null) => void
resolvedPath: string
windowMode: boolean
}
function checkGitRepo(resolvedPath: string): Promise<boolean> {
return isTauri()
? invoke<boolean>('is_git_repo', { vaultPath: resolvedPath })
: mockInvoke<boolean>('is_git_repo', { vaultPath: resolvedPath })
}
function useCheckedGitRepoState(resolvedPath: string) {
const [gitRepoStatus, setGitRepoStatus] = useState<GitRepoStatus>({
path: '',
state: 'checking',
})
const gitRepoState = gitRepoStatus.path === resolvedPath ? gitRepoStatus.state : 'checking'
useEffect(() => {
if (!resolvedPath) return
let cancelled = false
checkGitRepo(resolvedPath)
.then(isGit => {
if (!cancelled) setGitRepoStatus({ path: resolvedPath, state: isGit ? 'ready' : 'missing' })
})
.catch(() => {
if (!cancelled) setGitRepoStatus({ path: resolvedPath, state: 'ready' })
})
return () => {
cancelled = true
}
}, [resolvedPath])
const markGitRepoReady = useCallback(() => {
setGitRepoStatus({ path: resolvedPath, state: 'ready' })
}, [resolvedPath])
return { gitRepoState, markGitRepoReady }
}
function shouldShowGitSetupDialog({
dismissedGitSetupPath,
gitRepoState,
gitSetupPreference,
manuallyOpened,
resolvedPath,
windowMode,
}: {
dismissedGitSetupPath: string | null
gitRepoState: GitRepoState
gitSetupPreference: GitSetupPreference | null | undefined
manuallyOpened: boolean
resolvedPath: string
windowMode: boolean
}): boolean {
if (windowMode || gitRepoState !== 'missing') return false
if (manuallyOpened) return true
return gitSetupPreference !== 'never' && dismissedGitSetupPath !== resolvedPath
}
export function useGitSetupState({
gitSetupPreference = 'prompt',
onGitSetupPreferenceChange,
onToast,
resolvedPath,
windowMode,
}: GitSetupStateConfig) {
const [dismissedGitSetupPath, setDismissedGitSetupPath] = useState<string | null>(null)
const [manuallyOpened, setManuallyOpened] = useState(false)
const { gitRepoState, markGitRepoReady } = useCheckedGitRepoState(resolvedPath)
const openGitSetupDialog = useCallback(() => {
if (gitRepoState !== 'missing') return
setManuallyOpened(true)
setDismissedGitSetupPath(null)
}, [gitRepoState])
const dismissGitSetupDialog = useCallback(() => {
setManuallyOpened(false)
setDismissedGitSetupPath(resolvedPath)
}, [resolvedPath])
const neverForVaultGitSetupDialog = useCallback(() => {
onGitSetupPreferenceChange?.('never')
setManuallyOpened(false)
setDismissedGitSetupPath(resolvedPath)
}, [onGitSetupPreferenceChange, resolvedPath])
const handleInitGitRepo = useCallback(async () => {
if (isTauri()) {
await invoke('init_git_repo', { vaultPath: resolvedPath })
} else {
await mockInvoke('init_git_repo', { vaultPath: resolvedPath })
}
markGitRepoReady()
onGitSetupPreferenceChange?.('prompt')
setManuallyOpened(false)
setDismissedGitSetupPath(null)
onToast('Git initialized for this vault')
}, [markGitRepoReady, onGitSetupPreferenceChange, onToast, resolvedPath])
const showGitSetupDialog = shouldShowGitSetupDialog({
dismissedGitSetupPath,
gitRepoState,
gitSetupPreference,
manuallyOpened,
resolvedPath,
windowMode,
})
return {
dismissGitSetupDialog,
gitRepoState,
handleInitGitRepo,
neverForVaultGitSetupDialog,
openGitSetupDialog,
showGitSetupDialog,
shouldShowGitSetupDialog: showGitSetupDialog,
}
}