Tuesday, May 13, 2014

T's OBGYN Patient Intake App - My Very First App!

My first personal project at gSchool was a very simple Sinatra + PostgreSQL app for my lady.  She had been complaining that she had to type out these ridiculously long text messages to her team every time she took in a new patient in triage, and that her life would be so much simpler if technology could do it for her.  Lucky her!  I happened to know exactly how to do it :)

So I made a simple form, styled with Bootstrap, that took all the required inputs, formatted them, saved them to a database (in case she wanted needed the data in the future), then gave her the option to: a) text the results to herself or someone else, or b) copy and paste the results.



There's a lot of fields to this form, but it kept her from having to manually type each one.   A little bit of background on its purpose.  She's an OBGYN and every time a new patient comes in, she has to get a history for each patient including such things as: how many times they've been pregnant, number of miscarriages, successful births, results of various tests, the weight of previous children at birth, the current baby's weight, etc.  Luckily, all of the information is anonymous, in that there is no identifying information that could possibly link this info to patient, so no need to worry about HIPAA.  Anyway, when the information is gathered, it's sent out to the team on call so everyone is aware of the current patients, their history, and possible complications.

Since all of the fields above are attributes of a single patient, I put them all in the patient class, which was ugly... nearly 20 instance variables!  Luckily there's a way to make that look decent:

1:  require 'patient_repository'  
2:    
3:  class Patient  
4:    
5:   ATTRIBUTES = [  
6:     :age, :g, :p, :at_weeks, :at_days, :by_weeks, :by_days, :ultrasound, :prenatal_care,  
7:     :placenta, :group_b_strep, :one_hr_diabetes, :three_hr_diabetes, :history, :times_delivery_type,  
8:     :largest_baby_birthed, :estimated_fetal_weight_lbs, :estimated_fetal_weight_oz, :efw_by,  
9:     :sterile_vaginal_exam_time, :sve_dilation, :sve_effacement, :sve_station, :comment, :time  
10:   ]  
11:    
12:   attr_accessor *ATTRIBUTES  
13:    
14:   def initialize(options)  
15:    ATTRIBUTES.each do |attr|  
16:     instance_variable_set(:"@#{attr}", options[attr])  
17:    end  
18:   end  
19:    
20:   def attributes  
21:    Hash[ATTRIBUTES.map { |name| [name, instance_variable_get("@#{name}")] }]  
22:   end  
23:    
24:   def validate  
25:    ATTRIBUTES.each do |attribute|  
26:     replace_attribute = ['', '--'].include?(instance_variable_get("@#{attribute}"))  
27:     instance_variable_set("@#{attribute}", nil) if replace_attribute  
28:    end  
29:   end  
30:  end  

Instead of initializing ~20 instance variables, I put them into an attributes array and iterated through the array in the initialize method.  This did two things, solved a potential security vulnerability and also made the class look a ton cleaner.

Also, since not all the values were required and the database wasn't too keen on taking empty strings or '--' values in integer cells, I made a validate method that checked the form inputs for these and replaced them with nil.

Below is a screenshot of what the database:




After all the values have been input and submitted, below is the results.  What really made my day was being told that this little app now saves my darling about hour per day!  Nothing like producing software (in my first month of gSchool) that is actually used in a professional setting :)


If there are any OBGYN's out there that think this would be useful for them, feel free to use it: 

http://www.tiare.herokupapp.com

It's optimized for mobile, and kind of looks poopy on desktop.  But hey, it was my first app, ever!

As a PS, I looked all over GitHub for a for an active gem that allowed sending text messages through Google Voice.  Unfortunately, there weren't any active gems... so I had use some code from a blog I read and repurpose it for my app.  I'll have to scour Google SERPs for the blog (because he deserves the credit) and add it later, since I didn't bookmark it.


1:  class TextMessage  
2:    
3:   attr_accessor :data, :phone_number  
4:    
5:   def initialize(data, phone_number)  
6:    @data = data  
7:    @phone_number = phone_number  
8:   end  
9:    
10:    
11:   def text_message  
12:    login_response = ''  
13:    
14:    url = URI.parse('https://www.google.com/accounts/ClientLogin')  
15:    login_req = Net::HTTP::Post.new(url.path)  
16:    login_req.form_data = {'accountType' => 'GOOGLE', 'Email' => 'pt.intake.generator@gmail.com', 'Passwd' => '****************', 'service' => 'grandcentral', 'source' => 'tiare.herokuapp.com'}  
17:    login_con = Net::HTTP.new(url.host, url.port)  
18:    login_con.use_ssl = true  
19:    login_con.start { |http| login_response = http.request(login_req) }  
20:    
21:    url = URI.parse('https://www.google.com/voice/sms/send/')  
22:    req = Net::HTTP::Post.new(url.path, {'Content-type' => 'application/x-www-form-urlencoded', 'Authorization' => 'GoogleLogin auth='+login_response.body.match("Auth\=(.*)")[0].gsub("Auth=", "")})  
23:    
24:    req.form_data = {'id' => '', 'phoneNumber' => @phone_number, 'text' => @data, '_rnr_se' => '********************'}  
25:    con = Net::HTTP.new(url.host, url.port)  
26:    con.use_ssl = true  
27:    con.start { |http| response = http.request(req) }  
28:   end  
29:    
30:  end  

1 comment: