app/javascript/react/components/Popups/ExportDataComponent.tsx
import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { PopupProps } from "reactjs-popup/dist/types";
import downloadWhite from "../../assets/icons/downloadWhite.svg";
import { white } from "../../assets/styles/colors";
import { exportSession } from "../../store/exportSessionSlice";
import { useAppDispatch } from "../../store/hooks";
import { useAutoDismissAlert } from "../../utils/useAutoDismissAlert";
import { BlueButton, FormWrapper } from "../Modals/Modals.style";
import { ModalInput, RedErrorMessage } from "../Modals/atoms/ModalInput";
import { AlertPopup } from "./AlertComponent";
import * as S from "./Popups.style";
interface ExportDataComponentProps {
button: JSX.Element | ((isOpen: boolean) => JSX.Element) | undefined;
sessionsIds: number[];
isIconOnly: boolean;
onSubmit: (data: ExportModalData) => void;
fixedSessionTypeSelected?: boolean;
isSessionList: boolean;
open?: boolean;
}
export interface ExportModalData {
email: string;
}
const initialExportModalData: ExportModalData = {
email: "",
};
type CustomPopupProps = {
children:
| React.ReactNode
| ((close: () => void, isOpen: boolean) => React.ReactNode);
};
const ExportDataPopup: React.FC<
CustomPopupProps & Omit<PopupProps, "children">
> = (props) => {
return <S.ExportDataSmallPopup {...(props as PopupProps)} />;
};
const ExportDataComponent = ({
button,
fixedSessionTypeSelected,
sessionsIds,
onSubmit,
isIconOnly,
isSessionList,
open,
}: ExportDataComponentProps) => {
const exportButtonRef = useRef<HTMLDivElement>(null);
const focusInputRef = useRef<HTMLInputElement | null>(null);
const [buttonPosition, setButtonPosition] = useState({ top: 0, left: 0 });
const [formState, setFormState] = useState<ExportModalData>(
initialExportModalData
);
const [showConfirmation, setShowConfirmation] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const NO_SESSIONS = sessionsIds.length === 0;
const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleInputChange = (
event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
): void => {
const { name, value } = event.target;
setFormState((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
const handleSubmit = (
event: React.FormEvent,
close: { (): void; (): void }
): void => {
event.preventDefault();
if (!validateEmail(formState.email)) {
setErrorMessage(t("exportDataModal.invalidEmailMessage"));
return;
}
dispatch(exportSession({ sessionsIds, email: formState.email }));
onSubmit(formState);
setFormState(initialExportModalData);
setShowConfirmation(true);
close();
};
const rect =
exportButtonRef.current && exportButtonRef.current.getBoundingClientRect();
const updateButtonPosition = () => {
if (rect) {
setButtonPosition({
top: rect.top + window.scrollY,
left: rect.left + window.scrollX,
});
}
};
useAutoDismissAlert(showConfirmation, setShowConfirmation);
useEffect(() => {
updateButtonPosition();
window.addEventListener("resize", updateButtonPosition);
return () => {
window.removeEventListener("resize", updateButtonPosition);
};
}, [rect?.top]);
const calculatePopupLeftPosition = () => {
if (isSessionList) {
return `${buttonPosition.left - 185}px`;
} else if (isIconOnly) {
if (fixedSessionTypeSelected) {
return `${buttonPosition.left - 60}px}`;
} else {
return `${buttonPosition.left - 30}px}`;
}
} else {
return `${buttonPosition.left - 2}px}`;
}
};
const dynamicArrowStyle = fixedSessionTypeSelected
? {}
: {
left: `${isIconOnly ? "32%" : "50%"}`,
borderColor: `transparent transparent ${white} transparent`,
borderWidth: "0 10px 10px 10px",
borderStyle: "solid",
};
return (
<S.WrapperButton ref={exportButtonRef}>
<ExportDataPopup
open={open}
trigger={button}
position={isSessionList ? "left center" : "top center"}
nested
closeOnDocumentClick
offsetX={fixedSessionTypeSelected ? 0 : 40}
arrowStyle={dynamicArrowStyle}
>
{(close) => (
<form onSubmit={(formData) => handleSubmit(formData, close)}>
<FormWrapper>
<ModalInput
focusInputRef={focusInputRef}
value={formState.email}
onChange={handleInputChange}
name="email"
type="email"
/>
<BlueButton
type="submit"
aria-label={t("exportDataModal.exportButton")}
>
{t("exportDataModal.exportButton")}
<img src={downloadWhite} style={{ width: "1.5rem" }} />
</BlueButton>
</FormWrapper>
{errorMessage && <RedErrorMessage>{errorMessage}</RedErrorMessage>}
</form>
)}
</ExportDataPopup>
{showConfirmation && (
<AlertPopup
open={showConfirmation}
message={t("exportDataModal.confirmationMessage")}
top={
isSessionList ? buttonPosition.top - 35 : buttonPosition.top - 95
}
left={calculatePopupLeftPosition()}
/>
)}
</S.WrapperButton>
);
};
export { ExportDataComponent };