fix bug: info elements never collapsing after being hovered over once

This commit is contained in:
bedlam343 2024-05-22 16:45:02 -07:00
parent 6d647b64c4
commit 87a1d81240
8 changed files with 42 additions and 58 deletions

View File

@ -26,23 +26,7 @@ const MapThreatInfoElement = ({ element, inGaze }: Props) => {
}
useEffect(() => {
// set its own expiration time in the beginning as soon as it is rendered
if (!collapsed && !element.expiration && element.expirationInterval) {
const expireAt = new Date();
expireAt.setMilliseconds(
expireAt.getMilliseconds() + element.expirationInterval,
);
dispatch(
updateElement(element.widgetId, {
...element,
expiration: expireAt.toISOString(),
}),
);
}
}, [collapsed, element, dispatch]);
useEffect(() => {
// react to deescalation
if (deescalate) {
dispatch(
updateElement(element.widgetId!, {

View File

@ -1,7 +1,10 @@
import type { MapWarningWidget as MapWarningWidgetType } from 'src/types/widget';
import { useAppDispatch, useAppSelector } from 'src/redux/hooks';
import { getElementsInGaze } from 'src/redux/slices/gazeSlice';
import { updateElement } from 'src/redux/slices/minimapSlice';
import {
updateElement,
updateElementExpiration,
} from 'src/redux/slices/minimapSlice';
import { useEffect } from 'react';
import type {
IconElement as IconElementType,
@ -15,10 +18,6 @@ type MapWarningWidgetProps = {
};
const MapWarningWidget = ({ widget }: MapWarningWidgetProps) => {
/** We have made widgets too generic, I think. Severely restricts our ability to design different widgets differently.
* It would be very useful for different widgets types to specify in detail the number of elements they will have
* as well as the type of each of those elements - Jagjit.
*/
const [iconElement, threatInfoElement] = widget.elements;
const elementsInGaze = useAppSelector(getElementsInGaze);
@ -28,13 +27,19 @@ const MapWarningWidget = ({ widget }: MapWarningWidgetProps) => {
(element) => element.id === iconElement.id,
);
// show threat info element if icon element is in gaze
useEffect(() => {
// show threat info element if icon element is in gaze
if (inGaze && threatInfoElement.collapsed) {
dispatch(
updateElement(widget.id, { ...threatInfoElement, collapsed: false }),
);
}
if (inGaze && threatInfoElement.expirationIntervalMs) {
// update expiration even if only icon element is in gaze
// keep displaying threat info element while we hover over the icon
dispatch(updateElementExpiration(widget.id, threatInfoElement.id));
}
}, [inGaze, dispatch, iconElement, threatInfoElement, widget.id]);
return (

View File

@ -67,7 +67,7 @@ const requestApprovalToAttackMessageHigh = (
message,
size: 'M', // size L when stress is low
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,
@ -196,7 +196,7 @@ const missileToOwnshipDetectedMessageHigh = (
w: 128,
widgetId: minimapWidgetId1,
src: mapTargetTypeToWarningIcon('missile'),
expirationInterval: 5000,
expirationIntervalMs: 5000,
onExpiration: 'escalate',
} satisfies IconElement,
{
@ -208,7 +208,7 @@ const missileToOwnshipDetectedMessageHigh = (
message,
size: 'M', // size L when stress is low
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,

View File

@ -50,7 +50,7 @@ const requestApprovalToAttackMessageLow = (
w: 80,
widgetId: minimapWidgetId1,
src: mapTargetTypeToWarningIcon(message.data.target.type),
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'escalate',
} satisfies IconElement,
{
@ -62,7 +62,7 @@ const requestApprovalToAttackMessageLow = (
message,
size: 'L', // size L when stress is low
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,
@ -183,7 +183,7 @@ const missileToOwnshipDetectedMessageLow = (
message,
size: 'L', // size L when stress is low
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,

View File

@ -60,7 +60,7 @@ const requestApprovalToAttackMessageMedium = (
message,
size: 'M', // size L when stress is low
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,
@ -199,7 +199,7 @@ const missileToOwnshipDetectedMessageMedium = (
message,
size: 'M', // size L when stress is medium
collapsed: true, // initially, the information elemnt is not displayed
expirationInterval: 3000,
expirationIntervalMs: 3000,
onExpiration: 'deescalate',
widgetId: minimapWidgetId1,
} satisfies InformationElement,

View File

@ -1,7 +1,7 @@
import { createSlice, createSelector } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { Widget, VehicleWidget, WidgetMap } from 'src/types/widget';
import type { Screen, WidgetChannel } from 'src/types/support-types';
import type { Screen } from 'src/types/support-types';
import type { Message } from 'src/types/schema-types';
import type { Element, ElementMap } from 'src/types/element';
import type { LinkedSectionWidget, Section } from 'src/types/support-types';
@ -10,11 +10,6 @@ export type InitialMinimapState = {
visualComplexity: number;
audioComplexity: number;
// for sharing data between widgets
widgetChannels: {
[key in WidgetChannel]: any;
};
// read-only
ownship: VehicleWidget | null;
drones: VehicleWidget[];
@ -29,11 +24,6 @@ export type InitialMinimapState = {
const initialState: InitialMinimapState = {
visualComplexity: 0,
audioComplexity: 0,
widgetChannels: {
'list-history': {
activeMessageId: '',
},
},
ownship: null,
drones: [],
messages: [],
@ -210,21 +200,26 @@ export const minimapSlice = createSlice({
// if widget exists
if (widget) {
const tempElements = state.widgets[widgetId].elements;
tempElements.forEach(function (element, elementIndex) {
if (element.id === elementId && element.expirationInterval) {
const newExpiration = new Date();
newExpiration.setSeconds(
newExpiration.getSeconds() + element.expirationInterval,
widget.elements.forEach((element) => {
if (element.id === elementId) {
// if element does not have an expiration interval, log an error
if (!element.expirationIntervalMs) {
console.error(
`Element with id ${elementId} does not have an expiration interval`,
);
return;
}
const expiration = new Date();
expiration.setMilliseconds(
expiration.getMilliseconds() + element.expirationIntervalMs,
);
tempElements[elementIndex].expiration =
newExpiration.toISOString();
element.expiration = expiration.toISOString();
}
});
state.widgets[widgetId] = {
...widget,
elements: tempElements,
};
state.widgets[widgetId] = widget;
} else {
console.error(`Widget with id ${widgetId} not found`);
}
@ -495,7 +490,7 @@ export const {
removeWidget,
deleteElementFromWidget,
toggleElementInteraction,
// toggleElementInteraction,
setStressLevel,
} = minimapSlice.actions;

View File

@ -20,7 +20,7 @@ export type BaseElement = {
priority?: number;
collapsed?: boolean;
expirationInterval?: number;
expirationIntervalMs?: number; // should be in ms
expiration?: string;
onExpiration?: 'delete' | 'escalate' | 'deescalate';
escalate?: boolean;

View File

@ -122,7 +122,7 @@ const generateBaseElement = (
priority?: number,
widgetId?: string,
collapsed?: boolean,
expirationInterval?: number,
expirationIntervalMs?: number,
expiration?: string,
onExpiration?: 'delete' | 'escalate' | 'deescalate',
interacted?: boolean,
@ -136,7 +136,7 @@ const generateBaseElement = (
widgetId,
priority,
collapsed,
expirationInterval,
expirationIntervalMs,
expiration,
onExpiration,
interacted,