diff --git a/src/components/ChallengeRoom.tsx b/src/components/ChallengeRoom.tsx
index 54f2998e13161e68ca16910a5bbb01b8ce9b2ce7..ef0b07bc5c73c2aa1ed3c120599ccf42477716c6 100644
--- a/src/components/ChallengeRoom.tsx
+++ b/src/components/ChallengeRoom.tsx
@@ -1,4 +1,4 @@
-import { Box, Button, ButtonGroup, Collapse, Stack, Tooltip, Typography, Alert, AlertTitle, Dialog } from "@mui/material"
+import { Box, Button, ButtonGroup, Collapse, Stack, Tooltip, Typography, Alert, AlertTitle, Dialog, TextField } from "@mui/material"
 import { useEffect, useState, useRef, useContext } from "react"
 import { Socket } from "socket.io-client"
 import { ChallengeFile, FileStatusPlayerResponse, JoinChallengeSuccessResponse, NewFileResponse, PlayerData, PlayerFileStatusesResponse, WaitingRoomList } from "../interfaces"
@@ -98,6 +98,8 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
   const [showApproveAlert, setShowApproveAlert] = useState(false)
   const [showCompletedAlert, setShowCompletedAlert] = useState(false)
   const [scores, setScores] = useState<PlayerData[]>([])
+  const [reviewResponse, setReviewResponse] = useState("") // GM's review message
+  const [reviewDescriptionInput, setReviewDescriptionInput] = useState("")
   const translation = useContext(LanguageContext)
 
   const initTasks = useRef(true) // Used to not show task alerts on page refresh
@@ -182,6 +184,7 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
     if (!isGameMaster) {
       // Get file status response when currentTaskNumber changes or file status changes
       socket?.on("fileStatusPlayer", (dataResponse: FileStatusPlayerResponse) => {
+        setReviewResponse(dataResponse.reviewDescription)
         switch (dataResponse.status) {
           case "Approved":
             if (randomTasks.findIndex((x) => x === dataResponse.taskNumber) + 1 >= roomInfo.details.challengeTasks.length) {
@@ -268,11 +271,13 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
 
   const handleReview = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, isAccepted: boolean) => {
     if (unReviewedSubmissions[0] !== undefined) {
+      setReviewDescriptionInput("")
       socket?.emit("approveFile", {
         token: roomInfo?.details.token,
         payload: {
           submissionId: unReviewedSubmissions[0].submissionId,
           fileStatus: isAccepted,
+          reviewDescription: reviewDescriptionInput,
         },
       })
     }
@@ -321,7 +326,9 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
                   {translation.texts.challenge}
                 </Typography>
                 <Typography variant="body1" component="p">
-                  <span id="current-task-number-player">{randomTasks.findIndex(x => x === currentTaskNumber) + 1} / {roomInfo.details.challengeTasks.length}</span>
+                  <span id="current-task-number-player">
+                    {randomTasks.findIndex((x) => x === currentTaskNumber) + 1} / {roomInfo.details.challengeTasks.length}
+                  </span>
                 </Typography>
                 <Typography variant="body1" component="p">
                   {translation.texts.description}
@@ -374,7 +381,11 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
                 <Typography variant="body1" component="p">
                   {translation.texts.challenge}: {unReviewedSubmissions[0].taskDescription}
                 </Typography>
+                <Typography variant="body1" component="p">
+                  {translation.texts.description}: {unReviewedSubmissions[0].submissionDescription}
+                </Typography>
                 <img src={currentSubmissionPhoto} alt={translation.imageAlts.reviewingPhoto} />
+                <TextField id="review-description" label={translation.inputs.texts.description} value={reviewDescriptionInput} onChange={(e) => setReviewDescriptionInput(e.target.value)}></TextField>
                 <Button id="accept-photo-btn-gm" color="success" onClick={(e) => handleReview(e, true)}>
                   {translation.inputs.buttons.accept}
                 </Button>
@@ -436,20 +447,35 @@ function ChallengeRoom({ roomInfo, socket, playerArray }: Props) {
       <Stack style={{ position: "absolute", top: "50px", left: "50%", transform: "translate(-50%, 0%)" }} sx={{ width: "auto", textAlign: "left" }} spacing={1}>
         {showRejectAlert && (
           <Alert onClick={() => setShowRejectAlert(false)} severity="error">
-            <AlertTitle>{translation.alerts.title.rejected}</AlertTitle>
+            <AlertTitle id="alert-title-rejected">{translation.alerts.title.rejected}</AlertTitle>
             {translation.alerts.alert.submissionRejected}
+            {reviewResponse !== "" && (
+              <p>
+                {translation.texts.message}: <span id="rejected-message">{reviewResponse}</span>
+              </p>
+            )}
           </Alert>
         )}
         {showApproveAlert && (
           <Alert onClick={() => setShowApproveAlert(false)} severity="success">
-            <AlertTitle>{translation.alerts.title.approved}</AlertTitle>
+            <AlertTitle id="alert-title-approved">{translation.alerts.title.approved}</AlertTitle>
             {translation.alerts.success.submissionApproved}
+            {reviewResponse !== "" && (
+              <p>
+                {translation.texts.message}: <span id="approved-message">{reviewResponse}</span>
+              </p>
+            )}
           </Alert>
         )}
         {showCompletedAlert && (
           <Alert onClick={() => setShowCompletedAlert(false)} severity="info">
-            <AlertTitle>{translation.alerts.title.tasksCompleted}</AlertTitle>
+            <AlertTitle id="alert-title-completed">{translation.alerts.title.tasksCompleted}</AlertTitle>
             {translation.alerts.info.tasksCompleted}
+            {reviewResponse !== "" && (
+              <p>
+                {translation.texts.message}: <span id="completed-message">{reviewResponse}</span>
+              </p>
+            )}
           </Alert>
         )}
       </Stack>
diff --git a/src/components/ChallengeRoomCamera.tsx b/src/components/ChallengeRoomCamera.tsx
index fa0f038fadaa821b3fb40c62d106a41bd80cc66e..8a33f3197c16552c76f9eff232360634c5ed5e87 100644
--- a/src/components/ChallengeRoomCamera.tsx
+++ b/src/components/ChallengeRoomCamera.tsx
@@ -1,4 +1,4 @@
-import { Button, Dialog, Stack } from "@mui/material"
+import { Button, Dialog, Stack, TextField } from "@mui/material"
 import React, { useEffect, useState, useContext, useRef } from "react"
 import { SendFileResponse } from "../interfaces"
 import LanguageContext from "./Context/LanguageContext"
@@ -23,6 +23,7 @@ function ChallengeRoomCamera({ taskId, onSubmit, open, close }: Props) {
   const [allowed, setAllowed] = useState(true)
   const [loading, setLoading] = useState(true)
   const [takenPhoto, setTakenPhoto] = useState("") // photo as base64 string
+  const [submissionDesc, setSubmissionDesc] = useState("")
   const translation = useContext(LanguageContext)
 
   let canvasHeight = 500
@@ -112,6 +113,7 @@ function ChallengeRoomCamera({ taskId, onSubmit, open, close }: Props) {
         body: JSON.stringify({
           challengeFile: takenPhoto.split(";base64,")[1],
           taskId: taskId,
+          submissionDescription: submissionDesc,
         }),
       })
         .then((res) => res.json())
@@ -136,6 +138,7 @@ function ChallengeRoomCamera({ taskId, onSubmit, open, close }: Props) {
       </Stack>
       <Stack display={takenPhoto !== "" && allowed ? "flex" : "none"} alignItems="center" spacing={1} p={1}>
         <img width={canvasWidth} height={canvasHeight} id="photo" src={takenPhoto} alt={translation.imageAlts.cameraScreen} />
+        <TextField id="submission-description" label={translation.inputs.texts.description} value={submissionDesc} onChange={(e) => setSubmissionDesc(e.target.value)}></TextField>
         <Button id="send-photo-btn" color="success" onClick={sendPhotoHandler}>
           {translation.inputs.buttons.send}
         </Button>
diff --git a/src/interfaces.ts b/src/interfaces.ts
index db1d42eb6e040ac00ea99143b89b39043a70f9d2..e3fb7db1de5e4aa89e04ba322b34c91e432a345b 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -92,6 +92,7 @@ export interface WaitingRoomNewPlayer {
 export interface FileStatusPlayerResponse {
   status: fileStatus
   taskNumber: number
+  reviewDescription: string
 }
 
 /**
@@ -122,6 +123,7 @@ export interface ChallengeFile {
   fileStatus: fileStatus
   challengeNumber: number
   taskDescription: string
+  submissionDescription: string
 }
 
 /**
diff --git a/src/translations.ts b/src/translations.ts
index 13d260d90c8cade040dd05b8a0f29a76699a6b55..4a94f2edf4da412e71745faadb19dc3f57969e6b 100644
--- a/src/translations.ts
+++ b/src/translations.ts
@@ -81,6 +81,7 @@ export interface Translation {
     allTasksCompleted: string
     submissionDeclined: string
     taskNumber: string
+    message: string
     randomTasks: string
   }
   tables: {
@@ -197,6 +198,7 @@ const finnish: Translation = {
     allTasksCompleted: "Kaikki haasteet suoritettu!",
     submissionDeclined: "Kuvasi on hylätty! Ota uusi kuva.",
     taskNumber: "Haasteen numero",
+    message: "Viesti",
     randomTasks: "Sekoita haasteiden järjestys",
   },
   tables: {
@@ -313,6 +315,7 @@ const english: Translation = {
     allTasksCompleted: "All tasks have been completed!",
     submissionDeclined: "Your submission has been rejected! Take a new photo.",
     taskNumber: "Task number",
+    message: "Message",
     randomTasks: "Randomise task order",
   },
   tables: {