Add sync to gist issue #19 feature and other fixes to global state
This commit is contained in:
136
state.ts
136
state.ts
@@ -1,8 +1,10 @@
|
||||
import { proxy, subscribe } from 'valtio';
|
||||
import { proxy } from 'valtio';
|
||||
import { devtools } from 'valtio/utils';
|
||||
import { Octokit } from '@octokit/core';
|
||||
import type monaco from 'monaco-editor';
|
||||
import toast from 'react-hot-toast';
|
||||
import Router from 'next/router';
|
||||
import type { Session } from 'next-auth';
|
||||
|
||||
const octokit = new Octokit();
|
||||
|
||||
@@ -14,8 +16,12 @@ interface File {
|
||||
|
||||
interface IState {
|
||||
files: File[],
|
||||
gistId?: string | null,
|
||||
gistOwner?: string | null,
|
||||
gistName?: string | null,
|
||||
active: number;
|
||||
loading: boolean;
|
||||
gistLoading: boolean;
|
||||
compiling: boolean;
|
||||
logs: {
|
||||
type: 'error' | 'warning' | 'log',
|
||||
@@ -24,10 +30,11 @@ interface IState {
|
||||
editorCtx?: typeof monaco.editor;
|
||||
editorSettings: {
|
||||
tabSize: number;
|
||||
}
|
||||
},
|
||||
mainModalOpen: boolean;
|
||||
}
|
||||
|
||||
let localStorageState: null | string = null;
|
||||
// let localStorageState: null | string = null;
|
||||
let initialState = {
|
||||
files: [],
|
||||
active: 0,
|
||||
@@ -35,31 +42,38 @@ let initialState = {
|
||||
compiling: false,
|
||||
logs: [],
|
||||
editorCtx: undefined,
|
||||
gistId: undefined,
|
||||
gistOwner: undefined,
|
||||
gistName: undefined,
|
||||
gistLoading: false,
|
||||
editorSettings: {
|
||||
tabSize: 2
|
||||
}
|
||||
},
|
||||
mainModalOpen: false
|
||||
}
|
||||
|
||||
// Check if there's a persited state in localStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorageState = localStorage.getItem('hooksIdeState');
|
||||
} catch (err) {
|
||||
console.log(`localStorage state broken`);
|
||||
localStorage.removeItem('hooksIdeState');
|
||||
}
|
||||
}
|
||||
if (localStorageState) {
|
||||
initialState = JSON.parse(localStorageState);
|
||||
}
|
||||
// if (typeof window !== 'undefined') {
|
||||
// try {
|
||||
// localStorageState = localStorage.getItem('hooksIdeState');
|
||||
// } catch (err) {
|
||||
// console.log(`localStorage state broken`);
|
||||
// localStorage.removeItem('hooksIdeState');
|
||||
// }
|
||||
// }
|
||||
// if (localStorageState) {
|
||||
// initialState = JSON.parse(localStorageState);
|
||||
// }
|
||||
|
||||
// Initialize state
|
||||
export const state = proxy<IState>(initialState);
|
||||
export const state = proxy<IState>({ ...initialState, logs: [] });
|
||||
|
||||
// Fetch content from Githug Gists
|
||||
export const fetchFiles = (gistId: string) => {
|
||||
state.loading = true;
|
||||
if (gistId) {
|
||||
state.logs.push({ type: 'log', message: `Fetching Gist with id: ${gistId}` });
|
||||
|
||||
octokit.request("GET /gists/{gist_id}", { gist_id: gistId }).then(res => {
|
||||
if (res.data.files && Object.keys(res.data.files).length > 0) {
|
||||
const files = Object.keys(res.data.files).map(filename => ({
|
||||
@@ -71,11 +85,17 @@ export const fetchFiles = (gistId: string) => {
|
||||
if (files.length > 0) {
|
||||
state.logs.push({ type: 'log', message: 'Fetched successfully ✅' })
|
||||
state.files = files;
|
||||
state.gistId = gistId;
|
||||
state.gistName = Object.keys(res.data.files)?.[0] || 'untitled';
|
||||
state.gistOwner = res.data.owner?.login;
|
||||
return
|
||||
} else {
|
||||
// Open main modal if now files
|
||||
state.mainModalOpen = true;
|
||||
}
|
||||
return
|
||||
return Router.push({ pathname: '/develop' })
|
||||
}
|
||||
|
||||
state.loading = false;
|
||||
}).catch(err => {
|
||||
state.loading = false;
|
||||
state.logs.push({ type: 'error', message: `Couldn't find Gist with id: ${gistId}` })
|
||||
@@ -87,9 +107,72 @@ export const fetchFiles = (gistId: string) => {
|
||||
// return state.files = initFiles
|
||||
}
|
||||
|
||||
export const syncToGist = async (session?: Session | null, createNewGist?: boolean) => {
|
||||
let files: Record<string, { filename: string, content: string }> = {};
|
||||
state.gistLoading = true;
|
||||
|
||||
if (!session || !session.user) {
|
||||
state.gistLoading = false;
|
||||
return toast.error('You need to be logged in!')
|
||||
}
|
||||
const toastId = toast.loading('Pushing to Gist');
|
||||
if (!state.files || !state.files.length) {
|
||||
state.gistLoading = false;
|
||||
return toast.error(`You need to create some files we can push to gist`, { id: toastId })
|
||||
}
|
||||
if (state.gistId && session?.user.username === state.gistOwner && !createNewGist) {
|
||||
const currentFilesRes = await octokit.request("GET /gists/{gist_id}", { gist_id: state.gistId });
|
||||
if (currentFilesRes.data.files) {
|
||||
Object.keys(currentFilesRes?.data?.files).forEach(filename => {
|
||||
files[`${filename}`] = { filename, content: "" }
|
||||
})
|
||||
}
|
||||
state.files.forEach(file => {
|
||||
files[`${file.name}`] = { filename: file.name, content: file.content }
|
||||
})
|
||||
// Update existing Gist
|
||||
octokit.request("PATCH /gists/{gist_id}", {
|
||||
gist_id: state.gistId, files, headers: {
|
||||
authorization: `token ${session?.accessToken || ''}`
|
||||
}
|
||||
}).then(res => {
|
||||
state.gistLoading = false;
|
||||
return toast.success('Updated to gist successfully!', { id: toastId })
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
state.gistLoading = false;
|
||||
return toast.error(`Could not update Gist, try again later!`, { id: toastId })
|
||||
})
|
||||
} else {
|
||||
// Not Gist of the current user or it isn't Gist yet
|
||||
state.files.forEach(file => {
|
||||
files[`${file.name}`] = { filename: file.name, content: file.content }
|
||||
})
|
||||
octokit.request("POST /gists", {
|
||||
files,
|
||||
public: true,
|
||||
headers: {
|
||||
authorization: `token ${session?.accessToken || ''}`
|
||||
}
|
||||
}).then(res => {
|
||||
state.gistLoading = false;
|
||||
state.gistOwner = res.data.owner?.login;
|
||||
state.gistId = res.data.id;
|
||||
state.gistName = Array.isArray(res.data.files) ? Object.keys(res.data?.files)?.[0] : 'Untitled';
|
||||
Router.push({ pathname: `/develop/${res.data.id}` })
|
||||
return toast.success('Created new gist successfully!', { id: toastId })
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
state.gistLoading = false;
|
||||
return toast.error(`Could not create Gist, try again later!`, { id: toastId })
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const updateEditorSettings = (editorSettings: IState['editorSettings']) => {
|
||||
state.editorCtx?.getModels().forEach(model => {
|
||||
console.log(model.uri)
|
||||
model.updateOptions({
|
||||
...editorSettings
|
||||
})
|
||||
@@ -100,12 +183,9 @@ export const updateEditorSettings = (editorSettings: IState['editorSettings']) =
|
||||
export const saveFile = (value: string) => {
|
||||
const editorModels = state.editorCtx?.getModels();
|
||||
const currentModel = editorModels?.find(editorModel => editorModel.uri.path === `/${state.files[state.active].name}`);
|
||||
console.log(currentModel?.getValue())
|
||||
if (state.files.length > 0) {
|
||||
console.log('häää')
|
||||
state.files[state.active].content = currentModel?.getValue() || '';
|
||||
}
|
||||
console.log(state.files[state.active])
|
||||
toast.success('Saved successfully', { position: 'bottom-center' })
|
||||
}
|
||||
|
||||
@@ -164,9 +244,11 @@ export const compileCode = async (activeId: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
const unsub = devtools(state, 'Files State');
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
devtools(state, 'Files State');
|
||||
}
|
||||
|
||||
subscribe(state, () => {
|
||||
const { editorCtx, ...storedState } = state;
|
||||
localStorage.setItem('hooksIdeState', JSON.stringify(storedState))
|
||||
});
|
||||
// subscribe(state, () => {
|
||||
// const { editorCtx, ...storedState } = state;
|
||||
// localStorage.setItem('hooksIdeState', JSON.stringify(storedState))
|
||||
// });
|
||||
Reference in New Issue
Block a user