Android_Retail/src/Pages/BookingScreen/Components/UtillComponents/BSNavBarWeightScale.jsx

222 lines
7.2 KiB
JavaScript

import { useCallback, useRef, useState, useEffect } from 'react'; // ← add useEffect
import { useDispatch } from 'react-redux';
import PozoWeightScaleIcon from './Pozo retail icons/PozoWeightScaleIcon';
import {
changeWeightScalePort,
changeWeightScaleWeight,
} from '../../../../Features/BookingScreen/BookingData/BookingData';
import WeightScaleComp from '../../../../Components/WeightScale/weightScale.jsx';
import { Messages } from '../../../../Components/Notifications/Messages';
import TooltipWrapper from '../../../../Components/Tooltip/Tooltip';
import { isMobile } from 'react-device-detect';
import { Capacitor } from '@capacitor/core';
import { weightScaleService } from '../../../../Services/getusbdevices.js';
const BSNavBarWeightScale = ({Combo}) => {
const dispatch = useDispatch();
// ── FIX: init from service so remount restores correct status ──
const [usbStatus, setUsbStatus] = useState(
() => weightScaleService.isConnected ? 'connected' : 'disconnected'
);
const [WeightScale, setWeightScale] = useState(false);
const [WeightScale2, setWeightScale2] = useState(false);
const [wsport, setwsport] = useState(null);
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const lastStableWeightRef = useRef(null);
const lastWeightRef = useRef(null);
const stableCountRef = useRef(0);
const STABLE_THRESHOLD = 3;
const isNativeApp = Capacitor.isNativePlatform();
// ── FIX: on remount, if already connected re-attach the reading callback ──
useEffect(() => {
if (weightScaleService.isConnected) {
setUsbStatus('connected');
dispatch(changeWeightScalePort(true));
// Re-register the weight reading callback since component remounted
weightScaleService.startReading(
(w) => handleWeightReading(w),
(err) => {
setUsbStatus('disconnected');
dispatch(changeWeightScalePort(false));
dispatch(changeWeightScaleWeight(null));
resetStable();
setMessageType('error');
setMessageData('Scale error: ' + err.message);
}
);
}
// ── FIX: on unmount, do NOT disconnect — just clear the reading callback
// so old callbacks don't fire on the unmounted component (memory leak)
return () => {
weightScaleService.detachCallbacks();
};
}, []); // runs once on mount/remount
// ── ICON COLOR ────────────────────────────────────
const getIconColor = () => {
if (isNativeApp || isMobile) {
if (usbStatus === 'connected') return 'rgb(82, 196, 26)';
if (usbStatus === 'connecting') return '#faad14';
return '#ff4d4f';
}
return WeightScale2 ? 'rgb(82, 196, 26)' : '#ff4d4f';
};
// ── STABLE WEIGHT DETECTION ───────────────────────
const handleWeightReading = (w) => {
if (w === lastWeightRef.current) {
stableCountRef.current++;
} else {
stableCountRef.current = 1;
}
lastWeightRef.current = w;
const isStable = stableCountRef.current >= STABLE_THRESHOLD;
const isValid = typeof w === 'number' && !isNaN(w);
const hasChanged = w !== lastStableWeightRef.current;
if (isValid && isStable && hasChanged) {
lastStableWeightRef.current = w;
dispatch(changeWeightScaleWeight(w));
}
};
const resetStable = () => {
lastStableWeightRef.current = null;
lastWeightRef.current = null;
stableCountRef.current = 0;
};
// ── CONNECT ───────────────────────────────────────
const connectScale = async () => {
setUsbStatus('connecting');
resetStable();
const success = await weightScaleService.autoConnect();
if (success) {
setUsbStatus('connected');
dispatch(changeWeightScalePort(true));
await weightScaleService.startReading(
(w) => handleWeightReading(w),
(err) => {
setUsbStatus('disconnected');
dispatch(changeWeightScalePort(false));
dispatch(changeWeightScaleWeight(null));
resetStable();
setMessageType('error');
setMessageData('Scale error: ' + err.message);
}
);
} else {
setUsbStatus('disconnected');
setMessageType('error');
setMessageData(weightScaleService.lastError || 'Cannot connect. Check USB / OTG cable.');
}
};
// ── DISCONNECT ────────────────────────────────────
const disconnectScale = async () => {
await weightScaleService.disconnect();
setUsbStatus('disconnected');
dispatch(changeWeightScalePort(false));
dispatch(changeWeightScaleWeight(null));
resetStable();
};
// ── MAIN CLICK HANDLER ────────────────────────────
const handleWeightScaleOpen = async () => {
if (isNativeApp || isMobile) {
if (usbStatus === 'connected') {
await disconnectScale();
} else if (usbStatus === 'disconnected') {
await connectScale();
}
} else {
const next = !WeightScale2;
setWeightScale2(next);
setWeightScale(next);
dispatch(changeWeightScalePort(next));
}
};
// ── DESKTOP HANDLERS ──────────────────────────────
const setWsport = async (e) => {
if (e?.readable) {
setwsport(e);
} else {
setMessageType('error');
setMessageData('Please check weightscale connection');
setWeightScale2(false);
setWeightScale(false);
}
};
const myfun = async (e) => {
dispatch(changeWeightScaleWeight(e));
};
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
const msgAlert = async (e) => {
setMessageType(e.type);
setMessageData(e.msg);
};
return (
<div className="BSBilling7-icon-flex">
<Messages
messageType={messageType}
messageData={messageData}
onComplete={onComplete}
/>
<TooltipWrapper title={'Weight-Scale'} isMobile={isMobile}>
{Combo == 'combolayout' ? (
<button
className="BSC1Search-button1"
style={{ backgroundColor: getIconColor() }}
onClick={handleWeightScaleOpen}
disabled={usbStatus === 'connecting'}
>
{(isNativeApp || isMobile)
? usbStatus === 'connecting' ? 'Connecting...'
: usbStatus === 'connected' ? 'Scale ON'
: 'Weight Scale'
: 'Weight Scale'}
</button>
) : (
<PozoWeightScaleIcon
fill={getIconColor()}
className="BSBillingNav-icon"
onClick={handleWeightScaleOpen}
/>
)}
{WeightScale && !isMobile && !isNativeApp && (
<WeightScaleComp
testfun={myfun}
setportfun={setWsport}
portval={wsport}
portclose={WeightScale2}
msg={msgAlert}
/>
)}
</TooltipWrapper>
</div>
);
};
export default BSNavBarWeightScale;