Franknoirot/cmd bar (#328)
* Add XState and naive ActionBar
* Add basic dialog and combobox
* Selectable commands in command bar
* Add a few (broken) file actions
* Home commands
* Add subcommand descriptions, cleanup on navigate
* Refactor: move command creation and types to lib
* Refactor to allow any machine to add commands
* Add auth to command bar, add ability to hide cmds
* Refactor: consolidate theme utilities
* Add settings as machine and command set
* Fix: type tweaks
* Fix: only allow auth to navigate from signin
* Remove zustand-powered settings
* Fix: remove zustand settings from App
* Fix: browser infinite redirect
* Feature: allow commands to be hidden per-platform
* Fix: tsc errors
* Fix: hide default project directory from cmd bar
* Polish: transitions, css tweaks
* Feature: label current value in options settings
* Fix broken debug panel UI
* Refactor: move settings toasts to actions
* Tweak: css rounding
* Fix: set default directory recursion and reload 🐞
* Refactor: move machines to their own directory
* Fix formatting
* @Irev-Dev clean-up catches, import cleanup
This commit is contained in:
109
src/machines/authMachine.ts
Normal file
109
src/machines/authMachine.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { createMachine, assign } from 'xstate'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import withBaseURL from '../lib/withBaseURL'
|
||||
import { CommandBarMeta } from '../lib/commands'
|
||||
|
||||
export interface UserContext {
|
||||
user?: Models['User_type']
|
||||
token?: string
|
||||
}
|
||||
|
||||
export type Events =
|
||||
| {
|
||||
type: 'Log out'
|
||||
}
|
||||
| {
|
||||
type: 'Log in'
|
||||
token?: string
|
||||
}
|
||||
|
||||
export const TOKEN_PERSIST_KEY = 'TOKEN_PERSIST_KEY'
|
||||
const persistedToken = localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
|
||||
|
||||
export const authCommandBarMeta: CommandBarMeta = {
|
||||
'Log in': {
|
||||
hide: 'both',
|
||||
},
|
||||
}
|
||||
|
||||
export const authMachine = createMachine<UserContext, Events>(
|
||||
{
|
||||
id: 'Auth',
|
||||
initial: 'checkIfLoggedIn',
|
||||
states: {
|
||||
checkIfLoggedIn: {
|
||||
id: 'check-if-logged-in',
|
||||
invoke: {
|
||||
src: 'getUser',
|
||||
id: 'check-logged-in',
|
||||
onDone: [
|
||||
{
|
||||
target: 'loggedIn',
|
||||
actions: assign({
|
||||
user: (context, event) => event.data,
|
||||
}),
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: 'loggedOut',
|
||||
actions: assign({
|
||||
user: () => undefined,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
loggedIn: {
|
||||
entry: ['goToIndexPage'],
|
||||
on: {
|
||||
'Log out': {
|
||||
target: 'loggedOut',
|
||||
},
|
||||
},
|
||||
},
|
||||
loggedOut: {
|
||||
entry: ['goToSignInPage'],
|
||||
on: {
|
||||
'Log in': {
|
||||
target: 'checkIfLoggedIn',
|
||||
actions: assign({
|
||||
token: (_, event) => {
|
||||
const token = event.token || ''
|
||||
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
||||
return token
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: { events: {} as { type: 'Log out' } | { type: 'Log in' } },
|
||||
predictableActionArguments: true,
|
||||
preserveActionOrder: true,
|
||||
context: { token: persistedToken },
|
||||
},
|
||||
{
|
||||
actions: {},
|
||||
services: { getUser },
|
||||
guards: {},
|
||||
delays: {},
|
||||
}
|
||||
)
|
||||
|
||||
async function getUser(context: UserContext) {
|
||||
const url = withBaseURL('/user')
|
||||
const headers: { [key: string]: string } = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
if (!context.token && '__TAURI__' in window) throw 'not log in'
|
||||
if (context.token) headers['Authorization'] = `Bearer ${context.token}`
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers,
|
||||
})
|
||||
const user = await response.json()
|
||||
if ('error_code' in user) throw new Error(user.message)
|
||||
return user
|
||||
}
|
Reference in New Issue
Block a user