Class: Www::FloorHeatingCalculatorComponent

Inherits:
ApplicationComponent show all
Includes:
ActionView::Helpers::TagHelper, ActionView::Helpers::UrlHelper
Defined in:
app/components/www/floor_heating_calculator_component.rb

Overview

Floor Heating Operating Cost Calculator
Calculates estimated operating costs based on square footage, usage hours, and electricity rates

Examples:

Basic usage

<%= render Www::FloorHeatingCalculatorComponent.new %>

Spanish locale

<%= render Www::FloorHeatingCalculatorComponent.new(locale: :es) %>

Custom defaults

<%= render Www::FloorHeatingCalculatorComponent.new(default_sqft: 100, default_hours: 8) %>

With integrated SmartPlan CTA

<%= render Www::FloorHeatingCalculatorComponent.new(layout: :horizontal,
      smartplan: { product_type: :floor_heating, area_name: 'laminate floor', project_link: '/showcases' }
    ) %>

Constant Summary collapse

IMAGEKIT_BASE =

ImageKit base URL for product images

'https://ik.warmlyyours.com'
TRANSLATIONS =
{
  en: {
    title: 'Operating Cost Calculator for Floor Heating',
    location: 'Location',
    location_description: 'Your location is used to find the energy rate in your area.',
    my_location: 'My Location',
    zip_postal_code: 'Zip/Postal Code',
    cents_per_kwh: 'Rate',
    current_rate: 'Current rate',
    square_footage: 'Square Footage',
    sq_ft: 'sq. ft.',
    usage: 'Usage',
    estimated_cost: 'Estimated Cost',
    per_hour: 'per hour',
    per_day: 'per day',
    per_month: 'per month',
    per_year: 'per year',
    daily_usage: 'Daily Usage',
    hours_day: 'hours/day',
    hour: 'hour',
    hours: 'hours',
    surface_type: 'What surface are you heating?',
    room_size: 'Room Size',
    energy_rates: 'Energy Rates',
    energy_rates_description: 'Your location helps us find the average energy rate in your area to ensure our calculation is accurate.',
    consider_usage: 'Consider your room type and if this will be a supplemental or primary heat source.',
    bathroom: 'Bathroom',
    kitchen: 'Kitchen',
    basement: 'Basement',
    custom: 'Square Footage',
    calculator_settings: 'Calculator Settings',
    rae_quote: "Most homeowners are surprised how affordable radiant floor heating is to operate—often just pennies a day for a bathroom. It's the kind of everyday luxury that pays for itself in comfort!"
  },
  es: {
    title: 'Calculadora de Costos Operativos para Calefacción de Piso',
    location: 'Ubicación',
    location_description: 'Tu ubicación nos ayuda a encontrar la tasa de energía promedio en el área.',
    my_location: 'Mi ubicación actual',
    zip_postal_code: 'Código Postal',
    cents_per_kwh: 'Tarifa',
    current_rate: 'Tasa actual',
    square_footage: 'Pies Cuadrados',
    sq_ft: 'pies²',
    usage: 'Uso diario',
    estimated_cost: 'Costo estimado',
    per_hour: 'por hora',
    per_day: 'por día',
    per_month: 'por mes',
    per_year: 'por año',
    daily_usage: 'Uso diario',
    hours_day: 'horas por día',
    hour: 'hora',
    hours: 'horas',
    surface_type: '¿Qué superficie está calentando?',
    room_size: 'Tamaño de la Habitación',
    energy_rates: 'Tarifas de energía',
    energy_rates_description: 'Tu ubicación nos ayuda a encontrar la tasa de energía promedio en el área.',
    consider_usage: 'Considera tu tipo de habitación y si esta será una fuente de calor suplementaria o primaria.',
    bathroom: 'Baño',
    kitchen: 'Cocina',
    basement: 'Sótano',
    custom: 'Pies Cuadrados',
    calculator_settings: 'Configuración del Calculador',
    rae_quote: 'La mayoría de los propietarios se sorprenden de lo económico que es operar la calefacción por piso radiante—a menudo solo centavos al día para un baño. ¡Es el tipo de lujo cotidiano que se paga solo en comodidad!'
  }
}.freeze
SURFACE_TYPES =

Surface types map to heating systems
Surface type drives the product recommendation

[
  { id: 'tile_stone', name: 'Tile or Stone', product: 'TempZone™', wattage: 15 },
  { id: 'laminate_floating', name: 'Laminate, Floating Wood, or Carpet', product: 'Environ™', wattage: 12 },
  { id: 'concrete_embedded', name: 'Concrete Slab (New Pour)', product: 'Embedded Slab Heat Cable or Mat', wattage: 20 }
].freeze
ROOM_TYPES =

Room types with typical square footage for dropdown

[
  { id: 'bathroom', name: 'Bathroom', sqft: 35 },
  { id: 'master_bath', name: 'Master Bathroom', sqft: 80 },
  { id: 'powder_room', name: 'Powder Room', sqft: 25 },
  { id: 'kitchen', name: 'Kitchen', sqft: 150 },
  { id: 'entryway', name: 'Entryway/Foyer', sqft: 40 },
  { id: 'mudroom', name: 'Mudroom', sqft: 50 },
  { id: 'laundry', name: 'Laundry Room', sqft: 60 },
  { id: 'bedroom', name: 'Bedroom', sqft: 150 },
  { id: 'master_bed', name: 'Master Bedroom', sqft: 250 },
  { id: 'living_room', name: 'Living Room', sqft: 300 },
  { id: 'family_room', name: 'Family Room', sqft: 350 },
  { id: 'dining_room', name: 'Dining Room', sqft: 180 },
  { id: 'basement', name: 'Basement', sqft: 400 },
  { id: 'sunroom', name: 'Sunroom', sqft: 200 },
  { id: 'garage', name: 'Garage', sqft: 400 },
  { id: 'office', name: 'Home Office', sqft: 120 },
  { id: 'custom', name: 'Custom Size', sqft: nil }
].freeze
DEFAULT_KWH_CENTS =

param locale [Symbol] :en or :es for language
param default_sqft [Integer] Default square footage
param default_hours [Integer] Default hours per day
param default_kwh [Float] Default electricity rate in cents per kWh
param default_wattage [Integer] Default wattage per square foot (auto-derived from default_surface_type when provided)
param default_surface_type [String] Pre-selected surface id from SURFACE_TYPES (e.g. 'tile_stone', 'laminate_floating', 'concrete_embedded')
param default_room_type [String] Pre-selected room id from ROOM_TYPES (e.g. 'bathroom', 'kitchen', 'bedroom')
param layout [Symbol] :vertical (default, card-style) or :horizontal (side-by-side for inline use)
Default electricity rate in cents/kWh (US average ~16.26 cents)

16.26

Instance Method Summary collapse

Methods inherited from ApplicationComponent

#cms_link, #fetch_or_fallback, #image_asset_tag, #image_tag, #number_to_currency, #number_with_delimiter, #post_path, #post_url, #strip_tags

Constructor Details

#initialize(locale: :en, default_sqft: 35, default_hours: 4, default_kwh: nil, default_wattage: nil, default_surface_type: 'tile_stone', default_room_type: 'bathroom', layout: :vertical, smartplan: nil) ⇒ FloorHeatingCalculatorComponent

Returns a new instance of FloorHeatingCalculatorComponent.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'app/components/www/floor_heating_calculator_component.rb', line 134

def initialize(locale: :en, default_sqft: 35, default_hours: 4, default_kwh: nil, default_wattage: nil,
               default_surface_type: 'tile_stone', default_room_type: 'bathroom', layout: :vertical,
               smartplan: nil)
  super()
  @locale = locale.to_sym
  @default_surface_type = default_surface_type.to_s
  @default_room_type = default_room_type.to_s
  @default_sqft = default_sqft
  @default_hours = default_hours
  @default_kwh = default_kwh || calculate_default_kwh
  @default_wattage = default_wattage || wattage_for_surface(@default_surface_type)
  @layout = layout.to_sym
  @smartplan = smartplan
  resolve_smartplan_config if @smartplan
end

Instance Method Details

#calculate_default_kwhObject



178
179
180
181
182
# File 'app/components/www/floor_heating_calculator_component.rb', line 178

def calculate_default_kwh
  # ElectricityRate returns rate in dollars, we need cents
  rate = ElectricityRate.get_average_rate_for_locale(@locale)
  rate ? (rate * 100).round(2) : DEFAULT_KWH_CENTS
end

#currency_symbolObject



211
212
213
214
# File 'app/components/www/floor_heating_calculator_component.rb', line 211

def currency_symbol
  symbol = helpers.canada? ? 'C$' : '$'
  %(<span style="font-size:.55em;vertical-align:baseline;position:relative;top:-.45em;font-weight:500;color:#6c757d">#{symbol}</span>).html_safe
end

#horizontal?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'app/components/www/floor_heating_calculator_component.rb', line 150

def horizontal?
  @layout == :horizontal
end

#initial_daily_costObject



203
204
205
# File 'app/components/www/floor_heating_calculator_component.rb', line 203

def initial_daily_cost
  calculate_cost(@default_sqft, @default_hours, @default_kwh, @default_wattage)
end

#initial_hourly_costObject

Calculate initial cost for server-side rendering



199
200
201
# File 'app/components/www/floor_heating_calculator_component.rb', line 199

def initial_hourly_cost
  initial_daily_cost / @default_hours
end

#initial_monthly_costObject



207
208
209
# File 'app/components/www/floor_heating_calculator_component.rb', line 207

def initial_monthly_cost
  initial_daily_cost * 30
end

#room_typesObject

Room types for dropdown



194
195
196
# File 'app/components/www/floor_heating_calculator_component.rb', line 194

def room_types
  ROOM_TYPES.dup
end

#smartplan?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'app/components/www/floor_heating_calculator_component.rb', line 154

def smartplan?
  @smartplan.present?
end

#sp_app_typeObject



160
# File 'app/components/www/floor_heating_calculator_component.rb', line 160

def sp_app_type     = @sp_config&.dig(:application_type)

#sp_area_nameObject



165
# File 'app/components/www/floor_heating_calculator_component.rb', line 165

def sp_area_name    = @sp_area_name


168
169
170
171
# File 'app/components/www/floor_heating_calculator_component.rb', line 168

def sp_carousel_options
  { type: 'fade', perPage: 1, perMove: 1, arrows: true, pagination: true,
    autoplay: true, interval: 4000, pauseOnHover: true, rewind: true, speed: 600 }
end

#sp_iconObject



159
# File 'app/components/www/floor_heating_calculator_component.rb', line 159

def sp_icon         = @sp_config&.dig(:icon)


161
# File 'app/components/www/floor_heating_calculator_component.rb', line 161

def sp_link         = @sp_config&.dig(:smartplan_link)


166
# File 'app/components/www/floor_heating_calculator_component.rb', line 166

def sp_project_link = @sp_project_link

#sp_rae_avatarObject



162
# File 'app/components/www/floor_heating_calculator_component.rb', line 162

def sp_rae_avatar   = @sp_config&.dig(:rae_avatar)

#sp_rae_quoteObject



163
# File 'app/components/www/floor_heating_calculator_component.rb', line 163

def sp_rae_quote    = @sp_config&.dig(:rae_quote)

#sp_slidesObject



164
# File 'app/components/www/floor_heating_calculator_component.rb', line 164

def sp_slides       = @sp_config&.dig(:carousel_slides) || []

#sp_titleObject



158
# File 'app/components/www/floor_heating_calculator_component.rb', line 158

def sp_title        = @sp_config&.dig(:title)

#surface_typesObject

Surface types for dropdown



189
190
191
# File 'app/components/www/floor_heating_calculator_component.rb', line 189

def surface_types
  SURFACE_TYPES.dup
end

#t(key) ⇒ Object



184
185
186
# File 'app/components/www/floor_heating_calculator_component.rb', line 184

def t(key)
  TRANSLATIONS[@locale][key] || TRANSLATIONS[:en][key] || key.to_s.humanize
end

#wattage_for_surface(surface_id) ⇒ Object



173
174
175
176
# File 'app/components/www/floor_heating_calculator_component.rb', line 173

def wattage_for_surface(surface_id)
  match = SURFACE_TYPES.find { |s| s[:id] == surface_id }
  match ? match[:wattage] : 15
end