import type monaco from 'monaco-editor' import { proxy, ref, subscribe } from 'valtio' import { devtools, subscribeKey } from 'valtio/utils' import { XrplClient } from 'xrpl-client' import { SplitSize } from './actions/persistSplits' declare module 'valtio' { function useSnapshot(p: T): T function snapshot(p: T): T } export interface IFile { name: string language: string content: string compiledValueSnapshot?: string compiledContent?: ArrayBuffer | null compiledWatContent?: string | null lastCompiled?: Date containsErrors?: boolean } export interface FaucetAccountRes { address: string secret: string xrp: number hash: string code: string } export interface IAccount { name: string address: string secret: string xrp: string sequence: number hooks: string[] isLoading: boolean version?: string error?: { message: string code: string } | null } export interface ILog { type: 'error' | 'warning' | 'log' | 'success' message: string | JSX.Element key?: string jsonData?: any timestring?: string link?: string linkText?: string defaultCollapsed?: boolean } export type DeployValue = Record export interface IState { files: IFile[] gistId?: string | null gistOwner?: string | null gistName?: string | null active: number activeWat: number loading: boolean gistLoading: boolean zipLoading: boolean compiling: boolean logs: ILog[] deployLogs: ILog[] transactionLogs: ILog[] scriptLogs: ILog[] editorCtx?: typeof monaco.editor editorSettings: { tabSize: number } splits: { [id: string]: SplitSize } client: XrplClient | null clientStatus: 'offline' | 'online' mainModalOpen: boolean mainModalShowed: boolean accounts: IAccount[] compileOptions: { optimizationLevel: '-O0' | '-O1' | '-O2' | '-O3' | '-O4' | '-Os' strip: boolean } deployValues: DeployValue } // let localStorageState: null | string = null; let initialState: IState = { files: [], // active file index on the Develop page editor active: 0, // Active file index on the Deploy page editor activeWat: 0, loading: false, compiling: false, logs: [], deployLogs: [], transactionLogs: [], scriptLogs: [], editorCtx: undefined, gistId: undefined, gistOwner: undefined, gistName: undefined, gistLoading: false, zipLoading: false, editorSettings: { tabSize: 2 }, splits: {}, client: null, clientStatus: 'offline' as 'offline', mainModalOpen: false, mainModalShowed: false, accounts: [], compileOptions: { optimizationLevel: '-O2', strip: true }, deployValues: {} } let localStorageAccounts: string | null = null let initialAccounts: IAccount[] = [] // TODO: What exactly should we store in localStorage? editorSettings, splits, accounts? // Check if there's a persited accounts in localStorage if (typeof window !== 'undefined') { try { localStorageAccounts = localStorage.getItem('hooksIdeAccounts') } catch (err) { console.log(`localStorage state broken`) localStorage.removeItem('hooksIdeAccounts') } if (localStorageAccounts) { initialAccounts = JSON.parse(localStorageAccounts) } // filter out old accounts (they do not have version property at all) // initialAccounts = initialAccounts.filter(acc => acc.version === '2'); } // Initialize state const state = proxy({ ...initialState, accounts: initialAccounts.length > 0 ? initialAccounts : [], logs: [] }) // Initialize socket connection const client = new XrplClient(`wss://${process.env.NEXT_PUBLIC_TESTNET_URL}`) client.on('online', () => { state.client = ref(client) state.clientStatus = 'online' }) client.on('offline', () => { state.clientStatus = 'offline' }) if (process.env.NODE_ENV !== 'production') { devtools(state, 'Files State') } if (typeof window !== 'undefined') { subscribe(state.accounts, () => { const { accounts } = state const accountsNoLoading = accounts.map(acc => ({ ...acc, isLoading: false })) localStorage.setItem('hooksIdeAccounts', JSON.stringify(accountsNoLoading)) }) const updateActiveWat = () => { const filename = state.files[state.active]?.name const compiledFiles = state.files.filter(file => file.compiledContent) const idx = compiledFiles.findIndex(file => file.name === filename) if (idx !== -1) state.activeWat = idx } subscribeKey(state, 'active', updateActiveWat) subscribeKey(state, 'files', updateActiveWat) } export default state export * from './transactions'