Files
MikrotikManager/hooks/use-alerts-config-write.ts

38 lines
2.9 KiB
TypeScript

"use client"
import {useEffect,useRef,useState} from "react"
import {normalizeAlertsConfig,type PutRulesBody} from "@mmapp/contracts/alerts"
import {can} from "@/lib/auth"
import {ApiClientError} from "@/shared/api/http-client"
import {saveAlertRules} from "@/shared/api/alerts"
const pending=new Set<string>()
const key=(source:string)=>"mm:alerts-rules-pending:"+source
function unresolved(source:string){try{return pending.has(source)||sessionStorage.getItem(key(source))==="true"}catch{return pending.has(source)}}
function checkpoint(source:string,value:boolean){if(value)pending.add(source);else pending.delete(source);try{if(value)sessionStorage.setItem(key(source),"true");else sessionStorage.removeItem(key(source))}catch{/* The memory guard survives section navigation. */}}
export function useAlertsConfigWrite(base:string,live:boolean,available:boolean,expectedRevision:string|null,onBegin:()=>boolean,onEnd:()=>void){
const source=JSON.stringify([live,base])
const [busy,setBusy]=useState(false),[error,setError]=useState<string|null>(null),[outcome,setOutcome]=useState<string|null>(null),[unknown,setUnknown]=useState(false),[ready,setReady]=useState(false)
const active=useRef(true),lock=useRef(false),controller=useRef<AbortController|null>(null)
useEffect(()=>{active.current=true;queueMicrotask(()=>{if(active.current){setReady(true);setUnknown(unresolved(source))}});return()=>{active.current=false;controller.current?.abort()}},[source])
const enabled=ready&&live&&available&&!!expectedRevision&&can("mm:alerts:write")
async function save(payload:PutRulesBody){
if(!enabled||lock.current||unknown||!active.current||!can("mm:alerts:write"))return null
let normalized:ReturnType<typeof normalizeAlertsConfig>
try{normalized=normalizeAlertsConfig(payload)}catch(e){setError(e instanceof Error?e.message:"Проверьте параметры правил");return null}
if(!onBegin())return null
lock.current=true;controller.current=new AbortController();setBusy(true);setError(null);setOutcome(null);checkpoint(source,true);setUnknown(true)
const current=()=>active.current&&can("mm:alerts:write")
try{
const receipt=await saveAlertRules(base,normalized,{signal:controller.current.signal,expectedRevision:expectedRevision??undefined});if(!current())return null
checkpoint(source,false);setUnknown(false);setOutcome("Правила и группы сохранены в БД");return receipt
}catch(e){
const rejected=e instanceof ApiClientError&&[400,401,403,409,412,422,428].includes(e.status)
if(rejected&&current())checkpoint(source,false)
if(current()){setUnknown(!rejected);setError(e instanceof Error?e.message:"Результат сохранения правил не получен")};return null
}finally{lock.current=false;controller.current=null;if(active.current){setBusy(false);onEnd()}}
}
function review(){if(!enabled||busy)return;checkpoint(source,false);setUnknown(false)}
return {save,busy,error,outcome,unknown,enabled,review}
}