All files / client/src/views/admin/components AdminMessageEditor.tsx

94.11% Statements 16/17
100% Branches 11/11
100% Functions 5/5
94.11% Lines 16/17

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                                  356x           69x   69x   69x     69x       69x 69x 69x   69x                           6x                     6x               3x               1x 1x 1x                   1x                          
import { ReactElement, useState } from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import { Button, ButtonStyle } from "client/components/Button";
import { ButtonGroup } from "client/components/ButtonGroup";
import { TextArea } from "client/components/TextArea";
import { ADMIN_MESSAGE_LENGTH_MAX } from "shared/constants/validation";
 
interface Props {
  adminMessageFi: string;
  adminMessageEn: string;
  submitting: boolean;
  onSave: (adminMessageFi: string, adminMessageEn: string) => void;
}
 
// The inputs seed from the stored message; the parent keys this component on the stored value so
// it remounts (re-seeding) when the message changes, rather than syncing state in an effect
export const AdminMessageEditor = ({
  adminMessageFi,
  adminMessageEn,
  submitting,
  onSave,
}: Props): ReactElement => {
  const { t } = useTranslation();
  const [adminMessageFiInput, setAdminMessageFiInput] =
    useState<string>(adminMessageFi);
  const [adminMessageEnInput, setAdminMessageEnInput] =
    useState<string>(adminMessageEn);
 
  const unchanged =
    adminMessageFiInput === adminMessageFi &&
    adminMessageEnInput === adminMessageEn;
  // Save accepts a message only when both languages are filled, or both empty (which removes it) —
  // never a partial. Clear removes the message directly, whatever is currently typed
  const fiFilled = adminMessageFiInput.trim() !== "";
  const enFilled = adminMessageEnInput.trim() !== "";
  const partial = fiFilled !== enFilled;
  const nothingToClear =
    !adminMessageFi &&
    !adminMessageEn &&
    !adminMessageFiInput &&
    !adminMessageEnInput;
 
  return (
    <AdminMessageForm>
      <label>
        {t("signupQuestion.inFinnish")}
        <TextArea
          rows={3}
          maxLength={ADMIN_MESSAGE_LENGTH_MAX}
          placeholder={t("admin.adminMessagePlaceholder")}
          value={adminMessageFiInput}
          onChange={(event) => setAdminMessageFiInput(event.target.value)}
          disabled={submitting}
        />
      </label>
      <label>
        {t("signupQuestion.inEnglish")}
        <TextArea
          rows={3}
          maxLength={ADMIN_MESSAGE_LENGTH_MAX}
          placeholder={t("admin.adminMessagePlaceholder")}
          value={adminMessageEnInput}
          onChange={(event) => setAdminMessageEnInput(event.target.value)}
          disabled={submitting}
        />
      </label>
      <ButtonGroup>
        <Button
          disabled={submitting || unchanged || partial}
          buttonStyle={ButtonStyle.PRIMARY}
          onClick={() => onSave(adminMessageFiInput, adminMessageEnInput)}
        >
          {t("button.saveAdminMessage")}
        </Button>
        <Button
          disabled={submitting || nothingToClear}
          buttonStyle={ButtonStyle.SECONDARY}
          onClick={() => {
            setAdminMessageFiInput("");
            setAdminMessageEnInput("");
            onSave("", "");
          }}
        >
          {t("button.clearAdminMessage")}
        </Button>
      </ButtonGroup>
    </AdminMessageForm>
  );
};
 
const AdminMessageForm = styled.div`
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 24px;
 
  label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-width: 500px;
  }
`;