diff --git a/README.md b/README.md index b2588bc51..aebd7cf89 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -My groupmembers are: -- XXXX -- XXXX -- XXXX -- XXXX +# Group Members +- Caycee Harrell +- Edwina Sesay +- Malaya Conell +- Rigel Sliteris +- 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. diff --git a/Sprint 1/MediTrack Main Screen Code b/Sprint 1/MediTrack Main Screen Code new file mode 100644 index 000000000..148898619 --- /dev/null +++ b/Sprint 1/MediTrack Main Screen Code @@ -0,0 +1,110 @@ +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() + 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 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. + + diff --git a/Sprint 1/TestCasesPlaceholder.txt b/Sprint 1/TestCasesPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 1/codePlaceHolder.txt b/Sprint 1/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 1/videoPlaceholder.txt b/Sprint 1/videoPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 2/Sprint 2 Recording b/Sprint 2/Sprint 2 Recording new file mode 100644 index 000000000..8013e771c --- /dev/null +++ b/Sprint 2/Sprint 2 Recording @@ -0,0 +1 @@ +https://vcu.zoom.us/rec/share/QMlyAqaltyCIUfxmdpkLMSzu_f3dxUNJzAfEurDeKJXjgb2YtcwfXPzMQcCdH5mO.ckMbnzbtlpDzTwPD?startTime=1763164710000 diff --git a/Sprint 2/Sprint 2 Test Case b/Sprint 2/Sprint 2 Test Case new file mode 100644 index 000000000..7f37ce907 --- /dev/null +++ b/Sprint 2/Sprint 2 Test Case @@ -0,0 +1,96 @@ +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- “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 + + + +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 - “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 +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 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 - “Ibuprofen” +Dosage - “200 mg” +Time Taken = “8:00 AM” +Symptoms - “Nausea” +Expected results +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 + + diff --git a/Sprint 2/TestCasesPlaceholder.txt b/Sprint 2/TestCasesPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 2/codePlaceHolder.txt b/Sprint 2/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 2/meditrackCode.py b/Sprint 2/meditrackCode.py new file mode 100644 index 000000000..9749a222a --- /dev/null +++ b/Sprint 2/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() diff --git a/Sprint 2/videoPlaceholder.txt b/Sprint 2/videoPlaceholder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 3/codePlaceHolder.txt b/Sprint 3/codePlaceHolder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/Sprint 3/sprint3.py b/Sprint 3/sprint3.py new file mode 100644 index 000000000..d3f5a12fa --- /dev/null +++ b/Sprint 3/sprint3.py @@ -0,0 +1 @@ +