From a8de6e9937b48a49a019dd008f6d049dd6975cdf Mon Sep 17 00:00:00 2001
From: Nina Boord <86579493+ninaboord@users.noreply.github.com>
Date: Sun, 10 Mar 2024 20:44:20 -0700
Subject: [PATCH 1/2] Patient generalData flow refractor and PatientInfo View
(#64)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# *Patient generalData flow refractor and PatientInfo View*
## :recycle: Current situation & Problem
Before this PR, we did not have a way for the patient to enter or change
their personal information if they were not connected to FHIRStore.
- If the patient is NOT connected to FHIRStore, PatientInfo View allows
patient to update their general data (name, dob, age..), and view
updates global patient variables
- Global variables now passed into LLM, so LLMInteraction code is now
cleaner (moved my original code that did extraction from FHIRStore now
into PatientInfo for better code cleanliness!
- The Chief Complaint is now AFTER the forms. This is to set up for the
next bonus pull request of passing in patient medical history into the
LLM.
## :gear: Release Notes
calculateAge, getValue, and getInfo functions are now inside of a view,
and loadData() is a private function that then updates the data onAppear
of the Chief Complaint.
This code refractor is necessary for a future PR I will be doing where I
change the order of the navigation stack so that Chief Complaint is
actually the last item on the nav stack (before scrollable pdf and
export pdf).
## :books: Documentation
n/a
## :pencil: Code of Conduct & Contributing Guidelines
By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md).
---
Intake.xcodeproj/project.pbxproj | 12 ++
Intake/ChiefComplaint/LLMInteraction.swift | 125 ++++------------
Intake/ChiefComplaint/SummaryView.swift | 2 +-
Intake/EditPatient.swift | 34 ++---
Intake/Elements.swift | 25 ++++
Intake/General Data View/PatientInfo.swift | 159 +++++++++++++++++++++
Intake/Home.swift | 4 +-
Intake/Resources/Localizable.xcstrings | 54 +++++--
Intake/ScrollablePDF.swift | 25 ++--
Intake/SocialHistory/SmokingHistory.swift | 2 +-
Intake/Surgery/SurgeryView.swift | 2 +-
11 files changed, 298 insertions(+), 146 deletions(-)
create mode 100644 Intake/General Data View/PatientInfo.swift
diff --git a/Intake.xcodeproj/project.pbxproj b/Intake.xcodeproj/project.pbxproj
index 8c53aa0..a4453e4 100644
--- a/Intake.xcodeproj/project.pbxproj
+++ b/Intake.xcodeproj/project.pbxproj
@@ -56,6 +56,7 @@
2FE5DCB129EE6107004B9AB4 /* AccountOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */; };
2FF53D8B2A8725DE00042B76 /* SpeziMockWebService in Frameworks */ = {isa = PBXBuildFile; productRef = 2FF53D8A2A8725DE00042B76 /* SpeziMockWebService */; };
2FF53D8D2A8729D600042B76 /* IntakeStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FF53D8C2A8729D600042B76 /* IntakeStandard.swift */; };
+ 3C89F66D2B9D948B00A4F52D /* PatientInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89F66C2B9D948B00A4F52D /* PatientInfo.swift */; };
511827962B740192002033A0 /* SurgeryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511827952B740191002033A0 /* SurgeryView.swift */; };
51805C122B81853800D17109 /* IntakeMedication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51805C112B81853700D17109 /* IntakeMedication.swift */; };
51805C152B81857100D17109 /* IntakeMedicationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51805C142B81857100D17109 /* IntakeMedicationViewModel.swift */; };
@@ -176,6 +177,7 @@
2FE5DC5529EDD811004B9AB4 /* SocialSupportQuestionnaire.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SocialSupportQuestionnaire.json; sourceTree = ""; };
2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountOnboarding.swift; sourceTree = ""; };
2FF53D8C2A8729D600042B76 /* IntakeStandard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntakeStandard.swift; sourceTree = ""; };
+ 3C89F66C2B9D948B00A4F52D /* PatientInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatientInfo.swift; sourceTree = ""; };
511827952B740191002033A0 /* SurgeryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SurgeryView.swift; sourceTree = ""; };
51805C112B81853700D17109 /* IntakeMedication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntakeMedication.swift; sourceTree = ""; };
51805C142B81857100D17109 /* IntakeMedicationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntakeMedicationViewModel.swift; sourceTree = ""; };
@@ -382,6 +384,14 @@
path = Helper;
sourceTree = "";
};
+ 3C89F6682B9D939500A4F52D /* General Data View */ = {
+ isa = PBXGroup;
+ children = (
+ 3C89F66C2B9D948B00A4F52D /* PatientInfo.swift */,
+ );
+ path = "General Data View";
+ sourceTree = "";
+ };
511827942B740191002033A0 /* Surgery */ = {
isa = PBXGroup;
children = (
@@ -501,6 +511,7 @@
653A254F283387FE005D4D48 /* Intake */ = {
isa = PBXGroup;
children = (
+ 3C89F6682B9D939500A4F52D /* General Data View */,
ACF862BC2B96E28400ACBA1E /* Export */,
F4F4F8802B8C6FC5008FBEED /* Elements.swift */,
519E830A2B7C4F1600A2D92D /* Medication View */,
@@ -837,6 +848,7 @@
F42AB1DF2B637C9D002E13A6 /* LLMInteraction.swift in Sources */,
51A360162B965819004E7E12 /* AllergyLLMAssistant.swift in Sources */,
F42AB1F22B71B4D2002E13A6 /* AllergyViewTest.swift in Sources */,
+ 3C89F66D2B9D948B00A4F52D /* PatientInfo.swift in Sources */,
2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */,
2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */,
51A360182B9659AE004E7E12 /* MedicalHistoryLLMAssistant.swift in Sources */,
diff --git a/Intake/ChiefComplaint/LLMInteraction.swift b/Intake/ChiefComplaint/LLMInteraction.swift
index 7a71da7..9d32b42 100644
--- a/Intake/ChiefComplaint/LLMInteraction.swift
+++ b/Intake/ChiefComplaint/LLMInteraction.swift
@@ -19,79 +19,35 @@ import SpeziLLMLocal
import SpeziLLMOpenAI
import SwiftUI
-func calculateAge(from dobString: String, with format: String = "yyyy-MM-dd") -> String {
- if dobString.isEmpty {
- return ""
- }
- let dateFormatter = DateFormatter()
- dateFormatter.dateFormat = format
-
- guard let birthDate = dateFormatter.date(from: dobString) else {
- return "Invalid date format or date string."
- }
-
- let ageComponents = Calendar.current.dateComponents([.year], from: birthDate, to: Date())
- if let age = ageComponents.year {
- return "\(age)"
- } else {
- return "Could not calculate age"
- }
-}
-func getValue(forKey key: String, from jsonString: String) -> String? {
- guard let jsonData = jsonString.data(using: .utf8) else {
- print("Error: Cannot create Data from JSON string")
- return nil
- }
+struct LLMInteraction: View {
+ // swiftlint:disable type_contents_order
+ @State private var fullName: String = ""
+ @State private var firstName: String = ""
+ @State private var dob: String = ""
+ @State private var gender: String = ""
+ @Environment(LLMRunner.self) var runner: LLMRunner
+ @Environment(FHIRStore.self) private var fhirStore
+ @Environment(DataStore.self) private var data
+ @Environment(NavigationPathWrapper.self) private var navigationPath
- do {
- if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
- if key == "name" {
- if let nameArray = dictionary[key] as? [[String: Any]], !nameArray.isEmpty {
- let nameDict = nameArray[0] // Accessing the first name object
- if let family = nameDict["family"] as? String,
- let givenArray = nameDict["given"] as? [String],
- !givenArray.isEmpty {
- let given = givenArray.joined(separator: " ") // Assuming there might be more than one given name
-
- return "\(given) \(family)"
- }
- }
- } else {
- return dictionary[key] as? String
- }
- } else {
- print("Error: JSON is not a dictionary")
- }
- } catch {
- print("Error: \(error.localizedDescription)")
- }
-
- return nil
-}
+ @Binding var presentingAccount: Bool
+ @LLMSessionProvider var session: LLMOpenAISession
-func getInfo(patient: FHIRResource, field: String) -> String {
- let jsonDescription = patient.jsonDescription
+ @State var showOnboarding = true
+ @State var greeting = true
- if let infoValue = getValue(forKey: field, from: jsonDescription) {
- print("Info found: \(infoValue)")
- return infoValue
- }
+ @State var stringBox: StringBox = .init()
+ @State var showSheet = false
- print("Key \(field) not found")
- return ""
-}
-
-
-struct LLMInteraction: View {
@Observable
class StringBox: Equatable {
var llmResponseSummary: String
-
+
init() {
self.llmResponseSummary = ""
}
-
+
static func == (lhs: LLMInteraction.StringBox, rhs: LLMInteraction.StringBox) -> Bool {
lhs.llmResponseSummary == rhs.llmResponseSummary
}
@@ -123,20 +79,6 @@ struct LLMInteraction: View {
return nil
}
}
-
- @Environment(LLMRunner.self) var runner: LLMRunner
- @Environment(FHIRStore.self) private var fhirStore
- @Environment(DataStore.self) private var data
- @Environment(NavigationPathWrapper.self) private var navigationPath
-
- @Binding var presentingAccount: Bool
- @LLMSessionProvider var session: LLMOpenAISession
-
- @State var showOnboarding = true
- @State var greeting = true
-
- @State var stringBox: StringBox = .init()
- @State var showSheet = false
var body: some View {
@Bindable var data = data
@@ -154,37 +96,20 @@ struct LLMInteraction: View {
}
.onAppear {
- var fullName: String = ""
- var firstName: String = ""
- var dob: String = ""
- var gender: String = ""
- if let patient = fhirStore.patient {
- fullName = getInfo(patient: patient, field: "name").filter { !$0.isNumber }
- dob = getInfo(patient: patient, field: "birthDate")
- gender = getInfo(patient: patient, field: "gender")
-
- let age = calculateAge(from: dob)
- let nameString = fullName.components(separatedBy: " ")
-
- data.generalData.name = fullName
- data.generalData.birthdate = dob
- data.generalData.sex = gender
- data.generalData.age = age
-
- firstName = nameString.first ?? "First Name is empty"
- print(firstName == "First Name is empty" ? "First Name is empty" : "")
-
-
+ let nameString = data.generalData.name.components(separatedBy: " ")
+ if let firstNameValue = nameString.first {
+ firstName = firstNameValue
+ }
let systemMessage = """
- The first name of the patient is \(String(describing: firstName)) and the patient is \(String(describing: age))\
- years old. The patient's gender is \(String(describing: gender)) Please speak with\
+ The first name of the patient is \(String(describing: firstName)) and the patient is \(String(describing: data.generalData.age)) \
+ years old. The patient's sex is \(String(describing: data.generalData.sex)) Please speak with\
the patient as you would a person of this age group, using as simple words as possible\
if the patient is young. Address them by their first name when you ask questions.
"""
session.context.append(
systemMessage: systemMessage
)
- }
+
if greeting {
if firstName.isEmpty {
diff --git a/Intake/ChiefComplaint/SummaryView.swift b/Intake/ChiefComplaint/SummaryView.swift
index 6b5ef6e..c037d62 100644
--- a/Intake/ChiefComplaint/SummaryView.swift
+++ b/Intake/ChiefComplaint/SummaryView.swift
@@ -34,7 +34,7 @@ struct SummaryView: View {
var body: some View {
VStack(alignment: .leading, spacing: 20) {
ComplaintForm(chiefComplaint: $chiefComplaint)
- SubmitButton(nextView: NavigationViews.medical)
+ SubmitButton(nextView: NavigationViews.pdfs)
.padding()
}
}
diff --git a/Intake/EditPatient.swift b/Intake/EditPatient.swift
index d5e5f6f..735d6c1 100644
--- a/Intake/EditPatient.swift
+++ b/Intake/EditPatient.swift
@@ -12,33 +12,35 @@
//
import Foundation
+import SpeziFHIR
import SwiftUI
-
struct EditPatientView: View {
@Environment(DataStore.self) private var data
+ @Environment(FHIRStore.self) private var fhirStore
var body: some View {
@Bindable var data = data
- VStack {
- Form {
- Section(header: Text("Name")) {
- TextField("Name", text: $data.generalData.name)
- }
- Section(header: Text("Date of Birth")) {
- TextField("Date of Birth", text: $data.generalData.birthdate)
- }
- Section(header: Text("Age")) {
- TextField("Age", text: $data.generalData.age)
- }
- Section(header: Text("Sex")) {
- TextField("Sex", text: $data.generalData.sex)
+
+ VStack {
+ Form {
+ Section(header: Text("Name")) {
+ TextField("Name", text: $data.generalData.name)
+ }
+ Section(header: Text("Date of Birth")) {
+ TextField("Date of Birth", text: $data.generalData.birthdate)
+ }
+ Section(header: Text("Age")) {
+ TextField("Age", text: $data.generalData.age)
+ }
+ Section(header: Text("Sex")) {
+ TextField("Sex", text: $data.generalData.sex)
+ }
}
+ SubmitButton(nextView: NavigationViews.pdfs)
}
- SubmitButton(nextView: NavigationViews.pdfs)
}
}
-}
//
// #Preview {
diff --git a/Intake/Elements.swift b/Intake/Elements.swift
index fc8e220..50558b1 100644
--- a/Intake/Elements.swift
+++ b/Intake/Elements.swift
@@ -51,3 +51,28 @@ struct SubmitButton: View {
}
}
}
+
+struct SubmitButtonWithAction: View {
+ @Environment(NavigationPathWrapper.self) private var navigationPath
+ @Environment(ReachedEndWrapper.self) private var end
+ var nextView: NavigationViews
+ var onButtonTap: () -> Void
+
+ var body: some View {
+ Button(action: {
+ onButtonTap()
+ if end.reachedEnd {
+ navigationPath.path.append(NavigationViews.pdfs)
+ } else {
+ navigationPath.path.append(nextView)
+ }
+ }) {
+ Text("Next")
+ .foregroundColor(.white)
+ .padding()
+ .frame(maxWidth: .infinity)
+ .background(Color.blue)
+ .cornerRadius(8)
+ }
+ }
+}
diff --git a/Intake/General Data View/PatientInfo.swift b/Intake/General Data View/PatientInfo.swift
new file mode 100644
index 0000000..ad6d929
--- /dev/null
+++ b/Intake/General Data View/PatientInfo.swift
@@ -0,0 +1,159 @@
+////
+//// SwiftUIView.swift
+//// Intake
+////
+//// Created by Nina Boord on 3/9/24.
+////
+// This source file is part of the Intake based on the Stanford Spezi Template Medication project
+//
+// SPDX-FileCopyrightText: 2023 Stanford University
+//
+// SPDX-License-Identifier: MIT
+//
+import SpeziFHIR
+import SwiftUI
+// swiftlint:disable type_contents_order
+struct PatientInfo: View {
+ @Environment(DataStore.self) private var data
+ @Environment(NavigationPathWrapper.self) private var navigationPath
+ @Environment(FHIRStore.self) private var fhirStore
+
+
+ @State private var fullName: String = ""
+ @State private var firstName: String = ""
+ @State private var birthdate: String = ""
+ @State private var gender: String = ""
+ @State private var sexOption: String = ""
+ @State private var birthdateDateFormat = Date()
+
+ func calculateAge(from dobString: String, with format: String = "yyyy-MM-dd") -> String {
+ if dobString.isEmpty {
+ return ""
+ }
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = format
+
+ guard let birthDate = dateFormatter.date(from: dobString) else {
+ return "Invalid date format or date string."
+ }
+
+ let ageComponents = Calendar.current.dateComponents([.year], from: birthDate, to: Date())
+ if let age = ageComponents.year {
+ return "\(age)"
+ } else {
+ return "Could not calculate age"
+ }
+ }
+
+ func getValue(forKey key: String, from jsonString: String) -> String? {
+ guard let jsonData = jsonString.data(using: .utf8) else {
+ print("Error: Cannot create Data from JSON string")
+ return nil
+ }
+
+ do {
+ if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
+ if key == "name" {
+ if let nameArray = dictionary[key] as? [[String: Any]], !nameArray.isEmpty {
+ let nameDict = nameArray[0] // Accessing the first name object
+ if let family = nameDict["family"] as? String,
+ let givenArray = nameDict["given"] as? [String],
+ !givenArray.isEmpty {
+ let given = givenArray.joined(separator: " ") // Assuming there might be more than one given name
+
+ return "\(given) \(family)"
+ }
+ }
+ } else {
+ return dictionary[key] as? String
+ }
+ } else {
+ print("Error: JSON is not a dictionary")
+ }
+ } catch {
+ print("Error: \(error.localizedDescription)")
+ }
+
+ return nil
+ }
+
+ func getInfo(patient: FHIRResource, field: String) -> String {
+ let jsonDescription = patient.jsonDescription
+
+ if let infoValue = getValue(forKey: field, from: jsonDescription) {
+ print("Info found: \(infoValue)")
+ return infoValue
+ }
+
+ print("Key \(field) not found")
+ return ""
+ }
+
+ var body: some View {
+ @Bindable var data = data
+ Form {
+ Section(header: Text("Patient Information")) {
+ HStack {
+ TextField("Full name", text: $data.generalData.name)
+ Spacer()
+ }
+ HStack {
+ DatePicker("Date of Birth:", selection: $birthdateDateFormat, in: ...Date(), displayedComponents: .date)
+ .datePickerStyle(DefaultDatePickerStyle())
+ }
+ HStack {
+ let options = ["Female", "Male"]
+ Picker("Sex", selection: $sexOption) {
+ ForEach(options, id: \.self) { option in
+ Text(option).tag(option)
+ }
+ }
+ .pickerStyle(MenuPickerStyle())
+ }
+ }
+
+ SubmitButtonWithAction(nextView: .medical, onButtonTap: {
+ updateData()
+ })
+ }
+ .onAppear {
+ loadData()
+ }
+ }
+
+ private func loadData() {
+ if let patient = fhirStore.patient {
+ fullName = getInfo(patient: patient, field: "name").filter { !$0.isNumber }
+ birthdate = getInfo(patient: patient, field: "birthDate")
+ gender = getInfo(patient: patient, field: "gender")
+ let age = calculateAge(from: birthdate)
+
+ // string to date
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyy-MM-dd"
+ if let dob = dateFormatter.date(from: birthdate) {
+ birthdateDateFormat = dob
+ }
+ sexOption = gender
+ data.generalData = PatientData(name: fullName, birthdate: birthdate, age: age, sex: gender)
+ }
+ }
+
+ private func updateData() {
+ // date to string
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyy-MM-dd"
+ birthdate = dateFormatter.string(from: birthdateDateFormat)
+ data.generalData.birthdate = birthdate
+ let age = calculateAge(from: birthdate)
+ data.generalData.sex = sexOption
+ data.generalData.age = age
+ }
+}
+
+
+struct PatientInfo_Previews: PreviewProvider {
+ static var previews: some View {
+ PatientInfo()
+ }
+}
diff --git a/Intake/Home.swift b/Intake/Home.swift
index b568ec3..20ace34 100644
--- a/Intake/Home.swift
+++ b/Intake/Home.swift
@@ -23,6 +23,7 @@ enum NavigationViews: String {
case patient
case pdfs
case inspect
+ case general
}
struct HomeView: View {
@@ -84,7 +85,7 @@ struct HomeView: View {
Spacer()
Button(action: {
- navigationPath.path.append(NavigationViews.chat)
+ navigationPath.path.append(NavigationViews.general)
}) {
Text("Start")
.font(.headline)
@@ -110,6 +111,7 @@ struct HomeView: View {
case .patient: EditPatientView()
case .pdfs: ScrollablePDF()
case .inspect: InspectSurgeryView(surgery: $data.surgeries[data.surgeries.count - 1], isNew: true)
+ case .general: PatientInfo()
}
}
diff --git a/Intake/Resources/Localizable.xcstrings b/Intake/Resources/Localizable.xcstrings
index e37db7d..b82f420 100644
--- a/Intake/Resources/Localizable.xcstrings
+++ b/Intake/Resources/Localizable.xcstrings
@@ -121,13 +121,14 @@
"Auto-fill Intake Form" : {
},
-
-
"Calculation" : {
},
"Chat" : {
+ },
+ "Chief Complaint:" : {
+
},
"CHIEF_COMPLAINT_SYSTEM_PROMPT" : {
"extractionState" : "manual",
@@ -225,6 +226,9 @@
}
}
}
+ },
+ "Date" : {
+
},
"Date of Birth" : {
@@ -261,12 +265,18 @@
},
"Ex: Smoked for 10 years, quit 5 years ago..." : {
+ },
+ "Female" : {
+
},
"FHIR_RESOURCES_CHAT_CANCEL" : {
},
"fix medication" : {
+ },
+ "Full name" : {
+
},
"Get Started" : {
@@ -326,6 +336,9 @@
},
"Inactive" : {
+ },
+ "Intake Form" : {
+
},
"Integrate your Records" : {
@@ -349,7 +362,9 @@
"John Doe" : {
},
-
+ "Last Menstrural Period" : {
+
+ },
"Last period's end date" : {
},
@@ -381,10 +396,11 @@
"Medical History" : {
},
+ "MEDICAL HISTORY" : {
+ },
"Medical History Assistant" : {
-
},
"Medical Intake Form" : {
@@ -395,12 +411,13 @@
"Medications" : {
},
-
"Medications Assistant" : {
},
- "Menstrual Information" : {
+ "Medications:" : {
+ },
+ "Menstrual Information" : {
},
"Message" : {
@@ -553,22 +570,25 @@
"Pack years: %.2f" : {
},
- "Patient Form" : {
+ "Past Medical History:" : {
},
- "Performed" : {
+ "Past Surgical History:" : {
},
- "Please add your past surgeries" : {
+ "Patient did not enter chief complaint." : {
},
- "Past Medical History:" : {
+ "Patient Form" : {
},
- "Past Surgical History:" : {
+ "Patient Information" : {
},
- "Patient did not enter chief complaint." : {
+ "Performed" : {
+
+ },
+ "Please add your past surgeries" : {
},
"Please list conditions you have had" : {
@@ -672,20 +692,26 @@
"SETTINGS_TITLE" : {
},
- "Sex:" : {
+ "Sex" : {
},
- "Sex" : {
+ "Sex:" : {
},
"Share" : {
+ },
+ "Share Intake form" : {
+
},
"Share with provider of your choice." : {
},
"Skip" : {
+ },
+ "Smoking history" : {
+
},
"Smoking History" : {
diff --git a/Intake/ScrollablePDF.swift b/Intake/ScrollablePDF.swift
index 3147f51..67adc3b 100644
--- a/Intake/ScrollablePDF.swift
+++ b/Intake/ScrollablePDF.swift
@@ -20,7 +20,7 @@ struct HeaderTitle: View {
@Environment(NavigationPathWrapper.self) private var navigationPath
let title: String
var nextView: NavigationViews
-
+
var body: some View {
HStack {
Text(title)
@@ -41,15 +41,15 @@ struct ScrollablePDF: View {
private struct ConditionSection: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
-
+
var body: some View {
Section(header: HeaderTitle(title: "Conditions", nextView: NavigationViews.medical)) {
List(data.conditionData, id: \.id) { item in
HStack {
- Text(item.condition)
- Spacer()
- Text(item.active ? "Active" : "Inactive")
- .foregroundColor(.secondary)
+ Text(item.condition)
+ Spacer()
+ Text(item.active ? "Active" : "Inactive")
+ .foregroundColor(.secondary)
}
}
}
@@ -58,7 +58,7 @@ struct ScrollablePDF: View {
private struct ExportButton: View {
@Environment(NavigationPathWrapper.self) private var navigationPath
-
+
var body: some View {
Button(action: {
}) {
@@ -75,13 +75,12 @@ struct ScrollablePDF: View {
private struct SurgerySection: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
-
+
var body: some View {
Section(header: HeaderTitle(title: "Surgical History", nextView: NavigationViews.surgical)) {
List(data.surgeries, id: \.id) { item in
HStack {
Text(item.surgeryName)
- Spacer()
.foregroundColor(.secondary)
}
}
@@ -92,7 +91,7 @@ struct ScrollablePDF: View {
private struct MedicationSection: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
-
+
var body: some View {
Section(header: HeaderTitle(title: "Medications", nextView: NavigationViews.medication)) {
VStack(alignment: .leading) {
@@ -105,7 +104,7 @@ struct ScrollablePDF: View {
private struct ChiefComplaint: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
-
+
var body: some View {
Section(header: HeaderTitle(title: "Chief Complaint", nextView: NavigationViews.concern)) {
Text(data.chiefComplaint)
@@ -116,6 +115,8 @@ struct ScrollablePDF: View {
private struct PatientInfo: View {
@Environment(DataStore.self) private var data
@Environment(NavigationPathWrapper.self) private var navigationPath
+ @Environment(FHIRStore.self) private var fhirStore
+
var body: some View {
Section(header: HeaderTitle(title: "Patient Information", nextView: NavigationViews.patient)) {
List {
@@ -166,7 +167,7 @@ struct ScrollablePDF: View {
private func reactionPDFView() -> some View {
ReactionPDF(index: selectedIndex, showingReaction: $showingReaction)
}
-
+
private func allergyButton(index: Int) -> some View {
Button(action: {
self.selectedIndex = index
diff --git a/Intake/SocialHistory/SmokingHistory.swift b/Intake/SocialHistory/SmokingHistory.swift
index 8f5c310..e59b6ed 100644
--- a/Intake/SocialHistory/SmokingHistory.swift
+++ b/Intake/SocialHistory/SmokingHistory.swift
@@ -54,7 +54,7 @@ struct SmokingHistoryView: View {
data.smokingHistory = SmokingHistoryItem(packYears: packYears, additionalDetails: additionalDetails)
}
- SubmitButton(nextView: NavigationViews.pdfs)
+ SubmitButton(nextView: NavigationViews.chat)
.padding()
}
.navigationTitle("Social History")
diff --git a/Intake/Surgery/SurgeryView.swift b/Intake/Surgery/SurgeryView.swift
index 6ab462d..f8a9ed8 100644
--- a/Intake/Surgery/SurgeryView.swift
+++ b/Intake/Surgery/SurgeryView.swift
@@ -292,7 +292,7 @@ struct SurgeryView: View {
let LLMResponse = try await self.queryLLM(surgeryNames: surgeryNames)
let filteredNames = LLMResponse.components(separatedBy: ", ")
- let filteredSurgeries = surgeries.filter { self.containsAnyWords(item: $0.surgeryName, words: filteredNames) }
+ var filteredSurgeries = surgeries.filter { self.containsAnyWords(item: $0.surgeryName, words: filteredNames) }
return self.cleanSurgeryNames(surgeries: filteredSurgeries, filteredNames: filteredNames)
}
From 081ea982e54ddb8af3d8ad6c0908e56019fa4389 Mon Sep 17 00:00:00 2001
From: Kate Callon <70660419+kcallon@users.noreply.github.com>
Date: Sun, 10 Mar 2024 21:10:45 -0700
Subject: [PATCH 2/2] Minor Updates to Medications including Scrollable PDF
(#66)
# *Minor Updates to Medications including Scrollable PDF*
## :recycle: Current situation & Problem
The medications final view was missing the frequency of the medications.
Additionally, some patients didn't have any medications assigned to
them, so I added some options.
## :gear: Release Notes
*Add a bullet point list summary of the feature and possible migration
guides if this is a breaking change so this section can be added to the
release notes.*
*Include code snippets that provide examples of the feature implemented
or links to the documentation if it appends or changes the public
interface.*
## :books: Documentation
*Please ensure that you properly document any additions in conformance
to [Spezi Documentation
Guide](https://github.com/StanfordSpezi/.github/blob/main/DOCUMENTATIONGUIDE.md).*
*You can use this section to describe your solution, but we encourage
contributors to document your reasoning and changes using in-line
documentation.*
## :white_check_mark: Testing
*Please ensure that the PR meets the testing requirements set by CodeCov
and that new functionality is appropriately tested.*
*This section describes important information about the tests and why
some elements might not be testable.*
## :pencil: Code of Conduct & Contributing Guidelines
By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md):
- [x ] I agree to follow the [Code of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md).
---
.../xcshareddata/swiftpm/Package.resolved | 3 ++-
.../IntakeMedicationViewModel.swift | 26 ++++++++++++++++++-
.../MedicationContentView.swift | 2 +-
Intake/Resources/Localizable.xcstrings | 13 +++++++---
Intake/ScrollablePDF.swift | 12 +++++++--
5 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/Intake.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Intake.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 4b69e21..9f82483 100644
--- a/Intake.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Intake.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,4 +1,5 @@
{
+ "originHash" : "cdbe60a3382a8a962c7fcc00210e56e13314cb3e246d0e01fe8e25a1268623d8",
"pins" : [
{
"identity" : "abseil-cpp-binary",
@@ -379,5 +380,5 @@
}
}
],
- "version" : 2
+ "version" : 3
}
diff --git a/Intake/Medication View/IntakeMedicationViewModel.swift b/Intake/Medication View/IntakeMedicationViewModel.swift
index acd28ca..45342ac 100644
--- a/Intake/Medication View/IntakeMedicationViewModel.swift
+++ b/Intake/Medication View/IntakeMedicationViewModel.swift
@@ -69,7 +69,31 @@ class IntakeMedicationSettingsViewModel: Module, MedicationSettingsViewModel, Cu
IntakeMedication(
localizedDescription: "NDA020800 0.3 ML Epinephrine 1 MG/ML Auto-Injector",
dosages: [
- IntakeDosage(localizedDescription: "0.3ML / 1 MG/ML")
+ IntakeDosage(localizedDescription: "0.3 ML/1 MG/ML")
+ ]
+ ),
+ IntakeMedication(
+ localizedDescription: "Clopidogrel 75 MG Oral Tablet",
+ dosages: [
+ IntakeDosage(localizedDescription: "75 MG")
+ ]
+ ),
+ IntakeMedication(
+ localizedDescription: "Verapamil Hydrochloride 40 MG",
+ dosages: [
+ IntakeDosage(localizedDescription: "40 MG")
+ ]
+ ),
+ IntakeMedication(
+ localizedDescription: "Simvastatin 20 MG Oral Tablet",
+ dosages: [
+ IntakeDosage(localizedDescription: "20 MG")
+ ]
+ ),
+ IntakeMedication(
+ localizedDescription: "amLODIPine 2.5 MG Oral Tablet",
+ dosages: [
+ IntakeDosage(localizedDescription: "2.5 MG")
]
)
]
diff --git a/Intake/Medication View/MedicationContentView.swift b/Intake/Medication View/MedicationContentView.swift
index 91d2b41..9873525 100644
--- a/Intake/Medication View/MedicationContentView.swift
+++ b/Intake/Medication View/MedicationContentView.swift
@@ -32,7 +32,7 @@ struct MedicationContentView: View {
data.medicationData = medicationSettingsViewModel.medicationInstances
navigationPath.path.append(NavigationViews.allergies)
}
- .navigationTitle("Medication Settings")
+ .navigationTitle("Medications")
.navigationBarItems(trailing: NavigationLink(destination: MedicationLLMAssistant(presentingAccount: .constant(false))) {
Text("Chat")
})
diff --git a/Intake/Resources/Localizable.xcstrings b/Intake/Resources/Localizable.xcstrings
index b82f420..620f482 100644
--- a/Intake/Resources/Localizable.xcstrings
+++ b/Intake/Resources/Localizable.xcstrings
@@ -12,6 +12,16 @@
},
"%.2f" : {
+ },
+ "%@ - %@" : {
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "%1$@ - %2$@"
+ }
+ }
+ }
},
"%@ Reactions" : {
@@ -404,9 +414,6 @@
},
"Medical Intake Form" : {
- },
- "Medication Settings" : {
-
},
"Medications" : {
diff --git a/Intake/ScrollablePDF.swift b/Intake/ScrollablePDF.swift
index 67adc3b..77f2394 100644
--- a/Intake/ScrollablePDF.swift
+++ b/Intake/ScrollablePDF.swift
@@ -93,9 +93,17 @@ struct ScrollablePDF: View {
@Environment(NavigationPathWrapper.self) private var navigationPath
var body: some View {
+ let medicationData = data.medicationData
Section(header: HeaderTitle(title: "Medications", nextView: NavigationViews.medication)) {
- VStack(alignment: .leading) {
- Text("fix medication")
+ ForEach(Array(medicationData), id: \.self) { medicationInstance in
+ List {
+ VStack(alignment: .leading, spacing: 0) {
+ Text(medicationInstance.type.localizedDescription)
+ .font(.headline)
+ Text("\(medicationInstance.dosage.localizedDescription) - \(medicationInstance.schedule.frequency.description)")
+ .font(.subheadline)
+ }
+ }
}
}
}