diff --git a/package-lock.json b/KaizenLAN/package-lock.json similarity index 100% rename from package-lock.json rename to KaizenLAN/package-lock.json diff --git a/package.json b/KaizenLAN/package.json similarity index 100% rename from package.json rename to KaizenLAN/package.json diff --git a/public/css/index.css b/KaizenLAN/public/css/index.css similarity index 100% rename from public/css/index.css rename to KaizenLAN/public/css/index.css diff --git a/public/habit.html b/KaizenLAN/public/habit.html similarity index 100% rename from public/habit.html rename to KaizenLAN/public/habit.html diff --git a/public/index.html b/KaizenLAN/public/index.html similarity index 100% rename from public/index.html rename to KaizenLAN/public/index.html diff --git a/public/js/habit.js b/KaizenLAN/public/js/habit.js similarity index 100% rename from public/js/habit.js rename to KaizenLAN/public/js/habit.js diff --git a/public/js/index.js b/KaizenLAN/public/js/index.js similarity index 100% rename from public/js/index.js rename to KaizenLAN/public/js/index.js diff --git a/public/js/profile.js b/KaizenLAN/public/js/profile.js similarity index 100% rename from public/js/profile.js rename to KaizenLAN/public/js/profile.js diff --git a/public/js/settings.js b/KaizenLAN/public/js/settings.js similarity index 100% rename from public/js/settings.js rename to KaizenLAN/public/js/settings.js diff --git a/public/js/water.js b/KaizenLAN/public/js/water.js similarity index 100% rename from public/js/water.js rename to KaizenLAN/public/js/water.js diff --git a/public/js/weight.js b/KaizenLAN/public/js/weight.js similarity index 100% rename from public/js/weight.js rename to KaizenLAN/public/js/weight.js diff --git a/old/kaizen_icon.png b/KaizenLAN/public/kaizen_icon.png similarity index 100% rename from old/kaizen_icon.png rename to KaizenLAN/public/kaizen_icon.png diff --git a/old/kaizen_icon_outline.png b/KaizenLAN/public/kaizen_icon_outline.png similarity index 100% rename from old/kaizen_icon_outline.png rename to KaizenLAN/public/kaizen_icon_outline.png diff --git a/old/kaizen_logo.png b/KaizenLAN/public/kaizen_logo.png similarity index 100% rename from old/kaizen_logo.png rename to KaizenLAN/public/kaizen_logo.png diff --git a/public/lib/graph/habitLoader.js b/KaizenLAN/public/lib/graph/habitLoader.js similarity index 100% rename from public/lib/graph/habitLoader.js rename to KaizenLAN/public/lib/graph/habitLoader.js diff --git a/KaizenLAN/public/lib/graph/kaizenGraphInterface.js b/KaizenLAN/public/lib/graph/kaizenGraphInterface.js new file mode 100644 index 0000000..bb3a1d5 --- /dev/null +++ b/KaizenLAN/public/lib/graph/kaizenGraphInterface.js @@ -0,0 +1,24 @@ +const GRAPH_ENDPOINT = "http://192.168.0.35:8080/graphql"; + +async function request(query) { + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({query}) + }; + try { + const response = await fetch(GRAPH_ENDPOINT, options); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + var responseBody = await response.json(); + return responseBody.data + } catch (error) { + console.error('Error fetching data:', error); + alert("An unexpected error occurred when querying kaizen graph - are the APIs running?") + } +} + +export { request } \ No newline at end of file diff --git a/public/lib/graph/kaizenGraphInterface.js b/KaizenLAN/public/lib/graph/kaizenGraphInterface.js.bak similarity index 100% rename from public/lib/graph/kaizenGraphInterface.js rename to KaizenLAN/public/lib/graph/kaizenGraphInterface.js.bak diff --git a/public/lib/graph/profileLoader.js b/KaizenLAN/public/lib/graph/profileLoader.js similarity index 100% rename from public/lib/graph/profileLoader.js rename to KaizenLAN/public/lib/graph/profileLoader.js diff --git a/public/lib/graph/waterLoader.js b/KaizenLAN/public/lib/graph/waterLoader.js similarity index 100% rename from public/lib/graph/waterLoader.js rename to KaizenLAN/public/lib/graph/waterLoader.js diff --git a/public/lib/graph/weightTrackLoader.js b/KaizenLAN/public/lib/graph/weightTrackLoader.js similarity index 100% rename from public/lib/graph/weightTrackLoader.js rename to KaizenLAN/public/lib/graph/weightTrackLoader.js diff --git a/public/lib/habitWidget.js b/KaizenLAN/public/lib/habitWidget.js similarity index 100% rename from public/lib/habitWidget.js rename to KaizenLAN/public/lib/habitWidget.js diff --git a/public/lib/profileWidget.js b/KaizenLAN/public/lib/profileWidget.js similarity index 100% rename from public/lib/profileWidget.js rename to KaizenLAN/public/lib/profileWidget.js diff --git a/public/lib/utils/utils.js b/KaizenLAN/public/lib/utils/utils.js similarity index 100% rename from public/lib/utils/utils.js rename to KaizenLAN/public/lib/utils/utils.js diff --git a/public/lib/waterWidget.js b/KaizenLAN/public/lib/waterWidget.js similarity index 100% rename from public/lib/waterWidget.js rename to KaizenLAN/public/lib/waterWidget.js diff --git a/public/lib/weightWidget.js b/KaizenLAN/public/lib/weightWidget.js similarity index 100% rename from public/lib/weightWidget.js rename to KaizenLAN/public/lib/weightWidget.js diff --git a/public/profile.html b/KaizenLAN/public/profile.html similarity index 100% rename from public/profile.html rename to KaizenLAN/public/profile.html diff --git a/public/res/manage_habits.png b/KaizenLAN/public/res/manage_habits.png similarity index 100% rename from public/res/manage_habits.png rename to KaizenLAN/public/res/manage_habits.png diff --git a/public/res/manage_hydrate.png b/KaizenLAN/public/res/manage_hydrate.png similarity index 100% rename from public/res/manage_hydrate.png rename to KaizenLAN/public/res/manage_hydrate.png diff --git a/public/res/manage_journal.png b/KaizenLAN/public/res/manage_journal.png similarity index 100% rename from public/res/manage_journal.png rename to KaizenLAN/public/res/manage_journal.png diff --git a/public/res/manage_lists.png b/KaizenLAN/public/res/manage_lists.png similarity index 100% rename from public/res/manage_lists.png rename to KaizenLAN/public/res/manage_lists.png diff --git a/public/res/manage_weight.png b/KaizenLAN/public/res/manage_weight.png similarity index 100% rename from public/res/manage_weight.png rename to KaizenLAN/public/res/manage_weight.png diff --git a/public/res/placeholder.png b/KaizenLAN/public/res/placeholder.png similarity index 100% rename from public/res/placeholder.png rename to KaizenLAN/public/res/placeholder.png diff --git a/public/res/settings.png b/KaizenLAN/public/res/settings.png similarity index 100% rename from public/res/settings.png rename to KaizenLAN/public/res/settings.png diff --git a/public/res/view_profile.png b/KaizenLAN/public/res/view_profile.png similarity index 100% rename from public/res/view_profile.png rename to KaizenLAN/public/res/view_profile.png diff --git a/public/settings.html b/KaizenLAN/public/settings.html similarity index 100% rename from public/settings.html rename to KaizenLAN/public/settings.html diff --git a/public/water.html b/KaizenLAN/public/water.html similarity index 100% rename from public/water.html rename to KaizenLAN/public/water.html diff --git a/public/weight.html b/KaizenLAN/public/weight.html similarity index 100% rename from public/weight.html rename to KaizenLAN/public/weight.html diff --git a/server.js b/KaizenLAN/server.js similarity index 100% rename from server.js rename to KaizenLAN/server.js diff --git a/README.md b/README.md index 5c59aea..02539ea 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # Kaizen LAN -> [!NOTE] -> This README is currently a **plan** for Kaizen LAN. There are no current releases at this time and the first version is in development. - ### Frontend ![Express.js](https://img.shields.io/badge/express.js-%23404d59.svg?style=for-the-badge&logo=express&logoColor=%2361DAFB) ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) @@ -23,17 +20,21 @@ **Kaizen LAN**: Continuously improve your life with helpful widgets - accessible around your home! This application offers a interface that contains many different self improvement tools. The goal is to provide the user a customized experience to help continuously improve their lives through the use of small and simple tools. The following tools are planned to be included in Kaizen LAN: -- **Kaizen profile** (planned for v1.0.0) -- **Weight tracking** (planned for v1.0.0) -- **Water/hydration tracking** (planned for v1.0.0) -- **Habit tracking** (planned for v1.0.0) + +### Currently Implemented +- **Kaizen profile** (v1.0.0) +- **Weight tracking** (v1.0.0) +- **Water/hydration tracking** (v1.0.0) +- **Habit tracking** (v1.0.0) + +### Planned to be Implemented - **Routine checklists** (planned for v1.1.0) - **Text/CSV editor** (planned for v1.1.0) - **Time blocking** (planned for v1.1.0) - **Journal** (planned for v1.1.0) - **Food calorie tracking** (planned for v1.2.0) - **Todo list** (planned for v1.2.0) - **Countdown workout** (planned for v1.2.0) +- **Countdown workout** (planned for v1.2.0) # Concept View @@ -51,12 +52,11 @@ This application offers a interface that contains many different self improvemen To utilize all of the features of Kaizen LAN, you will need to designate a computer system to run each part of the Kaizen LAN application. This includes the Kaizen LAN server, Kaizen GraphQL API, each microservice, and a MySQL database. To be able to run all of these, you must have the following: - **[Node.js](https://nodejs.org/en) version 18 or higher** (used to run Kaizen LAN server and Kaizen Profile API) -- **[Java](https://openjdk.org/projects/jdk/) version 17 or higher** and **Maven version 3 or higher** (used to build and run each microservice) +- **[Java](https://openjdk.org/projects/jdk/) version 17 or higher** (used to build and run each API microservice) - **[MySQL](https://www.mysql.com/) version 8 or higher** (used to run the MySQL database) - **Bash or related terminal interface** - macOS testing using [Zsh](https://en.wikipedia.org/wiki/Z_shell) (preinstalled on macOS) - Linux (Ubuntu) testing using [GNOME](https://en.wikipedia.org/wiki/GNOME_Terminal) (preinstalled on Ubuntu 22) - - Windows testing using [Git Bash](https://git-scm.com/downloads) (NOT preinstalled) ## Dependencies @@ -82,34 +82,43 @@ You can download the latest release of the application from the **[releases page ### Initial Setup -For initial setup, you must have your MySQL instance running on your machine. Open the `setup.sh` file to configure with your MySQL credentials: +For initial setup, you must have your MySQL instance running on your machine. Verify that you can open MySQL through the terminal by using the command and signing in with your MySQL password: ```bash -#!/bin/bash - -# MySQL credentials -MYSQL_USER="your_mysql_username" -MYSQL_PASSWORD="your_mysql_password" -MYSQL_HOST="localhost" -MYSQL_DB="your_database_name" +mysql -u {your_mysql_username} -p ``` -Specifically, you will need to modify the `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_DB` values. Kaizen LAN was designed to run on the local machine, so there is no need to modify the host value. -Running this script will create and configure the MySQL database along with each table utilized in this application. If the setup was successful, you will see a message that reads "`SUCCESS: Kaizen LAN setup complete`". If the setup was unsuccessful, you will see a message that reads "`FAILURE: Setup was unable to complete`". +If you are able to login with a username and password like this, you are ready to move forward with installing Kaizen. This README does not serve the purpose of showing users how to install MySQL on their device. -### Run the application +Run the `setup.sh` script in a bash-supported terminal. +- You will be prompted to sign into your MySQL using the script. This script will create all of the tables used in KaizenLAN. It will also create a **secrets** folder which stores the MySQL credentials and LAN address in the user's `Documents/narlock/secrets/mysql.properties` file. The APIs that KaizenLAN utilizes will read from this properties file so that it can communicate with the MySQL database. +- Next, you will setup your profile. The script will prompt you to create a Kaizen username and enter various information for your profile. After this is completed, a row in the Profile and Health tables for the Kaizen Profile will be added to the MySQL database and the setup will be completed. + +> [!NOTE] +> If you are interested in viewing the contents of the bash script, you can open the script in a text editor, or view it online on [GitHub](https://github.com/narlock/KaizenLAN/blob/main/setup.sh) - + +### Run the application Once the setup is complete, you can run the `start.sh` script in a new terminal. This will launch the Kaizen LAN server, Kaizen GraphQL API, and each microservice utilized by this application. > [!WARNING] -> By running this application, you are running roughly 10+ applications on your system. RAM usage may vary. +> By running this application, you are running roughly 6 applications on your system. RAM usage may vary. + +When you run the application, you will receive the messages indicating which applications are running on which port number: +```sh +Starting Kaizen Profile API{} on port 8079 +Starting Narlock Habit API{} on port 8089 +Starting Narlock Water Track API{} on port 8083 +Starting Narlock Weight Track API{} on port 8081 +Starting Narlock GraphQL API{} on port 8080 +Starting Kaizen LAN{} on port 3000 +``` -Once the script completes, you can choose to exit the terminal if you wish. Next, you can navigate to **http://localhost:3000/** to access Kaizen LAN. +Once the script completes, you can choose to exit the terminal if you wish. Next, you can navigate to **http://localhost:3000/** to access Kaizen LAN. On other devices within your local network, you can navigate to your LAN **http://{lan_address}:3000/** on any of the devices connected to your network to use the application. You can find the exact address in the secrets properties folder that was created during the setup if you cannot find this address. ### Stopping the application -When the start script is ran, it will run all of the required applications for Kaizen LAN in the background. The stop script will end each process that was opened by the start script. Simply just run the `stop.sh` script in a terminal. +When the start script is ran, it will run all of the required applications for Kaizen LAN in the background. The stop script will end each process that was opened by the start script. Simply just run the `stop.sh` script in a terminal. This will kill each process that is running on the ports above. # Concept Idea @@ -119,9 +128,7 @@ Based off of [Kaizen](https://github.com/narlock/Kaizen), which is a local Java ![First Iteration](./readme%20assets/Interface.png) -The first iteration of Kaizen LAN introduces a simple interface utilizing the checklist api, water tracking api, profile api, and weight tracking api. The navigation bar at the top of the screen expands on each of the widgets that appear on the home screen. +The first iteration of Kaizen LAN introduces a simple interface utilizing the habit api, water tracking api, profile api, and weight tracking api. The navigation bar at the top of the screen expands on each of the widgets that appear on the home screen. # Future Enhancements -- Multiprofile: require users to "login" to their profile. This allows multiple users to have a profile to utilize Kaizen LAN. - - This includes the functionality of providing a password (or not) to sign in to a profile. -- Anti Habit API integration +- Multiprofile: require users to "login" to their profile. This allows multiple users to have a profile to utilize Kaizen LAN. This includes the functionality of providing a password (or not) to sign in to a profile. diff --git a/old/css/index.css b/old/css/index.css deleted file mode 100644 index c8d23da..0000000 --- a/old/css/index.css +++ /dev/null @@ -1,291 +0,0 @@ -/* styles.css */ - -body { - background-color: #484848; - /* Grey background color */ - font-family: 'Fira Code', monospace; - /* Set Fira Code as the default font */ - color: #9c9c9c; - /* Set off-white text color for elements with the class 'off-white-text' */ -} - -footer { - padding-top: 20px; - text-align: center; -} - -footer a { - text-decoration: none; /* Remove underline */ - color: inherit; /* Inherit text color from parent */ -} - -footer a:hover { - color: #00a657; /* Change color on hover */ -} - -h2, h3, b { - color: #ffffff; -} - -p { - color: #9c9c9c; -} - -.special { - color: #00eb7b; -} - -h1 { - font-size: 64px; -} - -button { - margin-left: 10px; -} - -p { - /* Additional styling for paragraphs if needed */ - font-size: 16px; - /* Adjust font size as needed */ -} - -.topnav a { - float: left; - position: relative; - color: #f2f2f2; - text-align: center; - padding: 10px 10px; - text-decoration: none; - font-size: 17px; - -} - -.topnav-right { - float: right; - position: relative; - color: #f2f2f2; - text-align: center; - padding: 10px 10px; - padding-top: 50px; - text-decoration: none; - font-size: 17px; -} - -/* Add the tooltip styling */ -.tooltip { - position: absolute; - background-color: #000; - color: #fff; - padding: 5px; - border-radius: 5px; - visibility: hidden; - opacity: 0; - transition: opacity 0.3s; - z-index: 1; -} - -/* Position the tooltip above the link */ -.tooltip.top { - bottom: calc(100% + 5px); - left: 50%; - transform: translateX(-50%); -} - -/* Position the tooltip above the right-aligned links */ -.tooltip.right { - top: 50%; - left: calc(100% + 5px); - transform: translateY(-50%); -} - -.menuLink img { - transition: filter 0.3s; /* Add transition for smooth effect */ -} - -.menuLink:hover img { - filter: brightness(100%) sepia(100%) hue-rotate(120deg); -} - - -#homeLink img { - content: url('../kaizen_logo.png'); - width: 325px; -} - -.container { - display: flex; - flex-wrap: wrap; - width: 100%; /* Set a specific width for consistency */ - justify-content: space-around; /* Adjust as needed */ -} - -.center-container { - display: flex; - justify-content: center; - align-items: center; - margin-top: 30px; -} - -.add-button { - margin: 20px; - padding-top: 4px; - padding-left: 10px; - padding-right: 10px; - padding-bottom: 4px; - font-size: 25px; - background-color: #00eb7b; - color: black; - font-weight: bold; -} - -.checkBoxLabel { - margin-bottom: 12px; - cursor: pointer; - font-size: 22px; -} - -.checkBoxLabel input { - width: 24px; - height: 24px; - margin-right: 20px; - margin-bottom: 20px; -} - -.checkBoxIncomplete { - color: white; -} - -.blockDiv { - display: block; -} - -.box { - flex: 1; - min-width: 300px; - margin: 20px; - padding: 20px; - box-sizing: border-box; - border: 1px solid #ccc; -} - -.boxNoBorder { - flex: 1; - min-width: 300px; - margin: 20px; - padding: 20px; - box-sizing: border-box; -} - -.hiddenBox { - flex: 1; - min-width: 300px; - margin: 20px; - padding: 20px; - box-sizing: border-box; -} - -#profile img { - float: left; - margin-right: 20px; - width: 200px; - height: 200px; -} - -#xpBarProgress { - width: 100%; - max-width: 400px; - background-color: grey; - border: 1px solid #ccc; -} - -#xpBar { - width: 1%; - height: 30px; - background-color: #00eb7b; -} - -.bmi.underweight { - color: rgb(0, 145, 255); -} - -.bmi.normal { - color: #00eb7b; -} - -.bmi.overweight { - color: orange; -} - -.bmi.obese { - color: red; -} - -@media only screen and (min-width: 901px) { - /* Show the tooltip on hover */ - .topnav a:hover .tooltip { - visibility: visible; - opacity: 1; - } - - /* Customize tooltip content for each link */ - .topnav a[href="/profile"] .tooltip::before { - content: 'View Profile'; - } - - .topnav a[href="/lists"] .tooltip::before { - content: 'Manage Lists'; - } - - .topnav a[href="/schedule"] .tooltip::before { - content: 'Manage Schedule'; - } - - .topnav a[href="/weight"] .tooltip::before { - content: 'Manage Weight'; - } - - .topnav a[href="/water"] .tooltip::before { - content: 'Manage Hydration'; - } - - .topnav a[href="/journal"] .tooltip::before { - content: 'Manage Journal'; - } - - .topnav a[href="/settings"] .tooltip::before { - content: 'Change Settings'; - } -} - -@media only screen and (max-width: 900px) { - - /* Adjust the size for screens with a maximum width of 600px (typical for phones) */ - #homeLink img { - content: url('../kaizen_icon_outline.png'); - width: 32px; - } - - .menuLink img { - width: 20px; - height: 20px; - } - - .topnav-right { - padding-top: 5px; - } - - .box { - flex-basis: 100%; /* Set the basis to 100% for stacking */ - margin: auto; - margin-top: 20px; - } - - .hiddenBox { - display: none; - } - - #profile img { - width: 175px; - height: 175px; - } -} \ No newline at end of file diff --git a/old/hydration.html b/old/hydration.html deleted file mode 100644 index a17e6a5..0000000 --- a/old/hydration.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - Water • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-

-
- - - - \ No newline at end of file diff --git a/old/index.html b/old/index.html deleted file mode 100644 index fb073c2..0000000 --- a/old/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - Kaizen LAN - - - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
-

-
-
-

-
-
-

-
-
-

- -
-

-
-
-
- - - - - - \ No newline at end of file diff --git a/old/journal.html b/old/journal.html deleted file mode 100644 index ac07d11..0000000 --- a/old/journal.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - Journal • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-

-
- - - - \ No newline at end of file diff --git a/old/js/index.js b/old/js/index.js deleted file mode 100644 index d1a0703..0000000 --- a/old/js/index.js +++ /dev/null @@ -1,630 +0,0 @@ -HOST_ADDRESS = "192.168.0.129" - -document.addEventListener("DOMContentLoaded", function () { - setBoxInformation(); - configureChecklistWidget(); - configureProfileWidget(); - configureWeightWidget(); -}); - -function setBoxInformation() { - // Set checklist information - var box = document.getElementById('checklist'); - var currentTime = new Date().getHours(); - - if (currentTime >= 4 && currentTime < 10) { - box.innerText = 'Morning Checklist'; - } else if (currentTime >= 10 && currentTime < 17) { - box.innerText = 'Daily Checklist'; - } else { - box.innerText = 'Night Checklist'; - } - - box = document.getElementById('schedule'); - box.innerText = 'Schedule' - box = document.getElementById('profile') - box.innerHTML = 'Profile' - box = document.getElementById('weight'); - box.innerHTML = 'Weight' - box = document.getElementById('water') - box.innerHTML = 'Water' -} - -/** - * =============== - * CHECKLIST WIDGET - * =============== - */ - -var CHECKLIST_ITEMS = null; - -function configureChecklistWidget() { - retrieveListInformation(); -} - -function retrieveListInformation() { - var currentTime = new Date().getHours(); - if (currentTime >= 4 && currentTime < 10) { - getList("morning"); - } else if (currentTime >= 10 && currentTime < 17) { - getList("daily"); - } else { - getList("night"); - } -} - -function getList(checklistName) { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - CHECKLIST_ITEMS = JSON.parse(xmlhttp.response); - populateChecklistItems(checklistName); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?"); - } - } - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8085/checklist-item?checklistName=${checklistName}`); - xmlhttp.send(); -} - -function populateChecklistItems(checklistName) { - var checklistItemsDiv = document.getElementById('checklistItems'); - - // Remove each dom child - they will be dynamically readded - while (checklistItemsDiv.firstChild) { - checklistItemsDiv.removeChild(checklistItemsDiv.firstChild); - } - - CHECKLIST_ITEMS.forEach(element => { - addItemToChecklistDiv(checklistItemsDiv, element, checklistName); - }); -} - -function addItemToChecklistDiv(checklistDiv, element, checklistName) { - var elementDiv = document.createElement('div') - elementDiv.classList.add('checklist-element') - - var label = document.createElement('label'); - label.classList.add('checkBoxLabel'); - var checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - label.appendChild(checkbox); - var checkmark = document.createElement('span') - checkmark.classList.add('checkmark'); - label.appendChild(checkmark); - if(element.streak != null && element.streak != 0) { - label.appendChild(document.createTextNode(`${element.name} [🔥 ${element.streak}]`)); - } else { - label.appendChild(document.createTextNode(`${element.name}`)); - } - elementDiv.appendChild(label); - checklistDiv.appendChild(elementDiv); - - // check completed date - if(element.lastCompletedDate) { - sameDay = areDatesEqual(new Date(), new Date(`${element.lastCompletedDate}T00:00:00`)); - if(sameDay) { - checkbox.checked = true; - checkbox.disabled = true; - } else { - // Not checked, we can complete this today - label.classList.add('checkBoxIncomplete'); - } - } else { - // Not checked, we can complete this today - label.classList.add('checkBoxIncomplete'); - } - - // action - checkbox.addEventListener('click', function(event) { - if(event.shiftKey) { - checkbox.checked = false; - var result = window.confirm(`Kaizen Message\n\nWould you like to remove item ${element.name}?`) - if(result) { - var xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 204) { - console.log("successfully remove item"); - resetChecklist(checklistName); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - } - } - - xmlhttp.open("DELETE", `http://${HOST_ADDRESS}:8085/checklist-item/${element.id}`, true); - xmlhttp.send(); - } else { - // If checkbox is checked, disable it - if (checkbox.checked) { - checkbox.disabled = true; - } - label.classList.remove('checkBoxIncomplete'); - - // Call the streak endpoint to update date and streak - var xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - console.log("Backend updated"); - giveExperienceToProfile(PROFILE_ENTRY, 5); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - } - - xmlhttp.open("PATCH", `http://${HOST_ADDRESS}:8085/checklist-item/${element.id}/streak`, true); - xmlhttp.send(); - } - }); -} - -/** - * =============== - * PROFILE WIDGET - * =============== - */ -function configureProfileWidget() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Show profile details - PROFILE_ENTRY = JSON.parse(xmlhttp.response) - console.log(PROFILE_ENTRY) - displayProfile(); - } else if (this.readyState == 4 && this.status == 404) { - // Show create profile details - console.log("Profile not found, showing create profile interface") - } else if (this.readyState == 4) { - // Unknown error occurred - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8079/profile/1`, true); - xmlhttp.send(); -} - -var mainProfileDiv = null; - -function displayProfile() { - var profileDiv = document.getElementById('profile'); - - var mainDiv = document.createElement('div'); - mainDiv.classList.add("center-container"); - - var imageElement = document.createElement('img'); - imageElement.src = PROFILE_ENTRY.image_url; - - var contentElement = document.createElement('p'); - contentElement.innerHTML = ` - -

${PROFILE_ENTRY.username}

-
- Level: ${calculateLevel(PROFILE_ENTRY.xp)} (${PROFILE_ENTRY.xp} XP)
- Height: ${PROFILE_ENTRY.health.height}
- Weight: ${PROFILE_ENTRY.health.weight}
-
- `; - - var xpBarDiv = document.createElement('div'); - xpBarDiv.classList.add('center-container'); - - var xpBarElement = document.createElement('div'); - xpBarElement.id = 'xpBarProgress'; - var xpBar = document.createElement('div'); - xpBar.id = 'xpBar'; - xpBarElement.appendChild(xpBar); - xpBarDiv.appendChild(xpBarElement); - - mainDiv.appendChild(imageElement); - mainDiv.appendChild(contentElement); - profileDiv.appendChild(mainDiv); - profileDiv.appendChild(xpBarDiv); - - moveXpBar(PROFILE_ENTRY.xp, profileDiv); - mainProfileDiv = profileDiv; -} - -function moveXpBar(xp, profileDiv) { - var nextLevelXp = calculateExperienceToNextLevel(xp) - var percent = xp / nextLevelXp - - var nextLevelElement = document.getElementById('nextLevelElement') - if(nextLevelElement == null) { - var nextLevelElement = document.createElement('p') - nextLevelElement.id = 'nextLevelElement' - nextLevelElement.innerHTML = `XP to next level: ${nextLevelXp} (${Math.round(percent)}%)` - nextLevelElement.style.textAlign = "center"; - profileDiv.appendChild(nextLevelElement); - } else { - nextLevelElement.innerHTML = `XP to next level: ${nextLevelXp} (${Math.round(percent)}%)` - } - - var i = 0; - if (i == 0) { - i = 1; - var elem = document.getElementById("xpBar"); - var width = 1; - var id = setInterval(frame, 10); - function frame() { - if (width >= percent) { - clearInterval(id); - i = 0; - } else { - width++; - elem.style.width = width + "%"; - } - } - } -} - -/** - * =============== - * WEIGHT WIDGET - * =============== - */ - -let WEIGHT_TODAY_ENTRY = null -var myWeightChart = null - -function configureWeightWidget() { - var today = getCurrentDateString() - console.log(`attempting to retrieve /weight?date=${today}`) - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - // There is an entry for today - TODAY_ENTRY = JSON.parse(xmlhttp.response) - console.log(`weight entry for ${today} found`) - - showTodayWeightInterface("weight") - } else if (this.readyState == 4 && this.status == 404) { - // No entry found for date - var response = JSON.parse(xmlhttp.response) - console.log(response.message) - - // Give option to create entry - showCreateWeightInterface("weight") - } else if (this.readyState == 4) { - // Some error occurred` - var response = JSON.parse(xmlhttp.response) - console.error(`an unexpected error occurred when calling simple-time-block-api (is it running?)`) - } - }; - - xmlhttp.open("GET", `http://${HOST_ADDRESS}:8081/weight?date=${today}`, true) - xmlhttp.send(); -} - -function showTodayWeightInterface(elementId) { - console.log('showing today interface') - var element = document.getElementById(elementId) - - // TODO create a special div with an id that can be styled - var displayWeightDiv = document.createElement('div') - displayWeightDiv.id = 'displayWeightDiv' - displayWeightDiv.innerHTML = `

Today's weight: ${TODAY_ENTRY.weight}

` - - element.appendChild(displayWeightDiv); - getGraphEntries(7); -} - -function getGraphEntries(daysAgo) { - if(myWeightChart) { - myWeightChart.destroy(); - myWeightChart = null; - } - - // Default to show Week View - var today = getCurrentDateString() - var daysAgo = getDaysAgoDateString(daysAgo) - console.log(`attempting to retrieve /weight/range?startDate=${daysAgo}&endDate=${today}`) - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - GRAPH_RESPONSE = JSON.parse(xmlhttp.response) - - const xValues = []; - const yValues = []; - - GRAPH_RESPONSE.entries.forEach(element => { - xValues.push(element.date) - yValues.push(element.weight) - }); - - displayGraph("myWeightChart", xValues, yValues); - } else if (this.readyState == 4) { - // Some error occurred` - var response = JSON.parse(xmlhttp.response) - console.error(`an unexpected error occurred when calling simple-time-block-api ${response.error}`) - } - }; - - xmlhttp.open("GET", `http://${HOST_ADDRESS}:8081/weight/range?startDate=${daysAgo}&endDate=${today}`, true) - xmlhttp.send(); -} - -function displayGraph(element, xValues, yValues) { - myWeightChart = new Chart(element, { - type: "line", - data: { - labels: xValues, - datasets: [{ - label: "Weight Trend", - fill: false, - lineTension: 0.2, - backgroundColor: "rgba(0,235,123,1.0)", - borderColor: "rgba(0,166,87,0.7)", - pointRadius: 8, - pointHoverRadius: 12, - data: yValues - }] - }, - options: { - plugins: { - legend: { - labels: { - color: "white", - } - } - }, - scales: { - y: { - title: { - display: true, - color: "white", - text: "Weight" - }, - ticks: { - color: "white" - } - }, - x: { - title: { - display: true, - color: "white", - text: "Date" - }, - ticks: { - color: "white" - } - } - } - } - }); -} - -function showCreateWeightInterface(elementId) { - var element = document.getElementById(elementId) - - var createWeightDiv = document.createElement('div') - createWeightDiv.id = 'createWeightDiv' - - // Create text box for entering weight - var weightEntryBox = document.createElement('input') - weightEntryBox.type = 'text' - weightEntryBox.id = 'createWeightEntry' - weightEntryBox.placeholder = 'Enter weight here...'; - - // Create a button for submitting the weight entry to database - var weightEntrySubmit = document.createElement('button') - weightEntrySubmit.innerText = 'Submit Entry' - weightEntrySubmit.id = 'createWeightButton' - weightEntrySubmit.addEventListener('click', handleCreateWeightClick); - - // add them to the dom - createWeightDiv.appendChild(weightEntryBox) - createWeightDiv.appendChild(weightEntrySubmit) - element.appendChild(createWeightDiv) - - // Recreate the graph view - based off of what is already there... - getGraphEntries(7); -} - -// Function to be called when the button is clicked -function handleCreateWeightClick() { - var entry = document.getElementById('createWeightEntry').value - console.log(`user entered ${entry} into the box`) - if(isFloatingPointNumber(entry)) { - // Make call to backend api - createWeightEntry(entry); - syncProfileCurrentWeight(entry); - } else { - alert(`Unexpected entry value: ${entry}, please enter a valid weight entry.`) - } -} - -function createWeightEntry(entry) { - console.log(`creating weight entry for today with ${entry}`) - - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("POST", `http://${HOST_ADDRESS}:8081/weight`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 201) { - console.log("successfully created, change to view") - TODAY_ENTRY = JSON.parse(xmlhttp.response) - removeCreateWeightInterface(); - showTodayWeightInterface("weight"); - } else if(this.readyState == 4) { - alert("An unexpected error occurred when creating an entry") - } - } - - var data = { - weight: entry, - date: getCurrentDateString() - }; - var jsonData = JSON.stringify(data) - - xmlhttp.send(jsonData); -} - -function syncProfileCurrentWeight(entry) { - var PROFILE_ENTRY = null; - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Show profile details - PROFILE_ENTRY = JSON.parse(xmlhttp.response) - console.log(PROFILE_ENTRY) - updateWeightOnProfile(PROFILE_ENTRY, entry); - } else if (this.readyState == 4 && this.status == 404) { - // Show create profile details - console.log("Profile not found, showing create profile interface") - } else if (this.readyState == 4) { - // Unknown error occurred - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8079/profile/1`); - xmlhttp.send(); -} - -function updateWeightOnProfile(profile, entry) { - profile.health.weight = entry; - // gain 10 xp points for entering in daily weight - profile.xp = profile.xp + 10; - - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("PUT", `http://${HOST_ADDRESS}:8079/profile/1`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - console.log("successfully updated profile") - } else if(this.readyState == 4) { - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - } - var jsonData = JSON.stringify(profile) - xmlhttp.send(jsonData); - - moveXpBar(profile.xp, mainProfileDiv); -} - -function removeCreateWeightInterface() { - var createWeightDiv = document.getElementById('createWeightDiv') - if (createWeightDiv) { - createWeightDiv.remove(); - } -} - -/** - * ================= - * HELPER METHODS - * ================= - */ - -function calculateLevel(experience) { - // Define the base experience required for level 1 and the experience growth factor - const baseExperience = 100; - const experienceGrowthFactor = 1.2; - - // Ensure the input is a non-negative integer - const validatedExperience = Math.max(0, Math.floor(experience)); - - // Calculate the level using the exponential formula - const level = Math.floor(Math.log(validatedExperience / baseExperience) / Math.log(experienceGrowthFactor)) + 1; - - return level; -} - -function calculateExperienceToNextLevel(currentExperience) { - // Define the base experience for level 1 and the experience growth factor - const baseExperience = 100; - const experienceGrowthFactor = 1.2; - - // Ensure the input is a non-negative integer - const validatedExperience = Math.max(0, Math.floor(currentExperience)); - - // Calculate the current level using the same formula as before - const currentLevel = Math.floor(Math.log(validatedExperience / baseExperience) / Math.log(experienceGrowthFactor)) + 1; - - // Calculate the experience required for the next level - const experienceForNextLevel = Math.ceil(baseExperience * Math.pow(experienceGrowthFactor, currentLevel)); - - // Calculate the difference between the experience for the next level and the current experience - const experienceNeededForNextLevel = Math.max(0, experienceForNextLevel - validatedExperience); - - return experienceNeededForNextLevel; -} - -function getCurrentDateString() { - const today = new Date(); - - // Get year, month, and day - const year = today.getFullYear(); - const month = String(today.getMonth() + 1).padStart(2, '0'); // Month is zero-based, so add 1 - const day = String(today.getDate()).padStart(2, '0'); - - // Concatenate them in the "YYYY-mm-dd" format - const dateString = `${year}-${month}-${day}`; - - return dateString; -} - -function getDaysAgoDateString(days) { - const today = new Date(); - const sevenDaysAgo = new Date(today); - - // Subtract seven days - sevenDaysAgo.setDate(today.getDate() - days); - - // Get year, month, and day - const year = sevenDaysAgo.getFullYear(); - const month = String(sevenDaysAgo.getMonth() + 1).padStart(2, '0'); // Month is zero-based, so add 1 - const day = String(sevenDaysAgo.getDate()).padStart(2, '0'); - - // Concatenate them in the "YYYY-mm-dd" format - const dateString = `${year}-${month}-${day}`; - - return dateString; -} - -function isFloatingPointNumber(input) { - // Use a regular expression to match a floating-point number - const floatingPointPattern = /^[-+]?[0-9]*\.?[0-9]+$/; - - // Test the input against the pattern - return floatingPointPattern.test(input); -} - -function areDatesEqual(date1, date2) { - console.log(date1); - console.log(date2); - if(date1 == null || date2 == null) { - return false; - } - - return date1.getFullYear() === date2.getFullYear() && - date1.getMonth() === date2.getMonth() && - date1.getDate() === date2.getDate(); -} - -function giveExperienceToProfile(profile, amount) { - profile.xp = profile.xp + amount; - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("PUT", `http://${HOST_ADDRESS}:8079/profile/1`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - console.log("successfully updated profile") - } else if(this.readyState == 4) { - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - } - var jsonData = JSON.stringify(profile) - xmlhttp.send(jsonData); - - moveXpBar(profile.xp, mainProfileDiv); -} \ No newline at end of file diff --git a/old/js/lists.js b/old/js/lists.js deleted file mode 100644 index b8a0b95..0000000 --- a/old/js/lists.js +++ /dev/null @@ -1,322 +0,0 @@ -HOST_ADDRESS = "192.168.0.129" - -var MORNING_ITEMS = null; -var DAILY_ITEMS = null; -var NIGHT_ITEMS = null; - -document.addEventListener("DOMContentLoaded", function () { - getProfileEntry(); - retrieveListInformation(); - addButtonsToDom(); -}); - -function retrieveListInformation() { - getMorningList(); - getDailyList(); - getNightList(); -} - -function addButtonsToDom() { - addButtonToDom(document.getElementById('morningChecklist'), 'morning'); - addButtonToDom(document.getElementById('dayChecklist'), 'daily'); - addButtonToDom(document.getElementById('nightChecklist'), 'night') -} - -function addButtonToDom(rootElement, checklistName) { - var addItemDiv = document.createElement('div'); - addItemDiv.id = `${checklistName}ButtonDiv`; - addItemDiv.classList.add("center-container"); - - var button = document.createElement('button'); - button.classList.add("add-button") - button.innerText = '+'; - var itemTextField = document.createElement('input'); - itemTextField.type = 'text'; - itemTextField.id = `${checklistName}TextField`; - addItemDiv.appendChild(button); - addItemDiv.appendChild(itemTextField); - rootElement.appendChild(addItemDiv); - - button.addEventListener('click', () => { - // input validation against textfield - // then add the item to the list on backend - // then call the getList again - // if success, make sure to set itemTextField's text to nothing - if(itemTextField.value.trim() == '') { - alert("Kaizen Message\n\nYou must enter a in the text field to add a new item to a checklist.") - } else { - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("POST", `http://${HOST_ADDRESS}:8085/checklist-item`, true); - xmlhttp.setRequestHeader("Content-Type", "application/json"); - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 201) { - - console.log(`Successfully created new item for ${checklistName} checklist`) - - // Refresh the list - resetChecklist(checklistName); - } - } - - var requestPayload = { - checklistName: checklistName, - name: itemTextField.value - }; - var jsonData = JSON.stringify(requestPayload); - xmlhttp.send(jsonData); - - itemTextField.value = ''; - } - }); -} - -function resetChecklist(name) { - // Refresh the list - if(name == 'morning') { - getMorningList(); - } else if(name == 'daily') { - getDailyList(); - } else { - getNightList(); - } -} - -function printMorningList() { - console.log(MORNING_ITEMS); -} - -/** - * ================= - * API METHODS - * ================= - */ - -function getMorningList() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Retrieved the list - MORNING_ITEMS = JSON.parse(xmlhttp.response); - console.log(`retrieved morning items: ${MORNING_ITEMS}`) - populateMorningChecklistItems(); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8085/checklist-item?checklistName=morning`); - xmlhttp.send(); -} - -function populateMorningChecklistItems() { - var morningChecklistItemsDiv = document.getElementById('morningChecklistItems'); - - // Remove each dom child - they will be dynamically readded - while (morningChecklistItemsDiv.firstChild) { - morningChecklistItemsDiv.removeChild(morningChecklistItemsDiv.firstChild); - } - - MORNING_ITEMS.forEach(element => { - addItemToChecklistDiv(morningChecklistItemsDiv, element, 'morning'); - }); -} - -function getDailyList() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Retrieved the list - DAILY_ITEMS = JSON.parse(xmlhttp.response); - console.log(`retrieved daily items: ${DAILY_ITEMS}`) - populateDailyChecklistItems(); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8085/checklist-item?checklistName=daily`); - xmlhttp.send(); -} - -function populateDailyChecklistItems() { - var dailyChecklistItemsDiv = document.getElementById('dayChecklistItems'); - - // Remove each dom child - they will be dynamically readded - while(dailyChecklistItemsDiv.firstChild) { - dailyChecklistItemsDiv.removeChild(dailyChecklistItemsDiv.firstChild); - } - - DAILY_ITEMS.forEach(element => { - addItemToChecklistDiv(dailyChecklistItemsDiv, element, 'daily'); - }); -} - -function getNightList() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Retrieved the list - NIGHT_ITEMS = JSON.parse(xmlhttp.response); - console.log(`retrieved night items: ${NIGHT_ITEMS}`) - populateNightChecklistItems(); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8085/checklist-item?checklistName=night`); - xmlhttp.send(); -} - -function populateNightChecklistItems() { - var nightChecklistItemsDiv = document.getElementById('nightChecklistItems'); - - // Remove each dom child - they will be dynamically readded - while(nightChecklistItemsDiv.firstChild) { - nightChecklistItemsDiv.removeChild(nightChecklistItemsDiv.firstChild); - } - - NIGHT_ITEMS.forEach(element => { - addItemToChecklistDiv(nightChecklistItemsDiv, element, 'night'); - }); -} - -function addItemToChecklistDiv(checklistDiv, element, checklistName) { - var elementDiv = document.createElement('div') - elementDiv.classList.add('checklist-element') - - var label = document.createElement('label'); - label.classList.add('checkBoxLabel'); - var checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - label.appendChild(checkbox); - var checkmark = document.createElement('span') - checkmark.classList.add('checkmark'); - label.appendChild(checkmark); - if(element.streak != null && element.streak != 0) { - label.appendChild(document.createTextNode(`${element.name} [🔥 ${element.streak}]`)); - } else { - label.appendChild(document.createTextNode(`${element.name}`)); - } - elementDiv.appendChild(label); - checklistDiv.appendChild(elementDiv); - - // check completed date - if(element.lastCompletedDate) { - sameDay = areDatesEqual(new Date(), new Date(`${element.lastCompletedDate}T00:00:00`)); - if(sameDay) { - checkbox.checked = true; - checkbox.disabled = true; - } else { - // Not checked, we can complete this today - label.classList.add('checkBoxIncomplete'); - } - } else { - // Not checked, we can complete this today - label.classList.add('checkBoxIncomplete'); - } - - // action - checkbox.addEventListener('click', function(event) { - if(event.shiftKey) { - checkbox.checked = false; - var result = window.confirm(`Kaizen Message\n\nWould you like to remove item ${element.name}?`) - if(result) { - var xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 204) { - console.log("successfully remove item"); - resetChecklist(checklistName); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - } - } - - xmlhttp.open("DELETE", `http://${HOST_ADDRESS}:8085/checklist-item/${element.id}`, true); - xmlhttp.send(); - } else { - // If checkbox is checked, disable it - if (checkbox.checked) { - checkbox.disabled = true; - } - label.classList.remove('checkBoxIncomplete'); - - // Call the streak endpoint to update date and streak - var xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - console.log("Backend updated"); - giveExperienceToProfile(PROFILE_ENTRY, 5); - } else if(this.readyState == 4) { - console.error("An unexpected error occurred when calling simple-checklist-api. Is it running?") - } - } - - xmlhttp.open("PATCH", `http://${HOST_ADDRESS}:8085/checklist-item/${element.id}/streak`, true); - xmlhttp.send(); - } - }); -} - -/** - * ================= - * HELPER METHODS - * ================= - */ - -function areDatesEqual(date1, date2) { - console.log(date1); - console.log(date2); - if(date1 == null || date2 == null) { - return false; - } - - return date1.getFullYear() === date2.getFullYear() && - date1.getMonth() === date2.getMonth() && - date1.getDate() === date2.getDate(); -} - -function giveExperienceToProfile(profile, amount) { - profile.xp = profile.xp + amount; - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("PUT", `http://${HOST_ADDRESS}:8079/profile/1`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - console.log("successfully updated profile") - } else if(this.readyState == 4) { - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - } - var jsonData = JSON.stringify(profile) - xmlhttp.send(jsonData); -} - -let PROFILE_ENTRY = null; -function getProfileEntry() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Show profile details - PROFILE_ENTRY = JSON.parse(xmlhttp.response) - } else if (this.readyState == 4 && this.status == 404) { - // Show create profile details - console.log("Profile not found, showing create profile interface") - - // TODO add create profile logic - } else if (this.readyState == 4) { - // Unknown error occurred - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8079/profile/1`, true); - xmlhttp.send(); -} \ No newline at end of file diff --git a/old/js/profile.js b/old/js/profile.js deleted file mode 100644 index 5cb3e7a..0000000 --- a/old/js/profile.js +++ /dev/null @@ -1,164 +0,0 @@ -const HOST_ADDRESS = "192.168.0.129"; -let PROFILE_ENTRY = null; - -/** - * ================= - * ON LOAD FUNCTIONS - * ================= - */ - -document.addEventListener("DOMContentLoaded", function () { - getProfileEntry(); -}); - -/** - * ================= - * GET PROFILE ENTRY - * ================= - */ - -// At the moment, we only support one profile, so we will just search for /profile/1 -function getProfileEntry() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Show profile details - PROFILE_ENTRY = JSON.parse(xmlhttp.response) - console.log(PROFILE_ENTRY) - displayProfile(); - } else if (this.readyState == 4 && this.status == 404) { - // Show create profile details - console.log("Profile not found, showing create profile interface") - - // TODO add create profile logic - } else if (this.readyState == 4) { - // Unknown error occurred - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8079/profile/1`, true); - xmlhttp.send(); -} - -/** - * ================= - * CREATE PROFILE ENTRY - * ================= - */ - -// TODO - -/** - * ================= - * DISPLAY PROFILE ENTRY - * ================= - */ - -function displayProfile() { - var profileDiv = document.getElementById('profile'); - - var mainDiv = document.createElement('div'); - mainDiv.classList.add("center-container"); - - var imageElement = document.createElement('img'); - imageElement.src = PROFILE_ENTRY.image_url; - - var contentElement = document.createElement('p'); - contentElement.innerHTML = ` - -

${PROFILE_ENTRY.username}

-
- Level: ${calculateLevel(PROFILE_ENTRY.xp)} (${PROFILE_ENTRY.xp} XP)
- Age: ${PROFILE_ENTRY.age}
- Birth Date: ${PROFILE_ENTRY.birth_date}
- Height: ${PROFILE_ENTRY.health.height}
- Weight: ${PROFILE_ENTRY.health.weight}
-
- `; - - var xpBarDiv = document.createElement('div'); - xpBarDiv.classList.add('center-container'); - - var xpBarElement = document.createElement('div'); - xpBarElement.id = 'xpBarProgress'; - var xpBar = document.createElement('div'); - xpBar.id = 'xpBar'; - xpBarElement.appendChild(xpBar); - xpBarDiv.appendChild(xpBarElement); - - mainDiv.appendChild(imageElement); - mainDiv.appendChild(contentElement); - profileDiv.appendChild(mainDiv); - profileDiv.appendChild(xpBarDiv); - - moveXpBar(PROFILE_ENTRY.xp, profileDiv); -} - -function moveXpBar(xp, profileDiv) { - var nextLevelXp = calculateExperienceToNextLevel(xp) - var percent = xp / nextLevelXp - - var nextLevelElement = document.createElement('p') - nextLevelElement.innerHTML = `XP to next level: ${nextLevelXp} (${Math.round(percent)}%)` - nextLevelElement.style.textAlign = "center"; - profileDiv.appendChild(nextLevelElement); - - var i = 0; - if (i == 0) { - i = 1; - var elem = document.getElementById("xpBar"); - var width = 1; - var id = setInterval(frame, 10); - function frame() { - if (width >= percent) { - clearInterval(id); - i = 0; - } else { - width++; - elem.style.width = width + "%"; - } - } - } -} - -/** - * ================= - * HELPER METHODS - * ================= - */ - -function calculateLevel(experience) { - // Define the base experience required for level 1 and the experience growth factor - const baseExperience = 100; - const experienceGrowthFactor = 1.2; - - // Ensure the input is a non-negative integer - const validatedExperience = Math.max(0, Math.floor(experience)); - - // Calculate the level using the exponential formula - const level = Math.floor(Math.log(validatedExperience / baseExperience) / Math.log(experienceGrowthFactor)) + 1; - - return level; -} - -function calculateExperienceToNextLevel(currentExperience) { - // Define the base experience for level 1 and the experience growth factor - const baseExperience = 100; - const experienceGrowthFactor = 1.2; - - // Ensure the input is a non-negative integer - const validatedExperience = Math.max(0, Math.floor(currentExperience)); - - // Calculate the current level using the same formula as before - const currentLevel = Math.floor(Math.log(validatedExperience / baseExperience) / Math.log(experienceGrowthFactor)) + 1; - - // Calculate the experience required for the next level - const experienceForNextLevel = Math.ceil(baseExperience * Math.pow(experienceGrowthFactor, currentLevel)); - - // Calculate the difference between the experience for the next level and the current experience - const experienceNeededForNextLevel = Math.max(0, experienceForNextLevel - validatedExperience); - - return experienceNeededForNextLevel; -} \ No newline at end of file diff --git a/old/js/weight.js b/old/js/weight.js deleted file mode 100644 index c19ef11..0000000 --- a/old/js/weight.js +++ /dev/null @@ -1,453 +0,0 @@ -const HOST_ADDRESS = "192.168.0.129" -let TODAY_ENTRY = null -var myChart = null -var PROFILE = null; - -/** - * ================= - * ON LOAD FUNCTIONS - * ================= - */ - -document.addEventListener("DOMContentLoaded", function () { - setWeightBoxInformation() - getProfileEntry(); - todayEntry(); -}); - -function getProfileEntry() { - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function () { - if(this.readyState == 4 && this.status == 200) { - // Show profile details - PROFILE = JSON.parse(xmlhttp.response) - console.log(PROFILE) - showStats(); - } else if (this.readyState == 4 && this.status == 404) { - // Show create profile details - console.log("Profile not found, showing create profile interface") - } else if (this.readyState == 4) { - // Unknown error occurred - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - }; - - xmlhttp.open('GET', `http://${HOST_ADDRESS}:8079/profile/1`); - xmlhttp.send(); -} - -function setWeightBoxInformation() { - // Set checklist information - var box = document.getElementById('weight'); - box.innerText = 'Weight' - box = document.getElementById('stats') - box.innerText = 'Statistics' - - // set Graph settings - var graphBox = document.getElementById('graph') - - var graphBoxTitle = document.createElement('h3') - graphBoxTitle.id = 'graphBoxTitle' - graphBoxTitle.innerText = 'Graph' - - var weekViewButton = document.createElement('button') - weekViewButton.innerText = 'Week View' - weekViewButton.id = 'weightGraphWeekView' - weekViewButton.addEventListener('click', createWeekGraph); - - var monthViewButton = document.createElement('button') - monthViewButton.innerText = 'Month View' - monthViewButton.id = 'weightGraphMonthView' - monthViewButton.addEventListener('click', createMonthGraph); - - var yearViewButton = document.createElement('button') - yearViewButton.innerText = 'Year View' - yearViewButton.id = 'weightGraphYearView' - yearViewButton.addEventListener('click', createYearGraph); - - graphBox.appendChild(graphBoxTitle); - graphBox.appendChild(weekViewButton); - graphBox.appendChild(monthViewButton); - graphBox.appendChild(yearViewButton); -} - -function todayEntry() { - var today = getCurrentDateString() - console.log(`attempting to retrieve /weight?date=${today}`) - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - // There is an entry for today - TODAY_ENTRY = JSON.parse(xmlhttp.response) - console.log(`weight entry for ${today} found`) - - showTodayWeightInterface("weight") - } else if (this.readyState == 4 && this.status == 404) { - // No entry found for date - var response = JSON.parse(xmlhttp.response) - console.log(response.message) - - // Give option to create entry - showCreateWeightInterface("weight") - } else if (this.readyState == 4) { - // Some error occurred` - var response = JSON.parse(xmlhttp.response) - console.error(`an unexpected error occurred when calling simple-time-block-api (is it running?)`) - } - }; - - xmlhttp.open("GET", `http://${HOST_ADDRESS}:8081/weight?date=${today}`, true) - xmlhttp.send(); -} - -/** - * ================= - * SHOW STATS - * ================= - */ - -function showStats() { - var bmi = getBmi(); - var bmiString = getBmiString(bmi); - - console.log('showing stats interface') - var element = document.getElementById('stats') - - // TODO create a special div with an id that can be styled - var displayStatsDiv = document.createElement('div') - displayStatsDiv.id = 'displayStatsDiv' - displayStatsDiv.innerHTML = `

BMI: ${bmi} [${bmiString}]

` - - element.appendChild(displayStatsDiv) - - var bmiElement = document.querySelector('.bmi'); - bmiElement.classList.remove('underweight', 'normal', 'overweight', 'obese'); - bmiElement.classList.add(bmiString.toLowerCase()); -} - -function getBmi() { - var heightInInches = PROFILE.health.height; - var weightInPounds = PROFILE.health.weight; - - // Convert height from inches to meters (1 inch = 0.0254 meters) - var heightInMeters = heightInInches * 0.0254; - - // Convert weight from pounds to kilograms (1 pound = 0.453592 kilograms) - var weightInKilograms = weightInPounds * 0.453592; - - // Calculate BMI - var bmi = weightInKilograms / (heightInMeters * heightInMeters); - - // Round the BMI to two decimal places - bmi = Math.round(bmi * 100) / 100; - - return bmi; -} - -function getBmiString(bmi) { - if (bmi < 18.5) { - return "Underweight"; - } else if (bmi >= 18.5 && bmi < 25) { - return "Normal"; - } else if (bmi >= 25 && bmi < 30) { - return "Overweight"; - } else { - return "Obese"; - } -} - -function updateStats() { - var displayStatsDiv = document.getElementById('displayStatsDiv') - var bmi = getBmi(); - var bmiString = getBmiString(bmi); - displayStatsDiv.innerHTML = `

BMI: ${bmi} [${bmiString}]

` - - var bmiElement = document.querySelector('.bmi'); - bmiElement.classList.remove('underweight', 'normal', 'overweight', 'obese'); - bmiElement.classList.add(bmiString.toLowerCase()); -} - -/** - * ================= - * GRAPH - * ================= - */ - -let GRAPH_RESPONSE = null; - -function createWeekGraph() { - getGraphEntries(7); - document.getElementById('graphBoxTitle').innerText = 'Graph (Week View)' -} - -function createMonthGraph() { - getGraphEntries(30); - document.getElementById('graphBoxTitle').innerText = 'Graph (Month View)' -} - -function createYearGraph() { - getGraphEntries(365); - document.getElementById('graphBoxTitle').innerText = 'Graph (Year View)' -} - -function getGraphEntries(daysAgo) { - if(myChart) { - myChart.destroy(); - myChart = null; - } - - // Default to show Week View - var today = getCurrentDateString() - var daysAgo = getDaysAgoDateString(daysAgo) - console.log(`attempting to retrieve /weight/range?startDate=${daysAgo}&endDate=${today}`) - var xmlhttp = new XMLHttpRequest(); - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - GRAPH_RESPONSE = JSON.parse(xmlhttp.response) - - const xValues = []; - const yValues = []; - - GRAPH_RESPONSE.entries.forEach(element => { - xValues.push(element.date) - yValues.push(element.weight) - }); - - displayGraph("myChart", xValues, yValues); - } else if (this.readyState == 4) { - // Some error occurred` - var response = JSON.parse(xmlhttp.response) - console.error(`an unexpected error occurred when calling simple-time-block-api ${response.error}`) - } - }; - - xmlhttp.open("GET", `http://${HOST_ADDRESS}:8081/weight/range?startDate=${daysAgo}&endDate=${today}`, true) - xmlhttp.send(); -} - -function displayGraph(element, xValues, yValues) { - myChart = new Chart(element, { - type: "line", - data: { - labels: xValues, - datasets: [{ - label: "Weight Trend", - fill: false, - lineTension: 0.2, - backgroundColor: "rgba(0,235,123,1.0)", - borderColor: "rgba(0,166,87,0.7)", - pointRadius: 8, - pointHoverRadius: 12, - data: yValues - }] - }, - options: { - plugins: { - legend: { - labels: { - color: "white", - } - } - }, - scales: { - y: { - title: { - display: true, - color: "white", - text: "Weight" - }, - ticks: { - color: "white" - } - }, - x: { - title: { - display: true, - color: "white", - text: "Date" - }, - ticks: { - color: "white" - } - } - } - } - }); -} - -/** - * ================= - * CREATE WEIGHT FUNCTIONS - * ================= - */ - -function showCreateWeightInterface(elementId) { - var element = document.getElementById(elementId) - - var createWeightDiv = document.createElement('div') - createWeightDiv.id = 'createWeightDiv' - - // Create text box for entering weight - var weightEntryBox = document.createElement('input') - weightEntryBox.type = 'text' - weightEntryBox.id = 'createWeightEntry' - weightEntryBox.placeholder = 'Enter weight here...'; - - // Create a button for submitting the weight entry to database - var weightEntrySubmit = document.createElement('button') - weightEntrySubmit.innerText = 'Submit Entry' - weightEntrySubmit.id = 'createWeightButton' - weightEntrySubmit.addEventListener('click', handleCreateWeightClick); - - // add them to the dom - createWeightDiv.appendChild(weightEntryBox) - createWeightDiv.appendChild(weightEntrySubmit) - element.appendChild(createWeightDiv) - - // Recreate the graph view - based off of what is already there... - graph_text = document.getElementById('graphBoxTitle').innerText - if(graph_text.includes('Month')) { - createMonthGraph(); - } else if(graph_text.includes('Year')) { - createYearGraph(); - } else { - createWeekGraph(); - } - -} - -// Function to be called when the button is clicked -function handleCreateWeightClick() { - var entry = document.getElementById('createWeightEntry').value - console.log(`user entered ${entry} into the box`) - if(isFloatingPointNumber(entry)) { - // Make call to backend api - createWeightEntry(entry); - updateWeightOnProfile(entry); - } else { - alert(`Unexpected entry value: ${entry}, please enter a valid weight entry.`) - } -} - -function createWeightEntry(entry) { - console.log(`creating weight entry for today with ${entry}`) - - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("POST", `http://${HOST_ADDRESS}:8081/weight`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 201) { - console.log("successfully created, change to view") - TODAY_ENTRY = JSON.parse(xmlhttp.response) - removeCreateWeightInterface(); - showTodayWeightInterface("weight"); - } else if(this.readyState == 4) { - alert("An unexpected error occurred when creating an entry") - } - } - - var data = { - weight: entry, - date: getCurrentDateString() - }; - var jsonData = JSON.stringify(data) - - xmlhttp.send(jsonData); -} - -function updateWeightOnProfile(entry) { - PROFILE.health.weight = entry; - // gain 10 xp points for entering in daily weight - PROFILE.xp = PROFILE.xp + 10; - - var xmlhttp = new XMLHttpRequest(); - xmlhttp.open("PUT", `http://${HOST_ADDRESS}:8079/profile/1`, true) - xmlhttp.setRequestHeader("Content-Type", "application/json") - - xmlhttp.onreadystatechange = function() { - if(this.readyState == 4 && this.status == 200) { - console.log("successfully updated profile") - updateStats(); - } else if(this.readyState == 4) { - console.error("an unexpected error occurred when calling kaizen-profile-api (is it running?)") - } - } - var jsonData = JSON.stringify(PROFILE) - xmlhttp.send(jsonData); -} - -function removeCreateWeightInterface() { - var createWeightDiv = document.getElementById('createWeightDiv') - if (createWeightDiv) { - createWeightDiv.remove(); - } -} - -/** - * ================= - * SHOW WEIGHT FUNCTIONS - * ================= - */ - -function showTodayWeightInterface(elementId) { - console.log('showing today interface') - var element = document.getElementById(elementId) - - // TODO create a special div with an id that can be styled - var displayWeightDiv = document.createElement('div') - displayWeightDiv.id = 'displayWeightDiv' - displayWeightDiv.innerHTML = `

Today's weight: ${TODAY_ENTRY.weight}

` - - element.appendChild(displayWeightDiv) - createWeekGraph() -} - -/** - * ================= - * HELPER FUNCTIONS - * ================= - */ - -function getCurrentDateString() { - const today = new Date(); - - // Get year, month, and day - const year = today.getFullYear(); - const month = String(today.getMonth() + 1).padStart(2, '0'); // Month is zero-based, so add 1 - const day = String(today.getDate()).padStart(2, '0'); - - // Concatenate them in the "YYYY-mm-dd" format - const dateString = `${year}-${month}-${day}`; - - return dateString; -} - -function getDaysAgoDateString(days) { - const today = new Date(); - const sevenDaysAgo = new Date(today); - - // Subtract seven days - sevenDaysAgo.setDate(today.getDate() - days); - - // Get year, month, and day - const year = sevenDaysAgo.getFullYear(); - const month = String(sevenDaysAgo.getMonth() + 1).padStart(2, '0'); // Month is zero-based, so add 1 - const day = String(sevenDaysAgo.getDate()).padStart(2, '0'); - - // Concatenate them in the "YYYY-mm-dd" format - const dateString = `${year}-${month}-${day}`; - - return dateString; -} - -function isFloatingPointNumber(input) { - // Use a regular expression to match a floating-point number - const floatingPointPattern = /^[-+]?[0-9]*\.?[0-9]+$/; - - // Test the input against the pattern - return floatingPointPattern.test(input); -} \ No newline at end of file diff --git a/old/lists.html b/old/lists.html deleted file mode 100644 index 6cc575c..0000000 --- a/old/lists.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - Manage Lists • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-

Morning Checklist

-
-
-

Daily Checklist

-
-
-

Night Checklist

-
-
-
- - - - - \ No newline at end of file diff --git a/old/profile.html b/old/profile.html deleted file mode 100644 index 03e17d1..0000000 --- a/old/profile.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - Profile • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
-
- - - - - \ No newline at end of file diff --git a/old/schedule.html b/old/schedule.html deleted file mode 100644 index 2e9b985..0000000 --- a/old/schedule.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - Manage Schedule • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-

-
- - - - \ No newline at end of file diff --git a/old/settings.html b/old/settings.html deleted file mode 100644 index 620faec..0000000 --- a/old/settings.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - Settings • Kaizen LAN - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - \ No newline at end of file diff --git a/old/weight.html b/old/weight.html deleted file mode 100644 index 7b0e719..0000000 --- a/old/weight.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - Manage Weight • Kaizen LAN - - - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-

-

-
-
-
-

- -
-
- - - - - \ No newline at end of file diff --git a/public/kaizen_icon.png b/public/kaizen_icon.png deleted file mode 100644 index cf6e246..0000000 Binary files a/public/kaizen_icon.png and /dev/null differ diff --git a/public/kaizen_icon_outline.png b/public/kaizen_icon_outline.png deleted file mode 100644 index 345b85c..0000000 Binary files a/public/kaizen_icon_outline.png and /dev/null differ diff --git a/public/kaizen_logo.png b/public/kaizen_logo.png deleted file mode 100644 index 3bd82c0..0000000 Binary files a/public/kaizen_logo.png and /dev/null differ diff --git a/readme assets/Interface.png b/readme assets/Interface.png index 86cc7e4..a9890c4 100644 Binary files a/readme assets/Interface.png and b/readme assets/Interface.png differ diff --git a/setup.sh b/setup.sh index e69de29..6143450 100644 --- a/setup.sh +++ b/setup.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +# ANSI color codes +GRE='\033[0;32m' +RED='\033[0;31m' +MAG='\033[0;35m' +CYA='\033[0;36m' +NC='\033[0m' # No Color + +echo -e "${MAG}====================================================================${NC}" +echo -e " ${MAG}Welcome to the ${GRE}KaizenLAN ${MAG}Setup${NC}" +echo -e " ${MAG}Created by narlock -- ${CYA}Version Beta v1.0.0${NC}" +echo -e "${MAG}Please make sure you have read the README before running the setup.${NC}" +echo -e "${MAG}====================================================================${NC}" + +# Prompt the user for MySQL credentials +echo -e "${RED}Enter MySQL username: ${NC}" +read USER +echo -e "${RED}Enter MySQL password: ${NC}" +read -s PASSWORD +echo +DATABASE="narlock" +SQL_FILE="setup_database.sql" + +# Check if the database exists and create it if it doesn't +DB_EXISTS=$( + mysql -u $USER -p$PASSWORD -e "SHOW DATABASES LIKE '$DATABASE';" | grep "$DATABASE" >/dev/null + echo "$?" +) + +if [ $DB_EXISTS -eq 0 ]; then + echo "Database $DATABASE already exists." +else + echo "Database $DATABASE does not exist. Creating database..." + mysql -u $USER -p$PASSWORD -e "CREATE DATABASE $DATABASE;" + if [ $? -eq 0 ]; then + echo -e "${GRE}Database $DATABASE created successfully.${NC}" + else + echo "Failed to create database $DATABASE." + exit 1 + fi +fi + +# Execute the SQL file +mysql -u $USER -p$PASSWORD $DATABASE <$SQL_FILE + +if [ $? -eq 0 ]; then + echo -e "${GRE}SQL script executed successfully.${NC}" + + if command -v ifconfig >/dev/null 2>&1; then + ip_address=$(ifconfig | grep 'inet ' | awk '{print $2}' | grep '192\.168\.0\.') + elif command -v ip >/dev/null 2>&1; then + ip_address=$(ip addr show | grep 'inet ' | grep '192\.168\.0\.' | awk '{print $2}' | cut -d'/' -f1) + else + echo "Neither ifconfig nor ip command found." + exit 1 + fi + + if [ -n "$ip_address" ]; then + echo "The IP address is: $ip_address" + else + echo "No 192.168.0.x IP address found." + fi + + # Create the properties file in the user's home directory + PROPERTIES_FILE="$HOME/Documents/narlock/secrets/mysql.properties" + mkdir -p "$(dirname "$PROPERTIES_FILE")" # Create the directory if it doesn't exist + + echo "lmysql.username=$USER" >"$PROPERTIES_FILE" + echo "lmysql.password=$PASSWORD" >>"$PROPERTIES_FILE" + echo "lan.address=$ip_address" >>"$PROPERTIES_FILE" + + echo -e "${GRE}Properties file created at $PROPERTIES_FILE${NC}" + + # Modify the kaizenGraphInterface.js file + KAIZEN_GRAPH_FILE="$(pwd)/KaizenLAN/public/lib/graph/kaizenGraphInterface.js" + if [ -f "$KAIZEN_GRAPH_FILE" ]; then + sed -i.bak "s|const GRAPH_ENDPOINT = .*|const GRAPH_ENDPOINT = \"http://$ip_address:8080/graphql\";|" "$KAIZEN_GRAPH_FILE" + if [ $? -eq 0 ]; then + echo -e "${GRE}Updated GRAPH_ENDPOINT in $KAIZEN_GRAPH_FILE with LAN address $ip_address${NC}" + else + echo "Failed to update GRAPH_ENDPOINT in $KAIZEN_GRAPH_FILE." + exit 1 + fi + else + echo "File $KAIZEN_GRAPH_FILE not found." + exit 1 + fi + +else + echo "Failed to execute SQL script." +fi + +# Prompt the user for MySQL credentials +echo -e "${RED}Create a Kaizen username: ${NC}" +read KAIZEN_USER +echo -e "${RED}Enter birthdate (yyyy-MM-dd): ${NC}" +read KAIZEN_BIRTHDATE +echo -e "${RED}Enter weight: ${NC}" +read KAIZEN_WEIGHT +echo -e "${RED}Enter goal weight: ${NC}" +read KAIZEN_WEIGHT_GOAL +echo -e "${RED}Enter height: ${NC}" +read KAIZEN_HEIGHT +echo -e "${RED}Enter water intake goal: ${NC}" +read KAIZEN_WATER_GOAL + +# Default values +KAIZEN_XP=100 +KAIZEN_NUM_ROWS=0 +KAIZEN_PIN="1234" + +# Insert into Profile table +INSERT_PROFILE="INSERT INTO Profile (id, username, birth_date, xp, num_rows, pin) VALUES (1, '$KAIZEN_USER', '$KAIZEN_BIRTHDATE', $KAIZEN_XP, $KAIZEN_NUM_ROWS, '$KAIZEN_PIN');" +mysql -u $USER -p$PASSWORD $DATABASE -e "$INSERT_PROFILE" + +if [ $? -eq 0 ]; then + echo -e "${GRE}Profile entry created successfully.${NC}" +else + echo "Failed to create Profile entry." + exit 1 +fi + +# Get the last inserted id from Profile +PROFILE_ID=$(mysql -u $USER -p$PASSWORD $DATABASE -se "SELECT LAST_INSERT_ID();") + +# Insert into Health table +INSERT_HEALTH="INSERT INTO Health (profile_id, height, weight, goal_weight, goal_water) VALUES (1, $KAIZEN_HEIGHT, $KAIZEN_WEIGHT, $KAIZEN_WEIGHT_GOAL, $KAIZEN_WATER_GOAL);" +mysql -u $USER -p$PASSWORD $DATABASE -e "$INSERT_HEALTH" + +if [ $? -eq 0 ]; then + echo -e "${GRE}Health entry created successfully.${NC}" +else + echo "Failed to create Health entry." + exit 1 +fi + +# Move to application directory +cd KaizenLAN + +# Define the node modules you want to check and install +modules=("express") + +# Check if the node_modules directory exists +if [ ! -d "node_modules" ]; then + echo "node_modules directory does not exist. Creating and installing all modules..." + npm install +else + echo "node_modules directory exists. Checking for missing modules..." + for module in "${modules[@]}"; do + if [ ! -d "node_modules/$module" ]; then + echo "Module $module is not installed. Installing..." + npm install "$module" + else + echo "Module $module is already installed." + fi + done +fi + +echo -e "${MAG}KaizenLAN Beta v1.0.0 Setup Completed. Run ${CYA}start.sh${MAG} to start the application${NC}" diff --git a/setup_database.sql b/setup_database.sql new file mode 100644 index 0000000..edd9baa --- /dev/null +++ b/setup_database.sql @@ -0,0 +1,51 @@ +CREATE TABLE Profile( + id INT, + username VARCHAR(50), + birth_date DATE, + image_url VARCHAR(255), + xp INT, + num_rows INT, + pin CHAR(4) CHECK (pin REGEXP '^[0-9]{4}$') +); + +CREATE TABLE Health( + profile_id INT PRIMARY KEY, + height FLOAT, + weight FLOAT, + goal_weight FLOAT, + goal_water FLOAT +); + +CREATE TABLE RowInfo ( + profile_id INT, + row_index INT, + widgets_list MEDIUMTEXT +); + +CREATE TABLE Habit( + name VARCHAR(250), + profile_id INT, + PRIMARY KEY(name, profile_id) +); + +CREATE TABLE HabitEntry( + habit_name VARCHAR(250), + profile_id INT, + completed_date DATE, + PRIMARY KEY(habit_name, profile_id, completed_date) +); + +CREATE TABLE WaterEntry( + profile_id INT, + entry_date DATE, + entry_amount INT, + PRIMARY KEY(profile_id, entry_date) +); + +CREATE TABLE WeightEntry( + profile_id INT, + entry_date DATE, + entry_amount FLOAT, + PRIMARY KEY(profile_id, entry_date) +); + diff --git a/start.sh b/start.sh index f87f5c1..74a8332 100644 --- a/start.sh +++ b/start.sh @@ -1 +1,41 @@ -# TODO \ No newline at end of file +#!/bin/bash + +# ANSI color codes +GRE='\033[0;32m' +RED='\033[0;31m' +MAG='\033[0;35m' +CYA='\033[0;36m' +NC='\033[0m' + +# Change directory to api +cd api + +# Start Kaizen Profile API +echo -e "${MAG}Starting ${GRE}Kaizen Profile API{$MAG} on port 8079${NC}" +nohup java -jar kaizen-profile-api.jar & + +# Start Narlock Habit API +echo -e "${MAG}Starting ${GRE}Narlock Habit API{$MAG} on port 8089${NC}" +nohup java -jar narlock-habit-api.jar & + +# Start Narlock Water Track API +echo -e "${MAG}Starting ${GRE}Narlock Water Track API{$MAG} on port 8083${NC}" +nohup java -jar narlock-water-track-api.jar & + +# Start Narlock Weight Track API +echo -e "${MAG}Starting ${GRE}Narlock Weight Track API{$MAG} on port 8081${NC}" +nohup java -jar narlock-weight-track-api.jar & + +# Start Kaizen GraphQL API +echo -e "${MAG}Starting ${GRE}Narlock GraphQL API{$MAG} on port 8080${NC}" +nohup java -jar kaizen-graphql-api.jar & + +# Change directory to KaizenLAN server +cd ../KaizenLAN + +# Start KaizenLAN +echo -e "${MAG}Starting ${GRE}Kaizen LAN{$MAG} on port 3000${NC}" +nohup node server.js & + +# Detach from terminal +exit \ No newline at end of file diff --git a/stop.sh b/stop.sh index f87f5c1..935c144 100644 --- a/stop.sh +++ b/stop.sh @@ -1 +1,18 @@ -# TODO \ No newline at end of file +#!/bin/bash + +# Array of ports to check +ports=(3000 8079 8080 8085 8089 8081 8083) + +# Iterate through each port +for port in "${ports[@]}"; do + # Check if any process is running on the port + pid=$(lsof -ti:$port) + if [ -n "$pid" ]; then + echo "Process running on port $port with PID $pid. Killing..." + # Kill the process + kill -9 $pid + echo "Process killed." + else + echo "No process running on port $port." + fi +done \ No newline at end of file