many updates

This commit is contained in:
liyunze 2024-05-09 22:22:10 +08:00
parent a5ea077f88
commit deb9344950
4 changed files with 194 additions and 124 deletions

View file

@ -5,6 +5,7 @@ const configs = (function () {
enableLimit: false, // true or false
limit: 10, // integer
automaticDoneIndex: false, // true or false - Automatically assume first unfinished task is complete
taskName: "task", // string (singular)
pointsName: "points", // string
pointsPerTask: 10, // integer
taskSeparator: [";", ","], // array of strings
@ -12,7 +13,7 @@ const configs = (function () {
headerGoogleFont: true, // true: use google font, false: use system font
taskGoogleFont: true, // true: use google font, false: use system font
displayTaskCount: true, // true or false
enableTaskMaster: false, // true or false
enableTaskMaster: true, // true or false
};
const animation = {
@ -302,50 +303,57 @@ const configs = (function () {
const responses = {
// Responses related to task addition
taskAdded: 'The task(s) "{task}" has been added, {user}!',
taskAdded: 'The {taskName}(s) "{task}" has been added, {user}!',
noTaskAdded:
"Looks like you already hit the limit of incomplete tasks, {user}",
noTaskContent: "Try using !task the-task-you-are-working-on {user}",
"Looks like you already hit the limit of incomplete {taskName}s, {user}",
noTaskContent:
"Try using !task the-{taskName}-you-are-working-on {user}",
duplicateTask:
"Looks like you already have the task '{message}' up there {user}!",
"Looks like you already have the {taskName} '{message}' up there {user}!",
taskEdited:
'Task "{originalTask}" has been edited to "{task}" successfully, {user}',
'{taskName} "{originalTask}" has been edited to "{task}" successfully, {user}',
noTaskEdit: "Try doing !edit [index] [new task] {user}",
nowTask: 'Task "{task}" is now the task you are working on, {user}!',
nowTask:
'{taskName} "{task}" is now the task you are working on, {user}!',
// Grouped by task progression responses
taskNext:
"Good job on finishing the task '{oldTask}'! Now moving onto '{newTask}', {user}!",
nextNoContent: "Try using !next the-task-you-want-to-do-next {user}",
taskNextFailed:
"Unable to perform command with multiple incomplete tasks, {user}!",
"Unable to perform command with multiple incomplete {taskName}s, {user}!",
// Grouped by task deletion responses
clearedMyDone: "All of your completed tasks have been cleared, {user}!",
taskDeleted: 'Task(s) "{task}" has been deleted successfully, {user}',
clearedMyDone:
"All of your completed {taskName}s have been cleared, {user}!",
taskDeleted:
'{taskName}(s) "{task}" has been deleted successfully, {user}',
specifyTaskIndex:
"Try specifying the index of the incomplete task(s) {user}",
"Try specifying the index of the incomplete {taskName}(s) {user}",
clearTasksExceptBroadcaster:
"All tasks have been cleared except for the streamer's, {user}!",
clearedTasks: "All tasks have been cleared, {user}!",
adminDeleteTasks: "All of {mentioned}'s tasks have been deleted",
clearedAll: "All tasks and points have been cleared, {user}!",
"All {taskName}s have been cleared except for the streamer's, {user}!",
clearedTasks: "All {taskName}s have been cleared, {user}!",
adminDeleteTasks: "All of {mentioned}'s {taskName}s have been deleted",
clearedAll: "All {taskName}s and points have been cleared, {user}!",
// Grouped by task completion responses
taskFinished:
'Good job on finishing the task(s) "{task}", {user}! You have earned {pointCount} {pointName} and completed {doneCount} task(s) so far!',
'Good job on finishing the {taskName}(s) "{task}", {user}! You have earned {pointCount} {pointName} and completed {doneCount} {taskName}(s) so far!',
allTasksFinished:
"Good job on finishing all your tasks, {user}! You have completed {doneCount} task(s) so far!",
taskUnfinished: 'Task(s) "{task}" has been unmarked as done, {user}!',
taskAlreadyFinished: "Looks like you already finished that task {user}",
"Good job on finishing all your {taskName}s, {user}! You have completed {doneCount} {taskName}(s) so far!",
taskUnfinished:
'{taskName}(s) "{task}" has been unmarked as done, {user}!',
taskAlreadyFinished:
"Looks like you already finished that {taskName} {user}",
// Grouped by task focus responses
clearFocused: "Task has been unfocused, {user}!",
noFocusedTask: "Looks like you don't have a focused task {user}!",
clearFocused: "{taskName} has been unfocused, {user}!",
noFocusedTask: "Looks like you don't have a focused {taskName} {user}!",
alreadyFocusedTask:
"Looks like you already have that task set to focus {user}!",
onlyOneFocus: "You can only focus one task at a time {user}!",
specifyFocusTask: "Try specifying an incomplete task to focus {user}!",
specifyFocusTask:
"Try specifying an incomplete {taskName} to focus {user}!",
taskFocused: 'Task "{task}" has been focused, {user}!',
// Grouped by task existence responses
@ -363,12 +371,12 @@ const configs = (function () {
// Grouped by count-related responses
checkYourCount:
"You have completed {doneCount} task(s) so far, {user}!",
"You have completed {doneCount} {taskName}(s) so far, {user}!",
checkUserCount:
"{mentioned} has completed {doneCount} task(s) so far, {user}!",
"{mentioned} has completed {doneCount} {taskName}(s) so far, {user}!",
checkAllCount:
"Everyone has completed {doneCount} task(s) so far, {user}!",
noCountAll: "Looks like no one has completed a task yet {user}",
"Everyone has completed {doneCount} {taskName}(s) so far, {user}!",
noCountAll: "Looks like no one has completed a {taskName} yet {user}",
leaderboard: "Leaderboard: {leaderboard}",
setUserTaskCount: "{mentioned} now has {taskCount} tasks!",

View file

@ -5,6 +5,7 @@ const defaultConfigs = (function () {
enableLimit: false, // true or false
limit: 10, // integer
automaticDoneIndex: false, // true or false - Automatically assume first unfinished task is complete
taskName: "task", // string
pointsName: "points", // string
pointsPerTask: 10, // integer
taskSeparator: [";", ","], // array of strings
@ -302,16 +303,18 @@ const defaultConfigs = (function () {
const responses = {
// Responses related to task addition
taskAdded: 'The task(s) "{task}" has been added, {user}!',
taskAdded: 'The {taskName}(s) "{task}" has been added, {user}!',
noTaskAdded:
"Looks like you already hit the limit of incomplete tasks, {user}",
noTaskContent: "Try using !task the-task-you-are-working-on {user}",
"Looks like you already hit the limit of incomplete {taskName}s, {user}",
noTaskContent:
"Try using !task the-{taskName}-you-are-working-on {user}",
duplicateTask:
"Looks like you already have the task '{message}' up there {user}!",
"Looks like you already have the {taskName} '{message}' up there {user}!",
taskEdited:
'Task "{originalTask}" has been edited to "{task}" successfully, {user}',
'{taskName} "{originalTask}" has been edited to "{task}" successfully, {user}',
noTaskEdit: "Try doing !edit [index] [new task] {user}",
nowTask: 'Task "{task}" is now the task you are working on, {user}!',
nowTask:
'{taskName} "{task}" is now the task you are working on, {user}!',
// Grouped by task progression responses
taskNext:
@ -321,31 +324,36 @@ const defaultConfigs = (function () {
"Unable to perform command with multiple incomplete tasks, {user}!",
// Grouped by task deletion responses
clearedMyDone: "All of your completed tasks have been cleared, {user}!",
taskDeleted: 'Task(s) "{task}" has been deleted successfully, {user}',
clearedMyDone:
"All of your completed {taskName}s have been cleared, {user}!",
taskDeleted:
'{taskName}(s) "{task}" has been deleted successfully, {user}',
specifyTaskIndex:
"Try specifying the index of the incomplete task(s) {user}",
"Try specifying the index of the incomplete {taskName}(s) {user}",
clearTasksExceptBroadcaster:
"All tasks have been cleared except for the streamer's, {user}!",
clearedTasks: "All tasks have been cleared, {user}!",
adminDeleteTasks: "All of {mentioned}'s tasks have been deleted",
clearedAll: "All tasks and points have been cleared, {user}!",
"All {taskName}s have been cleared except for the streamer's, {user}!",
clearedTasks: "All {taskName}s have been cleared, {user}!",
adminDeleteTasks: "All of {mentioned}'s {taskName}s have been deleted",
clearedAll: "All {taskName}s and points have been cleared, {user}!",
// Grouped by task completion responses
taskFinished:
'Good job on finishing the task(s) "{task}", {user}! You have earned {pointCount} {pointName} and completed {doneCount} task(s) so far!',
'Good job on finishing the {taskName}(s) "{task}", {user}! You have earned {pointCount} {pointName} and completed {doneCount} {taskName}(s) so far!',
allTasksFinished:
"Good job on finishing all your tasks, {user}! You have completed {doneCount} task(s) so far!",
taskUnfinished: 'Task(s) "{task}" has been unmarked as done, {user}!',
taskAlreadyFinished: "Looks like you already finished that task {user}",
"Good job on finishing all your {taskName}s, {user}! You have completed {doneCount} {taskName}(s) so far!",
taskUnfinished:
'{taskName}(s) "{task}" has been unmarked as done, {user}!',
taskAlreadyFinished:
"Looks like you already finished that {taskName} {user}",
// Grouped by task focus responses
clearFocused: "Task has been unfocused, {user}!",
noFocusedTask: "Looks like you don't have a focused task {user}!",
clearFocused: "{taskName} has been unfocused, {user}!",
noFocusedTask: "Looks like you don't have a focused {taskName} {user}!",
alreadyFocusedTask:
"Looks like you already have that task set to focus {user}!",
onlyOneFocus: "You can only focus one task at a time {user}!",
specifyFocusTask: "Try specifying an incomplete task to focus {user}!",
specifyFocusTask:
"Try specifying an incomplete {taskName} to focus {user}!",
taskFocused: 'Task "{task}" has been focused, {user}!',
// Grouped by task existence responses
@ -363,14 +371,14 @@ const defaultConfigs = (function () {
// Grouped by count-related responses
checkYourCount:
"You have completed {doneCount} task(s) so far, {user}!",
"You have completed {doneCount} {taskName}(s) so far, {user}!",
checkUserCount:
"{mentioned} has completed {doneCount} task(s) so far, {user}!",
"{mentioned} has completed {doneCount} {taskName}(s) so far, {user}!",
checkAllCount:
"Everyone has completed {doneCount} task(s) so far, {user}!",
noCountAll: "Looks like no one has completed a task yet {user}",
"Everyone has completed {doneCount} {taskName}(s) so far, {user}!",
noCountAll: "Looks like no one has completed a {taskName} yet {user}",
leaderboard: "Leaderboard: {leaderboard}",
setUserTaskCount: "{mentioned} now has {taskCount} tasks!",
setUserTaskCount: "{mentioned} now has {taskCount} {taskName}s!",
// Grouped by taskmaster-related responses
taskMaster: "{user} Task Master: {taskMaster} [{taskMasterCount}]",

View file

@ -3,6 +3,7 @@ async function processCommand(user, command, message, flags, extra) {
user: user,
message: message,
pointName: getSetting("pointsName"),
taskName: getSetting("taskName"),
};
if (getCommand("addTaskCommands").includes(command)) {
@ -172,7 +173,20 @@ async function processCommand(user, command, message, flags, extra) {
return;
}
return respond(checkRequest.body.reply, params);
// array of incomplete tasks
let incompleteTasks = checkRequest.body.reply.split(" | ");
// respond every 10 tasks
for (let i = 0; i < incompleteTasks.length; i += 10) {
let tasks = incompleteTasks.slice(i, i + 10);
params.tasks = tasks
.join(" | ")
.replaceAll("{taskName}", getSetting("taskName"));
await respond(`{user} {tasks}`, params);
}
// return respond(checkRequest.body.reply, params);
} else {
let mentioned = message.replace("@", "");
let checkRequest = await checkTasks(mentioned);
@ -183,7 +197,16 @@ async function processCommand(user, command, message, flags, extra) {
return;
}
return respond(checkRequest.body.reply, params);
// array of incomplete tasks
let incompleteTasks = checkRequest.body.reply.split(" | ");
// respond every 10 tasks
for (let i = 0; i < incompleteTasks.length; i += 10) {
let tasks = incompleteTasks.slice(i, i + 10);
params.tasks = tasks.join(" | ");
await respond(`{user} {tasks}`, params);
}
}
} else if (getCommand("adminDeleteCommands").includes(command)) {
if (!isMod(flags)) {
@ -215,7 +238,7 @@ async function processCommand(user, command, message, flags, extra) {
return;
}
clearAllDoneTasks();
await clearAllDoneTasks();
respond(getResponse("clearedDone"), params);
return;
} else if (getCommand("adminClearAllCommands").includes(command)) {
@ -224,7 +247,7 @@ async function processCommand(user, command, message, flags, extra) {
return;
}
clearAll();
await clearAll();
respond(getResponse("clearedAll"), params);
return;
} else if (getCommand("clearMyDoneCommands").includes(command)) {
@ -282,7 +305,7 @@ async function processCommand(user, command, message, flags, extra) {
return respond(getResponse("checkUserCount"), params);
}
} else if (getCommand("checkAllCountCommands").includes(command)) {
let count = getBoardTotalTaskCount();
let count = await getBoardTotalTaskCount();
if (count === 0) {
respond(getResponse("noCountAll"), params);
@ -440,16 +463,19 @@ async function processCommand(user, command, message, flags, extra) {
return;
}
points = parseInt(points);
let setUserTaskCountResponse = await setUserTaskCount(mentioned, count);
await setUserTaskCount(mentioned, count);
if (setUserTaskCountResponse.status !== 200) {
respond(setUserTaskCountResponse.body.message, params);
return;
}
params.mentioned = mentioned;
params.pointCount = count;
params.taskCount = count;
respond(getResponse("setUserTaskCount"), params);
respond(setUserTaskCountResponse.body.message, params);
} else if (getCommand("leaderboardCommands").includes(command)) {
let leaderboardResponse = leaderboardTaskCount(5);
let leaderboardResponse = await leaderboardTaskCount(5);
if (leaderboardResponse.status !== 200) {
respond(leaderboardResponse.body.error, params);

View file

@ -16,8 +16,7 @@ DB structure:
- taskmaster
- users
- [username]:
- completeCount
- totalCompleteCount
- taskMasterCompleteCount
- startDate
*/
@ -28,6 +27,11 @@ let scrolling = false;
let primaryAnimation, secondaryAnimation;
const taskSeparator = getSetting("taskSeparator");
var taskListMemory = {
doneTaskCount: 0,
totalTaskCount: 0,
};
const DBHandler = {
db: null,
open: function () {
@ -115,9 +119,6 @@ const DBHandler = {
};
async function transferLocalStorageToIndexedDB() {
// Open the database
await DBHandler.open();
// Get all keys in localStorage
let keys = Object.keys(localStorage);
@ -200,20 +201,17 @@ function hexToRgb(hex) {
*
* @param {string} username
*/
async function addCountToTaskMasterUser(username, count = 1) {
const taskmaster = (await DBHandler.get("taskmaster")) || {
users: {},
startDate: new Date(),
totalCompleteCount: 0,
};
async function addCountToTaskMasterUser(username, count) {
const taskmaster = await DBHandler.get("taskmaster");
if (!taskmaster.users[username.toLowerCase()]) {
taskmaster.users[username.toLowerCase()] = {
completeCount: 0,
taskMasterCompleteCount: 0,
};
}
taskmaster.users[username.toLowerCase()].completeCount += count;
taskmaster.users[username.toLowerCase()].taskMasterCompleteCount +=
parseInt(count);
await DBHandler.set("taskmaster", taskmaster);
}
@ -231,21 +229,28 @@ async function getUserTaskMasterCount(username) {
return 0;
}
return taskmaster.users[username.toLowerCase()].completeCount;
return taskmaster.users[username.toLowerCase()].taskMasterCompleteCount;
}
async function getTaskMasterChampion() {
const taskmaster = await DBHandler.get("taskmaster");
if (!taskmaster.users) {
return null;
}
let champion = {
username: "",
count: 0,
};
for (const user in taskmaster.users) {
if (taskmaster.users[user].completeCount > champion.count) {
if (
user.toLowerCase() === auth.channel &&
taskmaster.users[user].taskMasterCompleteCount > champion.count
) {
champion.username = user;
champion.count = taskmaster.users[user].completeCount;
champion.count = taskmaster.users[user].taskMasterCompleteCount;
}
}
@ -351,19 +356,36 @@ function importStyles() {
*/
async function resetDB() {
await DBHandler.clear();
setupDB();
await setupDB();
}
/**
* Sets up the local storage database.
* Sets up the database with the default values if it does not exist
*/
async function setupDB() {
if (!(await DBHandler.get("tasks"))) {
await DBHandler.set("tasks", {});
}
if (!(await DBHandler.get("counts"))) {
await DBHandler.set("counts", { users: {} });
const keys = ["tasks", "counts", "taskmaster"];
const defaultValues = [
{ ID: "tasks" },
{ ID: "counts", users: {} },
{
ID: "taskmaster",
users: {},
startDate: new Date(),
taskMasterCompleteCount: 0,
},
];
for (let i = 0; i < keys.length; i++) {
let value = await DBHandler.get(keys[i]);
if (!value) {
value = defaultValues[i];
} else if (!value.ID) {
value.ID = keys[i];
}
await DBHandler.set(keys[i], value);
}
return;
}
/**
@ -645,15 +667,15 @@ async function setUserTaskCount(username, value) {
if (!counts.users[username.toLowerCase()]) {
counts.users[username.toLowerCase()] = {
points: 0,
completeCount: 0,
};
}
if (!counts.users[username.toLowerCase()].points) {
counts.users[username.toLowerCase()].points = 0;
if (!counts.users[username.toLowerCase()].completeCount) {
counts.users[username.toLowerCase()].completeCount = 0;
}
counts.users[username.toLowerCase()].taskCount = parseInt(value);
counts.users[username.toLowerCase()].completeCount = parseInt(value);
await DBHandler.set("counts", counts);
@ -831,7 +853,7 @@ async function addTask(username, userColor, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -919,7 +941,7 @@ async function nowTask(username, userColor, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -997,7 +1019,7 @@ async function nowTask(username, userColor, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1092,7 +1114,7 @@ async function focusTask(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1135,7 +1157,7 @@ async function unfocusTask(username) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1238,7 +1260,7 @@ async function removeTask(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
status: 200,
@ -1283,7 +1305,7 @@ async function removeTask(username, task) {
tasks[username].todos.splice(index, 1);
taskListMemory.totalTaskCount--;
await DBHandler.set("tasks", tasks);
renderTaskListToDOM();
await renderTaskListToDOM();
return {
status: 200,
body: {
@ -1436,6 +1458,13 @@ function isInt(value) {
);
}
function clearMemory() {
taskListMemory = {
doneTaskCount: 0,
totalTaskCount: 0,
};
}
/**
* Clears all completed tasks for a given user. If the tasks are successfully cleared, the function returns an object with a status of 200. If the tasks are not cleared due to the user having no tasks, the function returns an object with a status indicating the error and an error message.
*
@ -1462,7 +1491,7 @@ async function clearOwnDoneTasks(username) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1578,7 +1607,7 @@ async function markTaskDone(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
status: 200,
@ -1649,7 +1678,7 @@ async function markTaskDone(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
status: 200,
@ -1691,7 +1720,7 @@ async function markAllTasksAsDone(username) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1779,7 +1808,7 @@ async function markTaskUndone(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1825,7 +1854,7 @@ async function markTaskUndone(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
status: 200,
@ -1841,7 +1870,7 @@ async function markTaskUndone(username, task) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
status: 200,
@ -1933,7 +1962,7 @@ async function editTask(username, message) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -1964,7 +1993,7 @@ async function checkTasks(username) {
status: 0,
body: {
"error message": `@${username} has no tasks`,
error: responses.noTask,
error: getResponse("noTask"),
},
};
}
@ -1974,7 +2003,7 @@ async function checkTasks(username) {
const completedTasks = tasks[username].todos.filter((t) => t.done);
// format incomplete tasks into string: 1. task 1 | 2. task 2 | 3. task 3...
let reply = `@${username} incomplete tasks (${incompleteTasks.length}) : `;
let reply = `incomplete {taskName}(s) (${incompleteTasks.length}) : `;
let taskIndex;
for (let i = 0; i < incompleteTasks.length; i++) {
// get index of task by task name
@ -2089,7 +2118,7 @@ async function clearUserTasks(username) {
await DBHandler.set("tasks", tasks);
if (!scrolling) {
renderTaskListToDOM();
await renderTaskListToDOM();
}
return {
@ -2109,7 +2138,7 @@ async function clearAllDoneTasks() {
}
cancelAnimation();
await DBHandler.set("tasks", tasks);
renderTaskListToDOM();
await renderTaskListToDOM();
return {
status: 200,
@ -2119,18 +2148,18 @@ async function clearAllDoneTasks() {
async function clearAllTasks() {
await DBHandler.set("tasks", {});
cancelAnimation();
renderTaskListToDOM();
await renderTaskListToDOM();
return {
status: 200,
};
}
function clearAll() {
async function clearAll() {
resetDB();
cancelAnimation();
checkToAnimate();
renderTaskListToDOM();
await renderTaskListToDOM();
return {
status: 200,
@ -2158,22 +2187,17 @@ async function clearAllExceptStreamer(streamerUsername) {
await DBHandler.set("tasks", tasks);
clearAllDoneTasks();
await clearAllDoneTasks();
cancelAnimation();
renderTaskListToDOM();
await renderTaskListToDOM();
return {
status: 200,
};
}
const taskListMemory = {
doneTaskCount: 0,
totalTaskCount: 0,
};
async function renderTaskListToDOM() {
const tasks = await DBHandler.get("tasks");
@ -2186,7 +2210,11 @@ async function renderTaskListToDOM() {
let completedTasksCount = 0;
for (const user in tasks) {
if (user === "ID") continue;
if (!tasks[user].todos) continue;
const userTasks = tasks[user];
if (userTasks.todos.length === 0) {
// remove user from tasks
delete tasks[user];
@ -2354,9 +2382,9 @@ function addAnimationListeners() {
}
}
function animationFinished() {
async function animationFinished() {
scrolling = false;
renderTaskListToDOM();
await renderTaskListToDOM();
checkToAnimate();
}
@ -2371,14 +2399,14 @@ function cancelAnimation() {
}
DBHandler.open()
.then(() => {
setupDB();
.then(async () => {
await setupDB();
if (getSetting("testTasks")) {
resetDB();
tests();
await resetDB();
await tests();
}
importStyles();
renderTaskListToDOM();
await renderTaskListToDOM();
})
.catch((error) => {
console.error("Error opening database:", error);