diff --git a/backend/src/controller/chatController.ts b/backend/src/controller/chatController.ts
index 809aa68e5..37d89208a 100644
--- a/backend/src/controller/chatController.ts
+++ b/backend/src/controller/chatController.ts
@@ -293,6 +293,7 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
...levelResult.chatResponse,
wonLevel:
!levelResult.chatResponse.defenceReport.isBlocked &&
+ !levelResult.chatResponse.openAIErrorMessage &&
isLevelWon(levelResult.chatResponse.sentEmails, currentLevel),
};
@@ -334,6 +335,29 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
req.session.levelState[currentLevel].chatHistory = updatedChatHistory;
req.session.levelState[currentLevel].sentEmails = totalSentEmails;
+ // If the level has just been won, add a level complete message to chat history and return it in the response
+ const levelCompleteMessageInChatHistory = req.session.levelState[
+ currentLevel
+ ].chatHistory.some((msg) => msg.chatMessageType === 'LEVEL_COMPLETE');
+ if (updatedChatResponse.wonLevel && !levelCompleteMessageInChatHistory) {
+ const levelCompleteMessage = {
+ chatMessageType: 'LEVEL_COMPLETE',
+ infoMessage:
+ currentLevel === LEVEL_NAMES.LEVEL_3
+ ? `🎉 Congratulations, you have completed the final level of your assignment!`
+ : `🎉 Congratulations! You have completed this level. Please click on the next level to continue.`,
+ } as ChatInfoMessage;
+
+ // add level complete message to chat history
+ req.session.levelState[currentLevel].chatHistory = pushMessageToHistory(
+ req.session.levelState[currentLevel].chatHistory,
+ levelCompleteMessage
+ );
+
+ // add level complete message to chat response
+ updatedChatResponse.wonLevelMessage = levelCompleteMessage;
+ }
+
console.log('chatResponse: ', updatedChatResponse);
console.log('chatHistory: ', updatedChatHistory);
diff --git a/backend/src/models/chat.ts b/backend/src/models/chat.ts
index 22a4fdc31..6025249b3 100644
--- a/backend/src/models/chat.ts
+++ b/backend/src/models/chat.ts
@@ -3,7 +3,7 @@ import {
ChatCompletionMessageParam,
} from 'openai/resources/chat/completions';
-import { ChatMessage } from './chatMessage';
+import { ChatInfoMessage, ChatMessage } from './chatMessage';
import { DEFENCE_ID } from './defence';
import { EmailInfo } from './email';
@@ -97,6 +97,7 @@ interface ChatHttpResponse {
openAIErrorMessage: string | null;
sentEmails: EmailInfo[];
transformedMessageInfo?: string;
+ wonLevelMessage?: ChatInfoMessage;
}
interface LevelHandlerResponse {
diff --git a/backend/src/models/chatMessage.ts b/backend/src/models/chatMessage.ts
index 97962bb2e..0fc60a64c 100644
--- a/backend/src/models/chatMessage.ts
+++ b/backend/src/models/chatMessage.ts
@@ -10,7 +10,7 @@ import { TransformedChatMessage } from './chat';
const chatInfoMessageTypes = [
'DEFENCE_ALERTED',
'DEFENCE_TRIGGERED',
- 'LEVEL_INFO',
+ 'LEVEL_COMPLETE',
'RESET_LEVEL',
'ERROR_MSG',
'BOT_BLOCKED',
diff --git a/backend/test/unit/controller/chatController.test.ts b/backend/test/unit/controller/chatController.test.ts
index a5760ea10..21dcbd924 100644
--- a/backend/test/unit/controller/chatController.test.ts
+++ b/backend/test/unit/controller/chatController.test.ts
@@ -781,8 +781,17 @@ describe('handleChatToGPT unit tests', () => {
await handleChatToGPT(req, res);
+ const expectedWonLevelMessage = {
+ infoMessage:
+ '🎉 Congratulations! You have completed this level. Please click on the next level to continue.',
+ chatMessageType: 'LEVEL_COMPLETE',
+ } as ChatMessage;
+
expect(res.send).toHaveBeenCalledWith(
- expect.objectContaining({ wonLevel: true })
+ expect.objectContaining({
+ wonLevel: true,
+ wonLevelMessage: expectedWonLevelMessage,
+ })
);
});
@@ -827,11 +836,13 @@ describe('handleChatToGPT unit tests', () => {
await handleChatToGPT(req, res);
expect(res.send).toHaveBeenCalledWith(
- expect.objectContaining({ wonLevel: false })
+ expect.objectContaining({
+ wonLevel: false,
+ })
);
});
- test('Given win condition met AND openAI error THEN level is won', async () => {
+ test('Given win condition met AND openAI error THEN level is not won', async () => {
const newUserChatMessage = {
completion: {
content: 'Here is the answer to the level',
@@ -868,7 +879,9 @@ describe('handleChatToGPT unit tests', () => {
await handleChatToGPT(req, res);
expect(res.send).toHaveBeenCalledWith(
- expect.objectContaining({ wonLevel: true })
+ expect.objectContaining({
+ wonLevel: false,
+ })
);
});
});
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 3fe892a5a..ceb511831 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -72,7 +72,6 @@ function App() {
setIsNewUser(false);
openOverlay(
{
setStartLevel(level);
}}
diff --git a/frontend/src/components/ChatBox/ChatBox.tsx b/frontend/src/components/ChatBox/ChatBox.tsx
index 8531914c3..2fe61e71f 100644
--- a/frontend/src/components/ChatBox/ChatBox.tsx
+++ b/frontend/src/components/ChatBox/ChatBox.tsx
@@ -65,21 +65,9 @@ function ChatBox({
setChatInput(recalledMessage);
}, [recalledMessageReverseIndex]);
- function getSuccessMessage() {
- return currentLevel < LEVEL_NAMES.LEVEL_3
- ? `Congratulations! You have completed this level. Please click on the next level to continue.`
- : `Congratulations, you have completed the final level of your assignment!`;
- }
-
- function isLevelComplete() {
- // level is complete if the chat contains a LEVEL_INFO message
- return messages.some((message) => message.type === 'LEVEL_INFO');
- }
-
function processChatResponse(response: ChatResponse) {
const transformedMessageInfo = response.transformedMessageInfo;
const transformedMessage = response.transformedMessage;
- // add transformation info message to the chat box
if (transformedMessageInfo) {
addChatMessage({
message: transformedMessageInfo,
@@ -156,19 +144,13 @@ function ChatBox({
// update emails
addSentEmails(response.sentEmails);
- if (response.wonLevel && !isLevelComplete()) {
+ if (response.wonLevelMessage) {
updateNumCompletedLevels(currentLevel);
- const successMessage = getSuccessMessage();
- addChatMessage({
- type: 'LEVEL_INFO',
- message: successMessage,
- });
- // asynchronously add the message to the chat history
- void chatService.addInfoMessageToChatHistory(
- successMessage,
- 'LEVEL_INFO',
- currentLevel
+ const levelCompleteMessage = chatService.makeChatMessageFromDTO(
+ response.wonLevelMessage
);
+ addChatMessage(levelCompleteMessage);
+
// if this is the last level, show the level complete overlay
if (currentLevel === LEVEL_NAMES.LEVEL_3) {
openLevelsCompleteOverlay();
diff --git a/frontend/src/components/ChatBox/ChatBoxMessage/MessageBubble.tsx b/frontend/src/components/ChatBox/ChatBoxMessage/MessageBubble.tsx
index a675552da..1416f2456 100644
--- a/frontend/src/components/ChatBox/ChatBoxMessage/MessageBubble.tsx
+++ b/frontend/src/components/ChatBox/ChatBoxMessage/MessageBubble.tsx
@@ -14,7 +14,7 @@ function MessageBubble({
const baseClassName = 'message-bubble';
const messageTypeClassName =
- message.type === 'LEVEL_INFO'
+ message.type === 'LEVEL_COMPLETE'
? 'level-info'
: message.type === 'USER'
? 'user'
@@ -35,7 +35,7 @@ function MessageBubble({
);
const messageAuthor =
- message.type === 'LEVEL_INFO'
+ message.type === 'LEVEL_COMPLETE'
? ''
: message.type === 'USER'
? 'You said:'
@@ -48,12 +48,6 @@ function MessageBubble({
return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
- {message.type === 'LEVEL_INFO' && (
- <>
-
Information
- message:
- >
- )}
{messageAuthor}
{message.transformedMessage ? (
diff --git a/frontend/src/components/DocumentViewer/DocumentViewBox.css b/frontend/src/components/DocumentViewer/DocumentViewBox.css
index 8f994be8b..a285a38d9 100644
--- a/frontend/src/components/DocumentViewer/DocumentViewBox.css
+++ b/frontend/src/components/DocumentViewer/DocumentViewBox.css
@@ -37,8 +37,8 @@
padding: 2rem;
border: 0.1875rem solid var(--main-border-colour);
background: var(--main-background);
- aspect-ratio: 7/8;
color: var(--main-text-colour);
+ aspect-ratio: 7/8;
}
.document-viewer-container {
diff --git a/frontend/src/components/ExportChat/ExportChatMessage.tsx b/frontend/src/components/ExportChat/ExportChatMessage.tsx
index 2dea933f3..55def05c5 100644
--- a/frontend/src/components/ExportChat/ExportChatMessage.tsx
+++ b/frontend/src/components/ExportChat/ExportChatMessage.tsx
@@ -72,7 +72,7 @@ function getMessageStyle(type: CHAT_MESSAGE_TYPE) {
return styles.chatBoxInfo;
case 'BOT_BLOCKED':
case 'BOT':
- case 'LEVEL_INFO':
+ case 'LEVEL_COMPLETE':
case 'ERROR_MSG':
return styles.chatBoxMessageBot;
case 'USER':
diff --git a/frontend/src/components/LevelSelectionBox/LevelSelectionBox.tsx b/frontend/src/components/LevelSelectionBox/LevelSelectionBox.tsx
index f31dcf16e..5ff607e2e 100644
--- a/frontend/src/components/LevelSelectionBox/LevelSelectionBox.tsx
+++ b/frontend/src/components/LevelSelectionBox/LevelSelectionBox.tsx
@@ -29,7 +29,7 @@ function LevelSelectionBox({
}
return (
-
+
+
);
}
diff --git a/frontend/src/components/Overlay/OverlayWelcome.tsx b/frontend/src/components/Overlay/OverlayWelcome.tsx
index 4f0865eb1..8d0910290 100644
--- a/frontend/src/components/Overlay/OverlayWelcome.tsx
+++ b/frontend/src/components/Overlay/OverlayWelcome.tsx
@@ -5,11 +5,9 @@ import { LEVEL_NAMES } from '@src/models/level';
import MultipageOverlay from './MultipageOverlay';
function OverlayWelcome({
- currentLevel,
setStartLevel,
closeOverlay,
}: {
- currentLevel: LEVEL_NAMES;
setStartLevel: (newLevel: LEVEL_NAMES) => void;
closeOverlay: () => void;
}) {
@@ -43,10 +41,7 @@ function OverlayWelcome({
beginning, or are you an expert spy, and would prefer to jump
straight in at the sandbox?