Rechtliches: Daten-Hook fuer Rechtstexte und Anbieter-Vertraege
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1212173cb4
commit
31be2af4c3
1 file changed
+167
@@ -0,0 +1,167 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import {
|
||||
COLLECTIONS,
|
||||
DATABASE_ID,
|
||||
LEGAL_BUCKET_ID,
|
||||
ID,
|
||||
Query,
|
||||
databases,
|
||||
storage,
|
||||
} from '../lib/appwrite'
|
||||
import { planNewVersion } from '../lib/legal'
|
||||
|
||||
const isMissing = (err) => err?.code === 404 || /not found/i.test(err?.message || '')
|
||||
|
||||
async function listAll(collectionId, queries = []) {
|
||||
const res = await databases.listDocuments(DATABASE_ID, collectionId, [...queries, Query.limit(5000)])
|
||||
return res.documents || []
|
||||
}
|
||||
|
||||
/** Laedt die Dateinamen des Buckets, damit Listen Namen statt IDs zeigen. */
|
||||
async function listFileNames() {
|
||||
try {
|
||||
const res = await storage.listFiles(LEGAL_BUCKET_ID, [Query.limit(5000)])
|
||||
return Object.fromEntries((res.files || []).map((f) => [f.$id, f.name]))
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadFiles(files = []) {
|
||||
const ids = []
|
||||
for (const file of files) {
|
||||
const created = await storage.createFile(LEGAL_BUCKET_ID, ID.unique(), file)
|
||||
ids.push(created.$id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
export function fileUrl(fileId) {
|
||||
return storage.getFileView(LEGAL_BUCKET_ID, fileId).toString()
|
||||
}
|
||||
|
||||
export function fileDownloadUrl(fileId) {
|
||||
return storage.getFileDownload(LEGAL_BUCKET_ID, fileId).toString()
|
||||
}
|
||||
|
||||
function useLoader(load) {
|
||||
const [state, setState] = useState({ loading: true, error: null, missingSetup: false })
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
setData(await load())
|
||||
setState({ loading: false, error: null, missingSetup: false })
|
||||
} catch (err) {
|
||||
console.error('Rechtliches laden:', err)
|
||||
setData(null)
|
||||
setState({ loading: false, error: isMissing(err) ? null : err.message, missingSetup: isMissing(err) })
|
||||
}
|
||||
}, [load])
|
||||
|
||||
useEffect(() => {
|
||||
refresh()
|
||||
}, [refresh])
|
||||
|
||||
return { data, ...state, setError: (error) => setState((s) => ({ ...s, error })), refresh }
|
||||
}
|
||||
|
||||
const loadTexts = async () => {
|
||||
const [documents, versions, fileNames] = await Promise.all([
|
||||
listAll(COLLECTIONS.LEGAL_DOCUMENTS, [Query.orderAsc('sort')]),
|
||||
listAll(COLLECTIONS.LEGAL_VERSIONS),
|
||||
listFileNames(),
|
||||
])
|
||||
return { documents, versions, fileNames }
|
||||
}
|
||||
|
||||
export function useLegalDocuments() {
|
||||
const { data, loading, error, missingSetup, setError, refresh } = useLoader(loadTexts)
|
||||
const versions = data?.versions || []
|
||||
|
||||
// Neue Version anlegen; eine juengere gueltige Version loest die bisherige ab.
|
||||
const addVersion = async (documentKey, input, files) => {
|
||||
const fileIds = await uploadFiles(files)
|
||||
const plan = planNewVersion(versions, { ...input, documentKey })
|
||||
await databases.createDocument(DATABASE_ID, COLLECTIONS.LEGAL_VERSIONS, ID.unique(), {
|
||||
...plan.create,
|
||||
fileIds,
|
||||
})
|
||||
await applyUpdates(plan.updates, 'Neue Version gespeichert')
|
||||
}
|
||||
|
||||
// Entwurf gueltig machen: dieselbe Abloese-Regel wie beim Anlegen.
|
||||
const promoteDraft = async (version) => {
|
||||
const plan = planNewVersion(versions, { ...version, status: 'current' })
|
||||
const { status, validTo } = plan.create
|
||||
await databases.updateDocument(DATABASE_ID, COLLECTIONS.LEGAL_VERSIONS, version.$id, { status, validTo })
|
||||
await applyUpdates(plan.updates, 'Version ist gültig')
|
||||
}
|
||||
|
||||
const applyUpdates = async (updates, done) => {
|
||||
try {
|
||||
for (const u of updates) {
|
||||
await databases.updateDocument(DATABASE_ID, COLLECTIONS.LEGAL_VERSIONS, u.id, u.patch)
|
||||
}
|
||||
await refresh()
|
||||
} catch (err) {
|
||||
await refresh()
|
||||
setError(`${done}, alte Version konnte nicht abgelöst werden: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
const updateVersion = async (id, patch) => {
|
||||
await databases.updateDocument(DATABASE_ID, COLLECTIONS.LEGAL_VERSIONS, id, patch)
|
||||
await refresh()
|
||||
}
|
||||
|
||||
return {
|
||||
documents: data?.documents || [],
|
||||
versions,
|
||||
fileNames: data?.fileNames || {},
|
||||
loading,
|
||||
error,
|
||||
missingSetup,
|
||||
addVersion,
|
||||
promoteDraft,
|
||||
updateVersion,
|
||||
refresh,
|
||||
}
|
||||
}
|
||||
|
||||
const loadContracts = async () => {
|
||||
const [contracts, fileNames] = await Promise.all([
|
||||
listAll(COLLECTIONS.PROVIDER_CONTRACTS, [Query.orderAsc('provider')]),
|
||||
listFileNames(),
|
||||
])
|
||||
return { contracts, fileNames }
|
||||
}
|
||||
|
||||
export function useProviderContracts() {
|
||||
const { data, loading, error, missingSetup, refresh } = useLoader(loadContracts)
|
||||
|
||||
const saveContract = async (values, files, id) => {
|
||||
const newIds = await uploadFiles(files)
|
||||
const existing = id ? data?.contracts.find((c) => c.$id === id)?.fileIds || [] : []
|
||||
const doc = { ...values, fileIds: [...existing, ...newIds] }
|
||||
if (id) await databases.updateDocument(DATABASE_ID, COLLECTIONS.PROVIDER_CONTRACTS, id, doc)
|
||||
else await databases.createDocument(DATABASE_ID, COLLECTIONS.PROVIDER_CONTRACTS, ID.unique(), doc)
|
||||
await refresh()
|
||||
}
|
||||
|
||||
const deleteContract = async (id) => {
|
||||
await databases.deleteDocument(DATABASE_ID, COLLECTIONS.PROVIDER_CONTRACTS, id)
|
||||
await refresh()
|
||||
}
|
||||
|
||||
return {
|
||||
contracts: data?.contracts || [],
|
||||
fileNames: data?.fileNames || {},
|
||||
loading,
|
||||
error,
|
||||
missingSetup,
|
||||
saveContract,
|
||||
deleteContract,
|
||||
refresh,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user