2021-06-23 05:37:08 -04:00
|
|
|
import {
|
2021-06-21 06:02:38 -04:00
|
|
|
createContext,
|
2024-01-26 04:23:48 -05:00
|
|
|
Dispatch,
|
|
|
|
FC,
|
|
|
|
SetStateAction,
|
2021-06-21 06:02:38 -04:00
|
|
|
useCallback,
|
|
|
|
useContext,
|
|
|
|
useEffect,
|
|
|
|
useMemo,
|
2023-08-30 09:37:07 -04:00
|
|
|
useState,
|
2021-06-21 06:02:38 -04:00
|
|
|
} from 'react'
|
2021-10-08 06:09:41 -04:00
|
|
|
import useScopeValue from '../hooks/use-scope-value'
|
2021-05-18 06:56:56 -04:00
|
|
|
import useBrowserWindow from '../hooks/use-browser-window'
|
2021-06-16 05:32:38 -04:00
|
|
|
import { useIdeContext } from './ide-context'
|
2021-06-25 04:13:17 -04:00
|
|
|
import { useProjectContext } from './project-context'
|
2022-05-20 04:15:49 -04:00
|
|
|
import { useDetachContext } from './detach-context'
|
2023-03-24 08:09:14 -04:00
|
|
|
import getMeta from '../../utils/meta'
|
|
|
|
import { useUserContext } from './user-context'
|
2023-09-28 12:36:08 -04:00
|
|
|
import { saveProjectSettings } from '@/features/editor-left-menu/utils/api'
|
2024-01-26 04:23:48 -05:00
|
|
|
import { PermissionsLevel } from '@/features/ide-react/types/permissions'
|
2024-06-24 07:26:31 -04:00
|
|
|
import { useModalsContext } from '@/features/ide-react/context/modals-context'
|
2024-01-26 04:23:48 -05:00
|
|
|
|
|
|
|
export const EditorContext = createContext<
|
|
|
|
| {
|
|
|
|
cobranding?: {
|
|
|
|
logoImgUrl: string
|
|
|
|
brandVariationName: string
|
|
|
|
brandVariationId: number
|
|
|
|
brandId: number
|
|
|
|
brandVariationHomeUrl: string
|
|
|
|
publishGuideHtml?: string
|
|
|
|
partner?: string
|
|
|
|
brandedMenu?: boolean
|
|
|
|
submitBtnHtml?: string
|
|
|
|
}
|
|
|
|
hasPremiumCompile?: boolean
|
|
|
|
loading?: boolean
|
|
|
|
renameProject: (newName: string) => void
|
|
|
|
setPermissionsLevel: (permissionsLevel: PermissionsLevel) => void
|
|
|
|
showSymbolPalette?: boolean
|
|
|
|
toggleSymbolPalette?: () => void
|
|
|
|
insertSymbol?: (symbol: string) => void
|
|
|
|
isProjectOwner: boolean
|
|
|
|
isRestrictedTokenMember?: boolean
|
2024-08-22 06:41:05 -04:00
|
|
|
isPendingEditor: boolean
|
2024-01-26 04:23:48 -05:00
|
|
|
permissionsLevel: 'readOnly' | 'readAndWrite' | 'owner'
|
|
|
|
deactivateTutorial: (tutorial: string) => void
|
2024-06-18 06:01:37 -04:00
|
|
|
inactiveTutorials: string[]
|
2024-01-26 04:23:48 -05:00
|
|
|
currentPopup: string | null
|
|
|
|
setCurrentPopup: Dispatch<SetStateAction<string | null>>
|
2024-05-20 06:30:33 -04:00
|
|
|
setOutOfSync: (value: boolean) => void
|
2024-11-04 11:44:40 -05:00
|
|
|
hasPremiumSuggestion: boolean
|
|
|
|
setHasPremiumSuggestion: (value: boolean) => void
|
|
|
|
setPremiumSuggestionResetDate: (date: Date) => void
|
|
|
|
premiumSuggestionResetDate: Date
|
2024-01-26 04:23:48 -05:00
|
|
|
}
|
|
|
|
| undefined
|
|
|
|
>(undefined)
|
2020-12-14 06:44:10 -05:00
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
export const EditorProvider: FC = ({ children }) => {
|
2021-06-16 05:32:38 -04:00
|
|
|
const ide = useIdeContext()
|
2024-11-04 11:44:40 -05:00
|
|
|
const { id: userId, featureUsage } = useUserContext()
|
2022-05-20 04:15:49 -04:00
|
|
|
const { role } = useDetachContext()
|
2024-06-24 07:26:31 -04:00
|
|
|
const { showGenericMessageModal } = useModalsContext()
|
2022-05-20 04:15:49 -04:00
|
|
|
|
2024-08-22 06:41:05 -04:00
|
|
|
const { owner, features, _id: projectId, members } = useProjectContext()
|
2021-06-25 04:13:17 -04:00
|
|
|
|
|
|
|
const cobranding = useMemo(() => {
|
2024-06-18 06:01:37 -04:00
|
|
|
const brandVariation = getMeta('ol-brandVariation')
|
2024-01-26 04:23:48 -05:00
|
|
|
return (
|
2024-06-18 06:01:37 -04:00
|
|
|
brandVariation && {
|
|
|
|
logoImgUrl: brandVariation.logo_url,
|
|
|
|
brandVariationName: brandVariation.name,
|
|
|
|
brandVariationId: brandVariation.id,
|
|
|
|
brandId: brandVariation.brand_id,
|
|
|
|
brandVariationHomeUrl: brandVariation.home_url,
|
|
|
|
publishGuideHtml: brandVariation.publish_guide_html,
|
|
|
|
partner: brandVariation.partner,
|
|
|
|
brandedMenu: brandVariation.branded_menu,
|
|
|
|
submitBtnHtml: brandVariation.submit_button_html,
|
2021-06-25 04:13:17 -04:00
|
|
|
}
|
2024-01-26 04:23:48 -05:00
|
|
|
)
|
2021-06-25 04:13:17 -04:00
|
|
|
}, [])
|
2021-01-27 05:30:55 -05:00
|
|
|
|
2021-06-16 05:32:38 -04:00
|
|
|
const [loading] = useScopeValue('state.loading')
|
|
|
|
const [projectName, setProjectName] = useScopeValue('project.name')
|
2023-12-14 06:06:36 -05:00
|
|
|
const [permissionsLevel, setPermissionsLevel] =
|
|
|
|
useScopeValue('permissionsLevel')
|
2024-05-20 06:30:33 -04:00
|
|
|
const [outOfSync, setOutOfSync] = useState(false)
|
2021-11-10 05:50:01 -05:00
|
|
|
const [showSymbolPalette] = useScopeValue('editor.showSymbolPalette')
|
|
|
|
const [toggleSymbolPalette] = useScopeValue('editor.toggleSymbolPalette')
|
2021-06-25 04:14:07 -04:00
|
|
|
|
2024-06-18 06:01:37 -04:00
|
|
|
const [inactiveTutorials, setInactiveTutorials] = useState(
|
|
|
|
() => getMeta('ol-inactiveTutorials') || []
|
2023-08-30 09:37:07 -04:00
|
|
|
)
|
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
const [currentPopup, setCurrentPopup] = useState<string | null>(null)
|
2024-11-04 11:44:40 -05:00
|
|
|
const [hasPremiumSuggestion, setHasPremiumSuggestion] = useState<boolean>(
|
|
|
|
() => {
|
|
|
|
return Boolean(
|
|
|
|
featureUsage?.aiErrorAssistant &&
|
|
|
|
featureUsage?.aiErrorAssistant.remainingUsage > 0
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const [premiumSuggestionResetDate, setPremiumSuggestionResetDate] =
|
|
|
|
useState<Date>(() => {
|
2024-11-05 10:32:09 -05:00
|
|
|
return featureUsage?.aiErrorAssistant?.resetDate
|
2024-11-04 11:44:40 -05:00
|
|
|
? new Date(featureUsage.aiErrorAssistant.resetDate)
|
|
|
|
: new Date()
|
|
|
|
})
|
2024-01-03 09:54:51 -05:00
|
|
|
|
2024-08-22 06:41:05 -04:00
|
|
|
const isPendingEditor = useMemo(
|
|
|
|
() =>
|
2024-08-26 09:03:37 -04:00
|
|
|
members?.some(member => member._id === userId && member.pendingEditor),
|
2024-08-22 06:41:05 -04:00
|
|
|
[members, userId]
|
|
|
|
)
|
|
|
|
|
2023-12-05 07:59:55 -05:00
|
|
|
const deactivateTutorial = useCallback(
|
2023-08-30 09:37:07 -04:00
|
|
|
tutorialKey => {
|
2023-12-05 07:59:55 -05:00
|
|
|
setInactiveTutorials([...inactiveTutorials, tutorialKey])
|
2023-08-30 09:37:07 -04:00
|
|
|
},
|
2023-12-05 07:59:55 -05:00
|
|
|
[inactiveTutorials]
|
2023-08-30 09:37:07 -04:00
|
|
|
)
|
|
|
|
|
2021-06-25 04:14:07 -04:00
|
|
|
useEffect(() => {
|
|
|
|
if (ide?.socket) {
|
|
|
|
ide.socket.on('projectNameUpdated', setProjectName)
|
|
|
|
return () =>
|
|
|
|
ide.socket.removeListener('projectNameUpdated', setProjectName)
|
|
|
|
}
|
|
|
|
}, [ide?.socket, setProjectName])
|
2021-04-19 08:38:03 -04:00
|
|
|
|
2021-03-10 07:19:54 -05:00
|
|
|
const renameProject = useCallback(
|
2024-01-26 04:23:48 -05:00
|
|
|
(newName: string) => {
|
|
|
|
setProjectName((oldName: string) => {
|
2021-03-10 07:19:54 -05:00
|
|
|
if (oldName !== newName) {
|
2024-01-26 04:23:48 -05:00
|
|
|
saveProjectSettings(projectId, { name: newName }).catch(
|
|
|
|
(response: any) => {
|
|
|
|
setProjectName(oldName)
|
|
|
|
const { data, status } = response
|
2024-06-24 07:26:31 -04:00
|
|
|
|
|
|
|
showGenericMessageModal(
|
|
|
|
'Error renaming project',
|
|
|
|
status === 400 ? data : 'Please try again in a moment'
|
|
|
|
)
|
2021-03-10 07:19:54 -05:00
|
|
|
}
|
2024-01-26 04:23:48 -05:00
|
|
|
)
|
2021-03-10 07:19:54 -05:00
|
|
|
}
|
|
|
|
return newName
|
|
|
|
})
|
|
|
|
},
|
2024-06-24 07:26:31 -04:00
|
|
|
[setProjectName, projectId, showGenericMessageModal]
|
2021-03-10 07:19:54 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const { setTitle } = useBrowserWindow()
|
2021-05-18 09:43:41 -04:00
|
|
|
useEffect(() => {
|
2022-05-20 04:15:49 -04:00
|
|
|
const parts = []
|
|
|
|
|
|
|
|
if (role === 'detached') {
|
|
|
|
parts.push('[PDF]')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (projectName) {
|
|
|
|
parts.push(projectName)
|
|
|
|
parts.push('-')
|
|
|
|
}
|
|
|
|
|
|
|
|
parts.push('Online LaTeX Editor')
|
2024-06-18 06:01:37 -04:00
|
|
|
parts.push(getMeta('ol-ExposedSettings').appName)
|
2022-05-20 04:15:49 -04:00
|
|
|
|
|
|
|
const title = parts.join(' ')
|
|
|
|
|
|
|
|
setTitle(title)
|
|
|
|
}, [projectName, setTitle, role])
|
2021-02-09 10:37:48 -05:00
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
const insertSymbol = useCallback((symbol: string) => {
|
2022-01-10 08:56:36 -05:00
|
|
|
window.dispatchEvent(
|
|
|
|
new CustomEvent('editor:insert-symbol', {
|
|
|
|
detail: symbol,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
}, [])
|
|
|
|
|
2021-06-21 06:02:38 -04:00
|
|
|
const value = useMemo(
|
|
|
|
() => ({
|
|
|
|
cobranding,
|
2021-06-25 04:13:17 -04:00
|
|
|
hasPremiumCompile: features?.compileGroup === 'priority',
|
2021-06-21 06:02:38 -04:00
|
|
|
loading,
|
|
|
|
renameProject,
|
2024-05-20 06:30:33 -04:00
|
|
|
permissionsLevel: outOfSync ? 'readOnly' : permissionsLevel,
|
2023-12-14 06:06:36 -05:00
|
|
|
setPermissionsLevel,
|
2023-03-24 08:09:14 -04:00
|
|
|
isProjectOwner: owner?._id === userId,
|
|
|
|
isRestrictedTokenMember: getMeta('ol-isRestrictedTokenMember'),
|
2024-08-22 06:41:05 -04:00
|
|
|
isPendingEditor,
|
2021-11-10 05:50:01 -05:00
|
|
|
showSymbolPalette,
|
|
|
|
toggleSymbolPalette,
|
|
|
|
insertSymbol,
|
2023-12-05 07:59:55 -05:00
|
|
|
inactiveTutorials,
|
|
|
|
deactivateTutorial,
|
2024-01-03 09:54:51 -05:00
|
|
|
currentPopup,
|
|
|
|
setCurrentPopup,
|
2024-05-20 06:30:33 -04:00
|
|
|
setOutOfSync,
|
2024-11-04 11:44:40 -05:00
|
|
|
hasPremiumSuggestion,
|
|
|
|
setHasPremiumSuggestion,
|
|
|
|
premiumSuggestionResetDate,
|
|
|
|
setPremiumSuggestionResetDate,
|
2021-06-21 06:02:38 -04:00
|
|
|
}),
|
|
|
|
[
|
|
|
|
cobranding,
|
2021-06-25 04:13:17 -04:00
|
|
|
features?.compileGroup,
|
2023-03-24 08:09:14 -04:00
|
|
|
owner,
|
|
|
|
userId,
|
2021-06-21 06:02:38 -04:00
|
|
|
loading,
|
|
|
|
renameProject,
|
2021-06-25 04:14:07 -04:00
|
|
|
permissionsLevel,
|
2023-12-14 06:06:36 -05:00
|
|
|
setPermissionsLevel,
|
2024-08-22 06:41:05 -04:00
|
|
|
isPendingEditor,
|
2021-11-10 05:50:01 -05:00
|
|
|
showSymbolPalette,
|
|
|
|
toggleSymbolPalette,
|
|
|
|
insertSymbol,
|
2023-12-05 07:59:55 -05:00
|
|
|
inactiveTutorials,
|
|
|
|
deactivateTutorial,
|
2024-01-03 09:54:51 -05:00
|
|
|
currentPopup,
|
|
|
|
setCurrentPopup,
|
2024-05-20 06:30:33 -04:00
|
|
|
outOfSync,
|
|
|
|
setOutOfSync,
|
2024-11-04 11:44:40 -05:00
|
|
|
hasPremiumSuggestion,
|
|
|
|
setHasPremiumSuggestion,
|
|
|
|
premiumSuggestionResetDate,
|
|
|
|
setPremiumSuggestionResetDate,
|
2021-06-21 06:02:38 -04:00
|
|
|
]
|
|
|
|
)
|
2021-01-14 10:16:54 -05:00
|
|
|
|
2020-12-14 06:44:10 -05:00
|
|
|
return (
|
2021-06-21 06:02:38 -04:00
|
|
|
<EditorContext.Provider value={value}>{children}</EditorContext.Provider>
|
2020-12-14 06:44:10 -05:00
|
|
|
)
|
|
|
|
}
|
2024-01-26 04:23:48 -05:00
|
|
|
export function useEditorContext() {
|
2021-06-16 05:32:38 -04:00
|
|
|
const context = useContext(EditorContext)
|
|
|
|
|
|
|
|
if (!context) {
|
|
|
|
throw new Error('useEditorContext is only available inside EditorProvider')
|
|
|
|
}
|
|
|
|
|
|
|
|
return context
|
2020-12-14 06:44:10 -05:00
|
|
|
}
|