@@ -3,27 +3,23 @@ import { Link, useLocation, useNavigate } from "react-router-dom";
import { connect } from "react-redux" ;
import { useTranslation } from "react-i18next" ;
import { createStructuredSelector } from "reselect" ;
import SocketIO from "socket.io-client" ;
import queryString from "query-string" ;
import { useQuery } from "@apollo/client" ;
import { Button , Card , Col , Result , Row , Select , Space , Switch } from "antd" ;
import { useSplitTreatments } from "@splitsoftware/splitio-react" ;
import { auth } from "../../firebase/firebase.utils" ;
import { useSocket } from "../../contexts/SocketIO/useSocket.js" ;
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx" ;
import { QUERY _JOB _EXPORT _DMS } from "../../graphql/jobs.queries" ;
import { selectBodyshop } from "../../redux/user/user.selectors" ;
import { insertAuditTrail , setBreadcrumbs , setSelectedHeader } from "../../redux/application/application.actions" ;
import InstanceRenderManager from "../../utils/instanceRenderMgr" ;
import AuditTrailMapping from "../../utils/AuditTrailMappings" ;
import { determineDmsTyp e } from "../../utils/determineDmsType " ;
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.componen t";
import { bodyshopHasDmsKey , DMS _MAP , getDmsMode , isWssMod e } from "../../utils/dmsUtils.js " ;
import legacySocket from "../../utils/legacySocke t";
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component" ;
import AlertComponent from "../../components/alert/alert.component" ;
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component" ;
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component" ;
@@ -43,30 +39,37 @@ const mapDispatchToProps = (dispatch) => ({
export default connect ( mapStateToProps , mapDispatchToProps ) ( DmsContainer ) ;
// Legacy /ws socket (CDK/PBS)
export const socket = SocketIO ( import . meta . env . PROD ? import . meta . env . VITE _APP _AXIOS _BASE _API _URL : "" , {
path : "/ws " ,
withCredentials : true ,
auth : async ( callback ) => {
const token = auth . currentUser && ( await auth . currentUser . getIdToken ( ) ) ;
callback ( { token } ) ;
const DMS _SOCKET _EVENTS = {
[ DMS _MAP . reynolds ] : {
log : "rr-log-event " ,
partialResult : "rr-export-job:result" ,
cashierNeeded : "rr-cashiering-required" ,
exportSuccess : "export-success" ,
exportFailed : "export-failed"
} ,
[ DMS _MAP . fortellis ] : {
log : "fortellis-log-event" ,
exportSuccess : "export-success" ,
exportFailed : "export-failed"
} ,
[ DMS _MAP . cdk ] : {
log : "log-event" ,
exportSuccess : "export-success" ,
exportFailed : "export-failed"
} ,
[ DMS _MAP . pbs ] : {
log : "log-event" ,
exportSuccess : "export-success" ,
exportFailed : "export-failed"
}
} ) ;
} ;
export function DmsContainer ( { bodyshop , setBreadcrumbs , setSelectedHeader , insertAuditTrail } ) {
const { t } = useTranslation ( ) ;
const dms = determineDmsType ( bodyshop ) ;
const history = useNavigate ( ) ;
const search = queryString . parse ( useLocation ( ) . search ) ;
const [ logLevel , setLogLevel ] = useState ( dms === "pbs" ? "INFO" : "DEBUG" ) ;
const [ logs , setLogs ] = useState ( [ ] ) ;
const [ detailsOpen , setDetailsOpen ] = useState ( false ) ; // false => button shows "Expand All"
const [ detailsNonce , setDetailsNonce ] = useState ( 0 ) ; // forces child to react to toggles
const [ colorizeJson , setColorizeJson ] = useState ( false ) ; // default: OFF
const { jobId } = search ;
const notification = useNotification ( ) ;
const {
@@ -77,11 +80,31 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
splitKey : bodyshop . imexshopid
} ) ;
// New unified wss socket (Fortellis, RR)
// Compute a single normalized mode and pick the proper socket
const mode = getDmsMode ( bodyshop , Fortellis . treatment ) ; // "rr" | "fortellis" | "cdk" | "pbs" | "none"
const { socket : wsssocket } = useSocket ( ) ;
const activeSocket = useMemo ( ( ) => {
return dms === "rr" || ( dms === "cdk" && Fortellis . treatment === "on" ) ? wsssocket : socket ;
} , [ dms , Fortellis . treatment , wsssocket , socket ] ) ;
const activeSocket = useMemo ( ( ) => ( isWssMode ( mode ) ? wsssocket : legacySocket ) , [ mode , wsssocket ] ) ;
const [ isConnected , setIsConnected ] = useState ( ! ! activeSocket ? . connected ) ;
// One place to set log level
const [ logLevel , setLogLevel ] = useState ( mode === DMS _MAP . pbs ? "INFO" : "DEBUG" ) ;
const setActiveLogLevel = ( level ) => {
if ( ! activeSocket ) return ;
activeSocket . emit ( "set-log-level" , level ) ;
} ;
const [ logs , setLogs ] = useState ( [ ] ) ;
const [ detailsOpen , setDetailsOpen ] = useState ( false ) ;
const [ detailsNonce , setDetailsNonce ] = useState ( 0 ) ;
const [ colorizeJson , setColorizeJson ] = useState ( false ) ;
const [ rrOpenRoLimit , setRrOpenRoLimit ] = useState ( false ) ;
const clearRrOpenRoLimit = ( ) => setRrOpenRoLimit ( false ) ;
const [ rrCashierPending , setRrCashierPending ] = useState ( false ) ;
const { loading , error , data } = useQuery ( QUERY _JOB _EXPORT _DMS , {
variables : { id : jobId } ,
@@ -97,45 +120,51 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
setDetailsNonce ( ( n ) => n + 1 ) ;
} ;
const [ rrOpenRoLimit , setRrOpenRoLimit ] = useState ( false ) ;
const clearRrOpenRoLimit = ( ) => setRrOpenRoLimit ( false ) ;
// Channel names per mode to avoid branching everywhere
const channels = useMemo ( ( ) => DMS _SOCKET _EVENTS [ mode ] || { } , [ mode ] ) ;
// NEW: RR “cashiering required” UX hold
const [ rrCashierPending , setRrCashierPending ] = useState ( false ) ;
const providerLabel = useMemo (
( ) =>
( {
[ DMS _MAP . reynolds ] : "Reynolds" ,
[ DMS _MAP . fortellis ] : "Fortellis" ,
[ DMS _MAP . cdk ] : "CDK" ,
[ DMS _MAP . pbs ] : "PBS"
} ) [ mode ] || "DMS" ,
[ mode ]
) ;
const transportLabel = isWssMode ( mode ) ? "App Socket (WSS)" : "Legacy Socket (WS)" ;
const bannerMessage = ` Posting to ${ providerLabel } | ${ transportLabel } | ${
isConnected ? "Connected" : "Disconnected"
} ` ;
const handleExportFailed = ( payload = { } ) => {
const { title , friendlyMessage , error , severity , errorCode , vendorStatusCode } = payload ;
const { title , friendlyMessage , error : errText , severity , errorCode , vendorStatusCode } = payload ;
const msg =
friendlyMessage ||
error ||
errText ||
t ( "dms.errors.exportfailedgeneric" , "We couldn't complete the export. Please try again." ) ;
const vendorTitle = title || ( dms === "rr" ? "Reynolds" : "DMS" ) ;
const vendorTitle = title || ( mode === DMS _MAP . reynolds ? "Reynolds" : "DMS" ) ;
// Detect the specific RR “max open ROs” case
const isRrOpenRoLimit =
dms === "rr" &&
mode === DMS _MAP . reynolds &&
( vendorStatusCode === 507 ||
/MAX_OPEN_ROS/i . test ( String ( errorCode || "" ) ) ||
/maximum number of open repair orders/i . test ( String ( msg || "" ) . toLowerCase ( ) ) ) ;
// Soft/warn default for known cases
const sev = severity || ( isRrOpenRoLimit ? "warning" : "error" ) ;
// Show toast for *other* failures; for the open RO limit, switch to blocking banner UX instead.
if ( ! isRrOpenRoLimit ) {
const notifyKind = sev === "warning" && typeof notification . warning === "function" ? "warning" : "error" ;
notification [ notifyKind ] ( {
message : vendorTitle ,
description : msg ,
duration : 10
} ) ;
notification [ notifyKind ] ( { message : vendorTitle , description : msg , duration : 10 } ) ;
} else {
setRrOpenRoLimit ( true ) ;
}
// Mirror to the on-screen log card
setLogs ( ( prev ) => [
... prev ,
{
@@ -147,254 +176,218 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
] ) ;
} ;
// keep this in sync if mode/socket flips
useEffect ( ( ) => {
setIsConnected ( ! ! activeSocket ? . connected ) ;
} , [ activeSocket ] ) ;
useEffect ( ( ) => {
document . title = t ( "titles.dms" , {
app : InstanceRenderManager ( {
imex : "$t(titles.imexonline)" ,
rome : "$t(titles.romeonline)"
} )
app : InstanceRenderManager ( { imex : "$t(titles.imexonline)" , rome : "$t(titles.romeonline)" } )
} ) ;
setSelectedHeader ( "dms" ) ;
setBreadcrumbs ( [
{
link : "/manage/accounting/receivables" ,
label : t ( "titles.bc.accounting-receivables" )
} ,
{
link : "/manage/dms" ,
label : t ( "titles.bc.dms" )
}
{ link : "/manage/accounting/receivables" , label : t ( "titles.bc.accounting-receivables" ) } ,
{ link : "/manage/dms" , label : t ( "titles.bc.dms" ) }
] ) ;
} , [ t , setBreadcrumbs , setSelectedHeader ] ) ;
// Socket wiring (mode-aware)
useEffect ( ( ) => {
// ✅ RR path uses WSS and has two-step flow
if ( dms === "rr" ) {
// set log level on connect and immediately
wsssocket . emit ( "set-log-level" , logLevel ) ;
if ( ! activeSocket ) return ;
const handleConnect = ( ) => wsssocket . emit ( "set-log-level" , logLevel ) ;
const handleReconnect = ( ) =>
setLogs ( ( prev ) => [
... prev ,
{ timestamp : new Date ( ) , level : "warn" , message : "Reconnected to RR Export Service" }
] ) ;
const handleConnectError = ( err ) => {
console . log ( ` connect_error due to ${ err } ` , err ) ;
notification . error ( { message : err . message } ) ;
} ;
const handleLogEvent = ( payload = { } ) => {
const normalized = {
timestamp : payload . timestamp ? new Date ( payload . timestamp ) : payload . ts ? new Date ( payload . ts ) : new Date ( ) ,
level : ( payload . level || "INFO" ) . toUpperCase ( ) ,
message : payload . message || payload . msg || "" ,
// show details regardless of property name
meta : payload . meta ? ? payload . ctx ? ? payload . details ? ? null
} ;
setLogs ( ( prev ) => [ ... prev , normalized ] ) ;
} ;
// FINAL step only (emitted by server after rr-finalize-repair-order)
const handleExportSuccess = ( payload ) => {
const jobId = payload ? . jobId ? ? payload ; // RR sends object; legacy sends raw id
notification . success ( { message : t ( "jobs.successes.exported" ) } ) ;
setRrCashierPending ( false ) ;
insertAuditTrail ( {
jobid : jobId ,
operation : AuditTrailMapping . jobexported ( ) ,
type : "jobexported"
} ) ;
history ( "/manage/accounting/receivables" ) ;
} ;
// STEP 1 result (RO created) – DO NOT navigate; wait for cashiering
const handleRrExportResult = ( ) => {
// Be defensive: if the server didn't already set the banner yet, make it obvious
setRrCashierPending ( true ) ;
setLogs ( ( prev ) => [
... prev ,
{
timestamp : new Date ( ) ,
level : "INFO" ,
message :
"Repair Order created in Reynolds. Complete cashiering in Reynolds, then click Finished/Close to finalize."
}
] ) ;
notification . info ( {
message : "Reynolds RO created" ,
description :
"Complete cashiering in Reynolds, then click Finished/Close to finalize and mark this export complete." ,
duration : 8
} ) ;
// No routing here — we remain on the page for step 2
} ;
// NEW: cashier step required (after create, before finalize)
const handleCashieringRequired = ( payload ) => {
setRrCashierPending ( true ) ;
setLogs ( ( prev ) => [
... prev ,
{
timestamp : new Date ( ) ,
level : "INFO" ,
message :
"Repair Order created in Reynolds. Complete cashiering in Reynolds, then click Finished/Close to finalize." ,
meta : { payload }
}
] ) ;
} ;
wsssocket . on ( "connect" , handleConnect ) ;
wsssocket . on ( "reconnect" , handleReconnect ) ;
wsssocket . on ( "connect_error" , handleConnectError ) ;
// RR channels (over wss)
wsssocket . on ( "rr-log-event" , handleLogEvent ) ;
wsssocket . on ( "rr-export-job:result" , handleRrExportResult ) ;
wsssocket . on ( "export-success" , handleExportSuccess ) ;
wsssocket . on ( "export-failed" , handleExportFailed ) ;
// NEW
wsssocket . on ( "rr-cashiering-required" , handleCashieringRequired ) ;
return ( ) => {
wsssocket . off ( "connect" , handleConnect ) ;
wsssocket . off ( "reconnect" , handleReconnect ) ;
wsssocket . off ( "connect_error" , handleConnectError ) ;
wsssocket . off ( "rr-log-event" , handleLogEvent ) ;
wsssocket . off ( "rr-export-job:result" , handleRrExportResult ) ;
wsssocket . off ( "export-success" , handleExportSuccess ) ;
wsssocket . off ( "export-failed" , handleExportFailed ) ;
wsssocket . off ( "rr-cashiering-required" , handleCashieringRequired ) ;
} ;
// Connect legacy socket if needed
if ( ! isWssMode ( mode ) ) {
if ( activeSocket . disconnected ) activeSocket . connect ( ) ;
}
// Fortellis / CDK behavior (when not RR)
if ( Fortellis . treatment === "on" ) {
wsssocket . emit ( "set-log-level" , logLevel ) ;
// Set log level now and on connect/reconnect
setActiveLogLevel ( logLevel ) ;
const handleLogEvent = ( payload ) => setLogs ( ( prev ) => [ ... prev , payload ] ) ;
const handleExportSuccess = ( payload ) => {
notification . success ( { message : t ( "jobs.successes.exported" ) } ) ;
insertAuditTrail ( {
jobid : payload ,
operation : AuditTrailMapping . jobexported ( ) ,
type : "jobexported"
} ) ;
history ( "/manage/accounting/receivables" ) ;
} ;
const onConnect = ( ) => {
setIsConnected ( true ) ;
setActiveLogLevel ( logLevel ) ;
} ;
// Fortellis logs (wss)
wsssocket . on ( "fortellis-log-event" , handleLogEvent ) ;
wsssocket . on ( "export-success" , handleExportSuccess ) ;
wsssocket . on ( "export-failed" , handleExportFailed ) ;
const onDisconnect = ( ) => setIsConnected ( false ) ;
return ( ) => {
wsssocket . off ( "fortellis-log-event" , handleLogEvent ) ;
wsssocket . off ( "export-success" , handleExportSuccess ) ;
wsssocket . off ( "export-failed" , handleExportFailed ) ;
} ;
} else {
// CDK/PBS via legacy /ws socket
socket . on ( "export-failed" , handleExportFailed ) ;
const onReconnect = ( ) => {
setIsConnected ( true ) ;
setLogs ( ( prev ) => [
... prev ,
{
timestamp : new Date ( ) ,
level : "warn" ,
message : ` Reconnected to ${ mode === DMS _MAP . reynolds ? "RR" : mode === DMS _MAP . fortellis ? "Fortellis" : "DMS" } Export Service `
}
] ) ;
} ;
socket . on ( "connect" , ( ) => socket . emit ( "set-log-level" , logLevel ) ) ;
socket . on ( "reconnect" , ( ) => {
setL ogs ( ( prev ) => [
... prev ,
{ timestamp : new Date ( ) , level : "warn" , message : "Reconnected to CDK Export Service" }
] ) ;
} ) ;
s ocket . on ( "connect_error" , ( err ) => {
console . log ( ` connect_error due to ${ err } ` , err ) ;
notification . error ( { message : err . message } ) ;
} ) ;
socket . on ( "log-event" , ( payload ) => setLogs ( ( prev ) => [ ... prev , payload ] ) ) ;
socket . on ( "export-success" , ( payload ) => {
notification . success ( { message : t ( "jobs.successes.exported" ) } ) ;
insertAuditTrail ( {
jobid : payload ,
operation : AuditTrailMapping . jobexported ( ) ,
type : "jobexported"
} ) ;
history ( "/manage/accounting/receivables" ) ;
const onConnectError = ( err ) => {
// Legacy and WSS both emit this
console . l og( ` connect_error due to ${ err } ` , err ) ;
notification . error ( { message : err . message } ) ;
};
activeSocket . on ( "disconnect" , onDisconnect ) ;
activeS ocket. on ( "connect" , onConnect ) ;
activeSocket . on ( "re connect" , onReconnect ) ;
activeSocket . on ( "connect_error" , onConnectError ) ;
// Logs
const onLog =
mode === DMS _MAP . reynolds
? ( payload = { } ) => {
const normalized = {
timestamp : payload . timestamp
? new Date ( payload . timestamp )
: payload . ts
? new Date ( payload . ts )
: new Date ( ) ,
level : ( payload . level || "INFO" ) . toUpperCase ( ) ,
message : payload . message || payload . msg || "" ,
meta : payload . meta ? ? payload . ctx ? ? payload . details ? ? null
} ;
setLogs ( ( prev ) => [ ... prev , normalized ] ) ;
}
: ( payload ) => setLogs ( ( prev ) => [ ... prev , payload ] ) ;
if ( channels . log ) activeSocket . on ( channels . log , onLog ) ;
// Success / Failed
const onExportSuccess = ( payload ) => {
const jobIdResolved = payload ? . jobId ? ? payload ;
notification . success ( { message : t ( "jobs.successes.exported" ) } ) ;
// Clear RR cashier flag if any
setRrCashierPending ( false ) ;
insertAuditTrail ( {
jobid : jobIdResolved ,
operation : AuditTrailMapping . jobexported ( ) ,
type : "jobexported"
} ) ;
history ( "/manage/accounting/receivables" ) ;
} ;
if ( socket . disconnected ) socket . connect ( ) ;
retur n ( ) => {
socket . removeAllListeners ( ) ;
socket . disconnect ( ) ;
} ;
}
} , [ dms , Fortellis ? . treatment , logLevel , history , insertAuditTrail , notification , t , wsssocket ] ) ;
if ( channels . exportSuccess ) activeSocket . on ( channels . exportSuccess , onExportSuccess ) ;
if ( channels . exportFailed ) activeSocket . o n( channels . exportFailed , handleExportFailed ) ;
// NEW: finalize button callback—emit finalize event
// RR-only extras
const onPartialResult = ( ) => {
setRrCashierPending ( true ) ;
setLogs ( ( prev ) => [
... prev ,
{
timestamp : new Date ( ) ,
level : "INFO" ,
message :
"Repair Order created in Reynolds. Complete cashiering in Reynolds, then click Finished/Close to finalize."
}
] ) ;
notification . info ( {
message : "Reynolds RO created" ,
description :
"Complete cashiering in Reynolds, then click Finished/Close to finalize and mark this export complete." ,
duration : 8
} ) ;
} ;
const onCashierRequired = ( payload ) => {
setRrCashierPending ( true ) ;
setLogs ( ( prev ) => [
... prev ,
{
timestamp : new Date ( ) ,
level : "INFO" ,
message :
"Repair Order created in Reynolds. Complete cashiering in Reynolds, then click Finished/Close to finalize." ,
meta : { payload }
}
] ) ;
} ;
if ( mode === DMS _MAP . reynolds && channels . partialResult ) activeSocket . on ( channels . partialResult , onPartialResult ) ;
if ( mode === DMS _MAP . reynolds && channels . cashierNeeded ) activeSocket . on ( channels . cashierNeeded , onCashierRequired ) ;
return ( ) => {
activeSocket . off ( "connect" , onConnect ) ;
activeSocket . off ( "reconnect" , onReconnect ) ;
activeSocket . off ( "connect_error" , onConnectError ) ;
activeSocket . off ( "disconnect" , onDisconnect ) ;
if ( channels . log ) activeSocket . off ( channels . log , onLog ) ;
if ( channels . exportSuccess ) activeSocket . off ( channels . exportSuccess , onExportSuccess ) ;
if ( channels . exportFailed ) activeSocket . off ( channels . exportFailed , handleExportFailed ) ;
if ( mode === DMS _MAP . reynolds && channels . partialResult )
activeSocket . off ( channels . partialResult , onPartialResult ) ;
if ( mode === DMS _MAP . reynolds && channels . cashierNeeded )
activeSocket . off ( channels . cashierNeeded , onCashierRequired ) ;
// Only tear down legacy socket listeners; don't disconnect WSS from here
if ( ! isWssMode ( mode ) ) {
activeSocket . removeAllListeners ( ) ;
activeSocket . disconnect ( ) ;
}
} ;
} , [ mode , activeSocket , channels , logLevel , notification , t , insertAuditTrail , history ] ) ;
// RR finalize callback (unchanged public behavior)
const handleRrCashierFinished = ( ) => {
if ( ! jobId ) return ;
wsssocket . emit ( "rr-finalize-repair-order" , { jobId } , ( ack ) => {
if ( ack ? . ok ) {
// success path handled by export-success listener
return ;
}
if ( ack ? . error ) {
notification . error ( { message : ack . error } ) ;
}
if ( ! isWssMode ( mode ) ) return ; // RR is WSS-only
activeSocket . emit ( "rr-finalize-repair-order" , { jobId } , ( ack ) => {
if ( ack ? . ok ) return ;
if ( ack ? . error ) notification . error ( { message : ack . error } ) ;
} ) ;
} ;
if ( loading ) return < LoadingSpinner / > ;
if ( error ) return < AlertComponent message = { error . message } type = "error" / > ;
if ( ! jobId || ! ( bodyshop. cdk _dealerid || bodyshop . pbs _serialnumber || bodyshop . rr _dealerid ) || ! data ? . jobs _by _pk )
if ( ! jobId || ! bodyshopHasDmsKey ( bodyshop ) || ! data ? . jobs _by _pk )
return < Result status = "404" title = { t ( "general.errors.notfound" ) } / > ;
if ( data . jobs _by _pk ? . date _exported ) return < Result status = "warning" title = { t ( "dms.errors.alreadyexported" ) } / > ;
return (
< div >
< AlertComponent
style = { { marginBottom : 10 } }
message = { ` Posting to ${ determineDmsType ( bodyshop ) } ` }
type = "warning"
showIcon
closable
/ >
< AlertComponent style = { { marginBottom : 10 } } message = { bannerMessage } type = "warning" showIcon closable / >
< Row gutter = { [ 16 , 16 ] } >
< Col md = { 24 } lg = { 10 } >
< DmsAllocationsSummary
title = {
< span >
< Link to = { ` /manage/jobs/ ${ data && data . jobs _by _pk . id } ` } > { ` ${
data ? . jobs _by _pk && data . jobs _by _pk . ro _number
} ` } < / Link >
{ ` | ${ OwnerNameDisplayFunction ( data . jobs _by _pk ) } | ${
data . jobs _by _pk . v _model _yr || ""
} ${ data . jobs _by _pk . v _make _desc || "" } ${ data . jobs _by _pk . v _model _desc || "" } ` }
< Link
to = { ` /manage/jobs/ ${ data && data . jobs _by _pk . id } ` }
> { ` ${ data ? . jobs _by _pk && data . jobs _by _pk . ro _number } ` } < / Link >
{ ` | ${ OwnerNameDisplayFunction ( data . jobs _by _pk ) } | ${ data . jobs _by _pk . v _model _yr || "" } ${ data . jobs _by _pk . v _make _desc || "" } ${ data . jobs _by _pk . v _model _desc || "" } ` }
< / span >
}
socket = { activeSocket }
jobId = { jobId }
mode = { mode }
/ >
< / Col >
< Col md = { 24 } lg = { 14 } >
< DmsPostForm socket = { activeSocket } job = { data ? . jobs _by _pk } logsRef = { logsRef } / >
< DmsPostForm socket = { activeSocket } job = { data ? . jobs _by _pk } logsRef = { logsRef } mode = { mode } / >
< / Col >
{ /* NEW props for two-step RR flow banners */ }
< DmsCustomerSelector
jobid = { jobId }
rrOpenRoLimit = { rrOpenRoLimit }
onRrOpenRoFinished = { clearRrOpenRoLimit }
rrCashierPending = { rrCashierPending }
onRrCashierFinished = { handleRrCashierFinished }
bodyshop = { bodyshop }
socket = { activeSocket }
mode = { mode }
rrOptions = { {
openRoLimit : rrOpenRoLimit ,
onOpenRoFinished : clearRrOpenRoLimit ,
cashierPending : rrCashierPending ,
onCashierFinished : handleRrCashierFinished
} }
/ >
< Col span = { 24 } >
@@ -415,11 +408,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
value = { logLevel }
onChange = { ( value ) => {
setLogLevel ( value ) ;
if ( dms === "rr" || Fortellis . treatment === "on" ) {
wsssocket . emit ( "set-log-level" , value ) ;
} else {
socket . emit ( "set-log-level" , value ) ;
}
setActiveLogLevel ( value ) ;
} }
>
< Select.Option key = "DEBUG" > DEBUG < / Select.Option >
@@ -431,11 +420,11 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
< Button
onClick = { ( ) => {
setLogs ( [ ] ) ;
if ( dms === "rr" || Fortellis . treatment === "on" ) {
wsssocket . emit ( "set-log-l evel" , logLevel ) ;
if ( isWssMode ( mode ) ) {
setActiveLogL evel( logLevel ) ;
} else {
s ocket. disconnect ( ) ;
s ocket. connect ( ) ;
activeS ocket. disconnect ( ) ;
activeS ocket. connect ( ) ;
}
} }
>
@@ -445,7 +434,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
}
>
< DmsLogEvents
socket = { socket }
logs = { logs }
detailsOpen = { detailsOpen }
detailsNonce = { detailsNonce }