import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'next-i18next'; import * as ReactDOMServer from 'react-dom/server'; import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context'; import { useEditingMarkdown, useIsConflict } from '~/stores/editor'; import { useHasDraftOnHackmd, useIsHackmdDraftUpdatingInRealtime, useRevisionIdHackmdSynced, } from '~/stores/hackmd'; import { useConflictDiffModal } from '~/stores/modal'; import { useSWRMUTxCurrentPage, useSWRxCurrentPage } from '~/stores/page'; import { useRemoteRevisionId, useRemoteRevisionLastUpdateUser } from '~/stores/remote-latest-page'; import { EditorMode, useEditorMode } from '~/stores/ui'; import { Username } from './User/Username'; import styles from './PageStatusAlert.module.scss'; type AlertComponentContents = { additionalClasses: string[], label: JSX.Element, btn: JSX.Element } export const PageStatusAlert = (): JSX.Element => { const { t } = useTranslation(); const { data: isHackmdDraftUpdatingInRealtime } = useIsHackmdDraftUpdatingInRealtime(); const { data: hasDraftOnHackmd } = useHasDraftOnHackmd(); const { data: isConflict } = useIsConflict(); const { mutate: mutateEditingMarkdown } = useEditingMarkdown(); const { open: openConflictDiffModal } = useConflictDiffModal(); const { mutate: mutateEditorMode } = useEditorMode(); const { data: isGuestUser } = useIsGuestUser(); const { data: isReadOnlyUser } = useIsReadOnlyUser(); // store remote latest page data const { data: revisionIdHackmdSynced } = useRevisionIdHackmdSynced(); const { data: remoteRevisionId } = useRemoteRevisionId(); const { data: remoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser(); const { data: pageData } = useSWRxCurrentPage(); const { trigger: mutatePageData } = useSWRMUTxCurrentPage(); const revision = pageData?.revision; const refreshPage = useCallback(async() => { const updatedPageData = await mutatePageData(); mutateEditingMarkdown(updatedPageData?.revision.body); }, [mutateEditingMarkdown, mutatePageData]); const onClickResolveConflict = useCallback(() => { openConflictDiffModal(); }, [openConflictDiffModal]); const getContentsForSomeoneEditingAlert = useCallback((): AlertComponentContents => { return { additionalClasses: ['bg-success', 'd-hackmd-none'], label: <> {t('hackmd.someone_editing')} , btn: Open HackMD Editor , }; }, [t]); const getContentsForDraftExistsAlert = useCallback((): AlertComponentContents => { return { additionalClasses: ['bg-success', 'd-hackmd-none'], label: <> {t('hackmd.this_page_has_draft')} , btn: , }; }, [mutateEditorMode, t]); const getContentsForUpdatedAlert = useCallback((): AlertComponentContents => { const usernameComponentToString = ReactDOMServer.renderToString(); const label1 = isConflict ? t('modal_resolve_conflict.file_conflicting_with_newer_remote') // eslint-disable-next-line react/no-danger : ; return { additionalClasses: ['bg-warning'], label: <> {label1} , btn: <> { isConflict && ( )} , }; }, [remoteRevisionLastUpdateUser, isConflict, t, onClickResolveConflict, refreshPage]); const alertComponentContents = useMemo(() => { const isRevisionOutdated = revision?._id !== remoteRevisionId; const isHackmdDocumentOutdated = revisionIdHackmdSynced !== remoteRevisionId; // 'revision?._id' and 'remoteRevisionId' are can not be undefined if (revision?._id == null || remoteRevisionId == null) { return } // when remote revision is newer than both if (isHackmdDocumentOutdated && isRevisionOutdated) { return getContentsForUpdatedAlert(); } // when someone editing with HackMD if (isHackmdDraftUpdatingInRealtime) { return getContentsForSomeoneEditingAlert(); } // when the draft of HackMD is newest if (hasDraftOnHackmd) { return getContentsForDraftExistsAlert(); } return null; }, [ revision?._id, remoteRevisionId, revisionIdHackmdSynced, isHackmdDraftUpdatingInRealtime, hasDraftOnHackmd, getContentsForUpdatedAlert, getContentsForSomeoneEditingAlert, getContentsForDraftExistsAlert, ]); if (!!isGuestUser || !!isReadOnlyUser || alertComponentContents == null) { return <> } const { additionalClasses, label, btn } = alertComponentContents; return (

{label}

{btn}

); };