Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/cloud/components/DashboardPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
import UnlockDashboardModal from '../Modal/contents/Subscription/UnlockDashboardModal'
import { useNav } from '../../lib/stores/nav'
import DashboardSubscriptionBanner from './DashboardSubscriptionBanner'
import { useCloudDocPreview } from '../../lib/hooks/useCloudDocPreview'

const DashboardPage = ({
dashboard: propsDashboard,
Expand Down Expand Up @@ -88,6 +89,8 @@ const DashboardPage = ({
openModal,
])

useCloudDocPreview(propsTeam)

const renderSmartview = useCallback(
(smartview: SerializedSmartView) => {
return (
Expand Down
22 changes: 21 additions & 1 deletion src/cloud/components/DocPreview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mdiArrowExpand, mdiClose, mdiPencil } from '@mdi/js'
import React from 'react'
import React, { useEffect } from 'react'
import { useState } from 'react'
import { useCallback } from 'react'
import { useMemo } from 'react'
Expand All @@ -14,10 +14,12 @@ import { overflowEllipsis } from '../../../design/lib/styled/styleFunctions'
import { getDocCollaborationToken } from '../../api/docs/token'
import { SerializedDocWithSupplemental } from '../../interfaces/db/doc'
import { SerializedTeam } from '../../interfaces/db/team'
import { docPreviewCloseEvent } from '../../lib/hooks/useCloudDocPreview'
import { useRouter } from '../../lib/router'
import { useGlobalData } from '../../lib/stores/globalData'
import { useNav } from '../../lib/stores/nav'
import { usePage } from '../../lib/stores/pageStore'
import { ModalEventDetails, modalEventEmitter } from '../../lib/utils/events'
import { getDocTitle } from '../../lib/utils/patterns'
import DocProperties from '../DocProperties'
import { getDocLinkHref } from '../Link/DocLink'
Expand Down Expand Up @@ -67,6 +69,24 @@ const DocPreviewModal = ({ doc, team }: DocPreviewModalProps) => {
return closeLastModal()
}, [push, closeLastModal, team, doc])

const closePreviewModal = useCallback(
(event: CustomEvent<ModalEventDetails>) => {
if (event.detail.type !== docPreviewCloseEvent) {
return
}

closeLastModal()
},
[closeLastModal]
)

useEffect(() => {
modalEventEmitter.listen(closePreviewModal)
return () => {
modalEventEmitter.unlisten(closePreviewModal)
}
}, [closePreviewModal])

if (currentDoc == null) {
return (
<Flexbox direction='column'>
Expand Down
6 changes: 3 additions & 3 deletions src/cloud/components/Views/Calendar/CalendarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const CalendarView = ({
}: CalendarViewProps) => {
const { openNewDocForm } = useCloudResourceModals()
const { openContextModal, closeLastModal } = useModal()
const { openDocPreview } = useCloudResourceModals()
const { goToDocPreview } = useCloudResourceModals()

const { watchedProp, actionsRef } = useCalendarView({
view,
Expand Down Expand Up @@ -96,7 +96,7 @@ const CalendarView = ({
extendedProps: {
doc,
displayedProps,
onClick: () => openDocPreview(doc, team),
onClick: () => goToDocPreview(doc),
onContextClick: (event: React.MouseEvent) =>
openContextModal(
event,
Expand All @@ -115,7 +115,7 @@ const CalendarView = ({
team,
view.data.props,
watchedProp,
openDocPreview,
goToDocPreview,
openContextModal,
])

Expand Down
6 changes: 3 additions & 3 deletions src/cloud/components/Views/Kanban/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const KanbanView = ({
const { openContextModal, closeLastModal } = useModal()
const { createDoc } = useCloudApi()
const { translate } = useI18n()
const { openDocPreview } = useCloudResourceModals()
const { goToDocPreview } = useCloudResourceModals()

const addListRef = useRef(addList)
useEffect(() => {
Expand Down Expand Up @@ -151,13 +151,13 @@ const KanbanView = ({
(doc: SerializedDocWithSupplemental) => {
return (
<Item
onClick={() => openDocPreview(doc, team)}
onClick={() => goToDocPreview(doc)}
doc={doc}
displayedProps={view.data.props || {}}
/>
)
},
[team, openDocPreview, view.data.props]
[goToDocPreview, view.data.props]
)

const renderListFooter = useCallback(
Expand Down
4 changes: 2 additions & 2 deletions src/cloud/components/Views/Table/TableView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const TableView = ({
const { translate } = useI18n()
const { createDoc } = useCloudApi()
const { openContextModal, closeLastModal } = useModal()
const { openDocPreview } = useCloudResourceModals()
const { goToDocPreview } = useCloudResourceModals()
const { permissions = [] } = usePage()

const {
Expand Down Expand Up @@ -270,7 +270,7 @@ const TableView = ({
children: (
<NavigationItem
labelHref={docLink}
labelClick={() => openDocPreview(doc, team)}
labelClick={() => goToDocPreview(doc)}
label={getDocTitle(doc, 'Untitled')}
icon={
doc.emoji != null
Expand Down
4 changes: 3 additions & 1 deletion src/cloud/components/Views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import KanbanView from './Kanban'
import ListView from './List'
import { sortListViewProps } from '../../lib/views/list'
import { useRouter } from '../../lib/router'
import { useCloudDocPreview } from '../../lib/hooks/useCloudDocPreview'

type ViewsManagerProps = {
views: SerializedView[]
Expand Down Expand Up @@ -67,9 +68,10 @@ export const ViewsManager = ({
reset: resetDocsInSelection,
},
] = useSet<string>(new Set())

const { query, push, pathname } = useRouter()

useCloudDocPreview(team)

const currentDocumentsRef = useRef(
new Map<string, SerializedDocWithSupplemental>(
docs.map((doc) => [doc.id, doc])
Expand Down
38 changes: 38 additions & 0 deletions src/cloud/lib/hooks/useCloudDocPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useCallback, useEffect, useRef } from 'react'
import { SerializedTeam } from '../../interfaces/db/team'
import { useRouter } from '../router'
import { useNav } from '../stores/nav'
import { modalEventEmitter } from '../utils/events'
import { useCloudResourceModals } from './useCloudResourceModals'

export const docPreviewCloseEvent = 'doc-preview-close'

export function useCloudDocPreview(team: SerializedTeam) {
const { query } = useRouter()
const { openDocPreview } = useCloudResourceModals()
const { docsMap } = useNav()
const prevPreviewRef = useRef<string>('')

const openDocInPreview = useCallback(
(docId: string) => {
const doc = docsMap.get(docId)
if (doc == null) {
return modalEventEmitter.dispatch({ type: docPreviewCloseEvent })
}
return openDocPreview(doc, team)
},
[openDocPreview, docsMap, team]
)
const openDocInPreviewRef = useRef(openDocInPreview)

useEffect(() => {
if (
typeof query.preview !== 'string' ||
query.preview === prevPreviewRef.current
) {
return
}
prevPreviewRef.current = query.preview
openDocInPreviewRef.current(query.preview)
}, [query.preview])
}
23 changes: 22 additions & 1 deletion src/cloud/lib/hooks/useCloudResourceModals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { PropData } from '../../interfaces/db/props'
import { SerializedTeam } from '../../interfaces/db/team'
import { SerializedWorkspace } from '../../interfaces/db/workspace'
import { lngKeys } from '../i18n/types'
import { useRouter } from '../router'
import { useNav } from '../stores/nav'
import { usePage } from '../stores/pageStore'
import { resourceDeleteEventEmitter } from '../utils/events'
Expand All @@ -31,6 +32,7 @@ import {
} from '../utils/patterns'
import { useCloudApi } from './useCloudApi'
import { useI18n } from './useI18n'
import { stringify } from 'querystring'

export function useCloudResourceModals() {
const { openModal, closeLastModal } = useModal()
Expand All @@ -48,6 +50,7 @@ export function useCloudResourceModals() {
const { translate } = useI18n()
const { team } = usePage()
const { foldersMap, workspacesMap } = useNav()
const { pathname, push, query } = useRouter()

const openWorkspaceCreateForm = useCallback(() => {
openModal(<WorkspaceModalForm />, {
Expand Down Expand Up @@ -414,12 +417,29 @@ export function useCloudResourceModals() {

const openDocPreview = useCallback(
(doc: SerializedDocWithSupplemental, team: SerializedTeam) => {
const cleanedupQuery = Object.assign({}, query)
delete cleanedupQuery.preview
const fallbackQuery = stringify(cleanedupQuery)
const fallbackUrl = `${pathname}${
fallbackQuery.trim() !== '' ? `?${fallbackQuery}` : ''
}`
return openModal(<DocPreviewModal doc={doc} team={team} />, {
showCloseIcon: false,
removePadding: true,
navigation: {
url: `${pathname}?preview=${doc.id}`,
fallbackUrl,
},
})
},
[openModal]
[openModal, pathname, query]
)

const goToDocPreview = useCallback(
(doc: SerializedDocWithSupplemental) => {
return push(`${pathname}?preview=${doc.id}`)
},
[pathname, push]
)

return {
Expand All @@ -428,6 +448,7 @@ export function useCloudResourceModals() {
openNewDocForm,
openNewFolderForm,
openDocPreview,
goToDocPreview,
openRenameFolderForm,
openRenameDocForm,
deleteFolder,
Expand Down
8 changes: 8 additions & 0 deletions src/cloud/lib/utils/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,11 @@ export type SignInViaAccessTokenDetails = {
export const signInViaAccessTokenEventEmitter = createCustomEventEmitter<
SignInViaAccessTokenDetails
>('sign-in-via-access-token')

export const modalEventEmitter = createCustomEventEmitter<ModalEventDetails>(
'modal'
)

export type ModalEventDetails = {
type: string
}
51 changes: 46 additions & 5 deletions src/design/components/organisms/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { CSSProperties, useCallback, useMemo, useRef } from 'react'
import { mdiClose } from '@mdi/js'
import cc from 'classcat'
import { ModalElement, useModal } from '../../../lib/stores/modal'
import {
ModalElement,
ModalNavigationProps,
useModal,
} from '../../../lib/stores/modal'
import { isActiveElementAnInput } from '../../../lib/dom'
import { useGlobalKeyDownHandler } from '../../../lib/keyboard'
import styled from '../../../lib/styled'
Expand All @@ -10,6 +14,8 @@ import Scroller from '../../atoms/Scroller'
import { useWindow } from '../../../lib/stores/window'
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'
import { useEffectOnce } from 'react-use'
import { useRouter } from '../../../../cloud/lib/router'
import { useEffectOnUnmount } from '../../../../lib/hooks'

const Modal = () => {
const { modals, closeLastModal } = useModal()
Expand Down Expand Up @@ -208,6 +214,12 @@ const ModalItem = ({
modal: ModalElement
}) => {
const contentRef = useRef<HTMLDivElement>(null)
const manualClosing = useRef(false)

const closing = useCallback(() => {
manualClosing.current = true
closeModal()
}, [closeModal])

const onScrollClickHandler: React.MouseEventHandler = useCallback(
(event) => {
Expand All @@ -217,12 +229,13 @@ const ModalItem = ({
) {
return
}

closeModal()
closing()
},
[closeModal]
[closing]
)

useModalNavigationHistory(manualClosing, modal.navigation)

return (
<Scroller
className='modal__window__scroller'
Expand All @@ -242,7 +255,7 @@ const ModalItem = ({
<Button
variant='icon'
iconPath={mdiClose}
onClick={closeModal}
onClick={closing}
className='modal__window__close'
iconSize={26}
/>
Expand All @@ -258,6 +271,34 @@ const ModalItem = ({
)
}

function useModalNavigationHistory(
manualClosing: React.MutableRefObject<boolean>,
navigation?: ModalNavigationProps
) {
const { push, goBack } = useRouter()

//push modal's url to history on load
useEffectOnce(() => {
if (navigation == null) {
return
}
push(navigation.url)
})

//on modal's closure, goes back to wanted URL
useEffectOnUnmount(() => {
if (!manualClosing.current || navigation == null) {
return
}

if (navigation.fallbackUrl != null) {
push(navigation.fallbackUrl)
} else if (goBack != null) {
goBack()
}
})
}

export const zIndexModals = 8001
const Container = styled.div`
z-index: ${zIndexModals};
Expand Down
7 changes: 7 additions & 0 deletions src/design/lib/stores/modal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ export interface ModalElement {
hideBackground?: boolean
removePadding?: boolean
onBlur?: boolean
navigation?: ModalNavigationProps
onClose?: () => void
}

export type ModalNavigationProps = {
url: string
fallbackUrl?: string
}

export type ContextModalAlignment =
| 'bottom-left'
| 'bottom-right'
Expand All @@ -32,6 +38,7 @@ export type ModalOpeningOptions = {
width?: 'large' | 'default' | 'small' | 'full' | number
hideBackground?: boolean
title?: string
navigation?: ModalNavigationProps
onClose?: () => void
}

Expand Down
Loading