diff --git a/src/components/Element/Complex/MissileIncomingElement.tsx b/src/components/Element/Complex/MissileIncomingElement.tsx
index 79e95e6..8d0472a 100644
--- a/src/components/Element/Complex/MissileIncomingElement.tsx
+++ b/src/components/Element/Complex/MissileIncomingElement.tsx
@@ -1,22 +1,15 @@
import type { MissileIncomingElement as MissileIncomingElementType } from 'src/types/element';
import IconElement from 'src/components/Element/Simple/IconElement';
+import { useAppSelector } from 'src/redux/hooks';
+import { getMessage } from 'src/redux/slices/minimapSlice';
type MissileIncomingProps = {
element: MissileIncomingElementType;
};
const MissileIncomingElement = ({ element }: MissileIncomingProps) => {
- const { id, h, w, message, icon: iconElement } = element;
- const {
- data: {
- detectedByAca,
- missileLocation,
- choiceWeight,
- survivability,
- acaAttackWeapon,
- },
- priority,
- } = message;
+ const { id, h, w, messageId, icon: iconElement } = element;
+ const message = useAppSelector((state) => getMessage(state, messageId));
return (
diff --git a/src/components/Element/Complex/RequestApprovalElement.tsx b/src/components/Element/Complex/RequestApprovalElement.tsx
index 7e0ba1e..c0b6cb2 100644
--- a/src/components/Element/Complex/RequestApprovalElement.tsx
+++ b/src/components/Element/Complex/RequestApprovalElement.tsx
@@ -1,7 +1,9 @@
-import type { ReactNode } from 'react';
+import { useEffect, type ReactNode } from 'react';
import { type RequestApprovalElement as RequestApprovalElementType } from 'src/types/element';
import ButtonElement from '../Simple/ButtonElement';
import IconElement from '../Simple/IconElement';
+import { useAppSelector } from 'src/redux/hooks';
+import { getMessage } from 'src/redux/slices/minimapSlice';
type RequestApprovalProps = {
element: RequestApprovalElementType;
@@ -12,28 +14,14 @@ const RequestApprovalElement = ({
element,
children,
}: RequestApprovalProps) => {
- const {
- id,
- collapsed,
- icon,
- rightButton,
- leftButton,
- message: {
- priority,
- data: {
- target,
- detectedByAca,
- choiceWeight,
- attackWeapon,
- collateralDamage,
- },
- },
- } = element;
+ const { id, collapsed, icon, rightButton, leftButton, messageId } = element;
+ const message = useAppSelector((state) => getMessage(state, messageId));
return (
- {target.type}
+ {/* @ts-ignore */}
+ {message?.data?.target?.type}
);
};
diff --git a/src/components/Widget/ListWidget.tsx b/src/components/Widget/ListWidget.tsx
index a0f4fd7..a8932bd 100644
--- a/src/components/Widget/ListWidget.tsx
+++ b/src/components/Widget/ListWidget.tsx
@@ -7,6 +7,7 @@ import {
import { getElementsInGaze, getGazesAndKeys } from 'src/redux/slices/gazeSlice';
import type { Widget } from 'src/types/widget';
import ListElement from 'src/components/Element/Complex/ListElement';
+import { getMessages } from 'src/redux/slices/minimapSlice';
type ListWidgetProps = {
widget: Widget;
@@ -16,6 +17,7 @@ const LIST_ELEMENT_HEIGHT = 80;
const GAP_BETWEEN_ELEMENTS = 6;
const ListWidget = ({ widget }: ListWidgetProps) => {
+ const messages = useAppSelector(getMessages);
const elementsInGaze = useAppSelector(getElementsInGaze);
const gazesAndKeys = useAppSelector(getGazesAndKeys);
const { activeElementId } = useAppSelector(getCommunication);
@@ -75,7 +77,7 @@ const ListWidget = ({ widget }: ListWidgetProps) => {
// just pick the first element in the gaze for now
if (element.id === mouseLeftClick.elemsInGaze[0].id) {
// @ts-ignore
- if (!element.message) {
+ if (!element.messageId) {
// FIX: all elements should have a message (at least the ones in the list)
// at the minimu, they should have a conversationId attached to them?
console.warn('Element does not have a message', element);
@@ -85,13 +87,13 @@ const ListWidget = ({ widget }: ListWidgetProps) => {
dispatch(
updateCommunication({
// @ts-ignore
- activeConversationId: element.message.conversationId,
+ activeConversationId: messages[element.messageId].conversationId,
activeElementId: element.id,
}),
);
}
});
- }, [gazesAndKeys, dispatch, elementInGazeId, widget.elements]);
+ }, [gazesAndKeys, dispatch, elementInGazeId, messages, widget.elements]);
// check if the list is overflowed
// useEffect(() => {
@@ -143,6 +145,15 @@ const ListWidget = ({ widget }: ListWidgetProps) => {
}}
>
{sortedElementsByPriority.map((element) => {
+ // don't render element if it's message is not the latest in the conversation
+ // @ts-ignore
+ const elemMessageId = element.messageId;
+ if (elemMessageId) {
+ if (!messages[elemMessageId].latestInConvo) {
+ return null;
+ }
+ }
+
// style for the element which is current being hoverd over
const hoverStyle =
element.id === elementInGazeId
diff --git a/src/hooks/useWorldSim.ts b/src/hooks/useWorldSim.ts
index 73ca764..01e9be1 100644
--- a/src/hooks/useWorldSim.ts
+++ b/src/hooks/useWorldSim.ts
@@ -19,7 +19,7 @@ const useWorldSim = () => {
if (message)
setMessages((prevMessages) => [
...prevMessages,
- { ...message, fulfilled: false },
+ { ...message, fulfilled: false, read: false, latestInConvo: true }, // newest message is latest in convo
]);
if (stressLevel) setStressLevel(stressLevel);
});
diff --git a/src/prototype/lpd/stress/highLPD.ts b/src/prototype/lpd/stress/highLPD.ts
index eb45dbd..49b8f17 100644
--- a/src/prototype/lpd/stress/highLPD.ts
+++ b/src/prototype/lpd/stress/highLPD.ts
@@ -34,7 +34,7 @@ const requestApprovalToAttackMessageHigh = (
message.priority,
'list',
),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
@@ -181,7 +181,7 @@ const missileToOwnshipDetectedMessageHigh = (
message.priority,
'list',
),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
diff --git a/src/prototype/lpd/stress/lowLPD.ts b/src/prototype/lpd/stress/lowLPD.ts
index c283c9d..59bbba3 100644
--- a/src/prototype/lpd/stress/lowLPD.ts
+++ b/src/prototype/lpd/stress/lowLPD.ts
@@ -27,7 +27,7 @@ const requestApprovalToAttackMessageLow = (
const pearceScreenElements = [
lpdHelper.generateRequestApprovalElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 30, 30, message.priority),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
@@ -223,7 +223,7 @@ const missileToOwnshipDetectedMessageLow = (
200,
message.priority,
),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
diff --git a/src/prototype/lpd/stress/mediumLPD.ts b/src/prototype/lpd/stress/mediumLPD.ts
index d7d962f..dc872b4 100644
--- a/src/prototype/lpd/stress/mediumLPD.ts
+++ b/src/prototype/lpd/stress/mediumLPD.ts
@@ -27,7 +27,7 @@ const requestApprovalToAttackMessageMedium = (
const pearceScreenElements: Element[] = [
lpdHelper.generateRequestApprovalElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 30, 30, message.priority),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
@@ -173,7 +173,7 @@ const missileToOwnshipDetectedMessageMedium = (
200,
message.priority,
),
- message,
+ message.id,
listWidgetId,
lpdHelper.generateIconElement(
lpdHelper.generateBaseElement(uuid(), 'visual', 56, 56),
diff --git a/src/redux/slices/minimapSlice.ts b/src/redux/slices/minimapSlice.ts
index 90fa4b4..0c493d0 100644
--- a/src/redux/slices/minimapSlice.ts
+++ b/src/redux/slices/minimapSlice.ts
@@ -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 } from 'src/types/support-types';
+import type { MessageMap, 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';
@@ -15,7 +15,7 @@ export type InitialMinimapState = {
drones: VehicleWidget[];
widgets: WidgetMap;
- messages: Message[];
+ messages: MessageMap;
sections: Section[];
stressLevel: number;
@@ -26,7 +26,7 @@ const initialState: InitialMinimapState = {
audioComplexity: 0,
ownship: null,
drones: [],
- messages: [],
+ messages: {},
widgets: {},
sections: [],
stressLevel: 0,
@@ -397,7 +397,19 @@ export const minimapSlice = createSlice({
},
addMessage: (state, action: PayloadAction
) => {
- state.messages.push(action.payload);
+ const updatedMessages = { ...state.messages };
+
+ // set latestInConvo to false for all messages in the same conversation
+ Object.keys(updatedMessages).forEach((id) => {
+ if (
+ updatedMessages[id].conversationId === action.payload.conversationId
+ ) {
+ updatedMessages[id].latestInConvo = false;
+ }
+ });
+
+ updatedMessages[action.payload.id] = action.payload;
+ state.messages = updatedMessages;
},
setStressLevel: (state, action: PayloadAction) => {
@@ -449,10 +461,16 @@ export const minimapSlice = createSlice({
getVisualComplexity: (state) => state.visualComplexity,
getAudioComplexity: (state) => state.audioComplexity,
getMessages: (state) => state.messages,
+ getMessage: (state, messageId: string) => state.messages[messageId],
getConversationMessages: (state, conversationId: string) => {
- return state.messages.filter(
- (message) => message.conversationId === conversationId,
- );
+ const messages: Message[] = [];
+ Object.keys(state.messages).forEach((messageId) => {
+ if (state.messages[messageId].conversationId === conversationId) {
+ messages.push(state.messages[messageId]);
+ }
+ });
+
+ return messages;
},
getStressLevel: (state) => state.stressLevel,
@@ -511,6 +529,7 @@ export const {
getElementsOnScreen,
getMessages,
+ getMessage,
getConversationMessages,
getOwnship,
diff --git a/src/types/element.ts b/src/types/element.ts
index be4fd84..fe9a57b 100644
--- a/src/types/element.ts
+++ b/src/types/element.ts
@@ -85,7 +85,7 @@ export type CustomElement = BaseElement & {
export type RequestApprovalElement = BaseElement & {
type: 'request-approval';
- message: RequestApprovalToAttack;
+ messageId: string;
icon: IconElement;
leftButton: ButtonElement;
rightButton: ButtonElement;
@@ -95,7 +95,7 @@ export type RequestApprovalElement = BaseElement & {
export type MissileIncomingElement = BaseElement & {
type: 'missile-incoming';
- message: MissileToOwnshipDetected;
+ messageId: string;
icon: IconElement;
widgetId: string;
};
diff --git a/src/types/schema-types.ts b/src/types/schema-types.ts
index 95059a5..d529202 100644
--- a/src/types/schema-types.ts
+++ b/src/types/schema-types.ts
@@ -24,8 +24,10 @@ export type BaseMessage = {
priority: Priority;
kind: TKind;
data: TData;
+ latestInConvo?: boolean;
+ read?: boolean;
fulfilled?: boolean;
- tags?: string[]
+ tags?: string[];
};
export type RequestApprovalToAttack = BaseMessage<
diff --git a/src/types/support-types.ts b/src/types/support-types.ts
index 4d1dba6..bfbb482 100644
--- a/src/types/support-types.ts
+++ b/src/types/support-types.ts
@@ -1,4 +1,5 @@
import { type Widget } from 'src/types/widget';
+import { type Message } from 'src/types/schema-types';
export type Cell = {
widgetIDs: string[];
@@ -45,3 +46,7 @@ export type WidgetCluster = {
sectionIds?: LinkedSectionWidget[];
actions?: string[];
};
+
+export type MessageMap = {
+ [key: string]: Message;
+};
diff --git a/src/utils/lpdHelper.ts b/src/utils/lpdHelper.ts
index 238c088..6cedf8d 100644
--- a/src/utils/lpdHelper.ts
+++ b/src/utils/lpdHelper.ts
@@ -210,20 +210,20 @@ const generateAudioElement = (
// Generate complex elements
const generateMissileIncomingElement = (
baseElement: Element.BaseElement,
- message: MissileToOwnshipDetected,
+ messageId: string,
widgetId: string,
icon: Element.IconElement,
): Element.MissileIncomingElement => ({
...baseElement,
type: 'missile-incoming',
- message,
+ messageId,
widgetId,
icon,
});
const generateRequestApprovalElement = (
baseElement: Element.BaseElement,
- message: RequestApprovalToAttack,
+ messageId: string,
widgetId: string,
icon: Element.IconElement,
leftButton: Element.ButtonElement,
@@ -231,7 +231,7 @@ const generateRequestApprovalElement = (
): Element.RequestApprovalElement => ({
...baseElement,
type: 'request-approval',
- message,
+ messageId,
widgetId,
icon,
leftButton,