All files / pages ChatPage.jsx

100% Statements 111/111
100% Branches 13/13
100% Functions 7/7
100% Lines 111/111

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 1591x 1x 1x 1x 1x 1x 1x   1x 56x 56x 56x   56x 56x   56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x     56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x     56x   56x 56x 56x   56x 106x 106x 56x   56x 7x 7x   56x 1x 1x 1x   56x 56x   56x 56x 56x 56x 56x 56x 56x 56x 56x   56x 56x 56x 56x   56x 56x 56x       56x 56x 56x       56x 56x 56x 56x             56x 56x 56x 56x 56x 56x 56x 56x 56x             56x 56x 56x 56x 56x 56x 56x     56x 56x 56x 56x 56x     56x 56x   56x 56x 56x 56x 56x     56x 56x 56x 56x 56x               56x  
import React, { useState } from "react";
import { Container, Card, Form, Button } from "react-bootstrap";
import { useParams } from "react-router";
import BasicLayout from "main/layouts/BasicLayout/BasicLayout";
import ChatMessageDisplay from "main/components/Chat/ChatMessageDisplay";
import ChatMessageCreate from "main/components/Chat/ChatMessageCreate";
import { useBackend } from "main/utils/useBackend";
 
export default function ChatPage() {
  const { commonsId } = useParams();
  const [currentPage, setCurrentPage] = useState(0);
  const [pageSize, setPageSize] = useState(10);
 
  // Stryker disable all
  const refreshRate = 2000;
 
  const { data: messagesPage, isLoading: messagesLoading } = useBackend(
    [`/api/chat/get`, commonsId, currentPage, pageSize],
    {
      method: "GET",
      url: `/api/chat/get`,
      params: {
        commonsId: commonsId,
        page: currentPage,
        size: pageSize,
      },
    },
    { content: [], totalPages: 0, totalElements: 0 },
    { refetchInterval: refreshRate },
  );
 
  const { data: userCommonsList } = useBackend(
    [`/api/usercommons/commons/all`],
    {
      method: "GET",
      url: "/api/usercommons/commons/all",
      params: {
        commonsId: commonsId,
      },
    },
    [],
    { refetchInterval: refreshRate },
  );
 
  // Stryker restore all
 
  const sortedMessages = messagesPage.content.sort((a, b) => b.id - a.id);
  const totalPages = messagesPage.totalPages || 0;
  const totalElements = messagesPage.totalElements || 0;
 
  const userIdToUsername = userCommonsList.reduce((acc, user) => {
    acc[user.userId] = user.username;
    return acc;
  }, {});
 
  const handlePageChange = (page) => {
    setCurrentPage(page);
  };
 
  const handlePageSizeChange = (e) => {
    setPageSize(parseInt(e.target.value));
    setCurrentPage(0); // reset to first page when page size changes
  };
 
  const canGoPrevious = currentPage > 0;
  const canGoNext = currentPage < totalPages - 1;
 
  return (
    <BasicLayout>
      <Container data-testid="ChatPage">
        <div className="mb-3">
          <Form.Label>Messages per page:</Form.Label>
          <Form.Select
            value={pageSize}
            onChange={handlePageSizeChange}
            data-testid="page-size-selector"
          >
            <option value={10}>10</option>
            <option value={20}>20</option>
            <option value={50}>50</option>
            <option value={100}>100</option>
          </Form.Select>
          <small className="text-muted" data-testid="page-info">
            Page {currentPage + 1} of {totalPages === 0 ? 1 : totalPages}{" "}
            (Total: {totalElements} messages)
          </small>
        </div>
 
        <Card className="mb-3">
          <Card.Body>
            <ChatMessageCreate commonsId={commonsId} />
          </Card.Body>
        </Card>
 
        {!messagesLoading && sortedMessages.length === 0 && (
          <Card className="text-center py-5">
            <Card.Body>
              <p className="text-muted" data-testid="no-messages">
                No messages found.
              </p>
            </Card.Body>
          </Card>
        )}
 
        {!messagesLoading && sortedMessages.length > 0 && (
          <div data-testid="message-list">
            {sortedMessages.map((message) => (
              <div key={message.id} className="mb-2">
                <ChatMessageDisplay
                  message={{
                    ...message,
                    username: userIdToUsername[message.userId],
                  }}
                />
              </div>
            ))}
          </div>
        )}
 
        {totalPages > 1 && (
          <div className="d-flex justify-content-center align-items-center gap-3 mt-4 mb-4">
            <Button
              onClick={() => handlePageChange(0)}
              disabled={!canGoPrevious}
              data-testid="pagination-first"
            >
              First
            </Button>
            <Button
              onClick={() => handlePageChange(currentPage - 1)}
              disabled={!canGoPrevious}
              data-testid="pagination-prev"
            >
              Previous
            </Button>
            <span data-testid="pagination-info">
              Page {currentPage + 1} of {totalPages}
            </span>
            <Button
              onClick={() => handlePageChange(currentPage + 1)}
              disabled={!canGoNext}
              data-testid="pagination-next"
            >
              Next
            </Button>
            <Button
              onClick={() => handlePageChange(totalPages - 1)}
              disabled={!canGoNext}
              data-testid="pagination-last"
            >
              Last
            </Button>
          </div>
        )}
      </Container>
    </BasicLayout>
  );
}