diff --git a/packages/client/app/graphql/chat.queries.js b/packages/client/app/graphql/chat.queries.js
index 9c7e9f3b1c0571a944ece7fa542e26af4ad8b99d..4ecc76a73ded9a6219a0280f5d9e02db864728bd 100644
--- a/packages/client/app/graphql/chat.queries.js
+++ b/packages/client/app/graphql/chat.queries.js
@@ -34,6 +34,34 @@ export const GET_CHAT_THREAD = gql`
   }
 `
 
+export const FILTER_CHAT_THREADS = gql`
+  query ChatThreads($where: CreateChatThreadInput) {
+    chatThreads(where: $where) {
+      result {
+        id
+        created
+        updated
+        chatType
+        relatedObjectId
+        messages {
+          id
+          content
+          created
+          user {
+            id
+            displayName
+          }
+          mentions
+          attachments {
+            name
+            url
+          }
+        }
+      }
+    }
+  }
+`
+
 export const SEND_MESSAGE = gql`
   mutation SendMessage($input: SendChatMessageInput!) {
     sendMessage(input: $input) {
diff --git a/packages/client/app/graphql/complexItemSet.queries.js b/packages/client/app/graphql/complexItemSet.queries.js
index c82e466427958f745d71beb2a5eb416a0b5e6dcc..e77ee63aa79f4552cc5a44959558804b85222764 100644
--- a/packages/client/app/graphql/complexItemSet.queries.js
+++ b/packages/client/app/graphql/complexItemSet.queries.js
@@ -67,6 +67,7 @@ export const GET_COMPLEX_ITEM_SET = gql`
             underReview
             inProduction
             published
+            unpublished
 
             topics {
               topic
diff --git a/packages/client/app/graphql/question.queries.js b/packages/client/app/graphql/question.queries.js
index 5a648f9303306ee7cd8293cbc0e424ffd8a7798e..3c87b4097fe2b88f3e5a5feb714d45e01c708884 100644
--- a/packages/client/app/graphql/question.queries.js
+++ b/packages/client/app/graphql/question.queries.js
@@ -369,8 +369,11 @@ export const GET_PRODUCTION_CHAT_PARTICIPANTS = gql`
 `
 
 export const GET_REVIEWER_CHAT_PARTICIPANTS = gql`
-  query GetReviewerChatParticipants($id: ID!) {
-    getReviewerChatParticipants(id: $id) {
+  query GetReviewerChatParticipants($questionId: ID!, $reviewerId: ID!) {
+    getReviewerChatParticipants(
+      questionId: $questionId
+      reviewerId: $reviewerId
+    ) {
       id
       display: displayName
       role
diff --git a/packages/client/app/pages/Question.page.js b/packages/client/app/pages/Question.page.js
index 1fb6ca95b5e6b75458d14b4041311947e34316ed..d0c88069548249313c2bb4dc7b97b9d90d631303 100644
--- a/packages/client/app/pages/Question.page.js
+++ b/packages/client/app/pages/Question.page.js
@@ -10,8 +10,7 @@ import {
 import debounce from 'lodash/debounce'
 // import { questionDataTransformer, questionDataMapper } from '../utilities'
 
-import { serverUrl } from '@coko/client'
-
+import { serverUrl, uuid } from '@coko/client'
 import { Question, Result, VisuallyHiddenElement } from 'ui'
 
 import {
@@ -54,6 +53,7 @@ import {
   CHANGE_AMOUNT_OF_REVIEWERS,
   CHANGE_REVIEWER_AUTOMATION_STATUS,
   SUBMIT_REPORT,
+  FILTER_CHAT_THREADS,
 } from '../graphql'
 import {
   useMetadata,
@@ -219,6 +219,8 @@ const QuestionPage = props => {
   const { metadata } = useMetadata()
 
   const requestedTab = window.location.hash.substring(1)
+  const [selectedReviewerId, setSelectedReviewerId] = useState(uuid())
+  const [reviewerChatThread, setReviewerChatThread] = useState()
 
   const {
     data: { question } = {},
@@ -253,9 +255,10 @@ const QuestionPage = props => {
   const {
     data: { getReviewerChatParticipants: reviewerChatParticipants } = {},
   } = useQuery(GET_REVIEWER_CHAT_PARTICIPANTS, {
-    skip: !question?.versions[0]?.underReview,
+    skip: !question?.versions[0]?.underReview || !selectedReviewerId,
     variables: {
-      id,
+      questionId: id,
+      reviewerId: selectedReviewerId,
     },
   })
 
@@ -348,16 +351,20 @@ const QuestionPage = props => {
     },
   )
 
-  const {
-    data: { chatThread: reviewerChatThread } = {},
-    loading: reviewerChatLoading,
-  } = useQuery(GET_CHAT_THREAD, {
-    skip: !question?.reviewerChatThreadId,
+  useQuery(GET_CHAT_THREAD, {
+    skip: !question?.reviewerChatThreadId || question?.versions[0].underReview,
     variables: {
       id: question?.reviewerChatThreadId,
     },
+    onCompleted: ({ chatThread: reviewerChat }) => {
+      setSelectedReviewerId(currentUser.id)
+      setReviewerChatMessages(reviewerChat?.messages)
+      setReviewerChatThread(reviewerChat)
+    },
   })
 
+  const [getReviewerChatThread] = useLazyQuery(FILTER_CHAT_THREADS)
+
   useSubscription(MESSAGE_CREATED_SUBSCRIPTION, {
     skip: !authorChatThread?.id,
     variables: { chatThreadId: authorChatThread?.id },
@@ -484,11 +491,11 @@ const QuestionPage = props => {
       setProductionChatMessages(productionChatThread.messages)
     }
   }, [productionChatThread])
-  useEffect(() => {
-    if (reviewerChatThread?.messages) {
-      setReviewerChatMessages(reviewerChatThread.messages)
-    }
-  }, [reviewerChatThread])
+  // useEffect(() => {
+  //   if (reviewerChatThread?.messages) {
+  //     setReviewerChatMessages(reviewerChatThread.messages)
+  //   }
+  // }, [reviewerChatThread])
 
   /* setup Prev/Next question functions */
   // read state from location to get filter values, if any
@@ -561,9 +568,9 @@ const QuestionPage = props => {
       createChat('productionChat')
     }
 
-    if (version?.underReview && !question?.reviewerChatThreadId) {
-      createChat('reviewerChat')
-    }
+    // if (version?.underReview && !question?.reviewerChatThreadId) {
+    //   createChat('reviewerChat')
+    // }
   }, [question, version])
 
   // declare lazy query to be called when no `relatedQuestionsIds` from previous state
@@ -649,8 +656,10 @@ const QuestionPage = props => {
         },
         {
           query: GET_REVIEWER_CHAT_PARTICIPANTS,
+          skip: !question?.versions[0]?.underReview || !selectedReviewerId,
           variables: {
-            id,
+            questionId: id,
+            reviewerId: selectedReviewerId,
           },
         },
       ],
@@ -1108,9 +1117,10 @@ const QuestionPage = props => {
         })
         break
       case 'reviewerChat':
-        cancelEmailNotification({
-          variables: { chatThreadId: reviewerChatThread?.id },
-        })
+        reviewerChatThread?.id &&
+          cancelEmailNotification({
+            variables: { chatThreadId: reviewerChatThread?.id },
+          })
         break
       default:
         break
@@ -1142,6 +1152,25 @@ const QuestionPage = props => {
     return sendMessage(mutationData)
   }
 
+  const handleSelectReviewer = async reviewerId => {
+    setSelectedReviewerId(reviewerId)
+
+    const variables = {
+      where: {
+        relatedObjectId: question?.id,
+        chatType: `reviewerChat-${reviewerId}`,
+      },
+    }
+
+    // this query doesn't work as expected, needs to be fixed in coko server
+    const threads = await getReviewerChatThread({ variables })
+
+    const reviewerChat = threads?.data.chatThreads.result[0]
+
+    setReviewerChatMessages(reviewerChat?.messages)
+    setReviewerChatThread(reviewerChat)
+  }
+
   const onSendAuthorChatMessage = async (content, mentions, attachments) => {
     return handleSendChatMessage(
       content,
@@ -1169,7 +1198,7 @@ const QuestionPage = props => {
       content,
       mentions,
       attachments,
-      question?.reviewerChatThreadId,
+      reviewerChatThread?.id,
     )
   }
 
@@ -1340,6 +1369,17 @@ const QuestionPage = props => {
   }
   // #endregion handlers
 
+  useEffect(() => {
+    if (
+      question &&
+      (!question?.reviewerChatThreadId || isUnderReview) &&
+      isReviewer &&
+      isUnderReview
+    ) {
+      handleSelectReviewer(currentUser.id)
+    }
+  }, [isReviewer, isUnderReview, question])
+
   if (error) {
     return (
       <Result
@@ -1392,7 +1432,7 @@ const QuestionPage = props => {
         canCreateNewVersion={isAdmin || isEditor}
         canPublish={isEditor || isHandlingEditor || isAdmin}
         canUnpublish={isAdmin || isEditor}
-        chatLoading={chatLoading || reviewerChatLoading}
+        chatLoading={chatLoading}
         complexItemSetId={version?.complexItemSetId}
         complexItemSetOptions={complexItemSetOptions}
         complexSetEditLink={
@@ -1411,6 +1451,9 @@ const QuestionPage = props => {
         facultyView={testMode || (isReviewer && isUnderReview)}
         handlingEditors={handlingEditors?.result || []}
         hasDeletedAuthor={!!question?.deletedAuthorName}
+        hasGeneralReviewerChatId={
+          !!question?.reviewerChatThreadId && !isUnderReview
+        }
         initialMetadataValues={metadataApiToUi(
           version,
           testMode || (isReviewer && isUnderReview),
@@ -1473,6 +1516,7 @@ const QuestionPage = props => {
         onReviewerTableChange={handleReviewerTableChange}
         onRevokeReviewerInvitation={handleRevokeReviewerInvitation}
         onSearchHE={handleSearchHE}
+        onSelectReviewer={handleSelectReviewer}
         onSendAuthorChatMessage={onSendAuthorChatMessage}
         onSendProductionChatMessage={onSendProductionChatMessage}
         onSendReviewerChatMessage={onSendReviewerChatMessage}
diff --git a/packages/client/app/routes.js b/packages/client/app/routes.js
index 7c80e997d2a95427e78b32b19e3efe516bf98e92..3ac2d2ccc2a14a4103d3c557bb9379460dcb713a 100644
--- a/packages/client/app/routes.js
+++ b/packages/client/app/routes.js
@@ -293,11 +293,10 @@ const SiteHeader = () => {
   const logout = () => {
     setCurrentUser(null)
     client.cache.reset()
+    localStorage.clear()
 
-    localStorage.removeItem('token')
-    localStorage.removeItem('dashboardLastUsedTab')
-
-    history.push('/login')
+    // refresh to unmount notification provider
+    window.location.href = '/login'
   }
 
   const isAdmin = hasGlobalRole(currentUser, 'admin')
diff --git a/packages/client/app/ui/chat/ChatThread.js b/packages/client/app/ui/chat/ChatThread.js
index 4a93d289b898f05cc478eac0bde1470c20e779a8..bb2d509cdfda3d7671b629f92d2883c36eb94ea2 100644
--- a/packages/client/app/ui/chat/ChatThread.js
+++ b/packages/client/app/ui/chat/ChatThread.js
@@ -33,6 +33,7 @@ const ChatThread = props => {
     onFetchMore,
     onSendMessage,
     infiniteScroll,
+    inputPlaceholder,
     ...rest
   } = props
 
@@ -95,7 +96,7 @@ const ChatThread = props => {
         aria-label="Write a message"
         onSend={onSendMessage}
         participants={participants}
-        placeholder="Write a message"
+        placeholder={inputPlaceholder || 'Write a message'}
         type="text"
       />
       {announcementText && (
@@ -122,6 +123,7 @@ ChatThread.propTypes = {
       role: PropTypes.string,
     }),
   ),
+  inputPlaceholder: PropTypes.string,
 }
 
 ChatThread.defaultProps = {
@@ -133,6 +135,7 @@ ChatThread.defaultProps = {
   onSendMessage: () => {},
   participants: [],
   infiniteScroll: false,
+  inputPlaceholder: null,
 }
 
 export default ChatThread
diff --git a/packages/client/app/ui/notifications/MentionsItem.js b/packages/client/app/ui/notifications/MentionsItem.js
index 110b75875a4c8a5496099300d802183e92ea6fda..1cb3f14931e5251f340026872f24ea49bc5ff856 100644
--- a/packages/client/app/ui/notifications/MentionsItem.js
+++ b/packages/client/app/ui/notifications/MentionsItem.js
@@ -231,7 +231,17 @@ const MentionsItem = ({ item, markAs }) => {
               {itemLink ? (
                 <>
                   <Link to={itemLink}>Go to Item</Link>
-                  <Link onClick={() => markAs(true, [id])} to={chatLink}>
+                  <Link
+                    onClick={() => markAs(true, [id])}
+                    to={
+                      chatLink.indexOf('#reviewerChat') > -1
+                        ? chatLink.substring(
+                            0,
+                            chatLink.indexOf('#reviewerChat') + 13,
+                          )
+                        : chatLink
+                    }
+                  >
                     Go to Chat
                   </Link>
                 </>
diff --git a/packages/client/app/ui/question/Question.js b/packages/client/app/ui/question/Question.js
index 5b8fe88328c00e9dc8e5f9ef1ba295b0cb4e246f..1baccb5de615a5619c1149ff96836c1c828cf47b 100644
--- a/packages/client/app/ui/question/Question.js
+++ b/packages/client/app/ui/question/Question.js
@@ -39,6 +39,7 @@ import AssignAuthorButton from './AssignAuthorButton'
 import ReviewerRejectButton from './ReviewerRejectButton'
 import ReviewerAcceptButton from './ReviewerAcceptButton'
 import ReviewerSubmitButton from './ReviewerSubmitButton'
+import ReviewerChats from './ReviewerChats'
 import { AssignReviewers } from '../assignReviewers'
 
 const ModalContext = React.createContext({ agree: false, setAgree: () => {} })
@@ -473,6 +474,8 @@ const Question = props => {
     showReviewerChatTab,
     showAssignReviewers,
     hasDeletedAuthor,
+    onSelectReviewer,
+    hasGeneralReviewerChatId,
   } = props
 
   const [modal, contextHolder] = Modal.useModal()
@@ -1568,6 +1571,209 @@ const Question = props => {
     }
   }
 
+  const tabItems = [
+    {
+      label: QuestionTab,
+      key: 'editor',
+      children: (
+        <>
+          {isRejected && (
+            <Ribbon status="error">
+              This item has been rejected by the editors.
+            </Ribbon>
+          )}
+          {isUnpublished && (
+            <Ribbon status="error">
+              This item has been unpublished by the editors.
+              {hasDeletedAuthor &&
+                ` The author of this item has been deleted. Assign a new author to be able to edit.`}
+            </Ribbon>
+          )}
+          {reviewInviteStatus === REVIEWER_STATUSES.revoked && (
+            <Ribbon status="error">
+              Invitation to review this item has been revoked.
+            </Ribbon>
+          )}
+          {reviewInviteStatus === REVIEWER_STATUSES.rejected && (
+            <Ribbon status="error">
+              You have rejected the invitation to review this item.
+            </Ribbon>
+          )}
+          {isArchived && (
+            <Ribbon status="error">This item has been archived.</Ribbon>
+          )}
+          <PanelWrapper
+            condition={false}
+            editor={
+              <QuestionEditor
+                complexItemSetId={complexItemSetId}
+                complexSetEditLink={complexSetEditLink}
+                content={editorContent}
+                innerRef={waxRef}
+                layout={preview || reviewerView ? TestModeLayout : HhmiLayout}
+                leadingContent={leadingContent}
+                onContentChange={handleQuestionContentChange}
+                onImageUpload={onImageUpload}
+                onSubmitReport={onSubmitReport}
+                published={isPublished}
+                readOnly={
+                  readOnly || preview || !selectedQuestionType //
+                }
+                refreshEditorContent={refreshEditorContent}
+                selectedQuestionType={selectedQuestionType}
+                showDialog={showDialog}
+                withFeedback={
+                  !(preview || reviewerView) || (showMetadata && facultyView)
+                }
+              />
+            }
+            metadata={
+              <>
+                <StyledMetadata
+                  complexItemSetOptions={complexItemSetOptions}
+                  editorView={editorView}
+                  initialValues={initialMetadataValues}
+                  innerRef={formRef}
+                  metadata={metadata}
+                  onAutoSave={handleMetadataAutoSave}
+                  onFormFinish={onFormFinish}
+                  presentationMode={facultyView}
+                  readOnly={readOnly}
+                  resources={resources}
+                  selectedQuestionType={selectedQuestionType?.metadataValue}
+                  showTopicAndSubtopicFields={
+                    isInProduction || isPublished || isUnpublished
+                  }
+                />
+                <SkipToTop
+                  href="#question-actions"
+                  onClick={e => {
+                    e.preventDefault()
+                    document.getElementById('question-actions').focus()
+                  }}
+                >
+                  {skipButtonText()}
+                </SkipToTop>
+              </>
+            }
+            showMetadata={showMetadata && (!preview || facultyView)}
+          />
+          <VisuallyHiddenElement as="div">
+            {imageLongDescs.map(longDesc => (
+              <p id={longDesc.id}>{longDesc.content}</p>
+            ))}
+          </VisuallyHiddenElement>
+        </>
+      ),
+    },
+    showAuthorChatTab && {
+      label: AuthorChatTab,
+      key: 'authorChat',
+      children: (
+        <ChatThread
+          announcementText={announcementText}
+          hasMore={hasMoreMessages}
+          isActive={activeKey === 'authorChat'}
+          messages={authorChatMessages}
+          onFetchMore={onFetchMoreMessages}
+          onSendMessage={onSendAuthorChatMessage}
+          participants={authorChatParticipants}
+        />
+      ),
+    },
+    showProductionChatTab && {
+      label: ProductionAssignmentsTab,
+      key: 'productionChat',
+      children: (
+        <ChatThread
+          isActive={activeKey === 'productionChat'}
+          messages={productionChatMessages}
+          onSendMessage={onSendProductionChatMessage}
+          participants={productionChatParticipants}
+        />
+      ),
+    },
+    showReviewerChatTab && {
+      label: ReviewerChatTab,
+      key: 'reviewerChat',
+      children:
+        reviewerView || hasGeneralReviewerChatId ? (
+          <ChatThread
+            hasMore={hasMoreMessages}
+            isActive={activeKey === 'reviewerChat'}
+            messages={reviewerChatMessages}
+            onFetchMore={onFetchMoreMessages}
+            onSendMessage={onSendReviewerChatMessage}
+            participants={reviewerChatParticipants}
+          />
+        ) : (
+          <ReviewerChats
+            hasMore={hasMoreMessages}
+            isActive={activeKey === 'reviewerChat'}
+            messages={reviewerChatMessages}
+            onFetchMore={onFetchMoreMessages}
+            onSelectReviewer={onSelectReviewer}
+            onSendMessage={onSendReviewerChatMessage}
+            participants={reviewerChatParticipants}
+            reviewers={reviewerPool.filter(r => r.acceptedInvitation)}
+          />
+        ),
+    },
+    showAssignReviewers && {
+      label: AssignReviewersTab,
+      key: 'assignReviewers',
+      children: (
+        <AssignReviewers
+          amountOfReviewers={amountOfReviewers}
+          automate={automateReviewerInvites}
+          canInviteMore={!!findAvailableReviewerSlots()}
+          onAddReviewers={onAddReviewers}
+          onAmountOfReviewersChange={onChangeAmountOfReviewers}
+          onAutomationChange={handleReviewerInviteAutomationChange}
+          onClickInvite={handleClickInviteReviewer}
+          onClickRemoveRow={onRemoveReviewerRow}
+          onClickRevokeInvitation={handleRevokeReviewerInvite}
+          onSearch={onReviewerSearch}
+          onTableChange={onReviewerTableChange}
+          reviewerPool={reviewerPool}
+          searchPlaceholder="Search by reviewer name or relevant topic"
+        />
+      ),
+    },
+  ]
+
+  useEffect(() => {
+    if (
+      showAuthorChatTab !== null &&
+      showProductionChatTab !== null &&
+      showReviewerChatTab !== null &&
+      showAssignReviewers !== null
+    ) {
+      switch (activeKey) {
+        case 'authorChat':
+          !showAuthorChatTab && handleTabChange('editor')
+          break
+        case 'reviewerChat':
+          !showReviewerChatTab && handleTabChange('editor')
+          break
+        case 'productionChat':
+          !showProductionChatTab && handleTabChange('editor')
+          break
+        case 'assignReviewers':
+          !showAssignReviewers && handleTabChange('editor')
+          break
+        default:
+          handleTabChange('editor')
+          break
+      }
+    }
+  }, [
+    showAuthorChatTab,
+    showProductionChatTab,
+    showReviewerChatTab,
+    showAssignReviewers,
+  ])
+
   return (
     <ModalContext.Provider value={contextValue}>
       <Wrapper>
@@ -1575,175 +1781,7 @@ const Question = props => {
           <StyledTabs
             $activebg="#fff"
             activeKey={activeKey}
-            items={[
-              {
-                label: QuestionTab,
-                key: 'editor',
-                children: (
-                  <>
-                    {isRejected && (
-                      <Ribbon status="error">
-                        This item has been rejected by the editors.
-                      </Ribbon>
-                    )}
-                    {isUnpublished && (
-                      <Ribbon status="error">
-                        This item has been unpublished by the editors.
-                        {hasDeletedAuthor &&
-                          ` The author of this item has been deleted. Assign a new author to be able to edit.`}
-                      </Ribbon>
-                    )}
-                    {reviewInviteStatus === REVIEWER_STATUSES.revoked && (
-                      <Ribbon status="error">
-                        Invitation to review this item has been revoked.
-                      </Ribbon>
-                    )}
-                    {reviewInviteStatus === REVIEWER_STATUSES.rejected && (
-                      <Ribbon status="error">
-                        You have rejected the invitation to review this item.
-                      </Ribbon>
-                    )}
-                    {isArchived && (
-                      <Ribbon status="error">
-                        This item has been archived.
-                      </Ribbon>
-                    )}
-                    <PanelWrapper
-                      condition={false}
-                      editor={
-                        <QuestionEditor
-                          complexItemSetId={complexItemSetId}
-                          complexSetEditLink={complexSetEditLink}
-                          content={editorContent}
-                          innerRef={waxRef}
-                          layout={
-                            preview || reviewerView
-                              ? TestModeLayout
-                              : HhmiLayout
-                          }
-                          leadingContent={leadingContent}
-                          onContentChange={handleQuestionContentChange}
-                          onImageUpload={onImageUpload}
-                          onSubmitReport={onSubmitReport}
-                          published={isPublished}
-                          readOnly={
-                            readOnly || preview || !selectedQuestionType //
-                          }
-                          refreshEditorContent={refreshEditorContent}
-                          selectedQuestionType={selectedQuestionType}
-                          showDialog={showDialog}
-                          withFeedback={
-                            !(preview || reviewerView) ||
-                            (showMetadata && facultyView)
-                          }
-                        />
-                      }
-                      metadata={
-                        <>
-                          <StyledMetadata
-                            complexItemSetOptions={complexItemSetOptions}
-                            editorView={editorView}
-                            initialValues={initialMetadataValues}
-                            innerRef={formRef}
-                            metadata={metadata}
-                            onAutoSave={handleMetadataAutoSave}
-                            onFormFinish={onFormFinish}
-                            presentationMode={facultyView}
-                            readOnly={readOnly}
-                            resources={resources}
-                            selectedQuestionType={
-                              selectedQuestionType?.metadataValue
-                            }
-                            showTopicAndSubtopicFields={
-                              isInProduction || isPublished || isUnpublished
-                            }
-                          />
-                          <SkipToTop
-                            href="#question-actions"
-                            onClick={e => {
-                              e.preventDefault()
-                              document
-                                .getElementById('question-actions')
-                                .focus()
-                            }}
-                          >
-                            {skipButtonText()}
-                          </SkipToTop>
-                        </>
-                      }
-                      showMetadata={showMetadata && (!preview || facultyView)}
-                    />
-                    <VisuallyHiddenElement as="div">
-                      {imageLongDescs.map(longDesc => (
-                        <p id={longDesc.id}>{longDesc.content}</p>
-                      ))}
-                    </VisuallyHiddenElement>
-                  </>
-                ),
-              },
-              showAuthorChatTab && {
-                label: AuthorChatTab,
-                key: 'authorChat',
-                children: (
-                  <ChatThread
-                    announcementText={announcementText}
-                    hasMore={hasMoreMessages}
-                    isActive={activeKey === 'authorChat'}
-                    messages={authorChatMessages}
-                    onFetchMore={onFetchMoreMessages}
-                    onSendMessage={onSendAuthorChatMessage}
-                    participants={authorChatParticipants}
-                  />
-                ),
-              },
-              showProductionChatTab && {
-                label: ProductionAssignmentsTab,
-                key: 'productionChat',
-                children: (
-                  <ChatThread
-                    isActive={activeKey === 'productionChat'}
-                    messages={productionChatMessages}
-                    onSendMessage={onSendProductionChatMessage}
-                    participants={productionChatParticipants}
-                  />
-                ),
-              },
-              showReviewerChatTab && {
-                label: ReviewerChatTab,
-                key: 'reviewerChat',
-                children: (
-                  <ChatThread
-                    hasMore={hasMoreMessages}
-                    isActive={activeKey === 'reviewerChat'}
-                    messages={reviewerChatMessages}
-                    onFetchMore={onFetchMoreMessages}
-                    onSendMessage={onSendReviewerChatMessage}
-                    participants={reviewerChatParticipants}
-                  />
-                ),
-              },
-              showAssignReviewers && {
-                label: AssignReviewersTab,
-                key: 'assignReviewers',
-                children: (
-                  <AssignReviewers
-                    amountOfReviewers={amountOfReviewers}
-                    automate={automateReviewerInvites}
-                    canInviteMore={!!findAvailableReviewerSlots()}
-                    onAddReviewers={onAddReviewers}
-                    onAmountOfReviewersChange={onChangeAmountOfReviewers}
-                    onAutomationChange={handleReviewerInviteAutomationChange}
-                    onClickInvite={handleClickInviteReviewer}
-                    onClickRemoveRow={onRemoveReviewerRow}
-                    onClickRevokeInvitation={handleRevokeReviewerInvite}
-                    onSearch={onReviewerSearch}
-                    onTableChange={onReviewerTableChange}
-                    reviewerPool={reviewerPool}
-                    searchPlaceholder="Search by reviewer name or relevant topic"
-                  />
-                ),
-              },
-            ]}
+            items={tabItems}
             onChange={handleTabChange}
             renderTabBar={(tabProps, DefaultTabBar) => {
               return facultyView && !reviewerView ? (
@@ -2145,6 +2183,8 @@ Question.propTypes = {
   showAssignReviewers: PropTypes.bool,
 
   hasDeletedAuthor: PropTypes.bool,
+  onSelectReviewer: PropTypes.func,
+  hasGeneralReviewerChatId: PropTypes.bool,
 }
 
 Question.defaultProps = {
@@ -2238,12 +2278,14 @@ Question.defaultProps = {
   selectedQuestionType: null,
 
   onChangeTab: () => {},
-  showAuthorChatTab: false,
-  showProductionChatTab: false,
-  showReviewerChatTab: false,
-  showAssignReviewers: false,
+  showAuthorChatTab: null,
+  showProductionChatTab: null,
+  showReviewerChatTab: null,
+  showAssignReviewers: null,
 
   hasDeletedAuthor: false,
+  onSelectReviewer: null,
+  hasGeneralReviewerChatId: false,
 }
 
 export default Question
diff --git a/packages/client/app/ui/question/ReviewerChats.js b/packages/client/app/ui/question/ReviewerChats.js
new file mode 100644
index 0000000000000000000000000000000000000000..7608dabc41cee078344a6f90bcc97d96d00b7650
--- /dev/null
+++ b/packages/client/app/ui/question/ReviewerChats.js
@@ -0,0 +1,111 @@
+/* eslint-disable jsx-a11y/label-has-associated-control */
+/* eslint-disable react/prop-types */
+import React, { useEffect, useState } from 'react'
+import styled from 'styled-components'
+import { grid, th } from '@coko/client'
+import { ChatThread } from '../chat'
+import { Select } from '../common'
+
+const ReviewerChatHeader = styled.header`
+  align-items: center;
+  border-bottom: 1px solid ${th('colorBorder')};
+  display: flex;
+  justify-content: flex-end;
+  padding: ${grid(1)} ${grid(3)};
+`
+
+const Wrapper = styled.section`
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  position: relative;
+`
+
+const StyledSelect = styled(Select)`
+  width: 200px;
+`
+
+const ReviewerSelectorWrapper = styled.div`
+  align-items: center;
+  display: flex;
+  gap: ${grid(2)};
+`
+
+const NoReviewer = styled.div`
+  display: grid;
+  height: 100%;
+  place-content: center;
+
+  p {
+    text-align: center;
+  }
+`
+
+const ReviewerChats = props => {
+  const {
+    hasMore,
+    isActive,
+    messages,
+    onFetchMore,
+    onSendMessage,
+    participants,
+
+    reviewers,
+    onSelectReviewer,
+  } = props
+
+  const [selectedReviewer, setSelectedReviewer] = useState()
+
+  useEffect(() => {
+    if (selectedReviewer?.id) {
+      // load chat
+      onSelectReviewer(selectedReviewer.id)
+    }
+  }, [selectedReviewer])
+
+  const handleChangeReviewer = val => {
+    setSelectedReviewer(reviewers.find(r => r.id === val))
+  }
+
+  return (
+    <Wrapper>
+      <ReviewerChatHeader>
+        <ReviewerSelectorWrapper>
+          <label htmlFor="selectReviewer">Chat with reviewer: </label>
+          <StyledSelect
+            id="selectReviewer"
+            onChange={handleChangeReviewer}
+            options={reviewers?.map(r => ({
+              label: r.displayName,
+              value: r.id,
+            }))}
+          />
+        </ReviewerSelectorWrapper>
+      </ReviewerChatHeader>
+      {selectedReviewer ? (
+        <ChatThread
+          hasMore={hasMore}
+          inputPlaceholder={`Write to ${selectedReviewer.displayName}`}
+          isActive={isActive}
+          messages={messages}
+          onFetchMore={onFetchMore}
+          onSendMessage={onSendMessage}
+          participants={participants.map(p =>
+            p.id === selectedReviewer?.id ? { ...p, role: 'reviewer' } : p,
+          )}
+        />
+      ) : (
+        <NoReviewer>
+          <div>
+            <p>
+              <strong>No reviewer selected</strong>
+            </p>
+            <p>Select a reviewer to chat</p>
+          </div>
+        </NoReviewer>
+      )}
+    </Wrapper>
+  )
+}
+
+export default ReviewerChats
diff --git a/packages/server/api/question/question.graphql b/packages/server/api/question/question.graphql
index e97aa110d28e070042f48ccd4e6ad2dd836f3d25..8f310312b0ec575f4fd242d257cb5100d0c16944 100644
--- a/packages/server/api/question/question.graphql
+++ b/packages/server/api/question/question.graphql
@@ -265,7 +265,7 @@ extend type Query {
   getQuestionsHandlingEditors(questionId: ID!): [User!]!
   getAuthorChatParticipants(id: ID!): [User!]!
   getProductionChatParticipants(id: ID!): [User!]!
-  getReviewerChatParticipants(id: ID!): [User!]!
+  getReviewerChatParticipants(questionId: ID!, reviewerId: ID!): [User!]!
 }
 
 extend type Mutation {
diff --git a/packages/server/api/question/question.resolvers.js b/packages/server/api/question/question.resolvers.js
index 56b3d3daca45cdc3cd4b9cccbf03b3e4ee176ab2..1522d14869814f3a565afab4176ff9adbe93c489 100644
--- a/packages/server/api/question/question.resolvers.js
+++ b/packages/server/api/question/question.resolvers.js
@@ -234,8 +234,11 @@ const getProductionChatParticipantsResolver = async (_, { id }) => {
   return getProductionChatParticipants(id)
 }
 
-const getReviewerChatParticipantsResolver = async (_, { id }) => {
-  return getReviewerChatParticipants(id)
+const getReviewerChatParticipantsResolver = async (
+  _,
+  { questionId, reviewerId },
+) => {
+  return getReviewerChatParticipants(questionId, reviewerId)
 }
 
 const updateReviewerPoolResolver = async (
diff --git a/packages/server/controllers/__tests__/question.controllers.test.js b/packages/server/controllers/__tests__/question.controllers.test.js
index 687cfbf1224307bcef64511343457764b9d25f65..7628ed63520a117addae3540238e7ca6ba3da6f8 100644
--- a/packages/server/controllers/__tests__/question.controllers.test.js
+++ b/packages/server/controllers/__tests__/question.controllers.test.js
@@ -958,7 +958,11 @@ describe('Question Controller', () => {
       reviewer2.id,
     ]
 
-    const participants = await getReviewerChatParticipants(question.id)
+    const participants = await getReviewerChatParticipants(
+      question.id,
+      reviewer1.id,
+    )
+
     const receivedParticipantIds = participants.map(p => p.id)
 
     expectedParticipantIds.forEach(participantId =>
diff --git a/packages/server/controllers/question.controllers.js b/packages/server/controllers/question.controllers.js
index 7dbbf600bea8acfa14121f485b0753e5599b3eb9..42090114c92e253d99abf3301678102caf40eb3b 100644
--- a/packages/server/controllers/question.controllers.js
+++ b/packages/server/controllers/question.controllers.js
@@ -289,9 +289,7 @@ const getProductionChatParticipants = async questionId => {
   return participants.filter(p => p.id !== author?.id)
 }
 
-const getReviewerChatParticipants = async questionId => {
-  const questionVersion = await QuestionVersion.findOne({ questionId })
-
+const getReviewerChatParticipants = async (questionId, reviewerId) => {
   const query = User.query()
     .select(
       'users.displayName',
@@ -305,7 +303,7 @@ const getReviewerChatParticipants = async questionId => {
     .where('teams.role', EDITOR_TEAM.role)
     .orWhere(subquery => {
       subquery
-        .whereIn('teams.role', [AUTHOR_TEAM.role, HE_TEAM.role])
+        .whereIn('teams.role', [HE_TEAM.role])
         .whereExists(
           Team.query()
             .select(1)
@@ -314,25 +312,15 @@ const getReviewerChatParticipants = async questionId => {
             .where('questions.id', questionId),
         )
     })
-    .orWhere(reviewerSubquery => {
-      reviewerSubquery
-        .where('teams.role', REVIEWER_TEAM.role)
-        .whereExists(
-          TeamMember.query()
-            .select(1)
-            .from('teams')
-            .whereRaw('team_members.team_id=teams.id')
-            .where('teams.object_id', questionVersion.id)
-            .where('team_members.status', REVIEWER_STATUSES.accepted),
-        )
-    })
+    .orWhere('users.id', reviewerId)
     .orderByRaw("CASE WHEN teams.role = 'handlingEditor' THEN 1 ELSE 0 END")
 
   const participants = await query
 
-  const author = participants.find(p => p.role === 'author')
-
-  return participants.filter(p => p.id !== author?.id)
+  // filter out duplicated reviewer entry
+  return participants.filter(
+    (p, index, self) => index === self.findIndex(t => t.id === p.id),
+  )
 }
 
 /**
diff --git a/packages/server/controllers/team.controllers.js b/packages/server/controllers/team.controllers.js
index e537ec762b56846180eb4224d07b0a328b78495a..7d783c492aa4ab184a5e029a33d219597433befc 100644
--- a/packages/server/controllers/team.controllers.js
+++ b/packages/server/controllers/team.controllers.js
@@ -1,4 +1,6 @@
 const { logger, useTransaction, pubsubManager } = require('@coko/server')
+
+const { ChatThread } = require('@coko/server/src/models')
 const config = require('config')
 const { uniq } = require('lodash')
 
@@ -512,6 +514,14 @@ const acceptOrRejectInvitation = async (
         },
         { trx },
       )
+
+      await ChatThread.insert(
+        {
+          relatedObjectId: questionVersion.questionId,
+          chatType: `reviewerChat-${userId}`,
+        },
+        { trx },
+      )
     }
 
     const notifier = new CokoNotifier()
diff --git a/packages/server/models/complexItemSet/complexItemSet.model.js b/packages/server/models/complexItemSet/complexItemSet.model.js
index 98043c09d896e6868244555f60d193fd29411c91..02fbf38766783e3f04035ffc90ccd98bc406a04a 100644
--- a/packages/server/models/complexItemSet/complexItemSet.model.js
+++ b/packages/server/models/complexItemSet/complexItemSet.model.js
@@ -114,6 +114,7 @@ class ComplexItemSet extends BaseModel {
 
   static async filterSetsForUser(userId, searchQuery, options) {
     // userId will be null if user is not logged in or only public sets were requested
+    // Does not apply, all pages require the user to log in
     if (!userId) {
       return ComplexItemSet.query().select('*').where('isPublished', true)
     }
@@ -154,10 +155,14 @@ class ComplexItemSet extends BaseModel {
       query.select(selectFields)
     } else {
       query
-        .select(selectFields)
-        .where(builder =>
-          builder.where('isPublished', true).orWhereIn('id', authoredSets),
+        .leftJoin(
+          'question_versions',
+          'question_versions.complexItemSetId',
+          'complexItemSets.id',
         )
+        .select([...selectFields, 'question_versions.published'])
+        .whereIn('complexItemSets.id', authoredSets)
+        .orWhere('question_versions.published', true)
     }
 
     if (searchQuery) {