Ensure settings are persisted before we navigate for onboarding dismissal (#2678)

* Nicer types on OnboardingPaths

* Update persistSettings to be a service
This commit is contained in:
Frank Noirot
2024-06-17 15:10:30 -04:00
committed by GitHub
parent 3d6cfa980f
commit 7ab015d783
4 changed files with 58 additions and 40 deletions

View File

@ -171,7 +171,9 @@ export const SettingsAuthProviderBase = ({
}) })
}, },
'Execute AST': () => kclManager.executeCode(true, true), 'Execute AST': () => kclManager.executeCode(true, true),
persistSettings: (context) => },
services: {
'Persist settings': (context) =>
saveSettings(context, loadedProject?.project?.path), saveSettings(context, loadedProject?.project?.path),
}, },
} }

View File

@ -17,15 +17,17 @@ const prependRoutes =
) )
} }
type OnboardingPaths = {
[K in keyof typeof onboardingPaths]: `/onboarding${(typeof onboardingPaths)[K]}`
}
export const paths = { export const paths = {
INDEX: '/', INDEX: '/',
HOME: '/home', HOME: '/home',
FILE: '/file', FILE: '/file',
SETTINGS: '/settings', SETTINGS: '/settings',
SIGN_IN: '/signin', SIGN_IN: '/signin',
ONBOARDING: prependRoutes(onboardingPaths)( ONBOARDING: prependRoutes(onboardingPaths)('/onboarding') as OnboardingPaths,
'/onboarding'
) as typeof onboardingPaths,
} as const } as const
export const BROWSER_PATH = `%2F${BROWSER_PROJECT_NAME}%2F${BROWSER_FILE_NAME}${FILE_EXT}` export const BROWSER_PATH = `%2F${BROWSER_PROJECT_NAME}%2F${BROWSER_FILE_NAME}${FILE_EXT}`

View File

@ -11,98 +11,98 @@ import {
export const settingsMachine = createMachine( export const settingsMachine = createMachine(
{ {
/** @xstate-layout N4IgpgJg5mDOIC5QGUwBc0EsB2VYDpMIAbMAYlnXwEMAHW-Ae2wCNHqAnCHKZNatAFdYAbQAMAXUShajWJizNpIAB6IAbAFZN+AOwAWAIwAOYwE4AzGYBM+-ZosAaEAE9Eh62LP51ls+v0LMWt1awMAX3DnVAweAiJSCio6BjQACzAAWzAAYUZiRg5xKSQQWXlFbGU1BA9vQ0N1CwCxdVbdY1DnNwQzPp8zTTFje1D1QwtjSOj0LFx4knJKNHxMxggwYh58DYAzakFiNABVbAVi5XKFTCVSmotNY3w7YysHRuNDTXV1bvdG7w-IKTcbaazWCzTEAxOZ4QiLJIrFL4dJZMAXUpXSrVDTGazPMQPR4GXRBAx-XoGfDWIadMx4n6EqEwuLwxLLVbrTbbNKYKBpLb8tAAUWgcAxMjk11uoHumn0+DEw2sJkMulCgWsFL6YnwfX0ELsYg61jMumZs1ZCXIACU4OgAATLWGiSSXKXYu4aLz4UwWBr6DqBYYUzSePXqUlBLxmyZmC2xeZs8gxB3UYjEJ2W+YSsoem5VL0IKy6z6EsJifQ2Czq0MTHzq8Yjfz6MQmBMu5NkABUuaxBZxCDD+DD5lJgUjxssFP0xl0I+0pm06uMmg8kSiIGwXPgpRZ83dFQHRYAtA0LCO2tZjGIHJNdB5fq5EK3dc1OsNGkrA+oO1bFoe0qFrKiAnlol7BDed5zo+FK+Doc7qhCNaVv4UwbkAA */ /** @xstate-layout N4IgpgJg5mDOIC5QGUwBc0EsB2VYDpMIAbMAYlnXwEMAHW-Ae2wCNHqAnCHKZNatAFdYAbQAMAXUShajWJizNpIAB6IALAFYAnPgBMARgDsBsQDY969QGYjmzQBoQAT0SnrADnwePY61r0PAwNtMyMAX3CnVAweAiJSCio6BjQACzAAWzAAYUZiRg5xKSQQWXlFbGU1BD1PfFtfE3UzTUNNaydXBCD1b209PTEPTTMtdQNNSOj0LFx4knJKNHxMxggwYh58DYAzakFiNABVbAVi5XKFTCVSmsGxfCMPM08PQaDNU0cXRG1tLwedTaKxif7+UJTKIgGJzPCERZJFYpfDpLJgC6lK6VaqIEx6fBmCw2Do2IJ6MxdRDvTT4MRDdRGEzWbQ6ELTGGzOIIxLLVbrTbbNKYKBpLaitAAUWgcExMjk11uoBqVgM3jMYhsAIMrVs6ipPWChOeYhC9KMFhGHNh3IS5AASnB0AACZZw0SSS4KnF3PFafADTV1YZ2IxiH7dNpGfCaIzAgE+IzWMzBa1c+Y88gxZ3UYjEV3pvBysrem5VX0IFq0y3aTXWOp6JmU34IKMxuz0joGEYWsxp2IZu1kABUxexZdxtRG+EmQMZmne3dNBs0jKewLBsbCwI81n77vwtDAHHksDhBYHeDIEGYYEI2AAbowANZ3o8nzBnm3zMelpWqRAAFp62sJ4jEsZ4AT0UJGwjPFzH6cwNW0AwWXpbRImhbABXgUpvzwL0KgnCtgJMMCII8KCYLsA11EGOkXneDxmXMCk92hfCFlIQjFXLZUgLjddWhaFkgRCaxOhbEYzBnXwXkmOjAjjfduXfU9zzdOIeJ9fiEEA6ckwMClQ2BFpmJXMF9DjYI6hZfxmMw8IgA */
id: 'Settings', id: 'Settings',
predictableActionArguments: true, predictableActionArguments: true,
context: {} as ReturnType<typeof createSettings>, context: {} as ReturnType<typeof createSettings>,
initial: 'idle', initial: 'idle',
states: { states: {
idle: { idle: {
entry: ['setThemeClass', 'setClientSideSceneUnits', 'persistSettings'], entry: ['setThemeClass', 'setClientSideSceneUnits'],
on: { on: {
'*': { '*': {
target: 'idle', target: 'persisting settings',
internal: true, actions: ['setSettingAtLevel', 'toastSuccess'],
actions: ['setSettingAtLevel', 'toastSuccess', 'persistSettings'],
}, },
'set.app.onboardingStatus': { 'set.app.onboardingStatus': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: ['setSettingAtLevel', 'persistSettings'], // No toast // No toast
actions: ['setSettingAtLevel'],
}, },
'set.app.themeColor': { 'set.app.themeColor': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: ['setSettingAtLevel', 'persistSettings'], // No toast // No toast
actions: ['setSettingAtLevel'],
}, },
'set.modeling.defaultUnit': { 'set.modeling.defaultUnit': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: [ actions: [
'setSettingAtLevel', 'setSettingAtLevel',
'toastSuccess', 'toastSuccess',
'setClientSideSceneUnits', 'setClientSideSceneUnits',
'Execute AST', 'Execute AST',
'persistSettings',
], ],
}, },
'set.app.theme': { 'set.app.theme': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: [ actions: [
'setSettingAtLevel', 'setSettingAtLevel',
'toastSuccess', 'toastSuccess',
'setThemeClass', 'setThemeClass',
'setEngineTheme', 'setEngineTheme',
'persistSettings',
'setClientTheme', 'setClientTheme',
], ],
}, },
'set.modeling.highlightEdges': { 'set.modeling.highlightEdges': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: [ actions: ['setSettingAtLevel', 'toastSuccess', 'setEngineEdges'],
'setSettingAtLevel',
'toastSuccess',
'setEngineEdges',
'persistSettings',
],
}, },
'Reset settings': { 'Reset settings': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: [ actions: [
'resetSettings', 'resetSettings',
'setThemeClass', 'setThemeClass',
'setEngineTheme', 'setEngineTheme',
'setClientSideSceneUnits', 'setClientSideSceneUnits',
'Execute AST', 'Execute AST',
'persistSettings',
'setClientTheme', 'setClientTheme',
], ],
}, },
'Set all settings': { 'Set all settings': {
target: 'idle', target: 'persisting settings',
internal: true,
actions: [ actions: [
'setAllSettings', 'setAllSettings',
'setThemeClass', 'setThemeClass',
'setEngineTheme', 'setEngineTheme',
'setClientSideSceneUnits', 'setClientSideSceneUnits',
'Execute AST', 'Execute AST',
'persistSettings',
'setClientTheme', 'setClientTheme',
], ],
}, },
}, },
}, },
'persisting settings': {
invoke: {
src: 'Persist settings',
id: 'persistSettings',
onDone: 'idle',
},
},
}, },
tsTypes: {} as import('./settingsMachine.typegen').Typegen0, tsTypes: {} as import('./settingsMachine.typegen').Typegen0,
schema: { schema: {

View File

@ -3,7 +3,7 @@ import { Outlet, useNavigate } from 'react-router-dom'
import Introduction from './Introduction' import Introduction from './Introduction'
import Camera from './Camera' import Camera from './Camera'
import Sketching from './Sketching' import Sketching from './Sketching'
import { useCallback } from 'react' import { useCallback, useEffect } from 'react'
import makeUrlPathRelative from '../../lib/makeUrlPathRelative' import makeUrlPathRelative from '../../lib/makeUrlPathRelative'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import Streaming from './Streaming' import Streaming from './Streaming'
@ -94,17 +94,31 @@ export function useNextClick(newStatus: string) {
export function useDismiss() { export function useDismiss() {
const filePath = useAbsoluteFilePath() const filePath = useAbsoluteFilePath()
const { const {
settings: { send }, settings: { state, send },
} = useSettingsAuthContext() } = useSettingsAuthContext()
const navigate = useNavigate() const navigate = useNavigate()
return useCallback(() => { const settingsCallback = useCallback(() => {
send({ send({
type: 'set.app.onboardingStatus', type: 'set.app.onboardingStatus',
data: { level: 'user', value: 'dismissed' }, data: { level: 'user', value: 'dismissed' },
}) })
navigate(filePath) }, [send])
}, [send, navigate, filePath])
/**
* A "listener" for the XState to return to "idle" state
* when the user dismisses the onboarding, using the callback above
*/
useEffect(() => {
if (
state.context.app.onboardingStatus.user === 'dismissed' &&
state.matches('idle')
) {
navigate(filePath)
}
}, [filePath, navigate, state])
return settingsCallback
} }
// Get the 1-indexed step number of the current onboarding step // Get the 1-indexed step number of the current onboarding step