Giter Club home page Giter Club logo

drappointment's Introduction

Dr. Appointment

Get it on Google Play Store: Dr. Appointment

Background

Making appointments with one's primary care physician can be difficult and time-consuming. Instead of patients trying to find time during their busy lives to place phone calls and make appointments with doctors, this mobile app allows the users to quickly find their doctor, view their availabilities, and make an appointment for them or their family members anytime, anywhere.

View Development README

Backend was built using Ruby on Rails and PostgreSQL: DrAppointment-BE

Functionality & MVP

@client = Twilio::REST::Client.new(account_sid, auth_token)
    @client.account.messages.create({
        :to => to,
        :from => from,
        :body => message
    })
  • Twilio API
    • Two factor authentication to verify users and their phone numbers.
    • Confirmation text when appointments are made.
    • Reminder text is sent one hour before the appointment time.
AsyncStorage.getItem('phone_number', (err, result) => {
  const phoneNumber = result;
  if (result) {
    AsyncStorage.getItem('authy_id', (err2, result2) => {
      fetch('https://www.drappointment.io/api/session', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          user: {
            phone_number: phoneNumber,
            authy_id: result2
          }
        })
      })
      .then((response) => response.json())
      .then((response) => Actions.home({ currentUser: response }));
    });
  } else {
    return Actions.register();
  }
});
this.props.authenticateUser(user)
  .then(response => {
    if (response.responseData.session_token) {
      let phone_number = response.responseData.phone_number;
      let authy_id = response.responseData.authy_id;
      AsyncStorage.setItem('phone_number', (phone_number))
        .then(() => AsyncStorage.setItem('authy_id', (authy_id)))
        .then(() => Actions.home({ currentUser: response.responseData }));
    } else {
      this.setState({
        errors: response.responseData
      });
    }
  });
  • AsyncStorage
    • Stores user's phone number and authentication code to local storage for convenience
    • The user no longer has to go through the login process once the phone is authenticated.
def search
  @user = current_user
  if params[:input].nil? || params[:input][:name].nil?
    @lat = params[:input][:lat]
    @lng = params[:input][:lng]
    @doctors = Doctor.all
  else
    @lat = params[:input][:lat]
    @lng = params[:input][:lng]
    @doctors = Doctor.where(
      "lower(first_name) LIKE ? OR lower(last_name) LIKE ?",
      "%#{params[:input][:name].downcase}%",
      "%#{params[:input][:name].downcase}%"
    )
  end
end
json.array! @doctors do |doctor|
  name = "#{doctor.salutation} #{doctor.first_name} #{doctor.last_name}"
  json.image_url doctor.image_url
  json.id doctor.id
  json.name name
  json.address "#{doctor.street_number} #{doctor.street}"
  json.address2 "#{doctor.city}, #{doctor.state} #{doctor.zip_code}"
  json.phone "+1 #{doctor.phone_number}"
  json.favorited @user.favorite_doctors.include?(Doctor.find(doctor.id))
  json.lat doctor.lat
  json.lng doctor.lng
  json.distance (Math.sqrt((@lng - doctor.lng)**2 + (@lat - doctor.lat)**2) * 70.117663977182174).round(1)
end.sort_by! do |el|
  [el["favorited"].to_s, -el["distance"]]
end.reverse!
  • Search
    • Search bias based on users' favorite status, location (distance to geolocation of the phone), and doctors' names.
    • User can swipe to toggle favorite or call the doctor.
validate :blocked?, :overlap?, :in_the_future?

private

  def blocks
    BlockedTime
      .where(doctor: self.doctor)
      .where(time_slot: self.time_slot)
  end

  def find_overlap
    Appointment
      .where.not(id: self.id)
      .where(doctor: self.doctor)
      .where(time_slot: self.time_slot)
  end

  def blocked?
    errors.add(:appointment, "is blocked by doctor") unless blocks.empty?
  end

  def overlap?
    errors.add(:appointment, "of another overlaps yours") unless find_overlap.empty?
  end

  def in_the_future?
    errors.add(:appointment, "must be in the future") if time_slot.appointment_date.appointment_date < Date.today
  end
  • Backend Validation of appointments
    • Validation methods on the model layer prevent bad data from entering the database.
    • Errors messages are sent back to the front end for error handling
after_create :reminder

@@REMINDER_TIME = 1.hours

def reminder
...
Twilio::REST::Client.new(account_sid, auth_token)
    sms = @client.account.messages.create({
        :to => to,
        :from => from,
        :body => message
    })
    puts sms.to
end

def time
    date = self.time_slot.appointment_date.appointment_date
    time = self.time_slot.time
    DateTime.new(date.year, date.month, date.day, time[0..1].to_i, time[-2..-1].to_i, 0, '-8')
  end

def when_to_run
  self.time - @@REMINDER_TIME
end

handle_asynchronously :reminder, :run_at => Proc.new { |i| i.when_to_run }
  • Asynchronous background workers handle the Twilio SMS reminder using the Delayed Job Active Record Gem.
    • The after_create lifecycle method on the model layer create a reminder event that is saved in the delayed job table and is executed when a background worker queries the table, removing it from the table when it is done
    • Adding additional 'time' and 'when_to_run' methods allow for determining the execution interval

Architecture and Technologies

This project will be implemented with the following technologies:

  • React Native (iOS / Android)
  • Rails (Heroku with SSL)
  • API Authy / Twilio (text messaging)

Future Implementations

  • Create website for doctors to input their schedule.
  • Implement Android version of the app.
  • Upload to both the app store and the play store.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.