diff --git a/backend/main.go b/backend/main.go index bca2a29..9e373d4 100644 --- a/backend/main.go +++ b/backend/main.go @@ -1,13 +1,85 @@ package main -import "net/http" +import ( + "encoding/json" + "net/http" +) + +// define the Model for a To Do item +type ToDoItem struct { + Title string `json:"title"` + Description string `json:"description"` +} + +// store ToDoItem using a slice named ToDoItems +var ToDoItems []ToDoItem func main() { // Your code here + http.HandleFunc("/", ToDoListHandler) + http.ListenAndServe(":8080", nil) + } func ToDoListHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - // Your code here + if r.Method == http.MethodOptions { + w.WriteHeader(http.StatusOK) + return + } + + // define what function to call if we get a GET request + if r.Method == http.MethodGet { + // define what function to call if we get a GET request + GetList(w, r) + } else if r.Method == http.MethodPost { + // define what function to call if we get a POST request + AddToList(w, r) + } else { + // error handling for if we recieve any other kind of requesy + http.Error(w, "Invalid Method", http.StatusMethodNotAllowed) + + } + +} + +func GetList(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + // return empty slice to avoid null map error on frontend + if len(ToDoItems) == 0 { + _, _ = w.Write([]byte("[]")) + return + } + + // return the to do items or an error if there is one + if err := json.NewEncoder(w).Encode(ToDoItems); err != nil { + http.Error(w, `{"error": "Internal Server Error"}`, http.StatusInternalServerError) + } +} + +func AddToList(w http.ResponseWriter, r *http.Request) { + var newToDo ToDoItem // initialise new to do item + + // check if the givn to do can be decoded into a ToDoItem + if err := json.NewDecoder(r.Body).Decode(&newToDo); err != nil { + // if it cannot we return a invalid input error + http.Error(w, "Invalid Input", http.StatusBadRequest) + return + } + + // check if title or description are empty + if newToDo.Title == "" || newToDo.Description == "" { + // if they are we return a bad request + http.Error(w, "Title and Description are required fields", http.StatusBadRequest) + return + } + + // append the new item into memory/ storage if all is well + ToDoItems = append(ToDoItems, newToDo) + + // return an OK status + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(ToDoItems) } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9f3281b..4a2bfe9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "@types/react-dom": "^18.2.14", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-scripts": "5.0.1", + "react-scripts": "^5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" } @@ -14467,6 +14467,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "license": "MIT", "dependencies": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", diff --git a/frontend/package.json b/frontend/package.json index 6133c53..10b0ece 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,7 @@ "@types/react-dom": "^18.2.14", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-scripts": "5.0.1", + "react-scripts": "^5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5396cf0..55ab8e8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,6 +4,8 @@ import Todo, { TodoType } from './Todo'; function App() { const [todos, setTodos] = useState([]); + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); // Initially fetch todo useEffect(() => { @@ -24,6 +26,39 @@ function App() { fetchTodos() }, []); + // handle posting a new To-Do + const postToDo = async () => { + if (!title || !description) { + alert("Title and description are required!"); + return; + } + + const newToDo = { title, description }; + + try { + const response = await fetch('http://localhost:8080/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(newToDo), + }); + + if (!response.ok) { + const errorMessage = await response.text(); + console.log(errorMessage); + } + + // update the list with the new item + const updatedTodos = await response.json(); + setTodos(updatedTodos); + + } catch (error) { + console.log(error); + } +}; + + return (
@@ -42,9 +77,9 @@ function App() {

Add a Todo

- - - + setTitle(e.target.value)} placeholder="Title" name="title" autoFocus={true} /> + setDescription(e.target.value)} placeholder="Description" name="description" /> +
);