From 9cc4eaa1de656fc3251139ec0258e62adaffefe8 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 12 Sep 2025 15:36:44 -0400 Subject: [PATCH 01/39] Update README.md --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b2588bc51..7c937d091 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ My groupmembers are: -- XXXX -- XXXX -- XXXX -- XXXX +- Caycee Harrell +- Edwina Sesay +- Malaya Conell +- Rigel Sliteris +- Abigiya Yohannes +- Aldaberto Gomez ------------------ Fill in some information about your project under this ------------------ +The Project is an app that will allow users to input their medications, when it was taken, and any side effects or symptoms they may be experiencing. From 98cd5e64880f5e9940016c5006b5fb8c185316e3 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Wed, 29 Oct 2025 21:28:00 -0400 Subject: [PATCH 02/39] Create MediTrack Main Screen --- Sprint 1/MediTrack Main Screen | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Sprint 1/MediTrack Main Screen diff --git a/Sprint 1/MediTrack Main Screen b/Sprint 1/MediTrack Main Screen new file mode 100644 index 000000000..c8aacf7f4 --- /dev/null +++ b/Sprint 1/MediTrack Main Screen @@ -0,0 +1,46 @@ +import tkinter as tk +import tkinter.font as tkFont +from tkinter import messagebox + +#Main window configurations +mainWindow = tk.Tk() +mainWindow.title("MediTrack Login form") +mainWindow.geometry("350x450") +mainWindow.configure(bg = '#F0F0F0') +font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) + +label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) +label.place(x= 125,y=0) + +def login(): + print("Hello") + username ="abc" + password = "123" + if userEntry.get() == username and passEntry.get() == password: + messagebox.showinfo(title = "Logged in", message= "Successfully logged in") + else: + messagebox.showinfo(title = "Login Failed", message= "Couldn't log in") + +#def signUp(): + #new user + #make pass + +#widgets +userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) +passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) +userEntry = tk.Entry(mainWindow) +passEntry = tk.Entry(mainWindow, show = "*") +loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) +signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1) + +#positions for labels and buttons +loginButton.place(x = 125, y = 100) +signUpButton.place(x = 125, y = 250) +userLabel.place(x=50, y=150) +userEntry.place(x=130 , y=150) +passLabel.place(x=50, y=190) +passEntry.place(x=130, y= 190) + + +mainWindow.mainloop() + From a114036e93050bba68a9375b6867d391b01fae0a Mon Sep 17 00:00:00 2001 From: harrellcc Date: Wed, 29 Oct 2025 22:14:12 -0400 Subject: [PATCH 03/39] Update and rename MediTrack Main Screen to MediTrack Main Screen Code --- .../{MediTrack Main Screen => MediTrack Main Screen Code} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename Sprint 1/{MediTrack Main Screen => MediTrack Main Screen Code} (92%) diff --git a/Sprint 1/MediTrack Main Screen b/Sprint 1/MediTrack Main Screen Code similarity index 92% rename from Sprint 1/MediTrack Main Screen rename to Sprint 1/MediTrack Main Screen Code index c8aacf7f4..0ddbbeae1 100644 --- a/Sprint 1/MediTrack Main Screen +++ b/Sprint 1/MediTrack Main Screen Code @@ -17,9 +17,9 @@ def login(): username ="abc" password = "123" if userEntry.get() == username and passEntry.get() == password: - messagebox.showinfo(title = "Logged in", message= "Successfully logged in") + messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") else: - messagebox.showinfo(title = "Login Failed", message= "Couldn't log in") + messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") #def signUp(): #new user From f93c75fd57efd41156375a76849910fdb5bcb7c1 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 31 Oct 2025 10:25:09 -0400 Subject: [PATCH 04/39] Meditrack Basic formatting the the application. Needs login logic. --- Sprint 1/MediTrack Main Screen Code | 66 ++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/Sprint 1/MediTrack Main Screen Code b/Sprint 1/MediTrack Main Screen Code index 0ddbbeae1..bf42de948 100644 --- a/Sprint 1/MediTrack Main Screen Code +++ b/Sprint 1/MediTrack Main Screen Code @@ -9,29 +9,70 @@ mainWindow.geometry("350x450") mainWindow.configure(bg = '#F0F0F0') font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) +#Dashboard Window configurations +dashboard = tk.Tk() +dashboard.title("MediTrack dashboard") +dashboard.geometry("350x450") +dashboard.configure(bg = '#F0F0F0') +dashboard.withdraw() + +#Sign-in Window +signIn = tk.Tk() +signIn.title("Create new User") +signIn.geometry("350x450") +signIn.configure(bg = '#F0F0F0') +signIn.withdraw() + label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) label.place(x= 125,y=0) + def login(): - print("Hello") - username ="abc" + username = "hello" password = "123" if userEntry.get() == username and passEntry.get() == password: + messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") + dashboard.deiconify() + mainWindow.withdraw() + + else: messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") -#def signUp(): - #new user - #make pass - -#widgets +def signUp(): + + mainWindow.withdraw() + signIn.deiconify() + + username = signUserEntry + password = signPassEntry + + if not userEntry.get() == username and not passEntry.get() == password: + messagebox.showinfo(title = "User created", message = "Redirecting back to login") + mainWindow.deiconify() + + else: + messagebox.showinfo(title = "User already exists", message = "Sign up failed, username already exists") + +#widgets main userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) userEntry = tk.Entry(mainWindow) passEntry = tk.Entry(mainWindow, show = "*") loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) -signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1) +signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) + +#widgets sign-in +signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) +signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) +passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) +signUserEntry = tk.Entry(signIn) +signPassEntry = tk.Entry(signIn) +passRentry = tk.Entry(signIn) + +#widgets dashboard +dashboardInput = tk.Entry(mainWindow) #positions for labels and buttons loginButton.place(x = 125, y = 100) @@ -40,7 +81,12 @@ userLabel.place(x=50, y=150) userEntry.place(x=130 , y=150) passLabel.place(x=50, y=190) passEntry.place(x=130, y= 190) +signUserEntry.place(x=195, y= 150) +signPassEntry.place(x=195, y= 190) +passRentry.place(x=195,y=230) +signUserEntryL.place(x=30, y=150) +signPassEntryL.place(x=30, y=190) +passRentryL.place(x=30, y=230) +dashboardInput.place(x=130, y=150) - mainWindow.mainloop() - From fff660b5d7e088ca51a17befa1bc81c7daf982bb Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 31 Oct 2025 18:10:21 -0400 Subject: [PATCH 05/39] Update MediTrack Code --- Sprint 1/MediTrack Main Screen Code | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Sprint 1/MediTrack Main Screen Code b/Sprint 1/MediTrack Main Screen Code index bf42de948..9123e230f 100644 --- a/Sprint 1/MediTrack Main Screen Code +++ b/Sprint 1/MediTrack Main Screen Code @@ -26,10 +26,11 @@ signIn.withdraw() label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) label.place(x= 125,y=0) +users = {} def login(): - username = "hello" - password = "123" + username = tk.Entry(userEntry) + password = tk.Entry(passEntry) if userEntry.get() == username and passEntry.get() == password: messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") @@ -39,6 +40,8 @@ def login(): else: messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") + +#def save(): def signUp(): @@ -50,7 +53,10 @@ def signUp(): if not userEntry.get() == username and not passEntry.get() == password: messagebox.showinfo(title = "User created", message = "Redirecting back to login") + + mainWindow.deiconify() + signIn.withdraw() else: messagebox.showinfo(title = "User already exists", message = "Sign up failed, username already exists") @@ -70,10 +76,13 @@ passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = signUserEntry = tk.Entry(signIn) signPassEntry = tk.Entry(signIn) passRentry = tk.Entry(signIn) +createUser = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1) + #widgets dashboard dashboardInput = tk.Entry(mainWindow) + #positions for labels and buttons loginButton.place(x = 125, y = 100) signUpButton.place(x = 125, y = 250) @@ -88,5 +97,8 @@ signUserEntryL.place(x=30, y=150) signPassEntryL.place(x=30, y=190) passRentryL.place(x=30, y=230) dashboardInput.place(x=130, y=150) +createUser.place(x = 130, y= 300) + mainWindow.mainloop() + From 576dc10e989ea651d9c0322ad5d7d38dee8f3a79 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:31:51 -0400 Subject: [PATCH 06/39] Delete Sprint 1/codePlaceHolder.txt --- Sprint 1/codePlaceHolder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 1/codePlaceHolder.txt diff --git a/Sprint 1/codePlaceHolder.txt b/Sprint 1/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 From 4e357248c5a0ca74965971b6f1318a4683677e1e Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:32:30 -0400 Subject: [PATCH 07/39] Meditrack Code --- Sprint 1/MediTrack Main Screen Code | 62 ++++++++++++++++------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/Sprint 1/MediTrack Main Screen Code b/Sprint 1/MediTrack Main Screen Code index 9123e230f..148898619 100644 --- a/Sprint 1/MediTrack Main Screen Code +++ b/Sprint 1/MediTrack Main Screen Code @@ -2,6 +2,8 @@ import tkinter as tk import tkinter.font as tkFont from tkinter import messagebox +users = {"sample":"123"} + #Main window configurations mainWindow = tk.Tk() mainWindow.title("MediTrack Login form") @@ -10,14 +12,14 @@ mainWindow.configure(bg = '#F0F0F0') font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) #Dashboard Window configurations -dashboard = tk.Tk() +dashboard = tk.Toplevel(mainWindow) dashboard.title("MediTrack dashboard") dashboard.geometry("350x450") dashboard.configure(bg = '#F0F0F0') dashboard.withdraw() #Sign-in Window -signIn = tk.Tk() +signIn = tk.Toplevel(mainWindow) signIn.title("Create new User") signIn.geometry("350x450") signIn.configure(bg = '#F0F0F0') @@ -26,40 +28,40 @@ signIn.withdraw() label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) label.place(x= 125,y=0) -users = {} - def login(): - username = tk.Entry(userEntry) - password = tk.Entry(passEntry) - if userEntry.get() == username and passEntry.get() == password: - + username = userEntry.get().strip() + password = passEntry.get().strip() + print("attempted login:", username, password) + + if username in users and users[username] == password: messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") dashboard.deiconify() mainWindow.withdraw() - else: messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") -#def save(): - def signUp(): - mainWindow.withdraw() signIn.deiconify() - username = signUserEntry - password = signPassEntry +def createUser(): + username = signUserEntry.get().strip() + password = signPassEntry.get().strip() + confirmPass = passRentry.get().strip() - if not userEntry.get() == username and not passEntry.get() == password: - messagebox.showinfo(title = "User created", message = "Redirecting back to login") - - - mainWindow.deiconify() - signIn.withdraw() + if username in users: + messagebox.showinfo(title = "Sign up failed", message = "Account with this user already exists") + elif password != confirmPass: + messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") + else: - messagebox.showinfo(title = "User already exists", message = "Sign up failed, username already exists") + users[username] = password + print(users) + messagebox.showinfo(title = "User created", message = "Redirecting back to login") + signIn.withdraw() + mainWindow.deiconify() #widgets main userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) @@ -74,31 +76,35 @@ signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) signUserEntry = tk.Entry(signIn) -signPassEntry = tk.Entry(signIn) -passRentry = tk.Entry(signIn) -createUser = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1) - +signPassEntry = tk.Entry(signIn, show = "*") +passRentry = tk.Entry(signIn,show = "*") +createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) #widgets dashboard -dashboardInput = tk.Entry(mainWindow) +dashboardInput = tk.Entry(dashboard) +dashboardInputL = passRentryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) #positions for labels and buttons +#login loginButton.place(x = 125, y = 100) signUpButton.place(x = 125, y = 250) userLabel.place(x=50, y=150) userEntry.place(x=130 , y=150) passLabel.place(x=50, y=190) passEntry.place(x=130, y= 190) +#signin signUserEntry.place(x=195, y= 150) signPassEntry.place(x=195, y= 190) passRentry.place(x=195,y=230) signUserEntryL.place(x=30, y=150) signPassEntryL.place(x=30, y=190) passRentryL.place(x=30, y=230) +createUserButton.place(x = 130, y= 300) +#dashboard dashboardInput.place(x=130, y=150) -createUser.place(x = 130, y= 300) - + + mainWindow.mainloop() From 8ee856de2fbb4ca83eadb163c79172e4b516bbda Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:34:20 -0400 Subject: [PATCH 08/39] Create Sprint 1 Test Cases --- Sprint 1/Sprint 1 Test Cases | 83 ++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Sprint 1/Sprint 1 Test Cases diff --git a/Sprint 1/Sprint 1 Test Cases b/Sprint 1/Sprint 1 Test Cases new file mode 100644 index 000000000..aa2dbe9d1 --- /dev/null +++ b/Sprint 1/Sprint 1 Test Cases @@ -0,0 +1,83 @@ +Use Case 1 - Meditrack Login/Sign-in Page +Test Case ID +TC01 - User attempts to login +Test Objective +The User will log into meditracker and be shown their dashboard +Preconditions +User must have a pre-existing username and password +Test steps +User opens the app +User inputs their username + User inputs their password +User presses login +Test ends +Input Values +Username- ##### +Password- ##### +Expected results +“Successfully logged in” will be displayed, +User will be redirected to a screen displaying an entry to input medications + + + +Test Case ID +TC02 - New user attempts to create an account +Test Objective +The user will attempt to create a new account +Preconditions +A supported browser is being used +Test steps +User selects ‘Create New Account’ +In the ‘E-mail or Phone Number’ field user enters their email or phone number +User creates a username in the ‘Username’ field +User creates a password in the ‘Create Password’ field +User re-enters password in the ‘Confirm Password’ field +Click the ‘Create User’ button +Input Values +Email : ##### +Password : ##### +Re-enter Password : ##### +Expected results +User is taken to the login page and “Account Created!” is displayed + + + +Test Case ID +TC03 - User’s login fails +Test Objective +If an invalid username or password is inputted, the login process should fail. +Preconditions +The entered username and/or password are not registered in the system +Test steps +User inputs their username in the ‘Username’ field +User inputs their password in the ‘Password’ field +Click ‘login’ +Input Values +Username : ##### +Password : ##### +Expected results +The login process will fail, and “Invalid Username or Password” will be displayed + + + +Test Case ID +TC04 - User’s sign in attempt fails/ account already exists +Test Objective +Ensure the system prevents users from creating an account that already exists. +Preconditions +An account must already be made with a username and password +Test steps +User opens the Meditrack sign-up page. +User enters an existing email address or phone number in the “Email or Phone Number” field. +User enters a username already associated with another account +User creates and confirms a password +User clicks the “Create User” button to complete registration. +Input Values +Email: #### (already registered) +Username: #### (already registered) +Password: ##### +Confirm Password: ##### +Expected results +The system displays an error message such as “Account with this user already exists.“ The user remains on the sign-up page, and no new account is created. + + From aca46acaa2be86b601f55cf7dd27bebd895e6a08 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:52:43 -0400 Subject: [PATCH 09/39] Create Sprint 1 Test Case Recording --- Sprint 1/Sprint 1 Test Case Recording | 1 + 1 file changed, 1 insertion(+) create mode 100644 Sprint 1/Sprint 1 Test Case Recording diff --git a/Sprint 1/Sprint 1 Test Case Recording b/Sprint 1/Sprint 1 Test Case Recording new file mode 100644 index 000000000..1d3c44c29 --- /dev/null +++ b/Sprint 1/Sprint 1 Test Case Recording @@ -0,0 +1 @@ +https://vcu.zoom.us/rec/share/NFEIxuddtujtpLaQX4Scsvssi1sRmw-_CzQKJ-3qdN_KS0dRzinh6_FWEiUNga9U.4hqBf_iIo3qciR-J?startTime=1762015481000 From 7c5f8866dce50f11fc025518ffb56af441d3ce32 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:53:05 -0400 Subject: [PATCH 10/39] Delete Sprint 1/TestCasesPlaceholder.txt --- Sprint 1/TestCasesPlaceholder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 1/TestCasesPlaceholder.txt diff --git a/Sprint 1/TestCasesPlaceholder.txt b/Sprint 1/TestCasesPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 From 06729bb0e08b58db27f40a31672b1ac619aa0780 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Sat, 1 Nov 2025 12:53:21 -0400 Subject: [PATCH 11/39] Delete Sprint 1/videoPlaceholder.txt --- Sprint 1/videoPlaceholder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 1/videoPlaceholder.txt diff --git a/Sprint 1/videoPlaceholder.txt b/Sprint 1/videoPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 From ff610c3a65a1820a61d106aa369327cd7233e1f1 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Wed, 12 Nov 2025 14:14:57 -0500 Subject: [PATCH 12/39] Create Meditrack Code --- Sprint 2/Meditrack Code | 109 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Sprint 2/Meditrack Code diff --git a/Sprint 2/Meditrack Code b/Sprint 2/Meditrack Code new file mode 100644 index 000000000..76ff66e73 --- /dev/null +++ b/Sprint 2/Meditrack Code @@ -0,0 +1,109 @@ +import tkinter as tk +import tkinter.font as tkFont +from tkinter import messagebox + +users = {"sample":"123"} + +#Main window configurations +mainWindow = tk.Tk() +mainWindow.title("MediTrack Login form") +mainWindow.geometry("350x450") +mainWindow.configure(bg = '#F0F0F0') +font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) + +#Dashboard Window configurations +dashboard = tk.Toplevel(mainWindow) +dashboard.title("MediTrack dashboard") +dashboard.geometry("350x450") +dashboard.configure(bg = '#F0F0F0') +dashboard.withdraw() + +#Sign-in Window +signIn = tk.Toplevel(mainWindow) +signIn.title("Create new User") +signIn.geometry("350x450") +signIn.configure(bg = '#F0F0F0') +signIn.withdraw() + +label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) +label.place(x= 125,y=0) + +def login(): + username = userEntry.get().strip() + password = passEntry.get().strip() + print("attempted login:", username, password) + + if username in users and users[username] == password: + messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") + dashboard.deiconify() + mainWindow.withdraw() + + else: + messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") + +def signUp(): + mainWindow.withdraw() + signIn.deiconify() + +def createUser(): + username = signUserEntry.get().strip() + password = signPassEntry.get().strip() + confirmPass = passRentry.get().strip() + + if username in users: + messagebox.showinfo(title = "Sign up failed", message = "Account with this user already exists") + + elif password != confirmPass: + messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") + + else: + users[username] = password + print(users) + messagebox.showinfo(title = "User created", message = "Redirecting back to login") + signIn.withdraw() + mainWindow.deiconify() + +#widgets main +userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) +passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) +userEntry = tk.Entry(mainWindow) +passEntry = tk.Entry(mainWindow, show = "*") +loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) +signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) + +#widgets sign-in +signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) +signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) +passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) +signUserEntry = tk.Entry(signIn) +signPassEntry = tk.Entry(signIn, show = "*") +passRentry = tk.Entry(signIn,show = "*") +createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) + +#widgets dashboard +dashboardInput = tk.Entry(dashboard) +dashboardInputL = passRentryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) + + +#positions for labels and buttons +#login +loginButton.place(x = 125, y = 100) +signUpButton.place(x = 125, y = 250) +userLabel.place(x=50, y=150) +userEntry.place(x=130 , y=150) +passLabel.place(x=50, y=190) +passEntry.place(x=130, y= 190) +#signin +signUserEntry.place(x=195, y= 150) +signPassEntry.place(x=195, y= 190) +passRentry.place(x=195,y=230) +signUserEntryL.place(x=30, y=150) +signPassEntryL.place(x=30, y=190) +passRentryL.place(x=30, y=230) +createUserButton.place(x = 130, y= 300) +#dashboard +dashboardInput.place(x=130, y=150) + + + +mainWindow.mainloop() From 49d84428641b0359e101fb806e7433fad76560f1 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Wed, 12 Nov 2025 15:13:44 -0500 Subject: [PATCH 13/39] TC04 Created global medications list and an addMedication() to check if medication has already been added. Also linked an "add medication" button to the function. Tested it and it works --- Sprint 2/{Meditrack Code => meditrackCode.py} | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) rename Sprint 2/{Meditrack Code => meditrackCode.py} (84%) diff --git a/Sprint 2/Meditrack Code b/Sprint 2/meditrackCode.py similarity index 84% rename from Sprint 2/Meditrack Code rename to Sprint 2/meditrackCode.py index 76ff66e73..552b9a78e 100644 --- a/Sprint 2/Meditrack Code +++ b/Sprint 2/meditrackCode.py @@ -2,7 +2,8 @@ import tkinter.font as tkFont from tkinter import messagebox -users = {"sample":"123"} +users = {"sample":"123"} #Predefined user for testing +medications = [] #List to store medications #Main window configurations mainWindow = tk.Tk() @@ -62,6 +63,18 @@ def createUser(): messagebox.showinfo(title = "User created", message = "Redirecting back to login") signIn.withdraw() mainWindow.deiconify() + +#adds medication to the list if not already present +def addMedication(): + global medications + med_input = dashboardInput.get().strip() + if med_input in medications: + messagebox.showinfo(title = "Duplicate Entry", message = "Medication already exists in the list") + else: + medications.append(med_input) + messagebox.showinfo(title = "Medication Added", message = f"{med_input} added to your medications") + + #widgets main userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) @@ -83,6 +96,7 @@ def createUser(): #widgets dashboard dashboardInput = tk.Entry(dashboard) dashboardInputL = passRentryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) +addButton = tk.Button(dashboard, text="Add Medication", command=addMedication) #positions for labels and buttons @@ -103,6 +117,7 @@ def createUser(): createUserButton.place(x = 130, y= 300) #dashboard dashboardInput.place(x=130, y=150) +addButton.place(x=130, y=190) From ca81e2cbd33f2a6ec47a18bc4191ccb8d92b3e16 Mon Sep 17 00:00:00 2001 From: mallc00 <158099350+mallc00@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:14:22 -0500 Subject: [PATCH 14/39] Update README with group members and project description Added project description and formatted group members section. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7c937d091..aebd7cf89 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -My groupmembers are: +# Group Members - Caycee Harrell - Edwina Sesay - Malaya Conell @@ -6,6 +6,6 @@ My groupmembers are: - Abigiya Yohannes - Aldaberto Gomez - ------------------- Fill in some information about your project under this ------------------ +--- +## Descriptions The Project is an app that will allow users to input their medications, when it was taken, and any side effects or symptoms they may be experiencing. From 85261a58ecf0a921589015374cd77642bf69c842 Mon Sep 17 00:00:00 2001 From: mallc00 <158099350+mallc00@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:23:01 -0500 Subject: [PATCH 15/39] Add test case for duplicate medication entry This test case verifies that the MediTrack system prevents duplicate medication entries. --- Sprint 2/Sprint 2 Test Case | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Sprint 2/Sprint 2 Test Case diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case new file mode 100644 index 000000000..2f0edcdf3 --- /dev/null +++ b/Sprint 2/Sprint 2 Test Case @@ -0,0 +1,20 @@ +TC04 - The user attempts to input an medication that is already registered + Test Objective: Verify that the MediTrack system prevents the user from adding a medication entry that has already been recorded + Preconditions: The dashboard window is active, at least one medication is on record + + Test Steps: + 1. Navigate to the Dashboard window + 2. In the medication input field, enter a medication record identical to an existing one + 3. Click the save or record button + 4. Observe the system's response + + Input Values: + - Medication Name + - Dosage + - Time + - Symptoms + + Expected Results: + - A message box appears stating: "Medication already exists in the list" + - The duplicate record is not saved or added to the log + - The existing medication remains unchanged From f3bd86a2f0c3d7adc85e68b4efcad1dd37e02b4f Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Wed, 12 Nov 2025 17:33:17 -0500 Subject: [PATCH 16/39] Updated the dashboard Still some bugs, in progress --- Sprint 2/meditrackCode.py | 147 +++++++++++++++++++++++++++++++------- 1 file changed, 123 insertions(+), 24 deletions(-) diff --git a/Sprint 2/meditrackCode.py b/Sprint 2/meditrackCode.py index 552b9a78e..05bba7ebd 100644 --- a/Sprint 2/meditrackCode.py +++ b/Sprint 2/meditrackCode.py @@ -2,8 +2,22 @@ import tkinter.font as tkFont from tkinter import messagebox -users = {"sample":"123"} #Predefined user for testing -medications = [] #List to store medications +#User database +users = { + "sample": { + "password": "123", + "medications": [ + { + "name": "Aspirin", + "dosage": "100mg", + "time": "08:00 AM", + "symptoms": "Headache" + } + ] + } +} + +current_user = None #Main window configurations mainWindow = tk.Tk() @@ -15,7 +29,7 @@ #Dashboard Window configurations dashboard = tk.Toplevel(mainWindow) dashboard.title("MediTrack dashboard") -dashboard.geometry("350x450") +dashboard.geometry("800x450") dashboard.configure(bg = '#F0F0F0') dashboard.withdraw() @@ -26,22 +40,35 @@ signIn.configure(bg = '#F0F0F0') signIn.withdraw() + + +''' TODO: Implement history window + CODE: + historyWindow = tk.Toplevel(dashboard) + historyWindow.title("Medication History") + historyWindow.geometry("350x450") + historyWindow.configure(bg = '#F0F0F0') + historyWindow.withdraw() ''' + label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) label.place(x= 125,y=0) def login(): + global users + global current_user username = userEntry.get().strip() password = passEntry.get().strip() print("attempted login:", username, password) - if username in users and users[username] == password: - messagebox.showinfo(title = "Logged in", message= "Successfully logged in!") + if username in users and users[username]["password"] == password: + current_user = username + messagebox.showinfo(title = "Login Successful", message = f"Welcome back, {username}!") dashboard.deiconify() mainWindow.withdraw() - + updateMedListbox() else: - messagebox.showinfo(title = "Login Failed", message= "Invalid Username or Password") - + messagebox.showinfo(title = "Login Failed", message = "Invalid username or password") + def signUp(): mainWindow.withdraw() signIn.deiconify() @@ -64,19 +91,52 @@ def createUser(): signIn.withdraw() mainWindow.deiconify() +def updateMedListbox(): + global current_user + medListbox.delete(0, tk.END) + user_medications = users[current_user].get("medications", []) + for med in user_medications: + line = f"{med['name']} | {med['dosage']} | {med['time']} | {med['symptoms']}" + medListbox.insert(tk.END, line) + #adds medication to the list if not already present def addMedication(): - global medications - med_input = dashboardInput.get().strip() - if med_input in medications: - messagebox.showinfo(title = "Duplicate Entry", message = "Medication already exists in the list") - else: - medications.append(med_input) - messagebox.showinfo(title = "Medication Added", message = f"{med_input} added to your medications") + global current_user + user_medications = users[current_user].setdefault("medications", []) + + med_input = medicationEntry.get().strip() + dosage = dosageEntry.get().strip() + time = timeEntry.get().strip() + symptoms = symptomsEntry.get().strip() + + #check the list for duplicate entries + if any(med['name'].lower() == med_input.lower() for med in user_medications): + messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") + return + + #add medication to the list + user_medications.append( { + "name": med_input, + "dosage": dosage, + "time": time, + "symptoms": symptoms + }) + + line= f"{med_input} | {dosage} | {time} | {symptoms}" + medListbox.insert(tk.END, line) + + #confirmation message + messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") + + #clear input fields + medicationEntry.delete(0, tk.END) + dosageEntry.delete(0, tk.END) + timeEntry.delete(0, tk.END) + symptomsEntry.delete(0, tk.END) + - -#widgets main +#widgets main login window userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) userEntry = tk.Entry(mainWindow) @@ -84,7 +144,7 @@ def addMedication(): loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) -#widgets sign-in +#widgets create user window signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) @@ -92,14 +152,36 @@ def addMedication(): signPassEntry = tk.Entry(signIn, show = "*") passRentry = tk.Entry(signIn,show = "*") createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) +backButton = tk.Button(signIn, text="Go Back", bg="#F5D5F7", font=font1, command=lambda: [signIn.withdraw(), mainWindow.deiconify()]) + + +#Widgets dashboard: -#widgets dashboard -dashboardInput = tk.Entry(dashboard) -dashboardInputL = passRentryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) +#Add Medication Button and Entries +addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), dashboard.deiconify()]) +medicationEntry = tk.Entry(dashboard) +medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) +dosageEntry = tk.Entry(dashboard) +dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) +timeEntry = tk.Entry(dashboard) +timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) +symptomsEntry = tk.Entry(dashboard) +symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) addButton = tk.Button(dashboard, text="Add Medication", command=addMedication) +#Listbox and Scrollbar for medications +medListbox = tk.Listbox(dashboard, font=font1) +scrollbar = tk.Scrollbar(dashboard, orient=tk.VERTICAL) + +medListbox.config(yscrollcommand=scrollbar.set) +scrollbar.config(command=medListbox.yview) + +'''TODO: Implement history window and its button +historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' + #positions for labels and buttons + #login loginButton.place(x = 125, y = 100) signUpButton.place(x = 125, y = 250) @@ -107,7 +189,7 @@ def addMedication(): userEntry.place(x=130 , y=150) passLabel.place(x=50, y=190) passEntry.place(x=130, y= 190) -#signin +#create signUserEntry.place(x=195, y= 150) signPassEntry.place(x=195, y= 190) passRentry.place(x=195,y=230) @@ -115,9 +197,26 @@ def addMedication(): signPassEntryL.place(x=30, y=190) passRentryL.place(x=30, y=230) createUserButton.place(x = 130, y= 300) +backButton.place(x=130, y=350) #dashboard -dashboardInput.place(x=130, y=150) -addButton.place(x=130, y=190) +medicationEntryL.place(x=20, y=30) +medicationEntry.place(x=150, y=30, width=140) + +dosageEntryL.place(x=20, y=80) +dosageEntry.place(x=150, y=80, width=140) + +timeEntryL.place(x=20, y=130) +timeEntry.place(x=150, y=130, width=140) + +symptomsEntryL.place(x=20, y=180) +symptomsEntry.place(x=150, y=180, width=140) + +addMedButton.place(x=20, y=230, width=260, height=30) + +medListbox.place(x=350, y=30, width=400, height=350) +scrollbar.place(x=750, y=30, width=20, height=350) + +'''TODO: Implement history window layout''' From 6e09fed0420da5cb8aa4ad99b94f9266864c59d3 Mon Sep 17 00:00:00 2001 From: mallc00 <158099350+mallc00@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:41:14 -0500 Subject: [PATCH 17/39] Revise test case for adding existing medication Updated test case steps to reflect new navigation and input values. --- Sprint 2/Sprint 2 Test Case | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case index 2f0edcdf3..92ac2a619 100644 --- a/Sprint 2/Sprint 2 Test Case +++ b/Sprint 2/Sprint 2 Test Case @@ -4,15 +4,16 @@ TC04 - The user attempts to input an medication that is already registered Test Steps: 1. Navigate to the Dashboard window - 2. In the medication input field, enter a medication record identical to an existing one - 3. Click the save or record button - 4. Observe the system's response + 2. Press Add New Medication which navigates to a different page + 3. In the medication input field, enter a medication record identical to an existing one + 4. Click the save or record button + 5. Observe the system's response Input Values: - Medication Name - Dosage - - Time - - Symptoms + - Time to Take + - Common Symptoms Expected Results: - A message box appears stating: "Medication already exists in the list" From 4ce9aafb5e3927b66a621f0b7b408410a458929c Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 11:20:54 -0500 Subject: [PATCH 18/39] Delete Sprint 2/codePlaceHolder.txt --- Sprint 2/codePlaceHolder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 2/codePlaceHolder.txt diff --git a/Sprint 2/codePlaceHolder.txt b/Sprint 2/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 From 7b86d9052772c658e1440078af8d80cb02d003e8 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 11:21:16 -0500 Subject: [PATCH 19/39] Delete Sprint 2/TestCasesPlaceholder.txt --- Sprint 2/TestCasesPlaceholder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 2/TestCasesPlaceholder.txt diff --git a/Sprint 2/TestCasesPlaceholder.txt b/Sprint 2/TestCasesPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 From dcf3ae64c57b77c356f8587c725fcf4a8f3cef81 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 12:06:14 -0500 Subject: [PATCH 20/39] Update Sprint 2 Test Case --- Sprint 2/Sprint 2 Test Case | 114 +++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case index 92ac2a619..b702be543 100644 --- a/Sprint 2/Sprint 2 Test Case +++ b/Sprint 2/Sprint 2 Test Case @@ -1,21 +1,95 @@ +Use Case 2 - <> +Test Case ID +TC01 - The user adds a medication to their list of medicine +Test Objective +The user will add a medicine to their account through the dashboard +Preconditions +The user has already logged into their account +Test steps +The user logs in and goes to their dashboard +The user presses Add Medicine +The user inputs the Medicine +The user presses add medicine +A pop up displaying “Medicine has been added” will show, and the medicine will be displayed in a list on the dashboard +Test case ends +Input Values +Medicine Name-########### +Dosages-############ +Symptoms-########### +Expected results +The medicine will be added and will be shown on a list of medicines + + + +Test Case ID +TC02 - The User records an administered dosage of a specific mediation, and symptoms +Test Objective +Verify that the user can record an administered dosage of a specific medication and note any symptoms after taking it. +Preconditions +The dashboard window is visible and active +Test steps +Navigate to dashboard window +The user input their medications +Click the save or record button +Observe confirmation of successful entry or appearance of the saved data in the log/list +Input Values +Medication name +Dosage +Time Taken +Symptoms +Expected results +A message box appears stating”Medication record saved successfully: or the data appears in a displayed medication history/log +The input field clears after saving +The saved record is stored in memory(or in a file/database, depending on implementation) + + + +Test Case ID +TC03 - The user removes a medication +Test Objective +To verify that the system correctly removes a medication from the user’s medication list and the display updates accordingly. +Preconditions +The user is logged into their account, the user has at least one medication on their list +Test steps +The user navigates to their Dashboard +The user opens the Medication List +The user selects a specific medication they wish to remove. +The user clicks on the “Remove” or “Delete button” next to the medication +The system will then prompt a confirmation message, “Are you sure you want to remove this medication?” +The user confirms the deletion by clicking “Yes”? +The system displays a success message (“Medication removed successfully”) +The list refreshes to reflect the removal +Input Values +Medication to remove: “Ibuprofen 200 mg” +Confirmation: Yes +Expected results +The selected medication is deleted from the list. +The updated medication list no longer displays the removed medication. +A success message appears confirming removal +No errors or crashes during. + + + +Test Case ID TC04 - The user attempts to input an medication that is already registered - Test Objective: Verify that the MediTrack system prevents the user from adding a medication entry that has already been recorded - Preconditions: The dashboard window is active, at least one medication is on record - - Test Steps: - 1. Navigate to the Dashboard window - 2. Press Add New Medication which navigates to a different page - 3. In the medication input field, enter a medication record identical to an existing one - 4. Click the save or record button - 5. Observe the system's response - - Input Values: - - Medication Name - - Dosage - - Time to Take - - Common Symptoms - - Expected Results: - - A message box appears stating: "Medication already exists in the list" - - The duplicate record is not saved or added to the log - - The existing medication remains unchanged +Test Objective +Verify that the MediTrack system prevents the user from adding a medication entry that has already been recorded +Preconditions +The dashboard window is active, at least one medication record +Test steps +Navigate to the Dashboard window +In the medication input field, enter a medication record identical to an existing one +Click the save or record button +Observe the system's response +Observe the system’s response +Input Values +Medication name +Dosage +Time +Symptoms +Expected results +A message box appears stating: “This is the medication entry already exists.” +The duplicate record is not saved or added to the log +The existing medication record remains unchanged + + From 08c6daf4c2b798ac590fcec03a3ca3483015a00e Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Fri, 14 Nov 2025 16:34:56 -0500 Subject: [PATCH 21/39] Fixed the error message The newly added medication sends an error message if it's already in the system. Also, if no symptoms were added, it displays "None" on the listBox --- Sprint 2/meditrackCode.py | 80 ++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/Sprint 2/meditrackCode.py b/Sprint 2/meditrackCode.py index 05bba7ebd..8d705aed3 100644 --- a/Sprint 2/meditrackCode.py +++ b/Sprint 2/meditrackCode.py @@ -10,7 +10,7 @@ { "name": "Aspirin", "dosage": "100mg", - "time": "08:00 AM", + "time": "8:00 AM", "symptoms": "Headache" } ] @@ -91,49 +91,78 @@ def createUser(): signIn.withdraw() mainWindow.deiconify() -def updateMedListbox(): - global current_user - medListbox.delete(0, tk.END) - user_medications = users[current_user].get("medications", []) - for med in user_medications: - line = f"{med['name']} | {med['dosage']} | {med['time']} | {med['symptoms']}" - medListbox.insert(tk.END, line) - #adds medication to the list if not already present def addMedication(): global current_user user_medications = users[current_user].setdefault("medications", []) med_input = medicationEntry.get().strip() - dosage = dosageEntry.get().strip() - time = timeEntry.get().strip() - symptoms = symptomsEntry.get().strip() + dosage_input = dosageEntry.get().strip() + time_input = timeEntry.get().strip() + symptoms_input = symptomsEntry.get().strip() + + #input validation + if not med_input: + messagebox.showinfo(title="Missing input", message="Medication cannot be empty!") + return + + if not dosage_input: + messagebox.showinfo(title="Missing input", message="Please enter the dosage") + return + + if not time_input: + messagebox.showinfo(title="Missing input", message="Please enter the time to take the medication") + return + - #check the list for duplicate entries - if any(med['name'].lower() == med_input.lower() for med in user_medications): + med_norm = med_input.casefold() + + #duplicate check + is_duplicate = any(med.get("name", "").strip().casefold() == med_norm + for med in user_medications) + + if is_duplicate: messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") return #add medication to the list - user_medications.append( { + new_med = ( { "name": med_input, - "dosage": dosage, - "time": time, - "symptoms": symptoms + "dosage": dosage_input, + "time": time_input, + "symptoms": symptoms_input }) + user_medications.append(new_med) + users[current_user]["medications"] = user_medications - line= f"{med_input} | {dosage} | {time} | {symptoms}" - medListbox.insert(tk.END, line) + #refresh listbox + updateMedListbox() - #confirmation message - messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") - - #clear input fields + #clear entries medicationEntry.delete(0, tk.END) dosageEntry.delete(0, tk.END) timeEntry.delete(0, tk.END) symptomsEntry.delete(0, tk.END) + #confirmation message + messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") + print(f"[DEBUG] Current medications for {current_user}: {users[current_user]['medications']}") + + +def updateMedListbox(): + global current_user + medListbox.delete(0, tk.END) + + medListbox.insert(tk.END, "Name | Dose | Time | Symptoms") + medListbox.itemconfig(0, {'fg': 'white', 'bg': 'black'}) + + user_medications = users[current_user].get("medications", []) + for med in user_medications: + #if symptoms is empty, display "None" + symptoms_display = med.get("symptoms", "").strip() or "None" + line = f"{med['name']} | {med['dosage']} | {med['time']} | {symptoms_display}" + medListbox.insert(tk.END, line) + #widgets main login window @@ -158,7 +187,7 @@ def addMedication(): #Widgets dashboard: #Add Medication Button and Entries -addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), dashboard.deiconify()]) +addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) medicationEntry = tk.Entry(dashboard) medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) dosageEntry = tk.Entry(dashboard) @@ -167,7 +196,6 @@ def addMedication(): timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) symptomsEntry = tk.Entry(dashboard) symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) -addButton = tk.Button(dashboard, text="Add Medication", command=addMedication) #Listbox and Scrollbar for medications medListbox = tk.Listbox(dashboard, font=font1) From e3f5a6fa99fc4b09dd0a85b592a02a9d21715083 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 17:21:13 -0500 Subject: [PATCH 22/39] Update Sprint 2 Test Case --- Sprint 2/Sprint 2 Test Case | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case index b702be543..17e247f84 100644 --- a/Sprint 2/Sprint 2 Test Case +++ b/Sprint 2/Sprint 2 Test Case @@ -13,9 +13,9 @@ The user presses add medicine A pop up displaying “Medicine has been added” will show, and the medicine will be displayed in a list on the dashboard Test case ends Input Values -Medicine Name-########### -Dosages-############ -Symptoms-########### +Medicine Name- “Ibuprofen” +Dosage- “200 mg” +Symptoms- “Nausea” Expected results The medicine will be added and will be shown on a list of medicines @@ -33,10 +33,9 @@ The user input their medications Click the save or record button Observe confirmation of successful entry or appearance of the saved data in the log/list Input Values -Medication name -Dosage -Time Taken -Symptoms +Medication name - "Ibuprofen" +Dosage - "200 mg" +Symptoms - "Nausea" Expected results A message box appears stating”Medication record saved successfully: or the data appears in a displayed medication history/log The input field clears after saving @@ -83,12 +82,11 @@ Click the save or record button Observe the system's response Observe the system’s response Input Values -Medication name -Dosage -Time -Symptoms +Medication name - “Ibuprofen” +Dosage - “200 mg” +Symptoms - “Nausea” Expected results -A message box appears stating: “This is the medication entry already exists.” +A message box appears stating: “This medication entry already exists.” The duplicate record is not saved or added to the log The existing medication record remains unchanged From 425af374f3d9be97c61989de6e3c448e21e2e92a Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Fri, 14 Nov 2025 17:31:14 -0500 Subject: [PATCH 23/39] Added TC03 remove button appears if medication is selected and returns a yes or no message --- Sprint 2/meditrackCode.py | 66 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/Sprint 2/meditrackCode.py b/Sprint 2/meditrackCode.py index 8d705aed3..9749a222a 100644 --- a/Sprint 2/meditrackCode.py +++ b/Sprint 2/meditrackCode.py @@ -1,6 +1,6 @@ import tkinter as tk import tkinter.font as tkFont -from tkinter import messagebox +from tkinter import Listbox, messagebox #User database users = { @@ -148,6 +148,37 @@ def addMedication(): messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") print(f"[DEBUG] Current medications for {current_user}: {users[current_user]['medications']}") +#function to remove selected medication from listbox and user data +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + + medListbox.bind('<>', onMedSelect) + + +#function to confirm and remove medication +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() + def updateMedListbox(): global current_user @@ -204,6 +235,12 @@ def updateMedListbox(): medListbox.config(yscrollcommand=scrollbar.set) scrollbar.config(command=medListbox.yview) +#remove medication button appears when a medication is selected +removeMedButton = tk.Button(dashboard, text="Remove Selected Medication", font=font1, bg="#F5D5F7", command=confirmRemoveMedication) +removeMedButton.place(x=350, y=390, width=200, height=30) +removeMedButton.place_forget() + + '''TODO: Implement history window and its button historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' @@ -246,6 +283,33 @@ def updateMedListbox(): '''TODO: Implement history window layout''' +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + +medListbox.bind('<>', onMedSelect) + +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() mainWindow.mainloop() From 7dd3519939d1a8cf24536ca983c0a133a9d48d7c Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 18:34:26 -0500 Subject: [PATCH 24/39] Update Sprint 2 Test Case --- Sprint 2/Sprint 2 Test Case | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case index 17e247f84..7f37ce907 100644 --- a/Sprint 2/Sprint 2 Test Case +++ b/Sprint 2/Sprint 2 Test Case @@ -15,6 +15,7 @@ Test case ends Input Values Medicine Name- “Ibuprofen” Dosage- “200 mg” +Time Taken = “8:00 AM” Symptoms- “Nausea” Expected results The medicine will be added and will be shown on a list of medicines @@ -33,9 +34,10 @@ The user input their medications Click the save or record button Observe confirmation of successful entry or appearance of the saved data in the log/list Input Values -Medication name - "Ibuprofen" -Dosage - "200 mg" -Symptoms - "Nausea" +Medication name - “ibuprofen +Dosage - “200 mg” +Time Taken = “8:00 AM” +Symptoms - “Nausea” Expected results A message box appears stating”Medication record saved successfully: or the data appears in a displayed medication history/log The input field clears after saving @@ -84,6 +86,7 @@ Observe the system’s response Input Values Medication name - “Ibuprofen” Dosage - “200 mg” +Time Taken = “8:00 AM” Symptoms - “Nausea” Expected results A message box appears stating: “This medication entry already exists.” From 5d5c1c12baf401ea506e160cfee1973745764167 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 19:09:38 -0500 Subject: [PATCH 25/39] Create Sprint 2 Recording --- Sprint 2/Sprint 2 Recording | 1 + 1 file changed, 1 insertion(+) create mode 100644 Sprint 2/Sprint 2 Recording diff --git a/Sprint 2/Sprint 2 Recording b/Sprint 2/Sprint 2 Recording new file mode 100644 index 000000000..37348f180 --- /dev/null +++ b/Sprint 2/Sprint 2 Recording @@ -0,0 +1 @@ +https://vcu.zoom.us/rec/play/CSbqLpNNao6o_fur1zASfeS9lyc9pzS7VauosFjgbYCe-CDNviy-IhAGtRnYtM-QYvpezksc0N9HRPR1.t4hJz9qMhrxyH2oq?eagerLoadZvaPages=sidemenu.billing.plan_management&isReferralProgramEnabled=false&isReferralProgramAvailable=false&accessLevel=meeting&canPlayFromShare=true&from=my_recording&continueMode=true&componentName=rec-play&originRequestUrl=https%3A%2F%2Fvcu.zoom.us%2Frec%2Fshare%2Fr2lm51MObN1fr-zCPBXFOWxf969z35Hp3zTN5Qu5gmymDZIAYFiTaIuKtt-ClbqK.Xo6vWVXoZAxG6FvY&autoplay=true&startTime=1763164710000 From 3a55b1522aaf650134b72a98de198edb80b06d73 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 19:09:51 -0500 Subject: [PATCH 26/39] Delete Sprint 2/videoPlaceholder.txt --- Sprint 2/videoPlaceholder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 2/videoPlaceholder.txt diff --git a/Sprint 2/videoPlaceholder.txt b/Sprint 2/videoPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 From ef5efd8b6cdc72dd7334b6207daf0756afd265fb Mon Sep 17 00:00:00 2001 From: harrellcc Date: Fri, 14 Nov 2025 19:23:27 -0500 Subject: [PATCH 27/39] Update Sprint 2 Recording --- Sprint 2/Sprint 2 Recording | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint 2/Sprint 2 Recording b/Sprint 2/Sprint 2 Recording index 37348f180..8013e771c 100644 --- a/Sprint 2/Sprint 2 Recording +++ b/Sprint 2/Sprint 2 Recording @@ -1 +1 @@ -https://vcu.zoom.us/rec/play/CSbqLpNNao6o_fur1zASfeS9lyc9pzS7VauosFjgbYCe-CDNviy-IhAGtRnYtM-QYvpezksc0N9HRPR1.t4hJz9qMhrxyH2oq?eagerLoadZvaPages=sidemenu.billing.plan_management&isReferralProgramEnabled=false&isReferralProgramAvailable=false&accessLevel=meeting&canPlayFromShare=true&from=my_recording&continueMode=true&componentName=rec-play&originRequestUrl=https%3A%2F%2Fvcu.zoom.us%2Frec%2Fshare%2Fr2lm51MObN1fr-zCPBXFOWxf969z35Hp3zTN5Qu5gmymDZIAYFiTaIuKtt-ClbqK.Xo6vWVXoZAxG6FvY&autoplay=true&startTime=1763164710000 +https://vcu.zoom.us/rec/share/QMlyAqaltyCIUfxmdpkLMSzu_f3dxUNJzAfEurDeKJXjgb2YtcwfXPzMQcCdH5mO.ckMbnzbtlpDzTwPD?startTime=1763164710000 From 7689ded744eb2510aeea784bd0ae47d4a4b0408c Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Tue, 2 Dec 2025 20:19:06 -0500 Subject: [PATCH 28/39] Add MediTrack.py to sprint3 --- Sprint 3/codePlaceHolder.txt | 0 Sprint 3/sprint-3/meditrackCode.py | 315 +++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+) delete mode 100644 Sprint 3/codePlaceHolder.txt create mode 100644 Sprint 3/sprint-3/meditrackCode.py diff --git a/Sprint 3/codePlaceHolder.txt b/Sprint 3/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 3/sprint-3/meditrackCode.py b/Sprint 3/sprint-3/meditrackCode.py new file mode 100644 index 000000000..3f88e6f09 --- /dev/null +++ b/Sprint 3/sprint-3/meditrackCode.py @@ -0,0 +1,315 @@ +import tkinter as tk +import tkinter.font as tkFont +from tkinter import Listbox, messagebox + +#User database +users = { + "sample": { + "password": "123", + "medications": [ + { + "name": "Aspirin", + "dosage": "100mg", + "time": "8:00 AM", + "symptoms": "Headache" + } + ] + } +} + +current_user = None + +#Main window configurations +mainWindow = tk.Tk() +mainWindow.title("MediTrack Login form") +mainWindow.geometry("350x450") +mainWindow.configure(bg = '#F0F0F0') +font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) + +#Dashboard Window configurations +dashboard = tk.Toplevel(mainWindow) +dashboard.title("MediTrack dashboard") +dashboard.geometry("800x450") +dashboard.configure(bg = '#F0F0F0') +dashboard.withdraw() + +#Sign-in Window +signIn = tk.Toplevel(mainWindow) +signIn.title("Create new User") +signIn.geometry("350x450") +signIn.configure(bg = '#F0F0F0') +signIn.withdraw() + + + +''' TODO: Implement history window + CODE: + historyWindow = tk.Toplevel(dashboard) + historyWindow.title("Medication History") + historyWindow.geometry("350x450") + historyWindow.configure(bg = '#F0F0F0') + historyWindow.withdraw() ''' + +label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) +label.place(x= 125,y=0) + +def login(): + global users + global current_user + username = userEntry.get().strip() + password = passEntry.get().strip() + print("attempted login:", username, password) + + if username in users and users[username]["password"] == password: + current_user = username + messagebox.showinfo(title = "Login Successful", message = f"Welcome back, {username}!") + dashboard.deiconify() + mainWindow.withdraw() + updateMedListbox() + else: + messagebox.showinfo(title = "Login Failed", message = "Invalid username or password") + +def signUp(): + mainWindow.withdraw() + signIn.deiconify() + +def createUser(): + username = signUserEntry.get().strip() + password = signPassEntry.get().strip() + confirmPass = passRentry.get().strip() + + if username in users: + messagebox.showinfo(title = "Sign up failed", message = "Account with this user already exists") + + elif password != confirmPass: + messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") + + else: + users[username] = password + print(users) + messagebox.showinfo(title = "User created", message = "Redirecting back to login") + signIn.withdraw() + mainWindow.deiconify() + +#adds medication to the list if not already present +def addMedication(): + global current_user + user_medications = users[current_user].setdefault("medications", []) + + med_input = medicationEntry.get().strip() + dosage_input = dosageEntry.get().strip() + time_input = timeEntry.get().strip() + symptoms_input = symptomsEntry.get().strip() + + #input validation + if not med_input: + messagebox.showinfo(title="Missing input", message="Medication cannot be empty!") + return + + if not dosage_input: + messagebox.showinfo(title="Missing input", message="Please enter the dosage") + return + + if not time_input: + messagebox.showinfo(title="Missing input", message="Please enter the time to take the medication") + return + + + med_norm = med_input.casefold() + + #duplicate check + is_duplicate = any(med.get("name", "").strip().casefold() == med_norm + for med in user_medications) + + if is_duplicate: + messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") + return + + #add medication to the list + new_med = ( { + "name": med_input, + "dosage": dosage_input, + "time": time_input, + "symptoms": symptoms_input + }) + user_medications.append(new_med) + users[current_user]["medications"] = user_medications + + #refresh listbox + updateMedListbox() + + #clear entries + medicationEntry.delete(0, tk.END) + dosageEntry.delete(0, tk.END) + timeEntry.delete(0, tk.END) + symptomsEntry.delete(0, tk.END) + + #confirmation message + messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") + print(f"[DEBUG] Current medications for {current_user}: {users[current_user]['medications']}") + +#function to remove selected medication from listbox and user data +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + + medListbox.bind('<>', onMedSelect) + + +#function to confirm and remove medication +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() + + +def updateMedListbox(): + global current_user + medListbox.delete(0, tk.END) + + medListbox.insert(tk.END, "Name | Dose | Time | Symptoms") + medListbox.itemconfig(0, {'fg': 'white', 'bg': 'black'}) + + user_medications = users[current_user].get("medications", []) + for med in user_medications: + #if symptoms is empty, display "None" + symptoms_display = med.get("symptoms", "").strip() or "None" + line = f"{med['name']} | {med['dosage']} | {med['time']} | {symptoms_display}" + medListbox.insert(tk.END, line) + + + +#widgets main login window +userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) +passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) +userEntry = tk.Entry(mainWindow) +passEntry = tk.Entry(mainWindow, show = "*") +loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) +signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) + +#widgets create user window +signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) +signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) +passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) +signUserEntry = tk.Entry(signIn) +signPassEntry = tk.Entry(signIn, show = "*") +passRentry = tk.Entry(signIn,show = "*") +createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) +backButton = tk.Button(signIn, text="Go Back", bg="#F5D5F7", font=font1, command=lambda: [signIn.withdraw(), mainWindow.deiconify()]) + + +#Widgets dashboard: + +#Add Medication Button and Entries +addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) +medicationEntry = tk.Entry(dashboard) +medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) +dosageEntry = tk.Entry(dashboard) +dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) +timeEntry = tk.Entry(dashboard) +timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) +symptomsEntry = tk.Entry(dashboard) +symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) + +#Listbox and Scrollbar for medications +medListbox = tk.Listbox(dashboard, font=font1) +scrollbar = tk.Scrollbar(dashboard, orient=tk.VERTICAL) + +medListbox.config(yscrollcommand=scrollbar.set) +scrollbar.config(command=medListbox.yview) + +#remove medication button appears when a medication is selected +removeMedButton = tk.Button(dashboard, text="Remove Selected Medication", font=font1, bg="#F5D5F7", command=confirmRemoveMedication) +removeMedButton.place(x=350, y=390, width=200, height=30) +removeMedButton.place_forget() + + +'''TODO: Implement history window and its button +historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' + + +#positions for labels and buttons + +#login +loginButton.place(x = 125, y = 100) +signUpButton.place(x = 125, y = 250) +userLabel.place(x=50, y=150) +userEntry.place(x=130 , y=150) +passLabel.place(x=50, y=190) +passEntry.place(x=130, y= 190) +#create +signUserEntry.place(x=195, y= 150) +signPassEntry.place(x=195, y= 190) +passRentry.place(x=195,y=230) +signUserEntryL.place(x=30, y=150) +signPassEntryL.place(x=30, y=190) +passRentryL.place(x=30, y=230) +createUserButton.place(x = 130, y= 300) +backButton.place(x=130, y=350) +#dashboard +medicationEntryL.place(x=20, y=30) +medicationEntry.place(x=150, y=30, width=140) + +dosageEntryL.place(x=20, y=80) +dosageEntry.place(x=150, y=80, width=140) + +timeEntryL.place(x=20, y=130) +timeEntry.place(x=150, y=130, width=140) + +symptomsEntryL.place(x=20, y=180) +symptomsEntry.place(x=150, y=180, width=140) + +addMedButton.place(x=20, y=230, width=260, height=30) + +medListbox.place(x=350, y=30, width=400, height=350) +scrollbar.place(x=750, y=30, width=20, height=350) + +'''TODO: Implement history window layout''' + +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + +medListbox.bind('<>', onMedSelect) + +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() + + +mainWindow.mainloop() From 87ebbe2ec9c26a40655465caad30a293869fecc0 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Tue, 2 Dec 2025 20:23:53 -0500 Subject: [PATCH 29/39] add meditrackCode to main sprint-3 folder --- Sprint 3/meditrackCode.py | 315 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 Sprint 3/meditrackCode.py diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py new file mode 100644 index 000000000..9749a222a --- /dev/null +++ b/Sprint 3/meditrackCode.py @@ -0,0 +1,315 @@ +import tkinter as tk +import tkinter.font as tkFont +from tkinter import Listbox, messagebox + +#User database +users = { + "sample": { + "password": "123", + "medications": [ + { + "name": "Aspirin", + "dosage": "100mg", + "time": "8:00 AM", + "symptoms": "Headache" + } + ] + } +} + +current_user = None + +#Main window configurations +mainWindow = tk.Tk() +mainWindow.title("MediTrack Login form") +mainWindow.geometry("350x450") +mainWindow.configure(bg = '#F0F0F0') +font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) + +#Dashboard Window configurations +dashboard = tk.Toplevel(mainWindow) +dashboard.title("MediTrack dashboard") +dashboard.geometry("800x450") +dashboard.configure(bg = '#F0F0F0') +dashboard.withdraw() + +#Sign-in Window +signIn = tk.Toplevel(mainWindow) +signIn.title("Create new User") +signIn.geometry("350x450") +signIn.configure(bg = '#F0F0F0') +signIn.withdraw() + + + +''' TODO: Implement history window + CODE: + historyWindow = tk.Toplevel(dashboard) + historyWindow.title("Medication History") + historyWindow.geometry("350x450") + historyWindow.configure(bg = '#F0F0F0') + historyWindow.withdraw() ''' + +label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) +label.place(x= 125,y=0) + +def login(): + global users + global current_user + username = userEntry.get().strip() + password = passEntry.get().strip() + print("attempted login:", username, password) + + if username in users and users[username]["password"] == password: + current_user = username + messagebox.showinfo(title = "Login Successful", message = f"Welcome back, {username}!") + dashboard.deiconify() + mainWindow.withdraw() + updateMedListbox() + else: + messagebox.showinfo(title = "Login Failed", message = "Invalid username or password") + +def signUp(): + mainWindow.withdraw() + signIn.deiconify() + +def createUser(): + username = signUserEntry.get().strip() + password = signPassEntry.get().strip() + confirmPass = passRentry.get().strip() + + if username in users: + messagebox.showinfo(title = "Sign up failed", message = "Account with this user already exists") + + elif password != confirmPass: + messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") + + else: + users[username] = password + print(users) + messagebox.showinfo(title = "User created", message = "Redirecting back to login") + signIn.withdraw() + mainWindow.deiconify() + +#adds medication to the list if not already present +def addMedication(): + global current_user + user_medications = users[current_user].setdefault("medications", []) + + med_input = medicationEntry.get().strip() + dosage_input = dosageEntry.get().strip() + time_input = timeEntry.get().strip() + symptoms_input = symptomsEntry.get().strip() + + #input validation + if not med_input: + messagebox.showinfo(title="Missing input", message="Medication cannot be empty!") + return + + if not dosage_input: + messagebox.showinfo(title="Missing input", message="Please enter the dosage") + return + + if not time_input: + messagebox.showinfo(title="Missing input", message="Please enter the time to take the medication") + return + + + med_norm = med_input.casefold() + + #duplicate check + is_duplicate = any(med.get("name", "").strip().casefold() == med_norm + for med in user_medications) + + if is_duplicate: + messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") + return + + #add medication to the list + new_med = ( { + "name": med_input, + "dosage": dosage_input, + "time": time_input, + "symptoms": symptoms_input + }) + user_medications.append(new_med) + users[current_user]["medications"] = user_medications + + #refresh listbox + updateMedListbox() + + #clear entries + medicationEntry.delete(0, tk.END) + dosageEntry.delete(0, tk.END) + timeEntry.delete(0, tk.END) + symptomsEntry.delete(0, tk.END) + + #confirmation message + messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") + print(f"[DEBUG] Current medications for {current_user}: {users[current_user]['medications']}") + +#function to remove selected medication from listbox and user data +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + + medListbox.bind('<>', onMedSelect) + + +#function to confirm and remove medication +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() + + +def updateMedListbox(): + global current_user + medListbox.delete(0, tk.END) + + medListbox.insert(tk.END, "Name | Dose | Time | Symptoms") + medListbox.itemconfig(0, {'fg': 'white', 'bg': 'black'}) + + user_medications = users[current_user].get("medications", []) + for med in user_medications: + #if symptoms is empty, display "None" + symptoms_display = med.get("symptoms", "").strip() or "None" + line = f"{med['name']} | {med['dosage']} | {med['time']} | {symptoms_display}" + medListbox.insert(tk.END, line) + + + +#widgets main login window +userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) +passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) +userEntry = tk.Entry(mainWindow) +passEntry = tk.Entry(mainWindow, show = "*") +loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) +signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) + +#widgets create user window +signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) +signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) +passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) +signUserEntry = tk.Entry(signIn) +signPassEntry = tk.Entry(signIn, show = "*") +passRentry = tk.Entry(signIn,show = "*") +createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) +backButton = tk.Button(signIn, text="Go Back", bg="#F5D5F7", font=font1, command=lambda: [signIn.withdraw(), mainWindow.deiconify()]) + + +#Widgets dashboard: + +#Add Medication Button and Entries +addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) +medicationEntry = tk.Entry(dashboard) +medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) +dosageEntry = tk.Entry(dashboard) +dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) +timeEntry = tk.Entry(dashboard) +timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) +symptomsEntry = tk.Entry(dashboard) +symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) + +#Listbox and Scrollbar for medications +medListbox = tk.Listbox(dashboard, font=font1) +scrollbar = tk.Scrollbar(dashboard, orient=tk.VERTICAL) + +medListbox.config(yscrollcommand=scrollbar.set) +scrollbar.config(command=medListbox.yview) + +#remove medication button appears when a medication is selected +removeMedButton = tk.Button(dashboard, text="Remove Selected Medication", font=font1, bg="#F5D5F7", command=confirmRemoveMedication) +removeMedButton.place(x=350, y=390, width=200, height=30) +removeMedButton.place_forget() + + +'''TODO: Implement history window and its button +historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' + + +#positions for labels and buttons + +#login +loginButton.place(x = 125, y = 100) +signUpButton.place(x = 125, y = 250) +userLabel.place(x=50, y=150) +userEntry.place(x=130 , y=150) +passLabel.place(x=50, y=190) +passEntry.place(x=130, y= 190) +#create +signUserEntry.place(x=195, y= 150) +signPassEntry.place(x=195, y= 190) +passRentry.place(x=195,y=230) +signUserEntryL.place(x=30, y=150) +signPassEntryL.place(x=30, y=190) +passRentryL.place(x=30, y=230) +createUserButton.place(x = 130, y= 300) +backButton.place(x=130, y=350) +#dashboard +medicationEntryL.place(x=20, y=30) +medicationEntry.place(x=150, y=30, width=140) + +dosageEntryL.place(x=20, y=80) +dosageEntry.place(x=150, y=80, width=140) + +timeEntryL.place(x=20, y=130) +timeEntry.place(x=150, y=130, width=140) + +symptomsEntryL.place(x=20, y=180) +symptomsEntry.place(x=150, y=180, width=140) + +addMedButton.place(x=20, y=230, width=260, height=30) + +medListbox.place(x=350, y=30, width=400, height=350) +scrollbar.place(x=750, y=30, width=20, height=350) + +'''TODO: Implement history window layout''' + +def onMedSelect(event): + selection = medListbox.curselection() + + if selection and selection[0] != 0: + removeMedButton.place(x=350, y=390, width=200, height=30) + else: + removeMedButton.place_forget() + selection = medListbox.curselection() + +medListbox.bind('<>', onMedSelect) + +def confirmRemoveMedication(): + global current_user + + selection = medListbox.curselection() + + if not selection or selection[0] == 0: + return + + med_index = selection[0] - 1 + med_name = users[current_user]["medications"][med_index]["name"] + + answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") + if answer: + users[current_user]["medications"].pop(med_index) + updateMedListbox() + removeMedButton.place_forget() + + +mainWindow.mainloop() From e195445ea40ba1ad6c16f067e6849abaf9e20b32 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Tue, 2 Dec 2025 20:24:48 -0500 Subject: [PATCH 30/39] Delete Sprint 3/sprint-3 directory --- Sprint 3/sprint-3/meditrackCode.py | 315 ----------------------------- 1 file changed, 315 deletions(-) delete mode 100644 Sprint 3/sprint-3/meditrackCode.py diff --git a/Sprint 3/sprint-3/meditrackCode.py b/Sprint 3/sprint-3/meditrackCode.py deleted file mode 100644 index 3f88e6f09..000000000 --- a/Sprint 3/sprint-3/meditrackCode.py +++ /dev/null @@ -1,315 +0,0 @@ -import tkinter as tk -import tkinter.font as tkFont -from tkinter import Listbox, messagebox - -#User database -users = { - "sample": { - "password": "123", - "medications": [ - { - "name": "Aspirin", - "dosage": "100mg", - "time": "8:00 AM", - "symptoms": "Headache" - } - ] - } -} - -current_user = None - -#Main window configurations -mainWindow = tk.Tk() -mainWindow.title("MediTrack Login form") -mainWindow.geometry("350x450") -mainWindow.configure(bg = '#F0F0F0') -font1 = tkFont.Font(family = "Arial", size = 12, weight = tkFont.NORMAL) - -#Dashboard Window configurations -dashboard = tk.Toplevel(mainWindow) -dashboard.title("MediTrack dashboard") -dashboard.geometry("800x450") -dashboard.configure(bg = '#F0F0F0') -dashboard.withdraw() - -#Sign-in Window -signIn = tk.Toplevel(mainWindow) -signIn.title("Create new User") -signIn.geometry("350x450") -signIn.configure(bg = '#F0F0F0') -signIn.withdraw() - - - -''' TODO: Implement history window - CODE: - historyWindow = tk.Toplevel(dashboard) - historyWindow.title("Medication History") - historyWindow.geometry("350x450") - historyWindow.configure(bg = '#F0F0F0') - historyWindow.withdraw() ''' - -label = tk.Label(mainWindow, text = "MediTrack", bg= "#F5D5F7", font = font1) -label.place(x= 125,y=0) - -def login(): - global users - global current_user - username = userEntry.get().strip() - password = passEntry.get().strip() - print("attempted login:", username, password) - - if username in users and users[username]["password"] == password: - current_user = username - messagebox.showinfo(title = "Login Successful", message = f"Welcome back, {username}!") - dashboard.deiconify() - mainWindow.withdraw() - updateMedListbox() - else: - messagebox.showinfo(title = "Login Failed", message = "Invalid username or password") - -def signUp(): - mainWindow.withdraw() - signIn.deiconify() - -def createUser(): - username = signUserEntry.get().strip() - password = signPassEntry.get().strip() - confirmPass = passRentry.get().strip() - - if username in users: - messagebox.showinfo(title = "Sign up failed", message = "Account with this user already exists") - - elif password != confirmPass: - messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") - - else: - users[username] = password - print(users) - messagebox.showinfo(title = "User created", message = "Redirecting back to login") - signIn.withdraw() - mainWindow.deiconify() - -#adds medication to the list if not already present -def addMedication(): - global current_user - user_medications = users[current_user].setdefault("medications", []) - - med_input = medicationEntry.get().strip() - dosage_input = dosageEntry.get().strip() - time_input = timeEntry.get().strip() - symptoms_input = symptomsEntry.get().strip() - - #input validation - if not med_input: - messagebox.showinfo(title="Missing input", message="Medication cannot be empty!") - return - - if not dosage_input: - messagebox.showinfo(title="Missing input", message="Please enter the dosage") - return - - if not time_input: - messagebox.showinfo(title="Missing input", message="Please enter the time to take the medication") - return - - - med_norm = med_input.casefold() - - #duplicate check - is_duplicate = any(med.get("name", "").strip().casefold() == med_norm - for med in user_medications) - - if is_duplicate: - messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") - return - - #add medication to the list - new_med = ( { - "name": med_input, - "dosage": dosage_input, - "time": time_input, - "symptoms": symptoms_input - }) - user_medications.append(new_med) - users[current_user]["medications"] = user_medications - - #refresh listbox - updateMedListbox() - - #clear entries - medicationEntry.delete(0, tk.END) - dosageEntry.delete(0, tk.END) - timeEntry.delete(0, tk.END) - symptomsEntry.delete(0, tk.END) - - #confirmation message - messagebox.showinfo(title = "Medication Added", message = f"{med_input} is added to your medications!") - print(f"[DEBUG] Current medications for {current_user}: {users[current_user]['medications']}") - -#function to remove selected medication from listbox and user data -def onMedSelect(event): - selection = medListbox.curselection() - - if selection and selection[0] != 0: - removeMedButton.place(x=350, y=390, width=200, height=30) - else: - removeMedButton.place_forget() - selection = medListbox.curselection() - - medListbox.bind('<>', onMedSelect) - - -#function to confirm and remove medication -def confirmRemoveMedication(): - global current_user - - selection = medListbox.curselection() - - if not selection or selection[0] == 0: - return - - med_index = selection[0] - 1 - med_name = users[current_user]["medications"][med_index]["name"] - - answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") - if answer: - users[current_user]["medications"].pop(med_index) - updateMedListbox() - removeMedButton.place_forget() - - -def updateMedListbox(): - global current_user - medListbox.delete(0, tk.END) - - medListbox.insert(tk.END, "Name | Dose | Time | Symptoms") - medListbox.itemconfig(0, {'fg': 'white', 'bg': 'black'}) - - user_medications = users[current_user].get("medications", []) - for med in user_medications: - #if symptoms is empty, display "None" - symptoms_display = med.get("symptoms", "").strip() or "None" - line = f"{med['name']} | {med['dosage']} | {med['time']} | {symptoms_display}" - medListbox.insert(tk.END, line) - - - -#widgets main login window -userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) -passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) -userEntry = tk.Entry(mainWindow) -passEntry = tk.Entry(mainWindow, show = "*") -loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) -signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) - -#widgets create user window -signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) -signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) -passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) -signUserEntry = tk.Entry(signIn) -signPassEntry = tk.Entry(signIn, show = "*") -passRentry = tk.Entry(signIn,show = "*") -createUserButton = tk.Button(signIn, text = "Create User", bg = "#F5D5F7", font = font1, command = createUser) -backButton = tk.Button(signIn, text="Go Back", bg="#F5D5F7", font=font1, command=lambda: [signIn.withdraw(), mainWindow.deiconify()]) - - -#Widgets dashboard: - -#Add Medication Button and Entries -addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) -medicationEntry = tk.Entry(dashboard) -medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) -dosageEntry = tk.Entry(dashboard) -dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) -timeEntry = tk.Entry(dashboard) -timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) -symptomsEntry = tk.Entry(dashboard) -symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) - -#Listbox and Scrollbar for medications -medListbox = tk.Listbox(dashboard, font=font1) -scrollbar = tk.Scrollbar(dashboard, orient=tk.VERTICAL) - -medListbox.config(yscrollcommand=scrollbar.set) -scrollbar.config(command=medListbox.yview) - -#remove medication button appears when a medication is selected -removeMedButton = tk.Button(dashboard, text="Remove Selected Medication", font=font1, bg="#F5D5F7", command=confirmRemoveMedication) -removeMedButton.place(x=350, y=390, width=200, height=30) -removeMedButton.place_forget() - - -'''TODO: Implement history window and its button -historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' - - -#positions for labels and buttons - -#login -loginButton.place(x = 125, y = 100) -signUpButton.place(x = 125, y = 250) -userLabel.place(x=50, y=150) -userEntry.place(x=130 , y=150) -passLabel.place(x=50, y=190) -passEntry.place(x=130, y= 190) -#create -signUserEntry.place(x=195, y= 150) -signPassEntry.place(x=195, y= 190) -passRentry.place(x=195,y=230) -signUserEntryL.place(x=30, y=150) -signPassEntryL.place(x=30, y=190) -passRentryL.place(x=30, y=230) -createUserButton.place(x = 130, y= 300) -backButton.place(x=130, y=350) -#dashboard -medicationEntryL.place(x=20, y=30) -medicationEntry.place(x=150, y=30, width=140) - -dosageEntryL.place(x=20, y=80) -dosageEntry.place(x=150, y=80, width=140) - -timeEntryL.place(x=20, y=130) -timeEntry.place(x=150, y=130, width=140) - -symptomsEntryL.place(x=20, y=180) -symptomsEntry.place(x=150, y=180, width=140) - -addMedButton.place(x=20, y=230, width=260, height=30) - -medListbox.place(x=350, y=30, width=400, height=350) -scrollbar.place(x=750, y=30, width=20, height=350) - -'''TODO: Implement history window layout''' - -def onMedSelect(event): - selection = medListbox.curselection() - - if selection and selection[0] != 0: - removeMedButton.place(x=350, y=390, width=200, height=30) - else: - removeMedButton.place_forget() - selection = medListbox.curselection() - -medListbox.bind('<>', onMedSelect) - -def confirmRemoveMedication(): - global current_user - - selection = medListbox.curselection() - - if not selection or selection[0] == 0: - return - - med_index = selection[0] - 1 - med_name = users[current_user]["medications"][med_index]["name"] - - answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") - if answer: - users[current_user]["medications"].pop(med_index) - updateMedListbox() - removeMedButton.place_forget() - - -mainWindow.mainloop() From ffeec0afe89e9d149be8b698b1f04e93fc995201 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Wed, 3 Dec 2025 18:01:25 -0500 Subject: [PATCH 31/39] TC01 update created scheduling window where user can schedule their reminders when they add a new medication. Notification pops-up according to their scheduling preferences. --- Sprint 3/meditrackCode.py | 245 ++++++++++++++++++++++++++++++++------ 1 file changed, 209 insertions(+), 36 deletions(-) diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py index 9749a222a..d80d1056d 100644 --- a/Sprint 3/meditrackCode.py +++ b/Sprint 3/meditrackCode.py @@ -1,6 +1,8 @@ import tkinter as tk import tkinter.font as tkFont from tkinter import Listbox, messagebox +from tkinter import ttk +from datetime import datetime, timedelta #User database users = { @@ -11,13 +13,22 @@ "name": "Aspirin", "dosage": "100mg", "time": "8:00 AM", - "symptoms": "Headache" + "symptoms": "Headache", + "occurrence": "Daily", + "days": [] } ] } } +#Global variables current_user = None +reminders = {} # key: (username, med_name, time), value: afterID +current_schedule = { #stores current schedule selections + "time": None, + "occurrence": None, + "days": [] +} #Main window configurations mainWindow = tk.Tk() @@ -85,7 +96,7 @@ def createUser(): messagebox.showinfo(title = "Invalid Password", message = "Passwords don't match") else: - users[username] = password + users[username] = {"password": password, "medications": []} print(users) messagebox.showinfo(title = "User created", message = "Redirecting back to login") signIn.withdraw() @@ -98,7 +109,6 @@ def addMedication(): med_input = medicationEntry.get().strip() dosage_input = dosageEntry.get().strip() - time_input = timeEntry.get().strip() symptoms_input = symptomsEntry.get().strip() #input validation @@ -110,31 +120,39 @@ def addMedication(): messagebox.showinfo(title="Missing input", message="Please enter the dosage") return - if not time_input: - messagebox.showinfo(title="Missing input", message="Please enter the time to take the medication") + if not current_schedule["time"]: + messagebox.showinfo(title="Missing input", message="Please set a schedule for the medication") + return + + if parse_time(current_schedule["time"]) is None: + messagebox.showinfo(title="Invalid Time Format", message="Please click 'Set Schedule' and choose a time and occurrence for the medication") return - - med_norm = med_input.casefold() + #normalize medication name for duplicate check + med_norm = med_input.casefold() #duplicate check is_duplicate = any(med.get("name", "").strip().casefold() == med_norm for med in user_medications) - if is_duplicate: messagebox.showinfo(title="Duplicate Entry", message=f"{med_input} is already in your medications!") return #add medication to the list - new_med = ( { + new_med = { "name": med_input, "dosage": dosage_input, - "time": time_input, - "symptoms": symptoms_input - }) + "time": current_schedule["time"], + "symptoms": symptoms_input, + "occurrence": current_schedule["occurrence"], + "days": current_schedule["days"], + } + user_medications.append(new_med) users[current_user]["medications"] = user_medications + scheduleReminder(current_user, new_med) + #refresh listbox updateMedListbox() @@ -179,7 +197,7 @@ def confirmRemoveMedication(): updateMedListbox() removeMedButton.place_forget() - +#function to update the medication listbox def updateMedListbox(): global current_user medListbox.delete(0, tk.END) @@ -195,8 +213,169 @@ def updateMedListbox(): medListbox.insert(tk.END, line) - -#widgets main login window +#parses the time input string into a real datetime object +def parse_time(time_str): + try: + parsed = datetime.strptime(time_str, "%I:%M %p") + return parsed.time() + except ValueError: + return None + +#function to calculate milliseconds until the next occurrence of the specified time +def seconds_until(time_str): + try: + now = datetime.now() + medTime = datetime.strptime(time_str, "%I:%M %p") #parse time string + medDate = now.replace(hour=medTime.hour, minute=medTime.minute, second=0, microsecond=0) + + if medDate <= now: + medDate += timedelta(days=1) #schedule for next day if time has passed + + return int((medDate - now).total_seconds()*1000) #convert to milliseconds + + except ValueError: + return None + + + +#function to schedule reminders +def scheduleReminder(username, med): + + #get time string and calculate delay + time_str = med['time'] + delay_ms = seconds_until(time_str) + if not delay_ms or delay_ms <= 0: + print(f"[ERROR] Invalid time format for medication {med['name']}: {time_str}") + return + + #unique key for each reminder + key = (username, med['name'], time_str) + + #cancel existing reminder if present + if key in reminders: + try: + dashboard.after_cancel(reminders[key]) + except Exception: + pass + reminders.pop(key, None) + + #function to show reminder popup + def showReminder(): + popup = tk.Toplevel(dashboard) + popup.title("Medication Reminder") + popup.geometry("300x150") + tk.Label(popup, text=f"Time to take {med['name']} ({med['dosage']})", font=font1).pack(pady=20) + tk.Button(popup, text="OK", command=popup.destroy).pack(pady=10) + + scheduleReminder(username, med) #reschedule the reminder for the next day + + remindID = dashboard.after(delay_ms, showReminder) #schedule the reminder + reminders[key] = remindID #store the reminder ID + + print(f"[DEBUG] Scheduled reminder for {username} to take {med['name']} in {delay_ms/1000:.2f} seconds.") + +#callback function when schedule is chosen +def on_schedule_chosen(time_str, occurence, days): + #update current schedule + current_schedule["time"] = time_str + current_schedule["occurrence"] = occurence + current_schedule["days"] = days + + #update time entry field + timeEntry.config(state="normal") + timeEntry.delete(0, tk.END) + timeEntry.insert(0, time_str) + timeEntry.config(state="readonly") + + print("[DEBUG] Selected schedule:", time_str, occurence, days) + + +#function to open scheduler window +def open_scheduler(on_done): + + #create scheduler window + window = tk.Toplevel(dashboard) + window.title("Schedule Your Medication") + window.geometry("320x260") + window.configure(bg='#F0F0F0') + window.grab_set() + + # --- time selection widgets --- + tk.Label(window, text="Time:", bg="#F0F0F0", font=font1).place(x=20, y=20) + + # default time values + hourVar = tk.StringVar(value="8") + minuteVar = tk.StringVar(value="00") + ampmVar = tk.StringVar(value="AM") + + # options for time selection + hours = [f"{i}" for i in range(1, 13)] + minutes = [f"{i:02d}" for i in range(0, 60)] + ampm = ["AM", "PM"] + + #time selection comboboxes + hours_box = ttk.Combobox(window, textvariable=hourVar, values=hours, width=5, state="readonly") + hours_box.place(x=80, y=20) + + tk.Label(window, text=":", bg="#F0F0F0", font=font1).place(x=140, y=20) + + minute_box = ttk.Combobox(window, textvariable=minuteVar, values=minutes, width=5, state="readonly") + minute_box.place(x=135, y=20) + + ampm_box = ttk.Combobox(window, textvariable=ampmVar, values=ampm, width=5, state="readonly") + ampm_box.place(x=195, y=20) + + tk.Label(window, text="Occurrrence:", bg="#F0F0F0", font=font1).place(x=20, y=70) + + # occurrence selection combobox + occurrenceVar = tk.StringVar(value="Daily") + occurrence_box = ttk.Combobox(window, textvariable=occurrenceVar, + values=["Once", "Daily", "Monthly", "Custom days"], + state="readonly", + width=15) + occurrence_box.place(x=120, y=70) + + # --- Optional specific days selection --- + + tk.Label(window, text="(Optional) Select Days:", bg="#F0F0F0", font=font1).place(x=20, y=110) + + days_frame = tk.Frame(window, bg="#F0F0F0") + days_frame.place(x=20, y=135) + + dayVars = {} + days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + for i, name in enumerate(days): + var = tk.BooleanVar(value=False) + chk = tk.Checkbutton(days_frame, text=name, variable=var, bg="#F0F0F0") + chk.grid(row=0, column=i, padx=2) + dayVars[name] = var + +# --- Save and Cancel buttons --- + + def on_save(): + hour = hourVar.get() + minute = minuteVar.get() + ampm = ampmVar.get() + occurrence = occurrenceVar.get() + + time_str = f"{int(hour)}:{minute} {ampm}" + selected_days = [name for name, var in dayVars.items() if var.get()] + + on_done(time_str, occurrence, selected_days) + window.destroy() + + def on_cancel(): + window.destroy() + + tk.Button(window, text="Save", bg="#F5D5F7", font=font1, command=on_save).place(x=70, y=200, width=80, height=30) + tk.Button(window, text="Cancel", bg="#F5D5F7", font=font1, command=on_cancel).place(x=170, y=200, width=80, height=30) + + + + + +# --- widgets main login window --- + userLabel = tk.Label(mainWindow, text = "Username", bg = "#F5D5F7", font = font1) passLabel = tk.Label(mainWindow, text = "Password", bg = "#F5D5F7", font = font1) userEntry = tk.Entry(mainWindow) @@ -204,7 +383,8 @@ def updateMedListbox(): loginButton = tk.Button(mainWindow, text = "Login", bg = "#F5D5F7", font = font1, command = login) signUpButton = tk.Button(mainWindow, text = "Sign up", bg = "#F5D5F7", font = font1, command = signUp) -#widgets create user window +# --- widgets create user window --- + signUserEntryL = tk.Label(signIn, text = "Enter Username", bg = "#F5D5F7", font = font1) signPassEntryL = tk.Label(signIn, text = "Enter Password", bg = "#F5D5F7", font = font1) passRentryL = tk.Label(signIn, text = "Confirm Password", bg = "#F5D5F7", font = font1) @@ -215,7 +395,7 @@ def updateMedListbox(): backButton = tk.Button(signIn, text="Go Back", bg="#F5D5F7", font=font1, command=lambda: [signIn.withdraw(), mainWindow.deiconify()]) -#Widgets dashboard: +# --- widgets dashboard window --- #Add Medication Button and Entries addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) @@ -223,7 +403,7 @@ def updateMedListbox(): medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) dosageEntry = tk.Entry(dashboard) dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) -timeEntry = tk.Entry(dashboard) +timeEntry = tk.Entry(dashboard, state="readonly") timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) symptomsEntry = tk.Entry(dashboard) symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) @@ -240,12 +420,20 @@ def updateMedListbox(): removeMedButton.place(x=350, y=390, width=200, height=30) removeMedButton.place_forget() +scheduleButton = tk.Button( + dashboard, + text="Set Schedule!", + bg="#F5D5F7", + font=font1, + command=lambda: open_scheduler(on_schedule_chosen) +) + '''TODO: Implement history window and its button historyButton = tk.Button(dashboard, text="View Medication History", bg="#F5D5F7", font=font1, command=lambda: [dashboard.withdraw(), historyWindow.deiconify()])''' -#positions for labels and buttons +# --- positions for labels and buttons --- #login loginButton.place(x = 125, y = 100) @@ -272,6 +460,7 @@ def updateMedListbox(): timeEntryL.place(x=20, y=130) timeEntry.place(x=150, y=130, width=140) +scheduleButton.place(x=300, y=130, width=100, height=24) symptomsEntryL.place(x=20, y=180) symptomsEntry.place(x=150, y=180, width=140) @@ -281,6 +470,7 @@ def updateMedListbox(): medListbox.place(x=350, y=30, width=400, height=350) scrollbar.place(x=750, y=30, width=20, height=350) + '''TODO: Implement history window layout''' def onMedSelect(event): @@ -294,22 +484,5 @@ def onMedSelect(event): medListbox.bind('<>', onMedSelect) -def confirmRemoveMedication(): - global current_user - - selection = medListbox.curselection() - - if not selection or selection[0] == 0: - return - - med_index = selection[0] - 1 - med_name = users[current_user]["medications"][med_index]["name"] - - answer = messagebox.askyesno(title="Confirm Removal", message=f"Are you sure you want to remove {med_name}?") - if answer: - users[current_user]["medications"].pop(med_index) - updateMedListbox() - removeMedButton.place_forget() - mainWindow.mainloop() From 6ac682a8ae2140ccf339426e2eb887ba555adecd Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Thu, 4 Dec 2025 00:58:22 -0500 Subject: [PATCH 32/39] Deleted timeEntry --- Sprint 3/meditrackCode.py | 46 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py index d80d1056d..d71d7c338 100644 --- a/Sprint 3/meditrackCode.py +++ b/Sprint 3/meditrackCode.py @@ -159,7 +159,6 @@ def addMedication(): #clear entries medicationEntry.delete(0, tk.END) dosageEntry.delete(0, tk.END) - timeEntry.delete(0, tk.END) symptomsEntry.delete(0, tk.END) #confirmation message @@ -282,11 +281,6 @@ def on_schedule_chosen(time_str, occurence, days): current_schedule["days"] = days #update time entry field - timeEntry.config(state="normal") - timeEntry.delete(0, tk.END) - timeEntry.insert(0, time_str) - timeEntry.config(state="readonly") - print("[DEBUG] Selected schedule:", time_str, occurence, days) @@ -397,17 +391,25 @@ def on_cancel(): # --- widgets dashboard window --- -#Add Medication Button and Entries -addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) +#Entries medicationEntry = tk.Entry(dashboard) medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) dosageEntry = tk.Entry(dashboard) dosageEntryL = tk.Label(dashboard, text = "Dosage", bg = "#F5D5F7", font = font1) -timeEntry = tk.Entry(dashboard, state="readonly") -timeEntryL = tk.Label(dashboard, text = "Take at", bg = "#F5D5F7", font = font1) symptomsEntry = tk.Entry(dashboard) symptomsEntryL = tk.Label(dashboard, text = "Symptoms", bg = "#F5D5F7", font = font1) +#buttons +scheduleButton = tk.Button( + dashboard, + text="Set Schedule", + bg="#F5D5F7", + font=font1, + command=lambda: open_scheduler(on_schedule_chosen) +) + +addMedButton = tk.Button(dashboard, text="Add Medication", bg="#F5D5F7", font=font1, command=addMedication) + #Listbox and Scrollbar for medications medListbox = tk.Listbox(dashboard, font=font1) scrollbar = tk.Scrollbar(dashboard, orient=tk.VERTICAL) @@ -420,13 +422,6 @@ def on_cancel(): removeMedButton.place(x=350, y=390, width=200, height=30) removeMedButton.place_forget() -scheduleButton = tk.Button( - dashboard, - text="Set Schedule!", - bg="#F5D5F7", - font=font1, - command=lambda: open_scheduler(on_schedule_chosen) -) '''TODO: Implement history window and its button @@ -453,19 +448,16 @@ def on_cancel(): backButton.place(x=130, y=350) #dashboard medicationEntryL.place(x=20, y=30) -medicationEntry.place(x=150, y=30, width=140) +medicationEntry.place(x=155, y=30, width=140) dosageEntryL.place(x=20, y=80) -dosageEntry.place(x=150, y=80, width=140) +dosageEntry.place(x=155, y=80, width=140) -timeEntryL.place(x=20, y=130) -timeEntry.place(x=150, y=130, width=140) -scheduleButton.place(x=300, y=130, width=100, height=24) +symptomsEntryL.place(x=20, y=130) +symptomsEntry.place(x=155, y=130, width=140) -symptomsEntryL.place(x=20, y=180) -symptomsEntry.place(x=150, y=180, width=140) - -addMedButton.place(x=20, y=230, width=260, height=30) +scheduleButton.place(x=20, y=180, width=110, height=30) +addMedButton.place(x=155, y=180, width=145, height=30) medListbox.place(x=350, y=30, width=400, height=350) scrollbar.place(x=750, y=30, width=20, height=350) @@ -477,7 +469,7 @@ def onMedSelect(event): selection = medListbox.curselection() if selection and selection[0] != 0: - removeMedButton.place(x=350, y=390, width=200, height=30) + removeMedButton.place(x=350, y=390, width=215, height=30) else: removeMedButton.place_forget() selection = medListbox.curselection() From 69aae8d1799d330009afcf4745a1e088d2c98ba0 Mon Sep 17 00:00:00 2001 From: abbyY <126789762+abigiyayohannes@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:24:18 -0500 Subject: [PATCH 33/39] added test case 2 --- Sprint 3/meditrackCode.py | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py index 9749a222a..a6aea8193 100644 --- a/Sprint 3/meditrackCode.py +++ b/Sprint 3/meditrackCode.py @@ -2,6 +2,18 @@ import tkinter.font as tkFont from tkinter import Listbox, messagebox +import datetime + +def parse_time(t): + return datetime.datetime.strptime(t, "%I:%M %p").time() + +def seconds_until(t): + now = datetime.datetime.now() + target = datetime.datetime.combine(now.date(), t) + if target < now: + target += datetime.timedelta(days=1) + return (target - now).total_seconds() + #User database users = { "sample": { @@ -219,6 +231,8 @@ def updateMedListbox(): #Add Medication Button and Entries addMedButton = tk.Button(dashboard, text="Add New Medication", bg="#F5D5F7", font=font1, command=addMedication) +setScheduleButton = tk.Button(dashboard, text="Set Schedule", bg="#F5D5F7", font=font1, command=lambda: openScheduler()) +setScheduleButton.place(x=20, y=280, width=260, height=30) medicationEntry = tk.Entry(dashboard) medicationEntryL = tk.Label(dashboard, text = "Input Medications", bg = "#F5D5F7", font = font1) dosageEntry = tk.Entry(dashboard) @@ -311,5 +325,52 @@ def confirmRemoveMedication(): updateMedListbox() removeMedButton.place_forget() + +def scheduleReminder(username, med): + t = parse_time(med["time"]) + wait = int(seconds_until(t)) * 1000 + + def notify(): + popup = tk.Toplevel() + popup.title("MediTrack Reminder") + popup.geometry("300x200") + tk.Label(popup, text=f"Time to take {med['name']}!").pack(pady=10) + tk.Label(popup, text=f"Dosage: {med['dosage']}").pack() + + def taken(): + popup.destroy() + scheduleReminder(username, med) + + tk.Button(popup, text="Taken", command=taken).pack(pady=20) + + dashboard.after(wait, notify) + +def openScheduler(): + global current_user + meds = users[current_user]["medications"] + if not meds: + messagebox.showinfo("Error", "You have no medications added.") + return + + win = tk.Toplevel() + win.title("Set Schedule") + win.geometry("300x300") + + lb = tk.Listbox(win) + for m in meds: + lb.insert(tk.END, m["name"]) + lb.pack(pady=10) + + def save(): + idx = lb.curselection() + if not idx: + return + med = meds[idx[0]] + scheduleReminder(current_user, med) + win.destroy() + messagebox.showinfo("Saved", "Reminder scheduled.") + + tk.Button(win, text="Save", command=save).pack(pady=15) + mainWindow.mainloop() From fc56e5dcede241b7de13c3100017efed813317ad Mon Sep 17 00:00:00 2001 From: harrellcc Date: Thu, 4 Dec 2025 20:15:00 -0500 Subject: [PATCH 34/39] Update meditrackCode.py Added TC03 --- Sprint 3/meditrackCode.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py index d71d7c338..1f8521ccd 100644 --- a/Sprint 3/meditrackCode.py +++ b/Sprint 3/meditrackCode.py @@ -264,13 +264,25 @@ def showReminder(): popup.title("Medication Reminder") popup.geometry("300x150") tk.Label(popup, text=f"Time to take {med['name']} ({med['dosage']})", font=font1).pack(pady=20) - tk.Button(popup, text="OK", command=popup.destroy).pack(pady=10) - - scheduleReminder(username, med) #reschedule the reminder for the next day + + #function to delay the reminder popup + def waitButton(): + popup.destroy() + + #delaying the reminder for 1 minute + waitDelay = 60*1000 + remindID = dashboard.after(waitDelay, showReminder) + reminders[key] = remindID + + def okButton(): + popup.destroy() + scheduleReminder(username, med) + + tk.Button(popup, text="OK", command=okButton).pack(pady=10) + tk.Button(popup, text = "Wait (1min)", command = waitButton).pack(pady = 5) remindID = dashboard.after(delay_ms, showReminder) #schedule the reminder reminders[key] = remindID #store the reminder ID - print(f"[DEBUG] Scheduled reminder for {username} to take {med['name']} in {delay_ms/1000:.2f} seconds.") #callback function when schedule is chosen From 12a4e4f531f80625aa6c8d72d7a0fc95a5eef381 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Thu, 4 Dec 2025 20:26:24 -0500 Subject: [PATCH 35/39] Create Sprint 3 Test cases --- Sprint 3/Sprint 3 Test cases | 163 +++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 Sprint 3/Sprint 3 Test cases diff --git a/Sprint 3/Sprint 3 Test cases b/Sprint 3/Sprint 3 Test cases new file mode 100644 index 000000000..1a5110525 --- /dev/null +++ b/Sprint 3/Sprint 3 Test cases @@ -0,0 +1,163 @@ +Use Case 3- <> +Test Case ID +TC01 - Notifications Pop up for the specified dosages +Test Objective +The notification for medication use will pop up for the user at the designated time +Preconditions +User’s account exists +User is logged in successfully +At least one medication with a name, dosage, and scheduled time is already added +Test steps +Login to the app +Add a new medication +Open the scheduling window +Select a time using the hour, minute, and AM/PM dropdowns +Select an occurrence value (example: Daily) +(Optional) Select specific days of the week if using custom days +Save the schedule so the time field is auto-filled +Save the medication +Wait for the scheduled time +Close the pop-up notification +Input Values +Username: sample, Password: 123 +Name: TestMed, Dosage: 10mg, Scheduling window values: Time 1–2 minutes from current time, Occurrence: Daily, symptoms: none +N/A +Click OK +Expected results +dashboard opens, user medications load +Scheduling window opens and accepts user selections +Selected time appears in the medication time field +Medication is added to the listbox and confirmation message shows +A pop-up appears at the scheduled time displaying: “Time to take TestMed (10mg)” +Pop-up closes + + + +Test Case ID +TC02 - Confirmation that dosage was taken +Test Objective +The user will be able to press taken or not taken. +Preconditions +The user has received a pop-up for the medication they need to take +Test steps +The user receives a pop-up alert for medication +The User presses yes +The pop-up window closes +Test case ends +Input Values +Click Yes +Expected results +The pop-up from the notification will disappear and will not reappear until the next dosage. + + + +Test Case ID +TC03 - Overdue Notifications +Test Objective +If the user has pressed wait, the pop-up will return in a minute +Preconditions +The user received a pop-up for the medication they needed to take +Test steps +The user receives a pop-up alert for the medication +The user selects wait +The pop-up opens again after a minute and the user is prompted to press “Ok” or “Wait” again. +User waits for the reminder to pop up again + +The user presses “Ok” +Test case ends. +Input Values +1. Input the Medication’s dosage and scheduled time + +2.Wait for the reminder to pop up + +3.Press “Wait” + + + +Expected results +The pop-up window will reappear after the user selects “Wait” to the prompt: +“Time to take MedA (5mg)” +The user can then press Wait again, or press Ok. + + + +Test Case ID +TC04 - Overlapping Dosage Handling +Test Objective +Ensure that when two or more medications have scheduled times that overlap (occur at the same minute), the app correctly displays multiple notifications without crashing, overlapping UI, or blocking the user from responding to each alert. +Preconditions +User’s account exists + + +User is logged in successfully + + +At least two medications are added with dosage times scheduled for the same minute + + +Both medications have valid names, dosages, and times saved + + +Test steps +Login to the app + + +Add Medication A + + +Add Medication B + + +Set both medications to notify within 1–2 minutes of the current time + + +Wait for scheduled notification time + + +Observe whether one or both pop-ups appear + + +Press Yes or OK on the first pop-up + + +Close the second pop-up after responding + + +End test case +Input Values +Username: sample, Password: 123 + + +Medication A: Name: MedA, Dosage: 5mg, Time: 1–2 minutes from now + + +Medication B: Name: MedB, Dosage: 20mg, Time: 1–2 minutes from now + + +User clicks Yes (taken) or OK on both pop-ups + + +Expected results +Both medications appear in the listbox after being added + + +Two separate pop-up notifications appear, one for each medication: + + +“Time to take MedA (5mg)” + + +“Time to take MedB (20mg)” + + +Pop-ups do not overlap in a way that prevents interaction + + +App does not freeze, delay, or prevent the user from closing each alert + + +Once each notification is handled, no duplicate notification appears until the next scheduled dosage time + + + + From ba5c456df8e9b29ef00c723ef5b1220d2477f7a6 Mon Sep 17 00:00:00 2001 From: harrellcc Date: Thu, 4 Dec 2025 20:26:34 -0500 Subject: [PATCH 36/39] Delete Sprint 3/TestCasesPlaceholder.txt --- Sprint 3/TestCasesPlaceholder.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 3/TestCasesPlaceholder.txt diff --git a/Sprint 3/TestCasesPlaceholder.txt b/Sprint 3/TestCasesPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 From 124e00d847a385153abb9d86233f39698978d23d Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Thu, 4 Dec 2025 23:28:21 -0500 Subject: [PATCH 37/39] update TC02 --- Sprint 3/meditrackCode.py | 63 ++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/Sprint 3/meditrackCode.py b/Sprint 3/meditrackCode.py index d71d7c338..b49f8f9fb 100644 --- a/Sprint 3/meditrackCode.py +++ b/Sprint 3/meditrackCode.py @@ -237,20 +237,19 @@ def seconds_until(time_str): -#function to schedule reminders +# function to schedule reminders (TC01 + TC02) def scheduleReminder(username, med): - - #get time string and calculate delay + # get time string and calculate delay using YOUR helper time_str = med['time'] delay_ms = seconds_until(time_str) if not delay_ms or delay_ms <= 0: print(f"[ERROR] Invalid time format for medication {med['name']}: {time_str}") return - - #unique key for each reminder + + # unique key for each reminder (so we can cancel/reschedule correctly) key = (username, med['name'], time_str) - #cancel existing reminder if present + # cancel existing reminder if present if key in reminders: try: dashboard.after_cancel(reminders[key]) @@ -258,21 +257,51 @@ def scheduleReminder(username, med): pass reminders.pop(key, None) - #function to show reminder popup - def showReminder(): + # function to show reminder popup + def notify(): popup = tk.Toplevel(dashboard) - popup.title("Medication Reminder") - popup.geometry("300x150") - tk.Label(popup, text=f"Time to take {med['name']} ({med['dosage']})", font=font1).pack(pady=20) - tk.Button(popup, text="OK", command=popup.destroy).pack(pady=10) - - scheduleReminder(username, med) #reschedule the reminder for the next day - - remindID = dashboard.after(delay_ms, showReminder) #schedule the reminder - reminders[key] = remindID #store the reminder ID + popup.title("MediTrack Reminder") + popup.geometry("300x200") + + # main text (like her code) + tk.Label( + popup, + text=f"Time to take {med['name']}!", + font=font1 + ).pack(pady=10) + + tk.Label( + popup, + text=f"Dosage: {med['dosage']}", + font=("Arial", 10) + ).pack() + + # inner functions: taken / not taken (from her pattern) + def taken(): + print(f"[DEBUG] {username} marked {med['name']} as TAKEN") + popup.destroy() + # schedule next dosage (same med, next day/time) + scheduleReminder(username, med) + + def not_taken(): + print(f"[DEBUG] {username} marked {med['name']} as NOT TAKEN") + popup.destroy() + # still schedule next dosage — app doesn’t skip future reminders + scheduleReminder(username, med) + + # buttons for TC02 + btn_frame = tk.Frame(popup) + btn_frame.pack(pady=20) + + tk.Button(btn_frame, text="Taken", width=10, command=taken).pack(side="left", padx=5) + tk.Button(btn_frame, text="Not Taken", width=10, command=not_taken).pack(side="left", padx=5) + + remindID = dashboard.after(delay_ms, notify) + reminders[key] = remindID print(f"[DEBUG] Scheduled reminder for {username} to take {med['name']} in {delay_ms/1000:.2f} seconds.") + #callback function when schedule is chosen def on_schedule_chosen(time_str, occurence, days): #update current schedule From a1f71e81d256010d0ac975d9cdbcf7356e5ff008 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Fri, 5 Dec 2025 11:52:08 -0500 Subject: [PATCH 38/39] Add video placeholder link to videoPlaceholder.txt --- Sprint 3/videoPlaceholder.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Sprint 3/videoPlaceholder.txt b/Sprint 3/videoPlaceholder.txt index e69de29bb..f0acd7102 100644 --- a/Sprint 3/videoPlaceholder.txt +++ b/Sprint 3/videoPlaceholder.txt @@ -0,0 +1 @@ +https://drive.google.com/file/d/1oMbpqjaWqCMOxSYe05NM6bsGCuZQFPtb/view?usp=sharing From 8396bc7afd1fde555b008a29763daf5c0c3a9a92 Mon Sep 17 00:00:00 2001 From: Malaya Conell Date: Fri, 5 Dec 2025 11:52:19 -0500 Subject: [PATCH 39/39] Delete Sprint 3/UMLDiagrams.txt --- Sprint 3/UMLDiagrams.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Sprint 3/UMLDiagrams.txt diff --git a/Sprint 3/UMLDiagrams.txt b/Sprint 3/UMLDiagrams.txt deleted file mode 100644 index e69de29bb..000000000