Integrated very basic firebase database into app

This commit is contained in:
Peter 2021-11-22 02:03:24 +08:00 committed by peter
parent be62724b91
commit 26e1b1dc2f
10 changed files with 16006 additions and 41 deletions

3
.gitignore vendored
View File

@ -21,3 +21,6 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# Secret
firebaseconfig.js

View File

@ -1,3 +1,3 @@
# Todo list # Todo list
React intro React and firebase intro

15876
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"firebase": "^9.5.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",

View File

@ -1,5 +0,0 @@
const RESET_ACTION = {
type: "RESET",
};
export default RESET_ACTION;

3
src/action.js Normal file
View File

@ -0,0 +1,3 @@
export const RESET_ACTION = {
type: "RESET",
};

View File

@ -1,5 +1,6 @@
import React, { useReducer, useState } from "react"; import React, { useReducer, useState } from "react";
import RESET_ACTION from "./RESET_ACTION"; import { RESET_ACTION } from "./action";
import { dbWriteTask, newTaskId } from "./firebase";
export function AddTask(props) { export function AddTask(props) {
const [showForm, setShowForm] = useState(false); const [showForm, setShowForm] = useState(false);
@ -23,11 +24,19 @@ export function AddTask(props) {
function AddTaskForm(props) { function AddTaskForm(props) {
const { addTask, show, toggleForm } = props; const { addTask, show, toggleForm } = props;
const INITIAL_STATE = { name: "", description: "", date: "" }; const INITIAL_STATE = {
done: false,
name: "",
description: "",
date: "",
taskId: -1,
};
const reducer = (state, event) => { const reducer = (state, event) => {
if (event.type === RESET_ACTION.type) { switch (event.type) {
case RESET_ACTION.type:
return INITIAL_STATE; return INITIAL_STATE;
} else { default:
// Form
return { ...state, [event.target.name]: event.target.value }; return { ...state, [event.target.name]: event.target.value };
} }
}; };
@ -38,8 +47,9 @@ function AddTaskForm(props) {
} }
const handleSubmit = (event) => { const handleSubmit = (event) => {
console.log(task); task.taskId = newTaskId();
addTask(task); addTask(task);
dbWriteTask(task);
setTask(RESET_ACTION); setTask(RESET_ACTION);
event.preventDefault(); event.preventDefault();
}; };

36
src/firebase.js Normal file
View File

@ -0,0 +1,36 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { firebaseConfig } from "./firebaseconfig";
import { getDatabase, ref, onValue, set, get, remove } from "firebase/database";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Get a reference to the database service
const database = getDatabase(app);
const taskIdRef = ref(database, "taskId");
var currentTaskId;
onValue(taskIdRef, (snapshot) => {
currentTaskId = snapshot.val();
});
export function newTaskId() {
const value = currentTaskId;
set(taskIdRef, value + 1);
return value;
}
export function dbWriteTask(task) {
set(ref(database, "tasks/" + task.taskId), task);
}
export function dbDeleteTask(task) {
remove(ref(database, "tasks/" + task.taskId));
}
export async function dbGetTasks() {
return get(ref(database, "tasks"));
}

View File

@ -1,31 +1,63 @@
import React, { useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import ReactDom from "react-dom"; import ReactDom from "react-dom";
import AddTask from "./addtask"; import AddTask from "./addtask";
import { dbDeleteTask, dbGetTasks } from "./firebase";
import { Task, TaskList } from "./tasklist"; import { Task, TaskList } from "./tasklist";
// Example task // Example task
// { name: "example task", description: "Amogus sus" }; // { name: "example task", description: "Amogus sus" };
function Root() { function Root() {
const [taskNumber, setTaskNumber] = useState(0);
const [tasks, setTasks] = useState([]); const [tasks, setTasks] = useState([]);
const addNewTask = (props) => { const addTask = useCallback(
(props) => {
setTasks((tasks) => [ setTasks((tasks) => [
...tasks, ...tasks,
<Task <Task
{...props} task={props}
key={taskNumber} key={props.taskId}
taskId={taskNumber}
deleteTask={deleteTask} deleteTask={deleteTask}
/>, />,
]); ]);
setTaskNumber((taskNumber) => taskNumber + 1); },
[setTasks]
);
const deleteTask = (task) => {
dbDeleteTask(task);
setTasks((tasks) =>
tasks.filter(
(otherTask) => otherTask.props.task.taskId !== task.taskId
)
);
}; };
const deleteTask = (id) => { // Run on startup - load tasks from firebase db.
setTasks((tasks) => tasks.filter((task) => task.props.taskId !== id)); useEffect(() => {
}; async function initializeTasks() {
let snapshot;
try {
snapshot = await dbGetTasks();
} catch (e) {
console.error(e);
}
let tasks = {};
if (snapshot.exists()) {
tasks = snapshot.val();
}
if (tasks) {
// eslint-disable-next-line
for (const [_, value] of Object.entries(tasks)) {
addTask(value);
}
}
}
initializeTasks();
}, [addTask]);
return ( return (
<div className="container mt-3"> <div className="container mt-3">
@ -33,7 +65,7 @@ function Root() {
<h1>Task list</h1> <h1>Task list</h1>
</div> </div>
<section> <section>
<AddTask addTask={addNewTask} /> <AddTask addTask={addTask} />
<h1>Tasks</h1> <h1>Tasks</h1>
<TaskList tasks={tasks} /> <TaskList tasks={tasks} />
</section> </section>

View File

@ -1,4 +1,5 @@
import { useState } from "react"; import { useReducer } from "react";
import { dbWriteTask } from "./firebase";
export function TaskList(props) { export function TaskList(props) {
const { tasks } = props; const { tasks } = props;
@ -23,8 +24,16 @@ export function TaskList(props) {
} }
export function Task(props) { export function Task(props) {
const { taskId, name, description, date, deleteTask } = props; const { task: task_, deleteTask } = props;
const [done, setDone] = useState(false);
const reducer = (state, event) => ({ ...state, [event.name]: event.value });
const [task, setTask] = useReducer(reducer, task_);
const setDone = (done) => {
setTask({ name: "done", value: done });
task.done = done; // Need to update variable as well
dbWriteTask(task);
};
const deleteBtn = (done) => { const deleteBtn = (done) => {
if (done) { if (done) {
@ -34,7 +43,7 @@ export function Task(props) {
type="button" type="button"
className="btn btn-danger" className="btn btn-danger"
value="Delete" value="Delete"
onClick={() => deleteTask(taskId)} onClick={() => deleteTask(task)}
/> />
</td> </td>
); );
@ -47,22 +56,22 @@ export function Task(props) {
<td> <td>
<input <input
type="checkbox" type="checkbox"
value={done} checked={task.done}
onClick={() => setDone(!done)} onChange={() => setDone(!task.done)}
></input> ></input>
</td> </td>
<td> <td>
<p>{name}</p> <p>{task.name}</p>
</td> </td>
<td style={{ whiteSpace: "pre" }}> <td style={{ whiteSpace: "pre" }}>
<p>{description}</p> <p>{task.description}</p>
</td> </td>
<td> <td>
{date === "" {task.date === ""
? "" ? ""
: new Date(Date.parse(date)).toLocaleDateString()} : new Date(Date.parse(task.date)).toLocaleDateString()}
</td> </td>
{deleteBtn(done)} {deleteBtn(task.done)}
</tr> </tr>
); );
} }