138 lines
3.8 KiB
Ruby
138 lines
3.8 KiB
Ruby
class ChartsPattern
|
|
attr_accessor :start_at, :end_at, :pattern, :user, :checkins_with_weather
|
|
attr_reader :used_color_ids
|
|
|
|
COLOR_IDS = Flaredown::Colorable::IDS
|
|
ADITIONAL_DAYS = 8
|
|
|
|
TYPE_CHART = {
|
|
line: %w[conditions symptoms],
|
|
marker: %w[treatments tags foods],
|
|
hbi: %w[harveyBradshawIndices],
|
|
weather: %w[weathersMeasures]
|
|
}.freeze
|
|
|
|
SUBTYPE = {
|
|
static: %i[line marker],
|
|
dynamic: %i[hbi weather]
|
|
}.freeze
|
|
|
|
def initialize(options)
|
|
@start_at = options[:start_at]
|
|
@end_at = options[:end_at]
|
|
@pattern = options[:pattern]
|
|
@used_color_ids = []
|
|
@checkins_with_weather = checkins.where(:weather_id.ne => nil)
|
|
end
|
|
|
|
def user
|
|
@user ||= pattern.author
|
|
end
|
|
|
|
def checkins
|
|
@checkins ||= user.checkins.order(date: :asc)
|
|
end
|
|
|
|
def scoped_checkins
|
|
@scoped_checkins ||= checkins.by_date(start_at.to_date - ADITIONAL_DAYS.days, end_at.to_date + ADITIONAL_DAYS.days)
|
|
end
|
|
|
|
def chart_data
|
|
@data ||=
|
|
{
|
|
pattern_id: pattern.id,
|
|
pattern_name: pattern.name,
|
|
author_email: user.email,
|
|
|
|
series: pattern_includes.map do |chart|
|
|
category = chart[:category]
|
|
type = TYPE_CHART.select { |_, value| value.include?(category) }.keys&.first
|
|
{
|
|
type: type,
|
|
subtype: SUBTYPE.select { |_, value| value.include? type }.keys&.first,
|
|
label: chart[:label],
|
|
category: category,
|
|
color_id: get_color_id(chart),
|
|
data: data(chart)
|
|
}
|
|
end
|
|
}
|
|
end
|
|
|
|
def pattern_includes
|
|
@pattern_includes ||= pattern.includes || []
|
|
end
|
|
|
|
def data(chart)
|
|
category = chart[:category]
|
|
id = chart[:id]
|
|
|
|
collected_data =
|
|
if %w[conditions symptoms treatments].include? category
|
|
static_trackables_coordinates(category, scoped_checkins.map(&:id), id)
|
|
else
|
|
health_factors_trackables_coordinate(category, scoped_checkins, id)
|
|
end
|
|
|
|
average = collected_data.inject(0.0) { |result, datum| result + datum[:y].to_f } / collected_data.count
|
|
|
|
[{x: collected_data[0]&.fetch(:x), y: average}]
|
|
end
|
|
|
|
def static_trackables_coordinates(category, checkin_ids, id)
|
|
find_coordinates_by_checkin(category, checkin_ids, id)
|
|
.sort! { |x, y| x[:x].to_time.to_i <=> y[:x].to_time.to_i }
|
|
end
|
|
|
|
def find_coordinates_by_checkin(category, checkin_ids, id)
|
|
category_name = category.singularize
|
|
|
|
"Checkin::#{category_name.camelize}".constantize.where(
|
|
checkin_id: {"$in": checkin_ids},
|
|
"#{category_name}_id": id
|
|
).map do |tr|
|
|
coord = {x: tr.checkin.date, y: tr.value}
|
|
coord[:is_taken] = tr.is_taken if category == "treatments"
|
|
|
|
coord
|
|
end.uniq
|
|
end
|
|
|
|
def health_factors_trackables_coordinate(category, selected_checkins, id)
|
|
is_weather = %w[weathersMeasures].include? category
|
|
|
|
trackables =
|
|
if %w[foods tags].include? category
|
|
selected_checkins.select { |checkin| checkin.send("#{category.singularize}_ids").include? id }
|
|
.map { |checkin| {x: checkin.date} }.uniq
|
|
elsif is_weather
|
|
selected_checkins.select(&:weather).map { |checkin| {x: checkin.date, y: checkin.weather.send(id)} }
|
|
else
|
|
selected_checkins.select(&:harvey_bradshaw_index)
|
|
.map { |checkin| {x: checkin.date, y: checkin.harvey_bradshaw_index.score} }
|
|
end
|
|
|
|
trackables.sort! { |x, y| x[:x].to_time.to_i <=> y[:x].to_time.to_i }
|
|
end
|
|
|
|
def get_color_id(chart)
|
|
model_name = chart[:category].singularize.camelize
|
|
|
|
color_id =
|
|
if Tracking::TYPES.include? model_name
|
|
user.trackings.where(trackable_type: model_name, trackable_id: chart[:id]).pluck(:color_id).compact.last
|
|
end
|
|
|
|
if color_id.present?
|
|
used_color_ids << color_id
|
|
|
|
return color_id
|
|
end
|
|
|
|
color_id = (COLOR_IDS - used_color_ids).shift
|
|
used_color_ids << color_id
|
|
|
|
color_id
|
|
end
|
|
end
|