Skip to content
Snippets Groups Projects
Commit 12a83c45 authored by zzzang12's avatar zzzang12
Browse files

Initialize project

parents
Branches
No related tags found
No related merge requests found
Showing
with 346 additions and 0 deletions
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
.Completed {
text-decoration: line-through;
}
import "./App.css";
import React, { useState, useEffect } from "react";
import Statistics from "./Component/Statistics";
import Utils from "./Component/Utils";
import Tasks from "./Component/Tasks";
import TodoContext from "./TodoContext";
function App() {
const [todos, setTodos] = useState([]);
const [numTotalRequests, setNumTotalRequests] = useState(0);
const fetchTodos = async () => {
try {
const response = await fetch("/api/todos");
const result = await response.json();
setTodos(result);
setNumTotalRequests((prevNum) => prevNum + 1);
} catch (error) {
console.error("Error fetching todos:", error);
}
};
useEffect(() => {
fetchTodos();
}, []);
const toggleTodoState = async (id) => {
try {
await fetch(`/api/todos/${id}/toggle`, { method: "PUT" });
fetchTodos();
} catch (error) {
console.error("Error toggling todo state:", error);
}
};
const addTodo = async (content, priority, state) => {
try {
await fetch("/api/todos", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ content, priority, state }),
});
fetchTodos();
} catch (error) {
console.error("Error adding todo:", error);
}
};
const addSubtask = async (parentId, content, priority, state) => {
try {
await fetch(`/api/todos/${parentId}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ content, priority, state }),
});
fetchTodos();
} catch (error) {
console.error("Error adding subtask:", error);
}
};
const removeTodo = async (id) => {
try {
await fetch(`/api/todos/${id}`, { method: "DELETE" });
fetchTodos();
} catch (error) {
console.error("Error removing todo:", error);
}
};
return (
<TodoContext.Provider value={{ todos, numTotalRequests }}>
<div>
<h1>Todo List</h1>
<button onClick={fetchTodos}>Load Todos</button>
<Statistics />
<Utils
addTodo={addTodo}
addSubtask={addSubtask}
removeTodo={removeTodo}
/>
<Tasks toggleTodoState={toggleTodoState} />
</div>
</TodoContext.Provider>
);
}
export default App;
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
import React, { useState, useContext, useEffect } from "react";
import TodoContext from "../TodoContext";
const Statistics = () => {
const { todos, numTotalRequests } = useContext(TodoContext);
const [numTotalTasks, setNumTotalTasks] = useState(0);
const getNumTotalTasks = (todos) => {
let total = 0;
todos.forEach((todo) => {
total += 1;
if (todo.subtasks.length > 0) {
total += getNumTotalTasks(todo.subtasks);
}
});
return total;
};
useEffect(() => {
setNumTotalTasks(getNumTotalTasks(todos));
// eslint-disable-next-line
}, [todos]);
return (
<div>
<p>Total Tasks: {numTotalTasks}</p>
<p>Total Requests: {numTotalRequests}</p>
</div>
);
};
export default Statistics;
import React, { useContext } from "react";
import TodoContext from "../TodoContext";
const Tasks = ({ toggleTodoState }) => {
const { todos } = useContext(TodoContext);
const toggleSubtaskState = (todo) => {
toggleTodoState(todo._id);
todo.subtasks.forEach((subtask) => toggleSubtaskState(subtask));
};
const renderTasks = (todos) => {
return todos.map((todo) => (
<li key={todo._id}>
<div className={todo.state ? "Completed" : ""}>
<input
type="checkbox"
checked={todo.state}
onChange={() => toggleSubtaskState(todo)}
/>
{todo.content} / {todo.priority}
</div>
{todo.subtasks.length > 0 && <ul>{renderTasks(todo.subtasks)}</ul>}
</li>
));
};
return (
<div>
<ul>{renderTasks(todos)}</ul>
</div>
);
};
export default Tasks;
import React, { useState } from "react";
const Utils = ({ addTodo, addSubtask, removeTodo }) => {
const [todoContent, setTodoContent] = useState("");
const [todoPriority, setTodoPriority] = useState("");
const [parentId, setParentId] = useState("");
const [subtaskContent, setSubtaskContent] = useState("");
const [subtaskPriority, setSubtaskPriority] = useState("");
const [deleteId, setDeleteId] = useState("");
const handleAddTodo = () => {
addTodo(todoContent, todoPriority, false);
setTodoContent("");
setTodoPriority("");
};
const handleAddSubtask = () => {
addSubtask(parentId, subtaskContent, subtaskPriority, false);
setParentId("");
setSubtaskContent("");
setSubtaskPriority("");
};
const handleRemoveTodo = () => {
removeTodo(deleteId);
setDeleteId("");
};
return (
<div>
<form onSubmit={handleAddTodo}>
<input
type="text"
placeholder="Content"
value={todoContent}
onChange={(e) => setTodoContent(e.target.value)}
/>
<input
type="text"
placeholder="Priority"
value={todoPriority}
onChange={(e) => setTodoPriority(e.target.value)}
/>
<button type="submit">Add Todo</button>
</form>
<form onSubmit={handleAddSubtask}>
<input
type="text"
placeholder="Parent ID"
value={parentId}
onChange={(e) => setParentId(e.target.value)}
/>
<input
type="text"
placeholder="Content"
value={subtaskContent}
onChange={(e) => setSubtaskContent(e.target.value)}
/>
<input
type="text"
placeholder="Priority"
value={subtaskPriority}
onChange={(e) => setSubtaskPriority(e.target.value)}
/>
<button type="submit">Add Subtask</button>
</form>
<form onSubmit={handleRemoveTodo}>
<input
type="text"
placeholder="Delete ID"
value={deleteId}
onChange={(e) => setDeleteId(e.target.value)}
/>
<button type="submit">Remove Todo</button>
</form>
</div>
);
};
export default Utils;
import { createContext } from "react";
const TodoContext = createContext();
export default TodoContext;
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<>
<App />
</>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
\ No newline at end of file
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
createProxyMiddleware("/api", {
target: "http://localhost:3080",
changeOrigin: true,
})
);
};
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment