Created
March 4, 2019 22:31
-
-
Save farism/06840d8568b183b6b4ad9e0a42a5a02c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from 'fs' | |
import { createContext, useReducer } from 'react' | |
import { array, option } from 'fp-ts' | |
import actionCreatorFactory from 'typescript-fsa' | |
import { isType } from 'typescript-fsa' | |
import { Action } from 'redux' | |
import { omit } from 'ramda' | |
import { File } from './File' | |
export interface State { | |
openFiles: { | |
[key: string]: File | |
} | |
selectedFile: option.Option<string> | |
} | |
const actionCreator = actionCreatorFactory('state') | |
interface CloseFilePayload { | |
file: File | |
} | |
interface OpenFilePayload { | |
path: string | |
} | |
interface SaveFilePayload { | |
file: File | |
} | |
interface SelectFilePayload { | |
file: File | |
} | |
export const closeFile = actionCreator<CloseFilePayload>('CLOSE_FILE') | |
export const openFile = actionCreator<OpenFilePayload>('OPEN_FILE') | |
export const saveFile = actionCreator<SaveFilePayload>('SAVE_FILE') | |
export const selectFile = actionCreator<SelectFilePayload>('SELECT_FILE') | |
export const defaultState = (): State => { | |
return { | |
openFiles: {}, | |
selectedFile: option.none, | |
} | |
} | |
export const closeFileReducer = (state: State, { file }: CloseFilePayload) => { | |
const path = file.path | |
const fileToClose = state.openFiles[path] | |
const openFiles = omit([path], state.openFiles) | |
// no open files remaining, clear the state | |
if (Object.keys(openFiles).length === 0) { | |
return { | |
...state, | |
openFiles: {}, | |
selectedFile: option.none, | |
} | |
} | |
// if the selectedFile is being closed, change it to something else | |
if (fileToClose.path === state.selectedFile.getOrElse('')) { | |
return { | |
...state, | |
openFiles: openFiles, | |
selectedFile: option.some(Object.values(openFiles)[0].path), | |
} | |
} | |
return { | |
...state, | |
openFiles, | |
} | |
} | |
export const openFileReducer = (state: State, { path }: OpenFilePayload) => { | |
// file is already open, set it to be the selectedFile | |
if (state.openFiles[path]) { | |
return { | |
...state, | |
selectedFile: option.some(path), | |
} | |
} | |
const content = fs.readFileSync(path).toString() | |
const file = { | |
path, | |
content, | |
name: array.last(path.split('/')).getOrElse(''), | |
} | |
return { | |
...state, | |
openFiles: { | |
...state.openFiles, | |
[path]: file, | |
}, | |
selectedFile: option.some(path), | |
} | |
} | |
export const saveFileReducer = (state: State, { file }: SaveFilePayload) => { | |
fs.writeFileSync(file.path, file.content) | |
return { | |
...state, | |
openFiles: { | |
[file.path]: file, | |
}, | |
} | |
} | |
export const selectFileReducer = (state: State, { file }: SaveFilePayload) => { | |
return { | |
...state, | |
selectedFile: option.some(file.path), | |
} | |
} | |
export const reducer = (state: State, action: Action): State => { | |
if (isType(action, closeFile)) { | |
return closeFileReducer(state, action.payload) | |
} else if (isType(action, openFile)) { | |
return openFileReducer(state, action.payload) | |
} else if (isType(action, saveFile)) { | |
return saveFileReducer(state, action.payload) | |
} else if (isType(action, selectFile)) { | |
return selectFileReducer(state, action.payload) | |
} | |
return state | |
} | |
export const useState = (initialState: State = defaultState()) => { | |
const [state, dispatch] = useReducer(reducer, initialState) | |
return { | |
state, | |
actions: { | |
closeFile: (payload: CloseFilePayload) => { | |
dispatch(closeFile(payload)) | |
}, | |
openFile: (payload: OpenFilePayload) => { | |
dispatch(openFile(payload)) | |
}, | |
saveFile: (payload: SaveFilePayload) => { | |
dispatch(saveFile(payload)) | |
}, | |
selectFile: (payload: SelectFilePayload) => { | |
dispatch(selectFile(payload)) | |
}, | |
}, | |
} | |
} | |
export const { Provider, Consumer } = createContext({ | |
state: defaultState(), | |
actions: { | |
closeFile: (p: CloseFilePayload) => {}, | |
openFile: (p: OpenFilePayload) => {}, | |
saveFile: (p: SaveFilePayload) => {}, | |
selectFile: (p: SelectFilePayload) => {}, | |
}, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment