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*
yarn-debug.log*
yarn-error.log*
# Secret
firebaseconfig.js

View File

@ -1,3 +1,3 @@
# 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/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"firebase": "^9.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"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 RESET_ACTION from "./RESET_ACTION";
import { RESET_ACTION } from "./action";
import { dbWriteTask, newTaskId } from "./firebase";
export function AddTask(props) {
const [showForm, setShowForm] = useState(false);
@ -23,11 +24,19 @@ export function AddTask(props) {
function AddTaskForm(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) => {
if (event.type === RESET_ACTION.type) {
switch (event.type) {
case RESET_ACTION.type:
return INITIAL_STATE;
} else {
default:
// Form
return { ...state, [event.target.name]: event.target.value };
}
};
@ -38,8 +47,9 @@ function AddTaskForm(props) {
}
const handleSubmit = (event) => {
console.log(task);
task.taskId = newTaskId();
addTask(task);
dbWriteTask(task);
setTask(RESET_ACTION);
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 AddTask from "./addtask";
import { dbDeleteTask, dbGetTasks } from "./firebase";
import { Task, TaskList } from "./tasklist";
// Example task
// { name: "example task", description: "Amogus sus" };
function Root() {
const [taskNumber, setTaskNumber] = useState(0);
const [tasks, setTasks] = useState([]);
const addNewTask = (props) => {
const addTask = useCallback(
(props) => {
setTasks((tasks) => [
...tasks,
<Task
{...props}
key={taskNumber}
taskId={taskNumber}
task={props}
key={props.taskId}
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) => {
setTasks((tasks) => tasks.filter((task) => task.props.taskId !== id));
};
// Run on startup - load tasks from firebase db.
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 (
<div className="container mt-3">
@ -33,7 +65,7 @@ function Root() {
<h1>Task list</h1>
</div>
<section>
<AddTask addTask={addNewTask} />
<AddTask addTask={addTask} />
<h1>Tasks</h1>
<TaskList tasks={tasks} />
</section>

View File

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