rectification audit options: TRUE auto-"Others", FALSE limited to true/false others

- rect TRUE: no category menu, verdict saved as "Others" (legacy behavior);
  Save/Enter work without a category, A auto-saves in Quick mode
- rect FALSE: only "true others" / "false others" (keys 1-2); audits safe
  menu no longer selectable in rect mode (closes the "duplicate" soft-delete trap)
- FALSE + "true others" now calls POST /auditor/rectified/false to re-open
  the defect (asset DAMAGED) - wired into single save, Bulk Mode phase 2b,
  and Audit All; per-record errors surfaced in toasts
- audits mode untouched (all changes gated on isRectActive)
This commit is contained in:
2026-07-17 11:27:36 +05:30
parent c872566e83
commit ee25bb6065
2 changed files with 184 additions and 35 deletions

View File

@@ -84,6 +84,15 @@ export const activityFeedsService = {
return response;
},
// Called after a rectification FALSE + 'true others' audit - the defect is
// NOT fixed, so this re-opens/creates it in the work-order layer with
// asset status DAMAGED. Backend only accepts rows already saved with
// Audit_value = 'true others' (exact lowercase).
rectifiedFalse: async (payload: { site_id: number; anomaly_id: number[] }) => {
const response = await axiosClient.post('/api/audit/auditor/rectified/false', payload);
return response;
},
getOrganizationSites: async (org_id: string) => {
const response = await axiosClient.get('/api/audit/Master/site', {
params: { org_id }

View File

@@ -37,6 +37,14 @@ const ANOMALY_CATEGORIES = [
{ id: 10, value: "occlusion", label: "Occlusion", color: "#6366f1", key: "0" }
];
// Rectification FALSE verdicts - the only two the legacy flow accepts.
// 'true others' (exact lowercase) is what POST /auditor/rectified/false
// matches on; anything else would silently skip the defect re-opening.
const RECT_SAFE_CATEGORIES = [
{ id: 1, value: "true others", label: "True Others", color: "#f97316", key: "1" },
{ id: 2, value: "false others", label: "False Others", color: "#64748b", key: "2" },
];
// The backend soft-deletes (deleted = 1) for these exact Audit_values -
// mirror of the list in anomalyModel.update. Note the UI's "low light
// condition" does NOT match the backend's "low light", so from this
@@ -49,7 +57,7 @@ type NotAnAnomalySub = 'comparison error' | 'low light' | 'far asset' | 'no dete
// A verdict staged in Bulk Mode - held in memory until Bulk Submit.
interface StagedVerdict {
isAnomaly: boolean;
category: number;
category: number | null;
notes: string;
plantSub: PlantSub | null;
notAnAnomalySub: NotAnAnomalySub | null;
@@ -61,12 +69,20 @@ const backendMsg = (err: any) =>
// Same Audit_value resolution the single-record save uses: category value,
// overridden by the nested sub-category for category 1 (Plant / Not an Anomaly).
// Rectification mode has its own legacy vocabulary: TRUE (rectified) is
// always 'Others' with no category menu; FALSE picks from the two
// RECT_SAFE_CATEGORIES options.
const computeAuditValue = (
isAnomalyBool: boolean,
catVal: number | null,
plantSub?: string | null,
notAnAnomalySub?: string | null
notAnAnomalySub?: string | null,
isRect = false
): string => {
if (isRect) {
if (isAnomalyBool) return 'Others';
return RECT_SAFE_CATEGORIES.find(c => c.id === catVal)?.value || '';
}
const categories = isAnomalyBool ? ANOMALY_CATEGORIES : SAFE_CATEGORIES;
const matchedCategory = categories.find(c => c.id === catVal);
let auditValueVal = matchedCategory ? matchedCategory.value : '';
@@ -633,7 +649,7 @@ export const AuditSession: React.FC = () => {
const toast = useToastStore.getState().showToast;
const isAnomalyBool = anomalyVal ?? true;
const auditValueVal = computeAuditValue(isAnomalyBool, catVal, plantSub, notAnAnomalySub);
const auditValueVal = computeAuditValue(isAnomalyBool, catVal, plantSub, notAnAnomalySub, isRectActive);
// Body matches exactly what the API expects (dbName + isRectificationEnabled go in URL params via axiosClient)
const auditPayload = {
@@ -677,6 +693,37 @@ export const AuditSession: React.FC = () => {
const softDeleted = SOFT_DELETE_AUDIT_VALUES.includes(auditValueVal);
if (!isAnomalyBool) {
// Rectification "true others" = the defect is NOT fixed - re-open it
// in the work-order layer (asset DAMAGED). The audit itself already
// saved, so failures here inform but never roll back.
if (isRectActive && auditValueVal === 'true others') {
try {
const res: any = await activityFeedsService.rectifiedFalse({
site_id: currentAnomaly.site_id,
anomaly_id: [recordId],
});
const ignored = res?.data?.ignoredAnomalies?.length > 0;
toast(
ignored
? `#${recordId} saved as "true others" — duplicate, defect already open`
: `#${recordId} saved as "true others" — defect re-opened for rectification`,
'success'
);
} catch (err: any) {
// The 404 body still carries per-record errorMessages when the
// record WAS eligible but processing failed (e.g. media copy).
const perRecordError = err?.response?.data?.data?.errorMessages?.[recordId];
if (perRecordError) {
toast(`#${recordId} saved, but defect re-opening failed — ${perRecordError}`, 'error');
} else if (err?.response?.status === 404) {
toast(`#${recordId} saved, but not eligible for defect re-opening (already processed or non linear/fixed algorithm)`, 'warning');
} else {
toast(`#${recordId} saved, but defect re-opening failed — ${backendMsg(err)}`, 'error');
}
}
markLocalAudited();
return true;
}
toast(
softDeleted
? `#${recordId} saved as "${auditValueVal}" — record soft-deleted`
@@ -732,7 +779,7 @@ export const AuditSession: React.FC = () => {
// Build the exact POST /anomaly body the single-record flow sends.
const buildAuditPayload = (rec: any, v: StagedVerdict) => ({
Audit_value: computeAuditValue(v.isAnomaly, v.category, v.plantSub, v.notAnAnomalySub),
Audit_value: computeAuditValue(v.isAnomaly, v.category, v.plantSub, v.notAnAnomalySub, isRectActive),
Comments: v.notes || '',
Audit_status: v.isAnomaly, // boolean true/false, not 1/0
Frame_Test: rec.Frame_Test || '',
@@ -748,7 +795,7 @@ export const AuditSession: React.FC = () => {
const successOf = (e: { rec: any; v: StagedVerdict }) => ({
id: e.rec.id as number,
isAnomaly: e.v.isAnomaly,
auditValue: computeAuditValue(e.v.isAnomaly, e.v.category, e.v.plantSub, e.v.notAnAnomalySub),
auditValue: computeAuditValue(e.v.isAnomaly, e.v.category, e.v.plantSub, e.v.notAnAnomalySub, isRectActive),
comments: e.v.notes || '',
});
@@ -793,6 +840,10 @@ export const AuditSession: React.FC = () => {
// had saved earlier ("locked", the same 409 retry path the single-record
// flow uses) - continue to anomaly processing; safe verdicts are final.
const toProcessBySite = new Map<string, { rec: any; v: StagedVerdict }[]>();
// Rectification FALSE + "true others" = the defect is NOT fixed: those
// records need a second call too (/auditor/rectified/false re-opens the
// defect in the work-order layer), grouped per site like phase 2.
const toRectifyFalseBySite = new Map<string, { rec: any; v: StagedVerdict }[]>();
for (const e of entries) {
const r = resultById.get(Number(e.rec.id));
const ok = r?.ok === true;
@@ -805,6 +856,14 @@ export const AuditSession: React.FC = () => {
} else {
failures.push({ id: e.rec.id, reason: r?.error || 'saving audit failed' });
}
} else if (isRectActive && computeAuditValue(false, e.v.category, e.v.plantSub, e.v.notAnAnomalySub, true) === 'true others') {
if (ok || locked) {
const key = String(e.rec.site_id);
if (!toRectifyFalseBySite.has(key)) toRectifyFalseBySite.set(key, []);
toRectifyFalseBySite.get(key)!.push(e);
} else {
failures.push({ id: e.rec.id, reason: r?.error || 'saving audit failed' });
}
} else if (ok) {
succeeded.push(successOf(e));
} else {
@@ -841,6 +900,45 @@ export const AuditSession: React.FC = () => {
}
}
// Phase 2b (rectification only): re-open the defects for FALSE +
// "true others" verdicts, one call per site.
for (const [, group] of toRectifyFalseBySite) {
const ids = group.map(e => e.rec.id);
try {
const res: any = await activityFeedsService.rectifiedFalse({
site_id: group[0].rec.site_id,
anomaly_id: ids,
});
const errMsgs = res?.data?.errorMessages || {};
const notFound = new Set((res?.data?.notFound || []).map(Number));
for (const e of group) {
const id = Number(e.rec.id);
if (errMsgs[id]) {
failures.push({ id: e.rec.id, reason: `audit saved, but defect re-opening failed — ${errMsgs[id]}` });
} else if (notFound.has(id)) {
// Not eligible (already processed / non linear-fixed) - the
// audit itself stands, same as the single-record flow.
succeeded.push(successOf(e));
} else {
succeeded.push(successOf(e));
}
}
} catch (err: any) {
// A 404 body still carries per-record errorMessages when records
// WERE eligible but processing failed - split accordingly.
const errMsgs = err?.response?.data?.data?.errorMessages || {};
if (err?.response?.status === 404) {
for (const e of group) {
const msg = errMsgs[Number(e.rec.id)];
if (msg) failures.push({ id: e.rec.id, reason: `audit saved, but defect re-opening failed — ${msg}` });
else succeeded.push(successOf(e));
}
} else {
group.forEach(e => failures.push({ id: e.rec.id, reason: `audit saved, but defect re-opening failed — ${backendMsg(err)}` }));
}
}
}
// Phase 3: apply successes locally; failures STAY STAGED so a retry only
// re-sends what actually failed.
applyAuditedLocally(succeeded);
@@ -862,12 +960,12 @@ export const AuditSession: React.FC = () => {
let anomalyCnt = 0, safeCnt = 0, softDeleteCnt = 0;
Object.values(stagedAudits).forEach(v => {
if (v.isAnomaly) anomalyCnt++; else safeCnt++;
if (SOFT_DELETE_AUDIT_VALUES.includes(computeAuditValue(v.isAnomaly, v.category, v.plantSub, v.notAnAnomalySub))) {
if (SOFT_DELETE_AUDIT_VALUES.includes(computeAuditValue(v.isAnomaly, v.category, v.plantSub, v.notAnAnomalySub, isRectActive))) {
softDeleteCnt++;
}
});
return { anomalies: anomalyCnt, safe: safeCnt, softDeletes: softDeleteCnt };
}, [stagedAudits]);
}, [stagedAudits, isRectActive]);
const handleToggleBulkMode = (val: boolean) => {
if (!val && stagedCount > 0) {
@@ -885,9 +983,10 @@ export const AuditSession: React.FC = () => {
const auditAllTargetCount = anomalies.reduce((n, a, i) =>
n + ((a.IsAudited === 1 || itemAuditStates[i] === 'audited') ? 0 : 1), 0);
const isAuditAllVerdictValid =
aaCategory !== null &&
(aaCategory !== 1 || (aaIsAnomaly ? aaPlantSub !== null : aaNotAnAnomalySub !== null));
const isAuditAllVerdictValid = isRectActive
? (aaIsAnomaly || aaCategory !== null)
: aaCategory !== null &&
(aaCategory !== 1 || (aaIsAnomaly ? aaPlantSub !== null : aaNotAnAnomalySub !== null));
const openAuditAllDialog = () => {
setAaIsAnomaly(true);
@@ -899,7 +998,8 @@ export const AuditSession: React.FC = () => {
};
const handleAuditAllApply = () => {
if (!isAuditAllVerdictValid || aaCategory === null) return;
if (!isAuditAllVerdictValid) return;
if (aaCategory === null && !(isRectActive && aaIsAnomaly)) return;
const verdict: StagedVerdict = {
isAnomaly: aaIsAnomaly,
category: aaCategory,
@@ -933,7 +1033,7 @@ export const AuditSession: React.FC = () => {
setIsAuditAllOpen(false);
useToastStore.getState().showToast(
`Staged ${stagedNow} record${stagedNow === 1 ? '' : 's'} as "${computeAuditValue(verdict.isAnomaly, verdict.category, verdict.plantSub, verdict.notAnAnomalySub)}" — review any tile, then press Bulk Submit.`,
`Staged ${stagedNow} record${stagedNow === 1 ? '' : 's'} as "${computeAuditValue(verdict.isAnomaly, verdict.category, verdict.plantSub, verdict.notAnAnomalySub, isRectActive)}" — review any tile, then press Bulk Submit.`,
'success'
);
};
@@ -1008,6 +1108,8 @@ export const AuditSession: React.FC = () => {
// Category 1 nests a sub-category (Plant / Not an Anomaly) - a verdict
// without it is incomplete, both for immediate save and for staging.
const validateSubCategory = (): boolean => {
// Rectification vocabulary has no nested sub-categories.
if (isRectActive) return true;
if (selectedCategory !== 1) return true;
if ((isAnomaly === null || isAnomaly === true) && !plantSubCategory) {
useToastStore.getState().showToast('Please select a feature before submitting.', 'warning');
@@ -1029,7 +1131,7 @@ export const AuditSession: React.FC = () => {
handleNext();
return;
}
if (selectedCategory === null) {
if (selectedCategory === null && !(isRectActive && isAnomaly === true)) {
handleSkip();
return;
}
@@ -1106,7 +1208,7 @@ export const AuditSession: React.FC = () => {
// Quick Auto Advance save trigger
const handleQuickSaveAndNext = useCallback(async (
anomalyVal: boolean,
catVal: number,
catVal: number | null,
plantSub?: string | null,
notAnAnomalySub?: string | null
) => {
@@ -1177,6 +1279,10 @@ export const AuditSession: React.FC = () => {
setSelectedCategory(null);
setPlantSubCategory(null);
setNotAnAnomalySubCategory(null);
// Rectification TRUE has no category step - Quick mode saves now.
if (isRectActive && isQuickAudit && !isBulkMode) {
setTimeout(() => handleQuickSaveAndNext(true, null), 120);
}
break;
case 's':
setIsAnomaly(false);
@@ -1200,6 +1306,19 @@ export const AuditSession: React.FC = () => {
};
const catId = keyMap[key];
// Rectification: TRUE has no categories (digits ignored); FALSE only
// accepts 1/2 (true others / false others). Nested sub-category
// handling below never applies in rect mode.
if (isRectActive) {
if (isAnomaly === false && (key === '1' || key === '2')) {
setSelectedCategory(catId);
if (isQuickAudit && !isBulkMode) {
setTimeout(() => handleQuickSaveAndNext(false, catId), 120);
}
}
break;
}
// Special nested case: Plant is already active (under Anomaly)
if (isAnomaly === true && selectedCategory === 1) {
if (key === '1') {
@@ -1253,7 +1372,7 @@ export const AuditSession: React.FC = () => {
break;
}
case 'enter':
if (selectedCategory !== null) {
if (selectedCategory !== null || (isRectActive && isAnomaly === true)) {
handleSaveAndNext();
} else {
handleSkip();
@@ -1270,7 +1389,7 @@ export const AuditSession: React.FC = () => {
handleSkip();
break;
}
}, [currentIndex, anomalies, isLocked, isAnomaly, selectedCategory, notes, plantSubCategory, isQuickAudit, isBulkMode, isNotesFocused, isReportDialogOpen, isShortcutsDialogOpen, isBulkConfirmOpen, isAuditAllOpen, isEditAssetOpen, bulkResult, showBatchEndPanel, stagedCount, handleNextBatch, handleLeaveSession, handleQuickSaveAndNext, handleSaveAndNext, handleSkip, handleNext]);
}, [currentIndex, anomalies, isLocked, isAnomaly, selectedCategory, notes, plantSubCategory, isQuickAudit, isBulkMode, isRectActive, isNotesFocused, isReportDialogOpen, isShortcutsDialogOpen, isBulkConfirmOpen, isAuditAllOpen, isEditAssetOpen, bulkResult, showBatchEndPanel, stagedCount, handleNextBatch, handleLeaveSession, handleQuickSaveAndNext, handleSaveAndNext, handleSkip, handleNext]);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
@@ -1737,11 +1856,18 @@ export const AuditSession: React.FC = () => {
</Button>
</Box>
</Box>
{/* Category */}
{/* Category. Rectification mode: TRUE (rectified) has no category
menu - the verdict is always saved as "Others"; FALSE shows only
the two legacy options (true others / false others). */}
<Box sx={{ flex: 1.5, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
<Typography sx={{ fontSize: '0.75rem', fontWeight: 'bold', color: '#94a3b8', letterSpacing: 1, mb: 1 }}>CATEGORY</Typography>
{isRectActive && isAnomaly !== false ? (
<Typography sx={{ fontSize: '0.8rem', color: '#64748b', pr: 1 }}>
Rectified will be saved as "Others". Press Enter (or A in Quick mode) to save.
</Typography>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, overflowY: 'auto', flex: 1, pr: 0.5, '&::-webkit-scrollbar': { width: '4px' }, '&::-webkit-scrollbar-thumb': { bgcolor: '#1e293b', borderRadius: '4px' } }}>
{(isAnomaly === false ? SAFE_CATEGORIES : ANOMALY_CATEGORIES).map(cat => (
{(isAnomaly === false ? (isRectActive ? RECT_SAFE_CATEGORIES : SAFE_CATEGORIES) : ANOMALY_CATEGORIES).map(cat => (
<React.Fragment key={cat.id}>
<Button
disabled={isLocked}
@@ -1753,7 +1879,8 @@ export const AuditSession: React.FC = () => {
}
// If selecting Plant (Anomaly 1) or Not an Anomaly (Safe 1), do not auto-advance; wait for nested sub-options
if (cat.id === 1) {
// (rect mode has no nested sub-options - its id 1 is "true others")
if (cat.id === 1 && !isRectActive) {
return;
}
@@ -1781,7 +1908,7 @@ export const AuditSession: React.FC = () => {
</Button>
{/* Plant Nested Subcategories (Anomaly Mode) */}
{cat.id === 1 && isAnomaly === true && selectedCategory === 1 && (
{!isRectActive && cat.id === 1 && isAnomaly === true && selectedCategory === 1 && (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, pl: 4, mt: 0.5, mb: 0.5 }}>
{[
{ val: 'in grown', label: 'In Grown', key: '1' },
@@ -1817,7 +1944,7 @@ export const AuditSession: React.FC = () => {
)}
{/* Not an Anomaly Nested Subcategories (Safe Mode) */}
{cat.id === 1 && isAnomaly === false && selectedCategory === 1 && (
{!isRectActive && cat.id === 1 && isAnomaly === false && selectedCategory === 1 && (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, pl: 4, mt: 0.5, mb: 0.5 }}>
{[
{ val: 'comparison error', label: 'Comparison Error', key: '1' },
@@ -1856,6 +1983,7 @@ export const AuditSession: React.FC = () => {
)}
</React.Fragment>
))} </Box>
)}
</Box>
{/* Notes */}
@@ -1894,7 +2022,8 @@ export const AuditSession: React.FC = () => {
stagedAudits[currentAnomaly.id].isAnomaly,
stagedAudits[currentAnomaly.id].category,
stagedAudits[currentAnomaly.id].plantSub,
stagedAudits[currentAnomaly.id].notAnAnomalySub
stagedAudits[currentAnomaly.id].notAnAnomalySub,
isRectActive
)}"
</Typography>
<Button size="small" onClick={handleUnstage} sx={{ color: '#94a3b8', textTransform: 'none', fontSize: '0.7rem', minWidth: 'auto', p: 0.25 }}>
@@ -1941,10 +2070,13 @@ export const AuditSession: React.FC = () => {
Audit All ({auditAllTargetCount}) same verdict
</Button>
)}
{/* Rect TRUE needs no category - the verdict is complete as soon
as "Anomaly" is picked (saved as "Others"). */}
{(() => { const saveReady = selectedCategory !== null || (isRectActive && isAnomaly === true); return (
<Button
variant="contained"
color={!isLocked && selectedCategory !== null ? "primary" : "inherit"}
onClick={isLocked ? handleNext : selectedCategory !== null ? handleSaveAndNext : handleSkip}
color={!isLocked && saveReady ? "primary" : "inherit"}
onClick={isLocked ? handleNext : saveReady ? handleSaveAndNext : handleSkip}
sx={{
borderRadius: 2,
py: 1.5,
@@ -1954,14 +2086,15 @@ export const AuditSession: React.FC = () => {
justifyContent: 'space-between',
px: 3,
transition: 'all 0.15s ease',
bgcolor: selectedCategory !== null ? '' : '#1e293b',
color: selectedCategory !== null ? '' : '#94a3b8',
border: (activeKeyFlash === 'enter') ? (selectedCategory !== null ? '2px solid #3b82f6' : '2px solid #64748b') : 'none',
'&:hover': { bgcolor: selectedCategory !== null ? '' : '#334155' }
bgcolor: saveReady ? '' : '#1e293b',
color: saveReady ? '' : '#94a3b8',
border: (activeKeyFlash === 'enter') ? (saveReady ? '2px solid #3b82f6' : '2px solid #64748b') : 'none',
'&:hover': { bgcolor: saveReady ? '' : '#334155' }
}}
>
{isLocked ? "Next (Read-only)" : selectedCategory !== null ? (isBulkMode ? "Stage & Next" : "Save & Next") : "Next (Skip)"} <Typography component="span" sx={{ fontSize: '0.75rem', opacity: 0.7 }}>Enter</Typography>
{isLocked ? "Next (Read-only)" : saveReady ? (isBulkMode ? "Stage & Next" : "Save & Next") : "Next (Skip)"} <Typography component="span" sx={{ fontSize: '0.75rem', opacity: 0.7 }}>Enter</Typography>
</Button>
); })()}
<Box sx={{ display: 'flex', gap: 1 }}>
<Button
variant="outlined"
@@ -2018,7 +2151,7 @@ export const AuditSession: React.FC = () => {
<Typography sx={{ fontSize: '0.75rem', color: '#94a3b8' }}>Safe</Typography>
</Box>
<Box>
<Chip label="1-5" size="small" sx={{ height: 20, fontSize: '0.65rem', bgcolor: '#1e293b', color: '#cbd5e1' }} />
<Chip label={isRectActive ? "1-2" : "1-5"} size="small" sx={{ height: 20, fontSize: '0.65rem', bgcolor: '#1e293b', color: '#cbd5e1' }} />
<Typography sx={{ fontSize: '0.75rem', color: '#94a3b8' }}>Category</Typography>
</Box>
<Box>
@@ -2273,9 +2406,14 @@ export const AuditSession: React.FC = () => {
</Button>
</Box>
{/* Category */}
{/* Category (rect: TRUE has none - auto "Others"; FALSE has two) */}
{isRectActive && aaIsAnomaly ? (
<Typography sx={{ fontSize: '0.8rem', color: '#64748b' }}>
Rectified every record will be saved as "Others".
</Typography>
) : (
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0.5 }}>
{(aaIsAnomaly ? ANOMALY_CATEGORIES : SAFE_CATEGORIES).map(cat => (
{(aaIsAnomaly ? ANOMALY_CATEGORIES : (isRectActive ? RECT_SAFE_CATEGORIES : SAFE_CATEGORIES)).map(cat => (
<Button
key={cat.id}
onClick={() => { setAaCategory(cat.id); setAaPlantSub(null); setAaNotAnAnomalySub(null); }}
@@ -2295,9 +2433,11 @@ export const AuditSession: React.FC = () => {
</Button>
))}
</Box>
)}
{/* Nested sub-category for category 1 (Plant / Not an Anomaly) */}
{aaCategory === 1 && (
{/* Nested sub-category for category 1 (Plant / Not an Anomaly) -
never applies in rect mode (its id 1 is "true others") */}
{!isRectActive && aaCategory === 1 && (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
{(aaIsAnomaly
? [{ val: 'in grown', label: 'In Grown' }, { val: 'out grown', label: 'Out Grown' }]
@@ -2351,7 +2491,7 @@ export const AuditSession: React.FC = () => {
}}
/>
{isAuditAllVerdictValid && SOFT_DELETE_AUDIT_VALUES.includes(computeAuditValue(aaIsAnomaly, aaCategory, aaPlantSub, aaNotAnAnomalySub)) && (
{isAuditAllVerdictValid && SOFT_DELETE_AUDIT_VALUES.includes(computeAuditValue(aaIsAnomaly, aaCategory, aaPlantSub, aaNotAnAnomalySub, isRectActive)) && (
<Typography variant="body2" sx={{ color: '#eab308' }}>
This verdict soft-deletes every record it's applied to.
</Typography>