@ -1,4 +1,4 @@
import { useEffect , use State } from 'react'
import { useEffect , use Ref, use State, type ReactNod e } from 'react'
import { Link , useNavigate , useParams } from 'react-router-dom'
import { formatINR } from '@sims/domain'
import {
@ -14,7 +14,7 @@ import { DOC_TONE, DOC_TYPE_TONE, DOC_TYPE_LABEL, useData } from './Clients'
import { PaymentForm } from './client-forms'
/** One pending confirmation — replaces the browser confirm() popup with the styled dialog. */
interface Confirm { title : string ; body : string ; label : string ; tone ? : 'danger' ; run : ( ) = > void }
interface Confirm { title : string ; body : ReactNode ; label : string ; tone ? : 'danger' ; run : ( ) = > void | Promise < void > }
const TITLE : Record < Doc [ ' docType ' ] , string > = {
QUOTATION : 'Quotation' , PROFORMA : 'Proforma Invoice' , INVOICE : 'Tax Invoice' ,
@ -43,6 +43,7 @@ export function DocumentView() {
const [ paying , setPaying ] = useState ( false )
const [ sending , setSending ] = useState ( false )
const [ confirm , setConfirm ] = useState < Confirm | undefined > ( )
const cancelReasonRef = useRef ( '' ) // read in the confirm's run() closure (state would be stale there)
// PDF preview via blob URL — an <iframe src> can't carry the bearer header.
const [ pdfUrl , setPdfUrl ] = useState < string | undefined > ( )
@ -182,13 +183,25 @@ export function DocumentView() {
< Button
tone = "danger"
disabled = { acting }
onClick = { ( ) = > setConfirm ( {
onClick = { ( ) = > { cancelReasonRef . current = '' ; setConfirm ( {
title : 'Cancel document' ,
body : ` Cancel ${ doc . docNo } ? The number stays consumed. ` ,
body : (
< div style = { { display : 'flex' , flexDirection : 'column' , gap : 8 } } >
< span > Cancel < strong > { doc . docNo } < / strong > ? The number stays consumed — this can ' t be undone . < / span >
< label style = { { fontSize : 13 } } >
Reason for cancelling < span style = { { color : 'var(--err)' } } > * < / span >
< textarea className = "wf" rows = { 2 } autoFocus placeholder = "e.g. wrong client, duplicate, billing error…"
onChange = { ( e ) = > { cancelReasonRef . current = e . target . value } } style = { { marginTop : 4 } } / >
< / label >
< / div >
) ,
label : 'Cancel document' ,
tone : 'danger' ,
run : ( ) = > act ( 'cancel' , undefined , { ok : 'Cancelled' } ) ,
} ) }
run : ( ) = > {
if ( cancelReasonRef . current . trim ( ) === '' ) return Promise . reject ( new Error ( 'Please add a reason for cancelling' ) )
act ( 'cancel' , { reason : cancelReasonRef.current.trim ( ) } , { ok : 'Cancelled' } )
} ,
} ) } }
>
Cancel
< / Button >