Skip to content

Commit

Permalink
Move demo state to context (#18)
Browse files Browse the repository at this point in the history
* remove unncessary useEffect

* disable eslint rule no-unused-vars

* feat: add generateRealisticDevDayState to SavedFunctionsContext

* feat: add useCallback hook to create functions

* chore: cleanup old code

* fix: remove extra spacing in the code
  • Loading branch information
ozhanefemeral authored Jul 28, 2024
1 parent af650d3 commit 905804f
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 127 deletions.
9 changes: 4 additions & 5 deletions apps/next/app/features/code-generator/CodeGenerator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ export const CodeGenerator: React.FC = () => {
const { saveCurrentState } = useSavedFunctions();

const isEmpty = state.blocks.length === 0;
const outputWithBreakLine = code.replace(/;/g, ";\n").replace(/{/g, "{\n");

const handleSave = (name: string) => {
saveCurrentState(name, state);
navigator.clipboard.writeText(outputWithBreakLine);
navigator.clipboard.writeText(code);
};

const handleClear = () => {
setState({
blocks: [],
variables: [],
isAsync: false
isAsync: false,
});
};

Expand All @@ -34,7 +33,7 @@ export const CodeGenerator: React.FC = () => {
<SortableBlockList />
</div>
<div className="col-span-1">
<CodeViewer code={outputWithBreakLine} />
<CodeViewer code={code} />
</div>
<div className="col-span-2 mt-auto flex justify-end gap-x-4 items-end">
<SaveDialog onSave={handleSave} isEmpty={isEmpty} />
Expand All @@ -49,4 +48,4 @@ export const CodeGenerator: React.FC = () => {
</div>
</section>
);
};
};
28 changes: 19 additions & 9 deletions apps/next/components/SearchDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useCallback } from "react";
import {
Dialog,
DialogContent,
Expand All @@ -9,7 +9,11 @@ import {
} from "@ui/dialog";
import { Input } from "@ui/input";
import { Button } from "@ui/button";
import { CodebaseInfo, createFunctionCallBlock, FunctionInfo } from "@ozhanefe/ts-codegenerator";
import {
CodebaseInfo,
createFunctionCallBlock,
FunctionInfo,
} from "@ozhanefe/ts-codegenerator";
import { useCodeGenerator } from "@/contexts/CodeGeneratorContext";
import { KeyCombinationLabel } from "@ui/key-combination-label";

Expand All @@ -23,6 +27,15 @@ export const SearchDialog: React.FC<SearchDialogProps> = ({ codebaseInfo }) => {
const [searchResults, setSearchResults] = useState<FunctionInfo[]>([]);
const { state, setState } = useCodeGenerator();

const addFunction = useCallback(
(func: FunctionInfo) => {
const { state: newState } = createFunctionCallBlock(func, state);

setState(newState);
},
[state, setState]
);

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
Expand All @@ -34,8 +47,7 @@ export const SearchDialog: React.FC<SearchDialogProps> = ({ codebaseInfo }) => {
event.preventDefault();
const index = parseInt(event.key) - 1;
if (index < searchResults.length) {
const {state: newState} = createFunctionCallBlock(searchResults[index], state);
setState(newState);
addFunction(searchResults[index]);
}
} else if (event.key === "Escape") {
setOpen(false);
Expand All @@ -47,7 +59,7 @@ export const SearchDialog: React.FC<SearchDialogProps> = ({ codebaseInfo }) => {
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, [open, searchResults]);
}, [open, searchResults, state]);

useEffect(() => {
if (searchQuery === "") {
Expand Down Expand Up @@ -99,14 +111,12 @@ export const SearchDialog: React.FC<SearchDialogProps> = ({ codebaseInfo }) => {
</code>
</p>

<Button onClick={() => createFunctionCallBlock(result, state)}>
Add
</Button>
<Button onClick={() => addFunction(result)}>Add</Button>
</div>
))
)}
</div>
</DialogContent>
</Dialog>
);
};
};
118 changes: 13 additions & 105 deletions apps/next/contexts/CodeGeneratorContext.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
/* eslint-disable no-unused-vars */
import { CodeGeneratorState, generateCode } from "@ozhanefe/ts-codegenerator";
import {
CodeBlock,
CodeGeneratorState,
ElseIfBlock,
FunctionCallBlock,
generateCode,
IfBlock,
WhileLoopBlock
} from "@ozhanefe/ts-codegenerator";
import {
PropsWithChildren,
createContext,
Dispatch,
PropsWithChildren,
SetStateAction,
useContext,
useEffect,
useState,
} from "react";

interface Context {
state: CodeGeneratorState;
setState: (state: CodeGeneratorState) => void;
setState: Dispatch<SetStateAction<CodeGeneratorState>>;
code: string;
}

const CodeGeneratorContext = createContext<Context>({
state: {
blocks: [],
variables: [],
isAsync: false
isAsync: false,
},
setState: () => {},
code: "",
Expand All @@ -35,27 +28,23 @@ const CodeGeneratorContext = createContext<Context>({
export const CodeGeneratorProvider: React.FC<PropsWithChildren> = ({
children,
}) => {
const [state, setState] = useState<CodeGeneratorState>(generateRealisticDevDayState());
const [state, setState] = useState<CodeGeneratorState>({
blocks: [],
variables: [],
isAsync: false,
});
const [code, setCode] = useState<string>("");

useEffect(() => {
const initializeTsMorph = async () => {

};

initializeTsMorph();
}, []);

useEffect(() => {
setCode(generateCode(state.blocks));
setCode(generateCode(state.blocks));
}, [state.blocks]);

return (
<CodeGeneratorContext.Provider
value={{
state,
setState,
code
code,
}}
>
{children}
Expand All @@ -66,84 +55,3 @@ export const CodeGeneratorProvider: React.FC<PropsWithChildren> = ({
export const useCodeGenerator = () => {
return useContext(CodeGeneratorContext);
};

function generateRealisticDevDayState(): CodeGeneratorState {
const wakeUp: FunctionCallBlock = {
functionInfo: { name: "wakeUp", returnType: "void" },
returnVariable: { name: "awake", type: "boolean" },
isAsync: false,
index: 0,
blockType: "functionCall",
};

const getCoffee: FunctionCallBlock = {
functionInfo: { name: "getCoffee", returnType: "void" },
returnVariable: { name: "caffeinated", type: "boolean" },
isAsync: false,
index: 1,
blockType: "functionCall",
};

const writeCode: FunctionCallBlock = {
functionInfo: { name: "writeCode", returnType: "number" },
returnVariable: { name: "linesOfCode", type: "number" },
isAsync: false,
index: 2,
blockType: "functionCall",
};

const ifTired: IfBlock = {
condition: "energyLevel < 30",
thenBlocks: [getCoffee],
elseBlock: { blocks: [writeCode] },
index: 3,
blockType: "if",
};

const coding: WhileLoopBlock = {
condition: "workHours < 8",
loopBlocks: [ifTired],
index: 4,
blockType: "while",
};

const celebrate: FunctionCallBlock = {
functionInfo: { name: "celebrate", returnType: "void" },
returnVariable: { name: "partyTime", type: "boolean" },
isAsync: false,
index: 5,
blockType: "functionCall",
};

const playVideoGames: FunctionCallBlock = {
functionInfo: { name: "playVideoGames", returnType: "void" },
returnVariable: { name: "stressRelieved", type: "boolean" },
isAsync: false,
index: 6,
blockType: "functionCall",
};

const afterWorkMood: IfBlock = {
condition: "linesOfCode > 100",
thenBlocks: [celebrate],
elseBlock: { blocks: [playVideoGames] },
index: 7,
blockType: "if",
};

const blocks: CodeBlock[] = [wakeUp, coding, afterWorkMood];

return {
blocks,
variables: [
{ name: "awake", type: "boolean", index: 0 },
{ name: "energyLevel", type: "number", index: 1 },
{ name: "workHours", type: "number", index: 2 },
{ name: "linesOfCode", type: "number", index: 3 },
{ name: "caffeinated", type: "boolean", index: 4 },
{ name: "partyTime", type: "boolean", index: 5 },
{ name: "stressRelieved", type: "boolean", index: 6 },
],
isAsync: false,
};
}
40 changes: 32 additions & 8 deletions apps/next/contexts/SavedFunctionsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable no-unused-vars */
import React, { createContext, useContext, useState, useEffect } from "react";
import { CodeGeneratorState } from "@ozhanefe/ts-codegenerator";
import { generateRealisticDevDayState } from "@/lib/utils";

interface SavedFunctionState {
name: string;
Expand All @@ -19,34 +21,54 @@ interface SavedFunctionsContextType {
deleteSavedState: (name: string) => void;
}

const SavedFunctionsContext = createContext<SavedFunctionsContextType | undefined>(undefined);
const SavedFunctionsContext = createContext<
SavedFunctionsContextType | undefined
>(undefined);

const initialState = [
{ name: "Demo - Dev Day", state: generateRealisticDevDayState() },
];

export const SavedFunctionsProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const [savedFunctions, setSavedFunctions] = useState<SavedFunctionState[]>([]);
const [savedFunctions, setSavedFunctions] =
useState<SavedFunctionState[]>(initialState);
const [saveDialogOpen, setSaveDialogOpen] = useState(false);
const [loadDialogOpen, setLoadDialogOpen] = useState(false);
const [saveName, setSaveName] = useState("");

useEffect(() => {
const savedFunctionsFromStorage = localStorage.getItem("savedFunctions");
if (savedFunctionsFromStorage) {
if (savedFunctionsFromStorage && savedFunctionsFromStorage !== "[]") {
setSavedFunctions(JSON.parse(savedFunctionsFromStorage));
return;
}

setSavedFunctions(initialState);
}, []);

const saveCurrentState = (name: string, state: CodeGeneratorState) => {
const newState: SavedFunctionState = { name, state };
const updatedSavedFunctions = [...savedFunctions, newState];
setSavedFunctions(updatedSavedFunctions);
localStorage.setItem("savedFunctions", JSON.stringify(updatedSavedFunctions));
localStorage.setItem(
"savedFunctions",
JSON.stringify(updatedSavedFunctions)
);
};

const deleteSavedState = (name: string) => {
const updatedSavedFunctions = savedFunctions.filter((func) => func.name !== name);
const index = savedFunctions.findIndex((func) => func.name === name);
if (index < 1) return;
const updatedSavedFunctions = savedFunctions.filter(
(func) => func.name !== name
);
setSavedFunctions(updatedSavedFunctions);
localStorage.setItem("savedFunctions", JSON.stringify(updatedSavedFunctions));
localStorage.setItem(
"savedFunctions",
JSON.stringify(updatedSavedFunctions)
);
};

return (
Expand All @@ -72,7 +94,9 @@ export const SavedFunctionsProvider: React.FC<React.PropsWithChildren> = ({
export const useSavedFunctions = () => {
const context = useContext(SavedFunctionsContext);
if (context === undefined) {
throw new Error("useSavedFunctions must be used within a SavedFunctionsProvider");
throw new Error(
"useSavedFunctions must be used within a SavedFunctionsProvider"
);
}
return context;
};
};
Loading

0 comments on commit 905804f

Please sign in to comment.