'use client' import type { Dispatch, SetStateAction } from 'react' import { useCallback, useState } from 'react' import { createContext, useContext, useContextSelector } from 'use-context-selector' import { useRouter, useSearchParams } from 'next/navigation' import AccountSetting from '@/app/components/header/account-setting' import ApiBasedExtensionModal from '@/app/components/header/account-setting/api-based-extension-page/modal' import ModerationSettingModal from '@/app/components/app/configuration/toolbox/moderation/moderation-setting-modal' import ExternalDataToolModal from '@/app/components/app/configuration/tools/external-data-tool-modal' import AnnotationFullModal from '@/app/components/billing/annotation-full/modal' import ModelModal from '@/app/components/header/account-setting/model-provider-page/model-modal' import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, ModelLoadBalancingConfigEntry, ModelProvider, } from '@/app/components/header/account-setting/model-provider-page/declarations' import Pricing from '@/app/components/billing/pricing' import type { ModerationConfig } from '@/models/debug' import type { ApiBasedExtension, ExternalDataTool, } from '@/models/common' import ModelLoadBalancingEntryModal from '@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal' import type { ModelLoadBalancingModalProps } from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal' import ModelLoadBalancingModal from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal' export type ModalState = { payload: T onCancelCallback?: () => void onSaveCallback?: (newPayload: T) => void onRemoveCallback?: (newPayload: T) => void onValidateBeforeSaveCallback?: (newPayload: T) => boolean } export type ModelModalType = { currentProvider: ModelProvider currentConfigurationMethod: ConfigurationMethodEnum currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields } export type LoadBalancingEntryModalType = ModelModalType & { entry?: ModelLoadBalancingConfigEntry index?: number } export type ModalContextState = { setShowAccountSettingModal: Dispatch | null>> setShowApiBasedExtensionModal: Dispatch | null>> setShowModerationSettingModal: Dispatch | null>> setShowExternalDataToolModal: Dispatch | null>> setShowPricingModal: () => void setShowAnnotationFullModal: () => void setShowModelModal: Dispatch | null>> setShowModelLoadBalancingModal: Dispatch> setShowModelLoadBalancingEntryModal: Dispatch | null>> } const ModalContext = createContext({ setShowAccountSettingModal: () => { }, setShowApiBasedExtensionModal: () => { }, setShowModerationSettingModal: () => { }, setShowExternalDataToolModal: () => { }, setShowPricingModal: () => { }, setShowAnnotationFullModal: () => { }, setShowModelModal: () => { }, setShowModelLoadBalancingModal: () => { }, setShowModelLoadBalancingEntryModal: () => { }, }) export const useModalContext = () => useContext(ModalContext) // Adding a dangling comma to avoid the generic parsing issue in tsx, see: // https://github.com/microsoft/TypeScript/issues/15713 // eslint-disable-next-line @typescript-eslint/comma-dangle export const useModalContextSelector = (selector: (state: ModalContextState) => T): T => useContextSelector(ModalContext, selector) type ModalContextProviderProps = { children: React.ReactNode } export const ModalContextProvider = ({ children, }: ModalContextProviderProps) => { const [showAccountSettingModal, setShowAccountSettingModal] = useState | null>(null) const [showApiBasedExtensionModal, setShowApiBasedExtensionModal] = useState | null>(null) const [showModerationSettingModal, setShowModerationSettingModal] = useState | null>(null) const [showExternalDataToolModal, setShowExternalDataToolModal] = useState | null>(null) const [showModelModal, setShowModelModal] = useState | null>(null) const [showModelLoadBalancingModal, setShowModelLoadBalancingModal] = useState(null) const [showModelLoadBalancingEntryModal, setShowModelLoadBalancingEntryModal] = useState | null>(null) const searchParams = useSearchParams() const router = useRouter() const [showPricingModal, setShowPricingModal] = useState(searchParams.get('show-pricing') === '1') const [showAnnotationFullModal, setShowAnnotationFullModal] = useState(false) const handleCancelAccountSettingModal = () => { setShowAccountSettingModal(null) if (showAccountSettingModal?.onCancelCallback) showAccountSettingModal?.onCancelCallback() } const handleCancelModerationSettingModal = () => { setShowModerationSettingModal(null) if (showModerationSettingModal?.onCancelCallback) showModerationSettingModal.onCancelCallback() } const handleCancelExternalDataToolModal = () => { setShowExternalDataToolModal(null) if (showExternalDataToolModal?.onCancelCallback) showExternalDataToolModal.onCancelCallback() } const handleCancelModelModal = useCallback(() => { setShowModelModal(null) if (showModelModal?.onCancelCallback) showModelModal.onCancelCallback() }, [showModelModal]) const handleSaveModelModal = useCallback(() => { if (showModelModal?.onSaveCallback) showModelModal.onSaveCallback(showModelModal.payload) setShowModelModal(null) }, [showModelModal]) const handleCancelModelLoadBalancingEntryModal = useCallback(() => { showModelLoadBalancingEntryModal?.onCancelCallback?.() setShowModelLoadBalancingEntryModal(null) }, [showModelLoadBalancingEntryModal]) const handleSaveModelLoadBalancingEntryModal = useCallback((entry: ModelLoadBalancingConfigEntry) => { showModelLoadBalancingEntryModal?.onSaveCallback?.({ ...showModelLoadBalancingEntryModal.payload, entry, }) setShowModelLoadBalancingEntryModal(null) }, [showModelLoadBalancingEntryModal]) const handleRemoveModelLoadBalancingEntry = useCallback(() => { showModelLoadBalancingEntryModal?.onRemoveCallback?.(showModelLoadBalancingEntryModal.payload) setShowModelLoadBalancingEntryModal(null) }, [showModelLoadBalancingEntryModal]) const handleSaveApiBasedExtension = (newApiBasedExtension: ApiBasedExtension) => { if (showApiBasedExtensionModal?.onSaveCallback) showApiBasedExtensionModal.onSaveCallback(newApiBasedExtension) setShowApiBasedExtensionModal(null) } const handleSaveModeration = (newModerationConfig: ModerationConfig) => { if (showModerationSettingModal?.onSaveCallback) showModerationSettingModal.onSaveCallback(newModerationConfig) setShowModerationSettingModal(null) } const handleSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => { if (showExternalDataToolModal?.onSaveCallback) showExternalDataToolModal.onSaveCallback(newExternalDataTool) setShowExternalDataToolModal(null) } const handleValidateBeforeSaveExternalDataTool = (newExternalDataTool: ExternalDataTool) => { if (showExternalDataToolModal?.onValidateBeforeSaveCallback) return showExternalDataToolModal?.onValidateBeforeSaveCallback(newExternalDataTool) return true } return ( setShowPricingModal(true), setShowAnnotationFullModal: () => setShowAnnotationFullModal(true), setShowModelModal, setShowModelLoadBalancingModal, setShowModelLoadBalancingEntryModal, }}> <> {children} { !!showAccountSettingModal && ( ) } { !!showApiBasedExtensionModal && ( setShowApiBasedExtensionModal(null)} onSave={handleSaveApiBasedExtension} /> ) } { !!showModerationSettingModal && ( ) } { !!showExternalDataToolModal && ( ) } { !!showPricingModal && ( { if (searchParams.get('show-pricing') === '1') router.push(location.pathname, { forceOptimisticNavigation: true } as any) setShowPricingModal(false) }} /> ) } { showAnnotationFullModal && ( setShowAnnotationFullModal(false)} /> ) } { !!showModelModal && ( ) } { Boolean(showModelLoadBalancingModal) && ( ) } { !!showModelLoadBalancingEntryModal && ( ) } ) } export default ModalContext