fix(alerts): подтверждать запись правил и сохранять формы при сбое
This commit is contained in:
1 parent
875819c577
commit
9c1d14635a
9 files changed
+198
-154
No files matched your search
@@ -0,0 +1,37 @@
|
||||
"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,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&&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});if(!current())return null
|
||||
checkpoint(source,false);setUnknown(false);setOutcome("Правила и группы сохранены в БД");return receipt
|
||||
}catch(e){
|
||||
const rejected=e instanceof ApiClientError&&[400,401,403,409,422].includes(e.status)
|
||||
if(rejected&¤t())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}
|
||||
}
|
||||
Reference in new issue
Block a user