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:
@ -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),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -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}`
|
||||||
|
|
||||||
|
@ -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: {
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user