Skip to content

Commit 49c4177

Browse files
Merge pull request #5070 from OneCommunityGlobal/sudheesh-daily-equipment-log-feedback
Sudheesh Enhance Validation, Feedback & Action Controls on Daily Equipment
2 parents 9a58b14 + 6a3df34 commit 49c4177

4 files changed

Lines changed: 3963 additions & 3836 deletions

File tree

src/actions/bmdashboard/equipmentActions.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ export const updateMultipleEquipmentLogs = (projectId, bulkArr) => dispatch => {
8888
)
8989
.then(res => {
9090
dispatch(setEquipments(res.data));
91-
toast.success('Equipment logs updated successfully!');
9291
return res.data;
9392
})
9493
.catch(err => {

src/components/BMDashboard/Equipment/DailyActivityLog/EDailyActivityLog.jsx

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '~/actions/bmdashboard/equipmentActions';
1111
import { getHeaderData } from '~/actions/authActions';
1212
import { getUserProfile } from '~/actions/userProfile';
13+
import { toast } from 'react-toastify';
1314

1415
import styles from './EDailyActivityLog.module.css';
1516

@@ -44,7 +45,7 @@ const buildRows = list =>
4445
.filter(l => l.type === 'Check Out')
4546
.reduce((s, l) => s + (l.quantity || 1), 0);
4647

47-
const usingQty = Math.max(checkInQty - checkOutQty, 0);
48+
const usingQty = Math.max(checkOutQty - checkInQty, 0);
4849
const availableQty = Math.max(total - usingQty, 0);
4950

5051
const allNumbers = buildToolNumbers(e.itemType?.name, total);
@@ -139,9 +140,15 @@ function EDailyActivityLog(props) {
139140

140141
const [rows, setRows] = useState([]);
141142
const [isLoading, setIsLoading] = useState(false);
142-
const [toastMessage, setToastMessage] = useState(null);
143143
const [showConfirm, setShowConfirm] = useState(false);
144144

145+
// Deriving validation states
146+
const isMissingProject = !selectedProject;
147+
const isInvalidDate = !date || isNaN(Date.parse(date));
148+
const hasNoEquipments = isMissingProject || rows.length === 0;
149+
const noEquipmentSelected = rows.length === 0 || rows.every(r => r.selectedNumbers.length === 0);
150+
const isSubmitDisabled = isMissingProject || isInvalidDate || noEquipmentSelected;
151+
145152
useEffect(() => {
146153
dispatch(fetchBMProjects());
147154
}, [dispatch]);
@@ -159,8 +166,8 @@ function EDailyActivityLog(props) {
159166
const onToolSelect = (rowIdx, selected) => {
160167
setRows(prev => {
161168
const row = prev[rowIdx];
162-
const valid = logType === 'check-in' ? row.availableNumbers : row.inUseNumbers;
163-
const limit = logType === 'check-in' ? row.availableQty : row.usingQty;
169+
const valid = logType === 'check-in' ? row.inUseNumbers : row.availableNumbers;
170+
const limit = logType === 'check-in' ? row.usingQty : row.availableQty;
164171

165172
const clean = selected
166173
.map(o => o.value)
@@ -175,8 +182,8 @@ function EDailyActivityLog(props) {
175182
setLogType(newType);
176183
setRows(prev =>
177184
prev.map(r => {
178-
const valid = newType === 'check-in' ? r.availableNumbers : r.inUseNumbers;
179-
const limit = newType === 'check-in' ? r.availableQty : r.usingQty;
185+
const valid = newType === 'check-in' ? r.inUseNumbers : r.availableNumbers;
186+
const limit = newType === 'check-in' ? r.usingQty : r.availableQty;
180187
return {
181188
...r,
182189
selectedNumbers: r.selectedNumbers.filter(n => valid.includes(n)).slice(0, limit),
@@ -193,6 +200,7 @@ function EDailyActivityLog(props) {
193200
};
194201

195202
const handleSubmit = () => {
203+
if (isSubmitDisabled) return;
196204
setShowConfirm(true);
197205
};
198206
const confirmSubmit = () => {
@@ -210,7 +218,14 @@ function EDailyActivityLog(props) {
210218

211219
dispatch(updateMultipleEquipmentLogs(selectedProject.value, payload));
212220
setShowConfirm(false);
213-
setToastMessage('Entry recorded.');
221+
toast.success(
222+
logType === 'check-in'
223+
? 'Equipment checked in successfully'
224+
: 'Equipment checked out successfully',
225+
);
226+
227+
// Clear selections immediately so UI responds while backend async request finishes
228+
setRows(prev => prev.map(r => ({ ...r, selectedNumbers: [] })));
214229
};
215230

216231
const projectSelectStyles = getSelectStyles(darkMode, false);
@@ -298,8 +313,13 @@ function EDailyActivityLog(props) {
298313
}
299314
>
300315
<span>Are you sure? This will update equipment availability.</span>
301-
<div className="d-flex gap-2">
302-
<Button size="sm" color="secondary" onClick={() => setShowConfirm(false)}>
316+
<div className="d-flex">
317+
<Button
318+
size="sm"
319+
color="secondary"
320+
className="mr-2"
321+
onClick={() => setShowConfirm(false)}
322+
>
303323
Cancel
304324
</Button>
305325
<Button size="sm" color="danger" onClick={confirmSubmit}>
@@ -336,6 +356,9 @@ function EDailyActivityLog(props) {
336356
: {}
337357
}
338358
/>
359+
{isInvalidDate && (
360+
<small className="text-danger mt-1 d-block">Please select a valid date.</small>
361+
)}
339362
{darkMode && (
340363
<small className="text-muted mt-1 d-block">
341364
Note: Calendar appearance depends on your browser and OS.
@@ -360,6 +383,9 @@ function EDailyActivityLog(props) {
360383
isClearable
361384
styles={projectSelectStyles}
362385
/>
386+
{isMissingProject && (
387+
<small className="text-danger mt-1 d-block">Project selection is required.</small>
388+
)}
363389
</div>
364390

365391
<div className="col-md-4">
@@ -374,19 +400,32 @@ function EDailyActivityLog(props) {
374400
<div className="d-flex" role="group" aria-labelledby="log-type-label">
375401
<Button
376402
color={logType === 'check-in' ? 'primary' : 'secondary'}
377-
onClick={() => flipLogType('check-in')}
403+
onClick={() => !hasNoEquipments && flipLogType('check-in')}
378404
className={styles.checkInBtn}
405+
disabled={hasNoEquipments}
406+
style={hasNoEquipments ? { opacity: 0.65, cursor: 'not-allowed' } : {}}
379407
>
380408
Check In
381409
</Button>
382410
<Button
383411
color={logType === 'check-out' ? 'primary' : 'secondary'}
384-
onClick={() => flipLogType('check-out')}
412+
onClick={() => !hasNoEquipments && flipLogType('check-out')}
385413
className={styles.checkOutBtn}
414+
disabled={hasNoEquipments}
415+
style={hasNoEquipments ? { opacity: 0.65, cursor: 'not-allowed' } : {}}
386416
>
387417
Check Out
388418
</Button>
389419
</div>
420+
<small
421+
className={`mt-2 d-block ${styles.helperText} ${
422+
darkMode ? 'text-light' : 'text-muted'
423+
}`}
424+
>
425+
<strong>Check In:</strong> Report equipment as returned and available.
426+
<br />
427+
<strong>Check Out:</strong> Assign equipment for current use.
428+
</small>
390429
</div>
391430
</div>
392431

@@ -445,8 +484,8 @@ function EDailyActivityLog(props) {
445484
{selectedProject &&
446485
rows.length > 0 &&
447486
rows.map((r, idx) => {
448-
const validList = logType === 'check-in' ? r.availableNumbers : r.inUseNumbers;
449-
const limit = logType === 'check-in' ? r.availableQty : r.usingQty;
487+
const validList = logType === 'check-in' ? r.inUseNumbers : r.availableNumbers;
488+
const limit = logType === 'check-in' ? r.usingQty : r.availableQty;
450489

451490
return (
452491
<tr
@@ -479,7 +518,12 @@ function EDailyActivityLog(props) {
479518
<Button color="secondary" onClick={handleCancel}>
480519
Cancel
481520
</Button>
482-
<Button color="primary" onClick={handleSubmit}>
521+
<Button
522+
color="primary"
523+
onClick={handleSubmit}
524+
disabled={isSubmitDisabled}
525+
style={isSubmitDisabled ? { cursor: 'not-allowed', opacity: 0.65 } : {}}
526+
>
483527
Submit
484528
</Button>
485529
</div>

src/components/BMDashboard/Equipment/DailyActivityLog/EDailyActivityLog.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@
4242
.checkOutBtn {
4343
width: 50%;
4444
}
45+
46+
.helperText {
47+
line-height: 1.4;
48+
font-size: 0.85rem;
49+
}

0 commit comments

Comments
 (0)