diff --git a/packages/client-core/src/admin/common/Project/ProjectFields.tsx b/packages/client-core/src/admin/common/Project/ProjectFields.tsx index 2addc06b39..6bb86a1433 100644 --- a/packages/client-core/src/admin/common/Project/ProjectFields.tsx +++ b/packages/client-core/src/admin/common/Project/ProjectFields.tsx @@ -233,8 +233,8 @@ const ProjectFields = ({ ProjectUpdateService.setSourceProjectName(project.name, '') return } - const valueRegex = new RegExp(`^${value}`, 'g') - let matchingCommit = commitData.find((data) => valueRegex.test(data.commitSHA)) + + let matchingCommit = commitData.find((data) => data.commitSHA.startsWith(value)) if (!matchingCommit) { const commitResponse = (await ProjectService.checkUnfetchedCommit({ url: projectUpdateStatus.value.sourceURL, @@ -251,7 +251,7 @@ const ProjectFields = ({ resolve(null) }, 100) }) - matchingCommit = commitData.find((data) => valueRegex.test(data.commitSHA)) + matchingCommit = commitData.find((data) => data.commitSHA.startsWith(value)) } } ProjectUpdateService.setSourceProjectName(project.name, matchingCommit?.projectName || '') diff --git a/packages/client-core/src/admin/components/locations/AddEditLocationModal.tsx b/packages/client-core/src/admin/components/locations/AddEditLocationModal.tsx index 969024a3e3..83deea0895 100644 --- a/packages/client-core/src/admin/components/locations/AddEditLocationModal.tsx +++ b/packages/client-core/src/admin/components/locations/AddEditLocationModal.tsx @@ -49,7 +49,13 @@ const locationTypeOptions = [ { label: 'Showroom', value: 'showroom' } ] -export default function AddEditLocationModal({ location }: { location?: LocationType }) { +export default function AddEditLocationModal({ + location, + sceneID +}: { + location?: LocationType + sceneID?: string | null +}) { const { t } = useTranslation() const locationMutation = useMutation(locationPath) @@ -59,7 +65,8 @@ export default function AddEditLocationModal({ location }: { location?: Location const name = useHookstate(location?.name || '') const maxUsers = useHookstate(location?.maxUsersPerInstance || 20) - const scene = useHookstate(location?.sceneId || '') + + const scene = useHookstate((location ? location.sceneId : sceneID) ?? '') const videoEnabled = useHookstate(location?.locationSetting.videoEnabled || true) const audioEnabled = useHookstate(location?.locationSetting.audioEnabled || true) const screenSharingEnabled = useHookstate(location?.locationSetting.screenSharingEnabled || true) diff --git a/packages/client-core/src/admin/components/project/AddEditProjectModal.tsx b/packages/client-core/src/admin/components/project/AddEditProjectModal.tsx index cde67234ab..f88e8da0a3 100644 --- a/packages/client-core/src/admin/components/project/AddEditProjectModal.tsx +++ b/packages/client-core/src/admin/components/project/AddEditProjectModal.tsx @@ -169,8 +169,8 @@ export default function AddEditProjectModal({ ProjectUpdateService.setSourceProjectName(project.name, '') return } - const valueRegex = new RegExp(`^${commitValue}`, 'g') - let matchingCommit = commitData.find((data) => valueRegex.test(data.commitSHA)) + + let matchingCommit = commitData.find((data) => data.commitSHA.startsWith(commitValue)) if (!matchingCommit) { const commitResponse = (await ProjectService.checkUnfetchedCommit({ url: projectUpdateStatus.value.sourceURL, @@ -187,7 +187,7 @@ export default function AddEditProjectModal({ resolve(null) }, 100) }) - matchingCommit = commitData.find((data) => valueRegex.test(data.commitSHA)) + matchingCommit = commitData.find((data) => data.commitSHA.startsWith(commitValue)) } } ProjectUpdateService.setSourceProjectName(project.name, matchingCommit?.projectName || '') diff --git a/packages/client-core/src/admin/components/settings/tabs/client.tsx b/packages/client-core/src/admin/components/settings/tabs/client.tsx index bfdfdc4ac4..9b2d6d625e 100644 --- a/packages/client-core/src/admin/components/settings/tabs/client.tsx +++ b/packages/client-core/src/admin/components/settings/tabs/client.tsx @@ -27,8 +27,8 @@ import React, { forwardRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { HiMinus, HiPlusSmall } from 'react-icons/hi2' -import { ClientSettingType } from '@etherealengine/common/src/schema.type.module' -import { getMutableState, NO_PROXY, none, useHookstate, useMutableState } from '@etherealengine/hyperflux' +import { clientSettingPath, ClientSettingType } from '@etherealengine/common/src/schema.type.module' +import { NO_PROXY, State, useHookstate } from '@etherealengine/hyperflux' import Accordion from '@etherealengine/ui/src/primitives/tailwind/Accordion' import Button from '@etherealengine/ui/src/primitives/tailwind/Button' import Input from '@etherealengine/ui/src/primitives/tailwind/Input' @@ -37,8 +37,8 @@ import Select from '@etherealengine/ui/src/primitives/tailwind/Select' import Text from '@etherealengine/ui/src/primitives/tailwind/Text' import Toggle from '@etherealengine/ui/src/primitives/tailwind/Toggle' -import { AuthState } from '../../../../user/services/AuthService' -import { AdminClientSettingsState, ClientSettingService } from '../../../services/Setting/ClientSettingService' +import { Engine } from '@etherealengine/ecs' +import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRefObject) => { const { t } = useTranslation() @@ -47,51 +47,25 @@ const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRef loading: false, errorMessage: '' }) - const user = useHookstate(getMutableState(AuthState).user) - const clientSettingState = useMutableState(AdminClientSettingsState) - const [clientSetting] = clientSettingState?.client?.get({ noproxy: true }) || [] - const id = clientSetting?.id + const clientSettingQuery = useFind(clientSettingPath) + const clientSettings = clientSettingQuery.data[0] ?? null + const id = clientSettings?.id - const settings = useHookstate(clientSetting) + const settingsState = useHookstate(null as null | ClientSettingType) useEffect(() => { - if (user?.id?.value != null && clientSettingState?.updateNeeded?.value === true) { - ClientSettingService.fetchClientSettings() + if (clientSettingQuery) { + state.set({ loading: clientSettingQuery.status === 'pending', errorMessage: clientSettingQuery.error }) } - }, [user?.id?.value, clientSettingState?.updateNeeded?.value]) + }, [clientSettingQuery]) useEffect(() => { - if (clientSetting) { - settings.merge({ - logo: clientSetting?.logo, - title: clientSetting?.title, - shortTitle: clientSetting?.shortTitle, - startPath: clientSetting?.startPath || '/', - appTitle: clientSetting?.appTitle, - appSubtitle: clientSetting?.appSubtitle, - appDescription: clientSetting?.appDescription, - appBackground: clientSetting?.appBackground, - appSocialLinks: JSON.parse(JSON.stringify(clientSetting?.appSocialLinks)) || [], - appleTouchIcon: clientSetting?.appleTouchIcon, - icon192px: clientSetting?.icon192px, - icon512px: clientSetting?.icon512px, - siteManifest: clientSetting?.siteManifest, - safariPinnedTab: clientSetting?.safariPinnedTab, - favicon: clientSetting?.favicon, - webmanifestLink: clientSetting?.webmanifestLink, - swScriptLink: clientSetting?.swScriptLink, - favicon16px: clientSetting?.favicon16px, - favicon32px: clientSetting?.favicon32px, - siteDescription: clientSetting?.siteDescription, - key8thWall: clientSetting?.key8thWall, - privacyPolicy: clientSetting?.privacyPolicy, - homepageLinkButtonEnabled: clientSetting?.homepageLinkButtonEnabled, - homepageLinkButtonRedirect: clientSetting?.homepageLinkButtonRedirect, - homepageLinkButtonText: clientSetting?.homepageLinkButtonText - }) + if (clientSettings) { + settingsState.set(clientSettings) + state.set({ loading: false, errorMessage: '' }) } - }, [clientSettingState?.updateNeeded?.value]) + }, [clientSettings]) const codecMenu = [ { @@ -130,14 +104,17 @@ const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRef const handleSubmit = (event) => { state.loading.set(true) event.preventDefault() - console.log(settings.get(NO_PROXY)) - settings.merge({ - createdAt: none, - updatedAt: none - }) - ClientSettingService.patchClientSetting(settings.value as ClientSettingType, id) + const newSettings = { + ...settingsState.get(NO_PROXY), + createdAt: undefined!, + updatedAt: undefined! + } as any as ClientSettingType + Engine.instance.api + .service(clientSettingPath) + .patch(id, newSettings) .then(() => { state.set({ loading: false, errorMessage: '' }) + clientSettingQuery.refetch() }) .catch((e) => { state.set({ loading: false, errorMessage: e.message }) @@ -145,9 +122,14 @@ const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRef } const handleCancel = () => { - settings.set(clientSetting) + settingsState.set(clientSettings) } + if (!settingsState.value) + return + + const settings = settingsState as State + return ( diff --git a/packages/client-core/src/admin/services/Setting/ClientSettingService.ts b/packages/client-core/src/admin/services/Setting/ClientSettingService.ts deleted file mode 100644 index 459a78eea3..0000000000 --- a/packages/client-core/src/admin/services/Setting/ClientSettingService.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* -CPAL-1.0 License - -The contents of this file are subject to the Common Public Attribution License -Version 1.0. (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. -The License is based on the Mozilla Public License Version 1.1, but Sections 14 -and 15 have been added to cover use of software over a computer network and -provide for limited attribution for the Original Developer. In addition, -Exhibit A has been modified to be consistent with Exhibit B. - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -specific language governing rights and limitations under the License. - -The Original Code is Ethereal Engine. - -The Original Developer is the Initial Developer. The Initial Developer of the -Original Code is the Ethereal Engine team. - -All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 -Ethereal Engine. All Rights Reserved. -*/ - -import { Paginated } from '@feathersjs/feathers' - -import config from '@etherealengine/common/src/config' -import multiLogger from '@etherealengine/common/src/logger' -import { ClientSettingPatch, clientSettingPath, ClientSettingType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' -import { defineState, getMutableState } from '@etherealengine/hyperflux' - -import { NotificationService } from '../../../common/services/NotificationService' -import waitForClientAuthenticated from '../../../util/wait-for-client-authenticated' - -const logger = multiLogger.child({ component: 'client-core:ClientSettingService' }) - -export const AdminClientSettingsState = defineState({ - name: 'AdminClientSettingsState', - initial: () => ({ - client: [] as Array, - updateNeeded: true - }) -}) - -export const ClientSettingService = { - fetchClientSettings: async () => { - try { - await waitForClientAuthenticated() - const clientSettings = (await Engine.instance.api - .service(clientSettingPath) - .find()) as Paginated - - if (clientSettings.data[0].key8thWall) { - config.client.key8thWall = clientSettings.data[0].key8thWall - } - - getMutableState(AdminClientSettingsState).merge({ client: clientSettings.data, updateNeeded: false }) - } catch (err) { - logger.error(err) - NotificationService.dispatchNotify(err.message, { variant: 'error' }) - } - }, - patchClientSetting: async (data: ClientSettingPatch, id: string) => { - try { - await Engine.instance.api.service(clientSettingPath).patch(id, data) - getMutableState(AdminClientSettingsState).merge({ updateNeeded: true }) - } catch (err) { - logger.error(err) - NotificationService.dispatchNotify(err.message, { variant: 'error' }) - } - } -} diff --git a/packages/client-core/src/common/services/AppThemeState.ts b/packages/client-core/src/common/services/AppThemeState.ts index 27ccf2e3d4..c621b0f922 100644 --- a/packages/client-core/src/common/services/AppThemeState.ts +++ b/packages/client-core/src/common/services/AppThemeState.ts @@ -27,7 +27,6 @@ import { defaultThemeSettings, getCurrentTheme } from '@etherealengine/common/sr import { ClientThemeOptionsType } from '@etherealengine/common/src/schema.type.module' import { defineState, getMutableState, getState, useMutableState } from '@etherealengine/hyperflux' -import { AdminClientSettingsState } from '../../admin/services/Setting/ClientSettingService' import { AuthState } from '../../user/services/AuthService' /** @deprected this is the thene for mui pages, it will be replaced with ThemeService / ThemeState */ @@ -70,9 +69,5 @@ export const getAppTheme = () => { const authState = getState(AuthState) const theme = getCurrentTheme(authState.user?.userSetting?.themeModes) - const clientSettingState = getState(AdminClientSettingsState) - const themeSettings = clientSettingState?.client?.[0]?.themeSettings - if (themeSettings) return themeSettings[theme] - return defaultThemeSettings[theme] } diff --git a/packages/client-core/src/common/services/RouterService.tsx b/packages/client-core/src/common/services/RouterService.tsx index 432ec2edf6..e917a4b207 100644 --- a/packages/client-core/src/common/services/RouterService.tsx +++ b/packages/client-core/src/common/services/RouterService.tsx @@ -70,7 +70,13 @@ export const RouterState = defineState({ export type CustomRoute = { route: string component: ReturnType - props: any + componentProps?: { + [x: string]: any + } + props?: { + [x: string]: any + exact?: boolean + } } /** @@ -110,5 +116,5 @@ export const useCustomRoutes = () => { }) }, []) - return customRoutes.get(NO_PROXY) + return customRoutes.get(NO_PROXY) as CustomRoute[] } diff --git a/packages/client-core/src/components/LoadWebappInjection.tsx b/packages/client-core/src/components/LoadWebappInjection.tsx index 81e4d284e6..d11d12afe8 100644 --- a/packages/client-core/src/components/LoadWebappInjection.tsx +++ b/packages/client-core/src/components/LoadWebappInjection.tsx @@ -23,16 +23,26 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import config from '@etherealengine/common/src/config' +import { clientSettingPath } from '@etherealengine/common/src/schema.type.module' import { NO_PROXY } from '@etherealengine/hyperflux' import { loadWebappInjection } from '@etherealengine/projects/loadWebappInjection' +import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' import { useHookstate } from '@hookstate/core' import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' -export const LoadWebappInjection = (props) => { +export const LoadWebappInjection = (props: { children: React.ReactNode }) => { const { t } = useTranslation() + const clientSettingQuery = useFind(clientSettingPath) + const clientSettings = clientSettingQuery.data[0] ?? null + useEffect(() => { + config.client.key8thWall = clientSettings?.key8thWall + config.client.mediaSettings = clientSettings?.mediaSettings + }, [clientSettings]) + const projectComponents = useHookstate(null as null | any[]) useEffect(() => { diff --git a/packages/client-core/src/components/UserMediaWindow/index.tsx b/packages/client-core/src/components/UserMediaWindow/index.tsx index ff4a2568e5..d27437d8ef 100755 --- a/packages/client-core/src/components/UserMediaWindow/index.tsx +++ b/packages/client-core/src/components/UserMediaWindow/index.tsx @@ -42,7 +42,7 @@ import { toggleWebcamPaused } from '@etherealengine/client-core/src/transports/SocketWebRTCClientFunctions' import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService' -import { UserName, userPath } from '@etherealengine/common/src/schema.type.module' +import { UserName, clientSettingPath, userPath } from '@etherealengine/common/src/schema.type.module' import { useExecute } from '@etherealengine/ecs' import { Engine } from '@etherealengine/ecs/src/Engine' import { AudioState } from '@etherealengine/engine/src/audio/AudioState' @@ -59,7 +59,7 @@ import { useMutableState } from '@etherealengine/hyperflux' import { NetworkState, VideoConstants } from '@etherealengine/network' -import { useGet } from '@etherealengine/spatial/src/common/functions/FeathersHooks' +import { useFind, useGet } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import { isMobile } from '@etherealengine/spatial/src/common/functions/isMobile' import { drawPoseToCanvas } from '@etherealengine/ui/src/pages/Capture' import Icon from '@etherealengine/ui/src/primitives/mui/Icon' @@ -68,7 +68,6 @@ import Slider from '@etherealengine/ui/src/primitives/mui/Slider' import Tooltip from '@etherealengine/ui/src/primitives/mui/Tooltip' import Canvas from '@etherealengine/ui/src/primitives/tailwind/Canvas' -import { AdminClientSettingsState } from '../../admin/services/Setting/ClientSettingService' import { MediaStreamState } from '../../transports/MediaStreams' import { PeerMediaChannelState, PeerMediaStreamInterface } from '../../transports/PeerMediaChannelState' import { ConsumerExtension, SocketWebRTCClientNetwork } from '../../transports/SocketWebRTCClientFunctions' @@ -491,6 +490,9 @@ export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => { const canvasRef = useRef(null) const canvasCtxRef = useRef() + const clientSettingQuery = useFind(clientSettingPath) + const clientSetting = clientSettingQuery.data[0] + useDrawMocapLandmarks(videoElement, canvasCtxRef, canvasRef, peerID) useEffect(() => { @@ -517,8 +519,7 @@ export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => { const encodings = videoStream.rtpParameters.encodings const immersiveMedia = getMutableState(MediaSettingsState).immersiveMedia - const clientSettingState = getMutableState(AdminClientSettingsState) - const { maxResolution } = clientSettingState.client[0].mediaSettings.video.value + const { maxResolution } = clientSetting.mediaSettings.video const resolution = VideoConstants.VIDEO_CONSTRAINTS[maxResolution] || VideoConstants.VIDEO_CONSTRAINTS.hd if (isPiP || immersiveMedia.value) { let maxLayer diff --git a/packages/client-core/src/components/World/LoadLocationScene.tsx b/packages/client-core/src/components/World/LoadLocationScene.tsx index c151cfa5b1..986f06272b 100755 --- a/packages/client-core/src/components/World/LoadLocationScene.tsx +++ b/packages/client-core/src/components/World/LoadLocationScene.tsx @@ -88,6 +88,7 @@ export const useLoadLocation = (props: { locationName: string }) => { export const useLoadScene = (props: { projectName: string; sceneName: string }) => { const sceneKey = `projects/${props.projectName}/${props.sceneName}` const assetID = useFind(staticResourcePath, { query: { key: sceneKey, type: 'scene' } }) + useEffect(() => { if (!props.sceneName || !props.projectName) return if (!assetID.data.length) return diff --git a/packages/client-core/src/social/services/InviteService.ts b/packages/client-core/src/social/services/InviteService.ts index 3ba40d81b0..b71085fcf8 100644 --- a/packages/client-core/src/social/services/InviteService.ts +++ b/packages/client-core/src/social/services/InviteService.ts @@ -26,12 +26,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' import { useEffect } from 'react' -import { - EMAIL_REGEX, - INVITE_CODE_REGEX, - PHONE_REGEX, - USER_ID_REGEX -} from '@etherealengine/common/src/constants/IdConstants' +import { EMAIL_REGEX, INVITE_CODE_REGEX, PHONE_REGEX, USER_ID_REGEX } from '@etherealengine/common/src/regex' import { InviteCode, InviteData, diff --git a/packages/client-core/src/systems/LoadingUISystem.tsx b/packages/client-core/src/systems/LoadingUISystem.tsx index ddda911b09..efadfd8cc8 100755 --- a/packages/client-core/src/systems/LoadingUISystem.tsx +++ b/packages/client-core/src/systems/LoadingUISystem.tsx @@ -70,7 +70,6 @@ import { ObjectFitFunctions } from '@etherealengine/spatial/src/xrui/functions/O import type { WebLayer3D } from '@etherealengine/xrui' import { EngineState } from '@etherealengine/spatial/src/EngineState' -import { AdminClientSettingsState } from '../admin/services/Setting/ClientSettingService' import { AppThemeState, getAppTheme } from '../common/services/AppThemeState' import { useRemoveEngineCanvas } from '../hooks/useEngineCanvas' import { LocationState } from '../social/services/LocationService' @@ -339,9 +338,6 @@ const execute = () => { const Reactor = () => { const themeState = useMutableState(AppThemeState) const themeModes = useHookstate(getMutableState(AuthState).user?.userSetting?.ornull?.themeModes) - const clientSettings = useHookstate( - getMutableState(AdminClientSettingsState)?.client?.[0]?.themeSettings?.clientSettings - ) const locationSceneID = useHookstate(getMutableState(LocationState).currentLocation.location.sceneId).value const sceneEntity = GLTFAssetState.useScene(locationSceneID) const gltfDocumentState = useMutableState(GLTFDocumentState) @@ -349,7 +345,7 @@ const Reactor = () => { useEffect(() => { const theme = getAppTheme() if (theme) defaultColor.set(theme!.textColor) - }, [themeState, themeModes, clientSettings]) + }, [themeState, themeModes]) if (!sceneEntity) return null diff --git a/packages/client-core/src/transports/MediaStreams.ts b/packages/client-core/src/transports/MediaStreams.ts index 01552ded3d..c0c2c751a4 100755 --- a/packages/client-core/src/transports/MediaStreams.ts +++ b/packages/client-core/src/transports/MediaStreams.ts @@ -24,10 +24,10 @@ Ethereal Engine. All Rights Reserved. */ import multiLogger from '@etherealengine/common/src/logger' -import { defineState, getMutableState, getState } from '@etherealengine/hyperflux' +import { defineState, getMutableState } from '@etherealengine/hyperflux' import { VideoConstants } from '@etherealengine/network' -import { AdminClientSettingsState } from '../admin/services/Setting/ClientSettingService' +import config from '@etherealengine/common/src/config' import { ProducerExtension } from './SocketWebRTCClientFunctions' const logger = multiLogger.child({ component: 'client-core:MediaStreams' }) @@ -182,9 +182,8 @@ export const MediaStreamService = { */ async getVideoStream() { const state = getMutableState(MediaStreamState) - const clientSettingState = getState(AdminClientSettingsState) try { - const { maxResolution } = clientSettingState.client[0].mediaSettings.video + const { maxResolution } = config.client.mediaSettings!.video const constraints = { video: VideoConstants.VIDEO_CONSTRAINTS[maxResolution] || VideoConstants.VIDEO_CONSTRAINTS.hd } diff --git a/packages/client-core/src/transports/SocketWebRTCClientFunctions.ts b/packages/client-core/src/transports/SocketWebRTCClientFunctions.ts index f24a406231..55176c1348 100755 --- a/packages/client-core/src/transports/SocketWebRTCClientFunctions.ts +++ b/packages/client-core/src/transports/SocketWebRTCClientFunctions.ts @@ -92,7 +92,6 @@ import { webcamVideoDataChannelType } from '@etherealengine/network' -import { AdminClientSettingsState } from '../admin/services/Setting/ClientSettingService' import { LocationInstanceState } from '../common/services/LocationInstanceConnectionService' import { MediaInstanceState } from '../common/services/MediaInstanceConnectionService' import { @@ -797,9 +796,8 @@ export async function configureMediaTransports(mediaTypes: string[]): Promise { - const clientSettingState = getState(AdminClientSettingsState).client[0] - const settings = - service === 'video' ? clientSettingState.mediaSettings.video : clientSettingState.mediaSettings.screenshare + const mediaSettings = config.client.mediaSettings + const settings = service === 'video' ? mediaSettings.video : mediaSettings.screenshare let codec, encodings if (settings) { switch (settings.codec) { @@ -869,7 +867,6 @@ export async function createCamVideoProducer(network: SocketWebRTCClientNetwork) export async function createCamAudioProducer(network: SocketWebRTCClientNetwork): Promise { const channelConnectionState = getState(MediaInstanceState) - const clientSettingState = getState(AdminClientSettingsState) const currentChannelInstanceConnection = channelConnectionState.instances[network.id] const channelId = currentChannelInstanceConnection.channelId const mediaStreamState = getMutableState(MediaStreamState) @@ -893,8 +890,8 @@ export async function createCamAudioProducer(network: SocketWebRTCClientNetwork) try { const codecOptions = { ...VideoConstants.CAM_AUDIO_CODEC_OPTIONS } - if (clientSettingState.client?.[0]?.mediaSettings?.audio) - codecOptions.opusMaxAverageBitrate = clientSettingState.client[0].mediaSettings.audio.maxBitrate * 1000 + const mediaSettings = config.client.mediaSettings + if (mediaSettings?.audio) codecOptions.opusMaxAverageBitrate = mediaSettings.audio.maxBitrate * 1000 // Create a new transport for audio and start producing let produceInProgress = false @@ -1183,8 +1180,8 @@ export const startScreenshare = async (network: SocketWebRTCClientNetwork) => { ) const channelConnectionState = getState(MediaInstanceState) - const clientSettingState = getState(AdminClientSettingsState).client[0] - const screenshareSettings = clientSettingState.mediaSettings.screenshare + const mediaSettings = config.client.mediaSettings + const screenshareSettings = mediaSettings.screenshare const currentChannelInstanceConnection = channelConnectionState.instances[network.id] const channelId = currentChannelInstanceConnection.channelId diff --git a/packages/client-core/src/user/components/UserMenu/menus/SettingMenu.tsx b/packages/client-core/src/user/components/UserMenu/menus/SettingMenu.tsx index 0cf3e59959..c29107515a 100755 --- a/packages/client-core/src/user/components/UserMenu/menus/SettingMenu.tsx +++ b/packages/client-core/src/user/components/UserMenu/menus/SettingMenu.tsx @@ -34,7 +34,7 @@ import Tabs from '@etherealengine/client-core/src/common/components/Tabs' import Text from '@etherealengine/client-core/src/common/components/Text' import { AuthService, AuthState } from '@etherealengine/client-core/src/user/services/AuthService' import { defaultThemeModes, defaultThemeSettings } from '@etherealengine/common/src/constants/DefaultThemeSettings' -import { UserSettingPatch } from '@etherealengine/common/src/schema.type.module' +import { UserSettingPatch, clientSettingPath } from '@etherealengine/common/src/schema.type.module' import capitalizeFirstLetter from '@etherealengine/common/src/utils/capitalizeFirstLetter' import { AudioState } from '@etherealengine/engine/src/audio/AudioState' import { @@ -43,7 +43,6 @@ import { } from '@etherealengine/engine/src/avatar/state/AvatarInputSettingsState' import { getMutableState, useHookstate, useMutableState } from '@etherealengine/hyperflux' import { isMobile } from '@etherealengine/spatial/src/common/functions/isMobile' -import { EngineState } from '@etherealengine/spatial/src/EngineState' import { InputState } from '@etherealengine/spatial/src/input/state/InputState' import { RendererState } from '@etherealengine/spatial/src/renderer/RendererState' import { XRState } from '@etherealengine/spatial/src/xr/XRState' @@ -51,11 +50,11 @@ import Box from '@etherealengine/ui/src/primitives/mui/Box' import Grid from '@etherealengine/ui/src/primitives/mui/Grid' import Icon from '@etherealengine/ui/src/primitives/mui/Icon' -import { AdminClientSettingsState } from '../../../../admin/services/Setting/ClientSettingService' -import { userHasAccess } from '../../../userHasAccess' +import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import { UserMenus } from '../../../UserUISystem' -import styles from '../index.module.scss' +import { userHasAccess } from '../../../userHasAccess' import { PopupMenuServices } from '../PopupMenuService' +import styles from '../index.module.scss' export const ShadowMapResolutionOptions: InputMenuItem[] = [ { @@ -104,15 +103,14 @@ const SettingMenu = ({ isPopover }: Props): JSX.Element => { const controlSchemes = Object.entries(AvatarAxesControlScheme) const handOptions = ['left', 'right'] const selectedTab = useHookstate('general') - const engineState = useMutableState(EngineState) - const clientSettingState = useMutableState(AdminClientSettingsState) - const [clientSetting] = clientSettingState?.client?.value || [] + const clientSettingQuery = useFind(clientSettingPath) + const clientSettings = clientSettingQuery.data[0] const userSettings = selfUser.userSetting.value const hasAdminAccess = userHasAccess('admin:admin') const hasEditorAccess = userHasAccess('editor:write') - const themeSettings = { ...defaultThemeSettings, ...clientSetting.themeSettings } + const themeSettings = { ...defaultThemeSettings, ...clientSettings?.themeSettings } const themeModes = { client: userSettings?.themeModes?.client ?? defaultThemeModes.client, studio: userSettings?.themeModes?.studio ?? defaultThemeModes.studio, diff --git a/packages/client-core/src/user/components/UserMenu/menus/ShareMenu.tsx b/packages/client-core/src/user/components/UserMenu/menus/ShareMenu.tsx index a3cc5cbd58..0a816ec9a2 100755 --- a/packages/client-core/src/user/components/UserMenu/menus/ShareMenu.tsx +++ b/packages/client-core/src/user/components/UserMenu/menus/ShareMenu.tsx @@ -33,8 +33,8 @@ import InputCheck from '@etherealengine/client-core/src/common/components/InputC import InputText from '@etherealengine/client-core/src/common/components/InputText' import Menu from '@etherealengine/client-core/src/common/components/Menu' import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' -import { EMAIL_REGEX, PHONE_REGEX } from '@etherealengine/common/src/constants/IdConstants' import multiLogger from '@etherealengine/common/src/logger' +import { EMAIL_REGEX, PHONE_REGEX } from '@etherealengine/common/src/regex' import { InviteCode, InviteData } from '@etherealengine/common/src/schema.type.module' import { useMutableState } from '@etherealengine/hyperflux' import { isShareAvailable } from '@etherealengine/spatial/src/common/functions/DetectFeatures' diff --git a/packages/client-core/src/user/services/AuthService.ts b/packages/client-core/src/user/services/AuthService.ts index fb37abaa6c..5c06153005 100755 --- a/packages/client-core/src/user/services/AuthService.ts +++ b/packages/client-core/src/user/services/AuthService.ts @@ -183,7 +183,7 @@ export const AuthService = { // This would normally cause doLoginAuto to make a guest user, which we do not want. // Instead, just skip it on oauth callbacks, and the callback handler will log them in. // The client and auth settigns will not be needed on these routes - if (/auth\/oauth/.test(location.pathname)) return + if (location.pathname.startsWith('/auth')) return const authState = getMutableState(AuthState) try { const accessToken = !forceClientAuthReset && authState?.authUser?.accessToken?.value diff --git a/packages/client-core/src/world/Location.tsx b/packages/client-core/src/world/Location.tsx index cf06b50242..939838ecd5 100755 --- a/packages/client-core/src/world/Location.tsx +++ b/packages/client-core/src/world/Location.tsx @@ -29,13 +29,16 @@ import { useParams } from 'react-router-dom' import { LocationIcons } from '@etherealengine/client-core/src/components/LocationIcons' import { useLoadLocation, useLoadScene } from '@etherealengine/client-core/src/components/World/LoadLocationScene' import { AuthService } from '@etherealengine/client-core/src/user/services/AuthService' +import { ThemeContextProvider } from '@etherealengine/client/src/pages/themeContext' +import { useMutableState } from '@etherealengine/hyperflux' + +import '@etherealengine/client-core/src/util/GlobalStyle.css' import './LocationModule' import { t } from 'i18next' -import { useMutableState } from '@etherealengine/hyperflux' - +import { StyledEngineProvider } from '@mui/material/styles' import { LoadingCircle } from '../components/LoadingCircle' import { useLoadEngineWithScene, useNetwork } from '../components/World/EngineHooks' import { LoadingUISystemState } from '../systems/LoadingUISystem' @@ -62,8 +65,12 @@ const LocationPage = ({ online }: Props) => { return ( <> - {!ready.value && } - + + + {!ready.value && } + + + ) } diff --git a/packages/client/pwa.config.ts b/packages/client/pwa.config.ts index 43843bb413..834303a1d3 100644 --- a/packages/client/pwa.config.ts +++ b/packages/client/pwa.config.ts @@ -27,6 +27,9 @@ import { VitePWA } from 'vite-plugin-pwa' import manifest from './manifest.default.json' +const WILDCARD_REGEX = /^\/.*$/ +const LOCAL_FILESYSTEM_REGEX = /^\/@fs\/.*$/ + /** * Creates a new instance of the VitePWA plugin for Vite.js. * @param {Object} clientSetting - An object containing custom settings for the PWA. @@ -75,9 +78,9 @@ const PWA = (clientSetting) => // Allowlist all paths for navigateFallback during development navigateFallbackAllowlist: [ // allow everything - new RegExp('^/.*$'), + WILDCARD_REGEX, // allow @fs - new RegExp('^/@fs/.*$') + LOCAL_FILESYSTEM_REGEX ] }, workbox: { @@ -94,7 +97,7 @@ const PWA = (clientSetting) => // Allowlist all paths for navigateFallback during production navigateFallbackAllowlist: [ // allow everything - new RegExp('^/.*$') + WILDCARD_REGEX ], // Set the glob directory and patterns for the cache globDirectory: process.env.APP_ENV === 'development' ? './public' : './dist', diff --git a/packages/client/src/main.tsx b/packages/client/src/main.tsx index ca452d5b1a..3276b867aa 100755 --- a/packages/client/src/main.tsx +++ b/packages/client/src/main.tsx @@ -37,11 +37,16 @@ import './pages/mui.styles.scss' /** @todo Remove when MUI is removed */ // @ts-ignore ;(globalThis as any).process = { env: { ...(import.meta as any).env, APP_ENV: (import.meta as any).env.MODE } } +const $offline = lazy(() => import('@etherealengine/client/src/pages/offline/offline')) +const $location = lazy(() => import('@etherealengine/client/src/pages/location/location')) +const $auth = lazy(() => import('@etherealengine/client/src/pages/auth/authRoutes')) + const Engine = lazy(() => import('./engine')) -/** @deprecated see https://github.com/EtherealEngine/etherealengine/issues/6485 */ -const AppPage = lazy(() => import('./pages/_app')) -const TailwindPage = lazy(() => import('./pages/_app_tw')) +const AppPage = lazy(() => import('./pages/AppPage')) +/** @todo we can import tailwind here immediately once mui is gone */ +const Tailwind = lazy(() => import('./pages/tailwind')) +const Router = lazy(() => import('./route/CustomRouter')) const App = () => { return ( @@ -54,7 +59,9 @@ const App = () => { path="/location/*" element={ }> - + + <$location /> + } /> @@ -63,17 +70,31 @@ const App = () => { path="/offline/*" element={ }> - + + <$offline /> + + + } + /> + {/* This will become redundant and we can embed the AppPage directly */} + }> + <$auth /> } /> - {/* This will become redundant and we can embed the TailwindPage directly */} - + + + + } /> diff --git a/packages/client/src/pages/503.tsx b/packages/client/src/pages/503.tsx index 8e17bfb24d..bf2b863064 100755 --- a/packages/client/src/pages/503.tsx +++ b/packages/client/src/pages/503.tsx @@ -23,15 +23,16 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import { AdminClientSettingsState } from '@etherealengine/client-core/src/admin/services/Setting/ClientSettingService' -import { useMutableState } from '@etherealengine/hyperflux' +import { clientSettingPath } from '@etherealengine/common/src/schema.type.module' +import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import React from 'react' import { useTranslation } from 'react-i18next' export const Custom503 = (): any => { + console.log('503') const { t } = useTranslation() - const clientSettingState = useMutableState(AdminClientSettingsState) - const [clientSetting] = clientSettingState?.client?.value || [] + const clientSettingQuery = useFind(clientSettingPath) + const clientSetting = clientSettingQuery.data[0] return ( <>

{t('503.msg')}

@@ -40,7 +41,7 @@ export const Custom503 = (): any => { height: 'auto', maxWidth: '100%' }} - src={clientSetting.appTitle} + src={clientSetting?.appTitle} /> ) diff --git a/packages/client/src/pages/_app_tw.tsx b/packages/client/src/pages/AppPage.tsx similarity index 73% rename from packages/client/src/pages/_app_tw.tsx rename to packages/client/src/pages/AppPage.tsx index feba56a8c3..2f98be6354 100755 --- a/packages/client/src/pages/_app_tw.tsx +++ b/packages/client/src/pages/AppPage.tsx @@ -28,29 +28,20 @@ Ethereal Engine. All Rights Reserved. import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' -import { - AdminClientSettingsState, - ClientSettingService -} from '@etherealengine/client-core/src/admin/services/Setting/ClientSettingService' import { initGA, logPageView } from '@etherealengine/client-core/src/common/analytics' import { NotificationSnackbar } from '@etherealengine/client-core/src/common/services/NotificationService' import { useThemeProvider } from '@etherealengine/client-core/src/common/services/ThemeService' import Debug from '@etherealengine/client-core/src/components/Debug' +import InviteToast from '@etherealengine/client-core/src/components/InviteToast' import { LoadWebappInjection } from '@etherealengine/client-core/src/components/LoadWebappInjection' +import { useZendesk } from '@etherealengine/client-core/src/hooks/useZendesk' import { useAuthenticated } from '@etherealengine/client-core/src/user/services/AuthService' -import { useMutableState } from '@etherealengine/hyperflux' import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' -import { useZendesk } from '@etherealengine/client-core/src/hooks/useZendesk' -import PublicRouter from '../route/public_tw' - -import '../themes/base.css' -import '../themes/components.css' -import '../themes/utilities.css' - -const AppPage = () => { +const AppPage = (props: { children: React.ReactNode }) => { const { t } = useTranslation() const isLoggedIn = useAuthenticated() + useZendesk() useEffect(() => { @@ -58,34 +49,20 @@ const AppPage = () => { logPageView() }, []) - if (!/auth\/oauth/.test(location.pathname) && !isLoggedIn) { + useThemeProvider() + + if (!isLoggedIn) { return } - return ( - <> - - - - - ) -} - -const TailwindPage = () => { - const clientSettingState = useMutableState(AdminClientSettingsState) - useEffect(() => { - if (clientSettingState?.updateNeeded?.value) ClientSettingService.fetchClientSettings() - }, [clientSettingState?.updateNeeded?.value]) - - useThemeProvider() - return ( <> - + {props.children} + ) } -export default TailwindPage +export default AppPage diff --git a/packages/client/src/pages/_app.tsx b/packages/client/src/pages/_app.tsx deleted file mode 100755 index 52ad347f74..0000000000 --- a/packages/client/src/pages/_app.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* -CPAL-1.0 License - -The contents of this file are subject to the Common Public Attribution License -Version 1.0. (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. -The License is based on the Mozilla Public License Version 1.1, but Sections 14 -and 15 have been added to cover use of software over a computer network and -provide for limited attribution for the Original Developer. In addition, -Exhibit A has been modified to be consistent with Exhibit B. - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -specific language governing rights and limitations under the License. - -The Original Code is Ethereal Engine. - -The Original Developer is the Initial Developer. The Initial Developer of the -Original Code is the Ethereal Engine team. - -All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 -Ethereal Engine. All Rights Reserved. -*/ - -// import * as chapiWalletPolyfill from 'credential-handler-polyfill' -import React, { useEffect } from 'react' - -import { initGA, logPageView } from '@etherealengine/client-core/src/common/analytics' -import { NotificationSnackbar } from '@etherealengine/client-core/src/common/services/NotificationService' -import Debug from '@etherealengine/client-core/src/components/Debug' -import InviteToast from '@etherealengine/client-core/src/components/InviteToast' -import { useAuthenticated } from '@etherealengine/client-core/src/user/services/AuthService' - -import '@etherealengine/client-core/src/util/GlobalStyle.css' - -import { StyledEngineProvider, Theme } from '@mui/material/styles' -import { useTranslation } from 'react-i18next' - -import { LoadingCircle } from '@etherealengine/client-core/src/components/LoadingCircle' - -import { LoadWebappInjection } from '@etherealengine/client-core/src/components/LoadWebappInjection' -import RouterComp from '../route/public' -import { ThemeContextProvider } from './themeContext' - -declare module '@mui/styles/defaultTheme' { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface DefaultTheme extends Theme {} -} - -/** @deprecated see https://github.com/EtherealEngine/etherealengine/issues/6485 */ -const AppPage = ({ route }: { route: string }) => { - const isLoggedIn = useAuthenticated() - const { t } = useTranslation() - - useEffect(() => { - initGA() - logPageView() - }, []) - - if (!isLoggedIn) { - return - } - - return ( - <> - - - -
- - -
- - - -
-
- - ) -} - -export default AppPage diff --git a/packages/client/src/pages/index.tsx b/packages/client/src/pages/index.tsx index 4b0f951932..c2ed9e98f0 100755 --- a/packages/client/src/pages/index.tsx +++ b/packages/client/src/pages/index.tsx @@ -28,7 +28,6 @@ import { Trans, useTranslation } from 'react-i18next' import { Navigate } from 'react-router-dom' import styles from '@etherealengine/client-core/src/admin/old-styles/admin.module.scss' -import { AdminClientSettingsState } from '@etherealengine/client-core/src/admin/services/Setting/ClientSettingService' import MetaTags from '@etherealengine/client-core/src/common/components/MetaTags' import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' @@ -43,14 +42,16 @@ import { Box, Button } from '@mui/material' import ProfileMenu from '@etherealengine/client-core/src/user/components/UserMenu/menus/ProfileMenu' import { UserMenus } from '@etherealengine/client-core/src/user/UserUISystem' +import { clientSettingPath } from '@etherealengine/common/src/schema.type.module' +import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import './index.scss' const ROOT_REDIRECT = config.client.rootRedirect export const HomePage = (): any => { const { t } = useTranslation() - const clientSettingState = useMutableState(AdminClientSettingsState) - const [clientSetting] = clientSettingState?.client?.value || [] + const clientSettingQuery = useFind(clientSettingPath) + const clientSetting = clientSettingQuery.data[0] const popupMenuState = useMutableState(PopupMenuState) const popupMenu = getState(PopupMenuState) const Panel = popupMenu.openMenu ? popupMenu.menus[popupMenu.openMenu] : null @@ -92,7 +93,7 @@ export const HomePage = (): any => { height: 'auto', maxWidth: '100%' }} - src={clientSetting.appBackground} + src={clientSetting?.appBackground} alt="" crossOrigin="anonymous" /> @@ -101,26 +102,26 @@ export const HomePage = (): any => {