diff --git a/CHANGELOG.md b/CHANGELOG.md index 914f338f..7ffbd820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,3 @@ - # Changelog All notable changes to this project will be documented in this file. diff --git a/e2e/feed-sources.spec.js b/e2e/feed-sources.spec.js index fe46480c..2380d695 100644 --- a/e2e/feed-sources.spec.js +++ b/e2e/feed-sources.spec.js @@ -219,7 +219,7 @@ test.describe("fest", () => { test("It loads create datakilde page", async ({ page }) => { page.getByText("Opret ny datakilde").click(); - await expect(page.locator("#save_feed-source")).toBeVisible(); + await expect(page.locator("#save")).toBeVisible(); }); test("It display error toast on save error", async ({ page }) => { @@ -238,7 +238,7 @@ test.describe("fest", () => { await expect( page.locator(".Toastify").locator(".Toastify__toast--error") ).not.toBeVisible(); - await page.locator("#save_feed-source").click(); + await page.locator("#save").click(); await expect( page.locator(".Toastify").locator(".Toastify__toast--error") ).toBeVisible(); @@ -253,9 +253,9 @@ test.describe("fest", () => { }); test("Cancel create datakilde", async ({ page }) => { page.getByText("Opret ny datakilde").click(); - await expect(page.locator("#cancel_feed-source")).toBeVisible(); - await page.locator("#cancel_feed-source").click(); - await expect(page.locator("#cancel_feed-source")).not.toBeVisible(); + await expect(page.locator("#cancel")).toBeVisible(); + await page.locator("#cancel").click(); + await expect(page.locator("#cancel")).not.toBeVisible(); }); }); diff --git a/e2e/playlist.spec.js b/e2e/playlist.spec.js index 465a1e94..0e118c20 100644 --- a/e2e/playlist.spec.js +++ b/e2e/playlist.spec.js @@ -59,7 +59,7 @@ test.describe("Playlist create tests", () => { await expect( page.locator(".Toastify").locator(".Toastify__toast--success") ).not.toBeVisible(); - await page.locator("#save_playlist").click(); + await page.locator("#save_slide_and_close").click(); await expect( page .locator(".Toastify") diff --git a/infrastructure/itkdev/etc/confd/templates/config.tmpl b/infrastructure/itkdev/etc/confd/templates/config.tmpl index 90ce5b67..e88daea4 100644 --- a/infrastructure/itkdev/etc/confd/templates/config.tmpl +++ b/infrastructure/itkdev/etc/confd/templates/config.tmpl @@ -1,6 +1,7 @@ { "api": "{{ getenv "API_PATH" "/" }}", "touchButtonRegions": "{{ getenv "APP_TOUCH_BUTTON_REGIONS" "false"}}", + "previewClient": "{{ getenv "APP_PREVIEW_CLIENT" "null"}}", "rejseplanenApiKey": "{{ getenv "APP_REJSEPLANEN_API_KEY" "null"}}", "loginMethods": [ { diff --git a/infrastructure/os2display/etc/confd/templates/config.tmpl b/infrastructure/os2display/etc/confd/templates/config.tmpl index 90ce5b67..e88daea4 100644 --- a/infrastructure/os2display/etc/confd/templates/config.tmpl +++ b/infrastructure/os2display/etc/confd/templates/config.tmpl @@ -1,6 +1,7 @@ { "api": "{{ getenv "API_PATH" "/" }}", "touchButtonRegions": "{{ getenv "APP_TOUCH_BUTTON_REGIONS" "false"}}", + "previewClient": "{{ getenv "APP_PREVIEW_CLIENT" "null"}}", "rejseplanenApiKey": "{{ getenv "APP_REJSEPLANEN_API_KEY" "null"}}", "loginMethods": [ { diff --git a/public/example_config.json b/public/example_config.json index 3ecbf9a6..66a93888 100644 --- a/public/example_config.json +++ b/public/example_config.json @@ -1,6 +1,7 @@ { "api": "/", "touchButtonRegions": false, + "previewClient": null, "rejseplanenApiKey": null, "loginMethods": [ { diff --git a/src/app.jsx b/src/app.jsx index 6f1d9c1a..1826fc41 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -213,7 +213,7 @@ function App() { {accessConfig && ( -
+
+
- +
); } diff --git a/src/components/activation-code/activation-code-form.jsx b/src/components/activation-code/activation-code-form.jsx index 6d4a6d82..6d4b4c63 100644 --- a/src/components/activation-code/activation-code-form.jsx +++ b/src/components/activation-code/activation-code-form.jsx @@ -1,14 +1,14 @@ import { React } from "react"; import { useNavigate } from "react-router-dom"; -import { Button } from "react-bootstrap"; +import { Button, Col, Row } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import PropTypes from "prop-types"; import Form from "react-bootstrap/Form"; import LoadingComponent from "../util/loading-component/loading-component"; import ContentBody from "../util/content-body/content-body"; -import ContentFooter from "../util/content-footer/content-footer"; import FormInput from "../util/forms/form-input"; import RadioButtons from "../util/forms/radio-buttons"; +import StickyFooter from "../util/sticky-footer"; /** * The user form component. @@ -48,44 +48,48 @@ function ActivationCodeForm({ <>
-

{headerText}

- -
- -
-
- -
- {t("role-external-user-helptext")} -
-
- {t("role-external-user-admin-helptext")} -
-
-
- + +

{headerText}

+ + +
+ +
+
+ +
+ {t("role-external-user-helptext")} +
+
+ {t("role-external-user-admin-helptext")} +
+
+
+ +
+ + @@ -94,12 +98,10 @@ function ActivationCodeForm({ type="button" onClick={handleSubmit} id="save_user" - size="lg" - className="col" > {t("save-button")} -
+
); diff --git a/src/components/activation-code/activation-code-list.jsx b/src/components/activation-code/activation-code-list.jsx index a5910ebc..cbf72dd9 100644 --- a/src/components/activation-code/activation-code-list.jsx +++ b/src/components/activation-code/activation-code-list.jsx @@ -185,7 +185,7 @@ function ActivationCodeList() { }, [listData]); return ( - <> +
- +
); } diff --git a/src/components/feed-sources/feed-source-form.jsx b/src/components/feed-sources/feed-source-form.jsx index 2cce65ae..4ad26434 100644 --- a/src/components/feed-sources/feed-source-form.jsx +++ b/src/components/feed-sources/feed-source-form.jsx @@ -1,5 +1,5 @@ import { React } from "react"; -import { Button } from "react-bootstrap"; +import { Button, Row, Col } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; @@ -8,11 +8,11 @@ import LoadingComponent from "../util/loading-component/loading-component"; import FormInputArea from "../util/forms/form-input-area"; import FormSelect from "../util/forms/select"; import ContentBody from "../util/content-body/content-body"; -import ContentFooter from "../util/content-footer/content-footer"; import FormInput from "../util/forms/form-input"; import CalendarApiFeedType from "./templates/calendar-api-feed-type"; import NotifiedFeedType from "./templates/notified-feed-type"; import EventDatabaseApiFeedType from "./templates/event-database-feed-type"; +import StickyFooter from "../util/sticky-footer"; /** * The feed-source form component. @@ -21,6 +21,7 @@ import EventDatabaseApiFeedType from "./templates/event-database-feed-type"; * @param {object} props.feedSource The feed-source object to modify in the form. * @param {Function} props.handleInput Handles form input. * @param {Function} props.handleSubmit Handles form submit. + * @param {Function} props.handleSaveNoClose Handles form submit with close. * @param {string} props.headerText Headline text. * @param {boolean} [props.isLoading] Indicator of whether the form is loading. * Default is `false` @@ -35,6 +36,7 @@ import EventDatabaseApiFeedType from "./templates/event-database-feed-type"; function FeedSourceForm({ handleInput, handleSubmit, + handleSaveNoClose, headerText, isLoading = false, loadingMessage = "", @@ -54,78 +56,90 @@ function FeedSourceForm({ isLoading={isLoading} loadingMessage={loadingMessage} /> -

{headerText}

- - - - + +

{headerText}

+ + + + + - {feedSource?.feedType === "App\\Feed\\CalendarApiFeedType" && ( - - )} - {feedSource?.feedType === "App\\Feed\\EventDatabaseApiFeedType" && ( - - )} - {feedSource?.feedType === "App\\Feed\\NotifiedFeedType" && ( - - )} - - + {feedSource?.feedType === "App\\Feed\\CalendarApiFeedType" && ( + + )} + {feedSource?.feedType === + "App\\Feed\\EventDatabaseApiFeedType" && ( + + )} + {feedSource?.feedType === "App\\Feed\\NotifiedFeedType" && ( + + )} +
+ + + + - + ); @@ -140,6 +154,7 @@ FeedSourceForm.propTypes = { }), handleInput: PropTypes.func.isRequired, handleSubmit: PropTypes.func.isRequired, + handleSaveNoClose: PropTypes.func.isRequired, handleSecretInput: PropTypes.func.isRequired, onFeedTypeChange: PropTypes.func.isRequired, headerText: PropTypes.string.isRequired, diff --git a/src/components/feed-sources/feed-source-manager.jsx b/src/components/feed-sources/feed-source-manager.jsx index 04fb2d9b..9be2ee9d 100644 --- a/src/components/feed-sources/feed-source-manager.jsx +++ b/src/components/feed-sources/feed-source-manager.jsx @@ -11,6 +11,7 @@ import { displayError, displaySuccess, } from "../util/list/toast-component/display-toast"; +import idFromUrl from "../util/helpers/id-from-url"; /** * The theme manager component. @@ -47,10 +48,11 @@ function FeedSourceManager({ const [submitting, setSubmitting] = useState(false); const [formStateObject, setFormStateObject] = useState({}); + const [saveWithoutClose, setSaveWithoutClose] = useState(false); const [ postV2FeedSources, - { error: saveErrorPost, isSuccess: isSaveSuccessPost }, + { error: saveErrorPost, isSuccess: isSaveSuccessPost, data }, ] = usePostV2FeedSourcesMutation(); const [ @@ -160,7 +162,16 @@ function FeedSourceManager({ if (isSaveSuccessPost || isSaveSuccessPut) { setSubmitting(false); displaySuccess(t("success-messages.saved-feed-source")); - navigate("/feed-sources/list"); + + if (saveWithoutClose) { + setSaveWithoutClose(false); + + if (isSaveSuccessPost) { + navigate(`/feed-sources/edit/${idFromUrl(data["@id"])}`); + } + } else { + navigate(`/feed-sources/list`); + } } }, [isSaveSuccessPut, isSaveSuccessPost]); @@ -170,6 +181,11 @@ function FeedSourceManager({ saveFeedSource(); }; + const handleSaveNoClose = () => { + setSaveWithoutClose(true); + handleSubmit(); + }; + /** If the theme is saved with error, display the error message */ useEffect(() => { if (saveErrorPut || saveErrorPost) { @@ -187,6 +203,7 @@ function FeedSourceManager({ headerText={`${headerText}: ${formStateObject?.title}`} handleInput={handleInput} handleSubmit={handleSubmit} + handleSaveNoClose={handleSaveNoClose} isLoading={isLoading || submitting} loadingMessage={loadingMessage} onFeedTypeChange={onFeedTypeChange} diff --git a/src/components/feed-sources/feed-sources-list.jsx b/src/components/feed-sources/feed-sources-list.jsx index aa852c00..514c4d59 100644 --- a/src/components/feed-sources/feed-sources-list.jsx +++ b/src/components/feed-sources/feed-sources-list.jsx @@ -129,7 +129,7 @@ function FeedSourcesList() { }, [feedSourcesGetError]); return ( - <> +
)} - +
); } diff --git a/src/components/groups/group-create.jsx b/src/components/groups/group-create.jsx index 3c7b11b1..c3ef0372 100644 --- a/src/components/groups/group-create.jsx +++ b/src/components/groups/group-create.jsx @@ -71,14 +71,16 @@ function GroupCreate() { }; return ( - +
+ +
); } diff --git a/src/components/groups/group-edit.jsx b/src/components/groups/group-edit.jsx index baaec894..7009f08f 100644 --- a/src/components/groups/group-edit.jsx +++ b/src/components/groups/group-edit.jsx @@ -1,7 +1,6 @@ import { React, useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; - import { useGetV2ScreenGroupsByIdQuery, usePutV2ScreenGroupsByIdMutation, @@ -103,7 +102,7 @@ function GroupEdit() { }; return ( - <> +
{formStateObject && ( )} - +
); } diff --git a/src/components/groups/groups-list.jsx b/src/components/groups/groups-list.jsx index 07f99a79..1031a790 100644 --- a/src/components/groups/groups-list.jsx +++ b/src/components/groups/groups-list.jsx @@ -125,7 +125,7 @@ function GroupsList() { }, [groupsGetError]); return ( - <> +
- +
); } diff --git a/src/components/media/media-list.jsx b/src/components/media/media-list.jsx index b0bdca65..9009158b 100644 --- a/src/components/media/media-list.jsx +++ b/src/components/media/media-list.jsx @@ -174,7 +174,7 @@ function MediaList({ fromModal = false, multiple = true }) { }; return ( - <> +

{t("header")}

@@ -233,7 +233,7 @@ function MediaList({ fromModal = false, multiple = true }) { currentPage={page} onPageChange={updateUrlAndChangePage} /> - +
); } diff --git a/src/components/playlist/playlist-campaign-form.jsx b/src/components/playlist/playlist-campaign-form.jsx index 69f9fd65..e194f15e 100644 --- a/src/components/playlist/playlist-campaign-form.jsx +++ b/src/components/playlist/playlist-campaign-form.jsx @@ -1,14 +1,21 @@ -import { React, useState } from "react"; -import { Button, Col, Form, Row } from "react-bootstrap"; +import { React, useContext, useState } from "react"; +import { Alert, Button, Col, Form, Row } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faExpand } from "@fortawesome/free-solid-svg-icons"; import ContentBody from "../util/content-body/content-body"; -import ContentFooter from "../util/content-footer/content-footer"; import FormInput from "../util/forms/form-input"; import FormInputArea from "../util/forms/form-input-area"; import SelectSlidesTable from "../util/multi-and-table/select-slides-table"; import LoadingComponent from "../util/loading-component/loading-component"; +import Preview from "../preview/preview"; +import idFromUrl from "../util/helpers/id-from-url"; +import StickyFooter from "../util/sticky-footer"; +import localStorageKeys from "../util/local-storage-keys"; +import Select from "../util/forms/select"; +import userContext from "../../context/user-context"; /** * The shared form component. @@ -24,11 +31,13 @@ import LoadingComponent from "../util/loading-component/loading-component"; * @param {boolean} props.isCampaign If it is a campaign form. * @param {string} props.location Either playlist or campaign. * @param {Array} props.children The children being passed from parent + * @param {Function} props.handleSaveNoClose Handles form submit with close. * @returns {object} The form shared by campaigns and playlists. */ function PlaylistCampaignForm({ handleInput, handleSubmit, + handleSaveNoClose, headerText, location, children, @@ -38,13 +47,38 @@ function PlaylistCampaignForm({ isCampaign = false, playlist = null, }) { - const { t } = useTranslation("common"); + const { t } = useTranslation("common", { + keyPrefix: "playlist-campaign-form", + }); + const { config } = useContext(userContext); + + const previewOrientationOptions = [ + { + value: "horizontal", + title: t("preview-orientation-landscape"), + key: "horizontal", + }, + { + value: "vertical", + title: t("preview-orientation-portrait"), + key: "vertical", + }, + ]; + const [previewOrientation, setPreviewOrientation] = useState( + previewOrientationOptions[0].value + ); const navigate = useNavigate(); const [publishedFromError, setPublishedFromError] = useState(false); const [publishedToError, setPublishedToError] = useState(false); + const [displayPreview, setDisplayPreview] = useState(null); + const [previewOverlayVisible, setPreviewOverlayVisible] = useState(false); - /** Check if published is set */ - const checkInputsHandleSubmit = () => { + /** + * Check if published is set + * + * @param {boolean | null} noRedirect - Save without redirect. + */ + const checkInputsHandleSubmit = (noRedirect) => { setPublishedToError(false); setPublishedFromError(false); let submit = true; @@ -58,97 +92,214 @@ function PlaylistCampaignForm({ } if (submit) { - handleSubmit(); + if (noRedirect === true) { + handleSaveNoClose(); + } else { + handleSubmit(); + } } }; + /** Toggle display preview. */ + const toggleDisplayPreview = () => { + const newValue = !displayPreview; + localStorage.setItem(localStorageKeys.PREVIEW, newValue); + setDisplayPreview(newValue); + }; + return ( <>
-

{headerText}

- -

{t("playlist-campaign-form.title-about")}

- - -
- -

{t("playlist-campaign-form.title-slides")}

- -
- {/* Playlist or campaign form */} - {children} - -

{t("playlist-campaign-form.publish-title")}

- - + +

{headerText}

+ + +

{t("title-about")}

- - - +
+ +

{t("title-slides")}

+ +
+ {/* Playlist or campaign form */} + {children} + +

{t("publish-title")}

+ + + + + + + + + + {t("publish-helptext")} + +
+ + + {displayPreview && ( + +

{t("playlist-preview")}

+
+ + {t("playlist-preview-small-about")} + +
+ + setPreviewOrientation(target.value) + } + required + name="preview-orientation" + options={previewOrientationOptions} + className="m-0" + value={previewOrientation} + /> + + +
+ +
+ {previewOverlayVisible && ( +
+ setPreviewOverlayVisible(!previewOverlayVisible) + } + role="presentation" + className="preview-overlay d-flex justify-content-center align-items-center flex-column" + > + + + {t("screen-preview-about")} + +
)} - -
- -

{t("enable-color-scheme-change-headline")}

- -
- + + )} + + + - + + {config?.previewClient && ( + + )} +
- + ); } diff --git a/src/components/screen/screen-list.jsx b/src/components/screen/screen-list.jsx index 3086f411..ef1a4096 100644 --- a/src/components/screen/screen-list.jsx +++ b/src/components/screen/screen-list.jsx @@ -126,7 +126,7 @@ function ScreenList() { }, [screensGetError]); return ( - <> +
- +
); } diff --git a/src/components/slide/preview/remote-component-wrapper.jsx b/src/components/slide/preview/remote-component-wrapper.jsx index f5540633..324f57aa 100644 --- a/src/components/slide/preview/remote-component-wrapper.jsx +++ b/src/components/slide/preview/remote-component-wrapper.jsx @@ -18,6 +18,7 @@ import "./remote-component-wrapper.scss"; * @param {boolean} props.showPreview Whether to display the preview. * @param {boolean} props.closeButton Display close button on preview * @param {Function} props.closeCallback Close button callback on preview + * @param {boolean} props.adjustFontSize Adjust the font size compared to size in full hd. * @returns {object} The component. */ function RemoteComponentWrapper({ @@ -29,11 +30,13 @@ function RemoteComponentWrapper({ closeCallback = () => {}, mediaData = null, themeData = {}, + adjustFontSize = true, }) { const { t } = useTranslation("common"); const [remoteComponentSlide, setRemoteComponentSlide] = useState(null); const [loading, err, Component] = useRemoteComponent(url); const [runId, setRunId] = useState(""); + const [fontSizeEm, setFontSizeEm] = useState(1); /** Create remoteComponentSlide from slide and mediaData */ useEffect(() => { @@ -81,10 +84,38 @@ function RemoteComponentWrapper({ } }, [showPreview]); + useEffect(() => { + // eslint-disable-next-line no-undef + const observer = new ResizeObserver((entries) => { + if (adjustFontSize) { + if (entries.length > 0) { + const first = entries[0]; + setFontSizeEm( + first.contentRect.width / (orientation === "vertical" ? 1080 : 1920) + ); + } + } + }); + + const targets = document.querySelector(".remote-component-wrapper"); + + observer.observe(targets); + + return () => { + observer.unobserve(targets); + }; + }, []); + + const remoteComponentStyle = {}; + + if (adjustFontSize) { + remoteComponentStyle["--font-size-base"] = `${fontSizeEm}rem`; + } + return ( <> -
- {closeButton && ( + {closeButton && ( +
- )} -
+
+ )}
{loading &&
} @@ -132,6 +164,7 @@ RemoteComponentWrapper.propTypes = { showPreview: PropTypes.bool.isRequired, closeButton: PropTypes.bool, orientation: PropTypes.string, + adjustFontSize: PropTypes.bool, }; export default RemoteComponentWrapper; diff --git a/src/components/slide/slide-form.jsx b/src/components/slide/slide-form.jsx index 1755b490..24c5791f 100644 --- a/src/components/slide/slide-form.jsx +++ b/src/components/slide/slide-form.jsx @@ -1,13 +1,13 @@ import { React, useEffect, useState, Fragment, useContext } from "react"; -import { Button, Row, Col } from "react-bootstrap"; +import { Button, Row, Col, Alert } from "react-bootstrap"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; import Form from "react-bootstrap/Form"; -import FormCheckbox from "../util/forms/form-checkbox"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faExpand } from "@fortawesome/free-solid-svg-icons"; import ContentBody from "../util/content-body/content-body"; import MultiSelectComponent from "../util/forms/multiselect-dropdown/multi-dropdown"; -import ContentFooter from "../util/content-footer/content-footer"; import { useGetV2TemplatesQuery, useGetV2ThemesQuery, @@ -18,12 +18,14 @@ import ContentForm from "./content/content-form"; import LoadingComponent from "../util/loading-component/loading-component"; import RemoteComponentWrapper from "./preview/remote-component-wrapper"; import FeedSelector from "./content/feed-selector"; -import RadioButtons from "../util/forms/radio-buttons"; import SelectPlaylistsTable from "../util/multi-and-table/select-playlists-table"; import localStorageKeys from "../util/local-storage-keys"; import { displayError } from "../util/list/toast-component/display-toast"; import userContext from "../../context/user-context"; import "./slide-form.scss"; +import Preview from "../preview/preview"; +import StickyFooter from "../util/sticky-footer"; +import Select from "../util/forms/select"; /** * The slide form component. @@ -32,6 +34,7 @@ import "./slide-form.scss"; * @param {object} props.slide The slide object to modify in the form. * @param {Function} props.handleInput Handles form input. * @param {Function} props.handleSubmit Handles form submit. + * @param {Function} props.handleSaveNoClose Handles form submit without redirecting. * @param {string} props.headerText Headline text. * @param {Function} props.handleContent Function for handling changes to content field * @param {Function} props.handleMedia Handle media field @@ -49,6 +52,7 @@ function SlideForm({ handleContent, handleMedia, handleSubmit, + handleSaveNoClose, selectTemplate, headerText, selectTheme, @@ -59,12 +63,26 @@ function SlideForm({ slide = null, mediaData = null, }) { - const { t } = useTranslation("common"); + const { t } = useTranslation("common", { keyPrefix: "slide-form" }); const navigate = useNavigate(); const { config } = useContext(userContext); - const [showPreview, setShowPreview] = useState(false); - const [previewLayout, setPreviewLayout] = useState("horizontal"); + const previewOrientationOptions = [ + { + value: "horizontal", + title: t("preview-orientation-landscape"), + key: "horizontal", + }, + { + value: "vertical", + title: t("preview-orientation-portrait"), + key: "vertical", + }, + ]; + const [previewOrientation, setPreviewOrientation] = useState( + previewOrientationOptions[0].value + ); + const [previewOverlayVisible, setPreviewOverlayVisible] = useState(false); const [templateOptions, setTemplateOptions] = useState([]); const [contentFormElements, setContentFormElements] = useState([]); @@ -72,6 +90,7 @@ function SlideForm({ const [searchTextTheme, setSearchTextTheme] = useState(""); const [selectedTemplates, setSelectedTemplates] = useState([]); const [themesOptions, setThemesOptions] = useState(); + const [displayPreview, setDisplayPreview] = useState(null); const [templateError, setTemplateError] = useState(false); // Load templates. @@ -88,18 +107,26 @@ function SlideForm({ order: { createdAt: "desc" }, }); - /** Check if published is set */ - const checkInputsHandleSubmit = () => { + /** + * Check if template is set + * + * @param {boolean | null} noRedirect Avoid close after save. + */ + const checkInputsHandleSubmit = (noRedirect) => { setTemplateError(false); let submit = true; if (!selectedTemplate) { setTemplateError(true); submit = false; - displayError(t("slide-form.remember-template-error")); + displayError(t("remember-template-error")); } if (submit) { - handleSubmit(); + if (noRedirect === true) { + handleSaveNoClose(); + } else { + handleSubmit(); + } } }; @@ -110,7 +137,7 @@ function SlideForm({ * @param {string} props.key - The key input. */ function downHandler({ key }) { - if (key === "Escape") { + if (key === "Escape" && previewOverlayVisible) { setPreviewOverlayVisible(false); } } @@ -138,7 +165,7 @@ function SlideForm({ setContentFormElements(data); }) .catch((er) => { - displayError(t("slide-form.template-error"), er); + displayError(t("template-error"), er); }); newSelectedTemplates.push(selectedTemplate); @@ -164,26 +191,14 @@ function SlideForm({ /** Get show from local storage */ useEffect(() => { const localStorageShow = localStorage.getItem(localStorageKeys.PREVIEW); - setShowPreview(localStorageShow === "true"); - const localStorageLayout = localStorage.getItem( - localStorageKeys.PREVIEW_LAYOUT - ); - if (localStorageLayout) { - setPreviewLayout(localStorageLayout); - } + setDisplayPreview(localStorageShow === "true"); }, []); - /** - * Changes the show value, and saves to localstorage - * - * @param {object} props Props. - * @param {boolean} props.target The returned value from the checkbox. - */ - const changeShowPreview = ({ target }) => { - const { value } = target; - localStorage.setItem(localStorageKeys.PREVIEW, value); - - setShowPreview(value); + /** Toggle display preview. */ + const toggleDisplayPreview = () => { + const newValue = !displayPreview; + localStorage.setItem(localStorageKeys.PREVIEW, newValue); + setDisplayPreview(newValue); }; /** @@ -204,30 +219,19 @@ function SlideForm({ setSearchTextTheme(filter); }; - /** - * Change preview layout. - * - * @param {object} props The props. - * @param {object} props.target Event target - */ - const onChangePreviewLayout = ({ target }) => { - setPreviewLayout(target.value); - localStorage.setItem(localStorageKeys.PREVIEW_LAYOUT, target.value); - }; - return ( - <> +
- +

{headerText}

@@ -238,8 +242,8 @@ function SlideForm({ templateOptions && ( 0 ? selectedTemplates[0].title @@ -298,84 +302,12 @@ function SlideForm({ ))} -
- -

- {t("slide-form.preview-slide-title")} -

-
- -
-
- -
- - {previewOverlayVisible && ( -
- setPreviewOverlayVisible(!previewOverlayVisible) - } - role="presentation" - className="preview-overlay" - > - {selectedTemplate?.resources?.component && ( - 0 ? selectedTheme[0] : 0 - } - showPreview={showPreview} - orientation="" - closeButton - closeCallback={() => - setPreviewOverlayVisible(false) - } - /> - )} -
- )} -
-
)} -

{t("slide-form.add-slide-to-playlists")}

+

{t("add-slide-to-playlists")}

{config?.touchButtonRegions && ( -

{t("slide-form.touch-region")}

+

{t("touch-region")}

- - {t("slide-form.touch-region-button-text-helptext")} - + {t("touch-region-button-text-helptext")}
)} -

{t("slide-form.slide-publish-title")}

+

{t("slide-publish-title")}

@@ -412,23 +342,23 @@ function SlideForm({ - {t("slide-form.publish-helptext")} + {t("publish-helptext")}
{themesOptions && ( -

{t("slide-form.theme")}

+

{t("theme")}

)} - {showPreview && ( + {displayPreview && ( - {selectedTemplate?.resources?.component && ( - 0 ? selectedTheme[0] : {}} - orientation={previewLayout} +

{t("slide-preview")}

+ +
+