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 =

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 Attribute Summary collapse

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.



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

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 Attribute Details

#sp_area_nameObject (readonly)

Returns the value of attribute sp_area_name.



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

def sp_area_name
  @sp_area_name
end

Returns the value of attribute sp_project_link.



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

def sp_project_link
  @sp_project_link
end

Instance Method Details

#calculate_default_kwhObject



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

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



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

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)


152
153
154
# File 'app/components/www/floor_heating_calculator_component.rb', line 152

def horizontal?
  @layout == :horizontal
end

#initial_daily_costObject



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

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



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

def initial_hourly_cost
  initial_daily_cost / @default_hours
end

#initial_monthly_costObject



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

def initial_monthly_cost
  initial_daily_cost * 30
end

#room_typesObject

Room types for dropdown



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

def room_types
  ROOM_TYPES.dup
end

#smartplan?Boolean

Returns:

  • (Boolean)


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

def smartplan?
  @smartplan.present?
end

#sp_app_typeObject



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

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


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

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



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

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


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

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

#sp_rae_avatarObject



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

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

#sp_rae_quoteObject



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

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

#sp_slidesObject



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

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

#sp_titleObject



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

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

#surface_typesObject

Surface types for dropdown



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

def surface_types
  SURFACE_TYPES.dup
end

#t(key) ⇒ Object



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

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

#wattage_for_surface(surface_id) ⇒ Object



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

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