import { t } from '../../../i18n'; import styled from '@emotion/styled'; import { deserializePB, PrevNext, serializePB, useBuilder, useEditor, } from '@tempi/core-editor'; import { Button, Dropdown, Spin, Switch } from 'antd'; import { BackIcon, LoadingBuilder } from 'modules/core'; import debounce from 'lodash.debounce'; import { Builder, BuilderConfig } from 'modules/builder'; import { BuilderHeader, DeviceSwitcher, LeftMenu, leftMenuData, } from 'modules/builder-header'; import { EmptyBuilderMobile } from 'modules/core'; import { Contact, DraggableElementsV2, InstructionDocument, Sidebar, } from 'modules/sidebar'; import { defaultRootPopup } from 'constants/index'; import { useEffect, useRef, useState } from 'react'; import { isMobile } from 'react-device-detect'; import { Helmet } from 'react-helmet'; import toast from 'react-hot-toast'; import { useParams } from 'react-router-dom'; import { PAGE_TITLE_MAPPING, POPUP_BUILDER, POPUP_LIST } from 'router/path'; import { popupApi } from '../utils/api'; import { usePopup } from '../hooks'; import { RootEditor } from '@tempi/core-elements'; import { ELEMENTS } from 'constants/elements'; export const PopupEditor = () => { const { pageContent, actions } = useEditor((_, query) => ({ pageContent: serializePB(JSON.parse(query.serialize()), { isEditingPopup: true, }), })); const params = useParams(); const { popup, loading: loadingGetPopup, onMutatePopup, } = usePopup(params?.id); const [loading, setLoading] = useState(false); const [autoSaving, setAutoSaving] = useState(false); const [allowAutoSave, setAllowAutoSave] = useState(false); const didMountRef = useRef(false); const { device, setDevice } = useBuilder(); const onSave = async (data) => { try { setLoading(true); await popupApi.updatePopup(+params?.id, data); toast.success(t('Cập nhật thành công')); onMutatePopup(); } finally { setLoading(false); } }; // Handle auto save when page changed useEffect(() => { if (!allowAutoSave || !pageContent) return; if (didMountRef.current) { handleAutoSave({ pbConfig: pageContent, }); } else { didMountRef.current = true; } // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(pageContent)]); const handleAutoSave = useRef( debounce(async (data) => { try { setAutoSaving(true); await popupApi.updatePopup(+params?.id, data); onMutatePopup(); } catch (error) { console.error(error); } finally { setAutoSaving(false); } }, 2000), ).current; const isActiveBlock = popup?.isActive; // Draft template: On auto save by default // Active template: Off auto save by default useEffect(() => { if (isActiveBlock) setAllowAutoSave(false); else setAllowAutoSave(true); }, [isActiveBlock]); useEffect(() => { if (popup?.id) { const popupContent = popup?.pbConfig && Object.keys(popup.pbConfig).length > 0 ? popup?.pbConfig : defaultRootPopup(); actions.history .ignore() .deserialize(deserializePB(popupContent, false, true)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [popup?.id]); const deviceSwitcherMenu = ( ); const saveMenu = ( <> setAllowAutoSave(!allowAutoSave)} /> } placement="bottom" > onSave({ pbConfig: pageContent })} loading={autoSaving} > {t('Lưu')} ); const builderSidebar = ( ]} bottomMenu={[, ]} /> ); const rightMenu = [deviceSwitcherMenu, , saveMenu]; const builderConfig: BuilderConfig = { content: pageContent, builderSidebar, builderHeader: ( , , ]} rightHeader={rightMenu.filter(Boolean)} /> ), RootEditor, }; return ( <> {PAGE_TITLE_MAPPING[POPUP_BUILDER]} {!isMobile && ( <> )} {isMobile && } ); }; const Wrapper = styled.div` height: 100vh; `; const OverlayWrapper = styled.div` background-color: var(--background-color); padding: 1em; box-shadow: 2px 2px 6px var(--box-shadow-color); border-radius: 8px; `; const SaveButton = styled(Button)` display: flex; align-items: center; gap: 4px; &.disabled { cursor: default; color: var(--text-secondary-color) !important; } `;