Skip to content

Commit 0e1a2f9

Browse files
stefan-burkeclaude
andauthored
Add Play Zone inspection type with assessment workflow (#497)
* Add play zone unit type (Chunk 5) Implements the final unit type from the upgrade plan. Play zone has a conditional has_slide toggle (like bouncy_castle) that controls whether the slide_assessment tab is included. Shared assessments: structure, materials, fan, user_height, slide (conditional). https://claude.ai/code/session_016Af3G5HbcoYzxLaQC4tDKp * Fix play_zone tests: override factory has_slide default The inspection factory defaults has_slide to true, so play_zone tests that check for no slide tab need to explicitly set has_slide: nil. https://claude.ai/code/session_016Af3G5HbcoYzxLaQC4tDKp --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0a5aa46 commit 0e1a2f9

File tree

13 files changed

+567
-11
lines changed

13 files changed

+567
-11
lines changed

NEW_UNIT_TYPES.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ Spencer's C# desktop app defines inspection checks for inflatable equipment type
88

99
| Order | Unit Type | Unique Assessment | Shared Assessments | Conditionals | Status |
1010
|---|---|---|---|---|---|
11-
| 1 | `inflatable_ball_pool` | `ball_pool_assessment` (9 fields) | structure, materials, fan | none | |
12-
| 2 | `inflatable_game` | `inflatable_game_assessment` (9 fields) | structure, materials, fan | none | |
13-
| 3 | `catch_bed` | `catch_bed_assessment` (15 fields) | structure, materials, fan, anchorage | none | |
14-
| 4 | `bungee_run` | `bungee_assessment` (19 fields) | structure, materials, fan, anchorage | none | |
15-
| 5 | `play_zone` | `play_zone_assessment` (14 fields) | structure, materials, fan, user_height, slide | `has_slide` toggle | |
11+
| 1 | `inflatable_ball_pool` | `ball_pool_assessment` (9 fields) | structure, materials, fan | none | Done |
12+
| 2 | `inflatable_game` | `inflatable_game_assessment` (9 fields) | structure, materials, fan | none | Done |
13+
| 3 | `catch_bed` | `catch_bed_assessment` (15 fields) | structure, materials, fan, anchorage | none | Done |
14+
| 4 | `bungee_run` | `bungee_assessment` (19 fields) | structure, materials, fan, anchorage | none | Done |
15+
| 5 | `play_zone` | `play_zone_assessment` (14 fields) | structure, materials, fan, user_height, slide | `has_slide` toggle | Done |
1616

1717
## Per-Chunk Recipe
1818

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# typed: false
2+
3+
class PlayZoneAssessmentsController < ApplicationController
4+
include AssessmentController
5+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# typed: true
2+
# frozen_string_literal: true
3+
4+
class Assessments::PlayZoneAssessment < ApplicationRecord
5+
extend T::Sig
6+
include AssessmentLogging
7+
include AssessmentCompletion
8+
include FormConfigurable
9+
include ValidationConfigurable
10+
11+
self.primary_key = "inspection_id"
12+
belongs_to :inspection
13+
14+
after_update :log_assessment_update, if: :saved_changes?
15+
end

app/models/inspection.rb

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class Inspection < ApplicationRecord
5959
catch_bed: "CATCH_BED",
6060
inflatable_ball_pool: "INFLATABLE_BALL_POOL",
6161
inflatable_game: "INFLATABLE_GAME",
62-
pat_testable: "PAT_TESTABLE"
62+
pat_testable: "PAT_TESTABLE",
63+
play_zone: "PLAY_ZONE"
6364
}
6465

6566
CASTLE_ASSESSMENT_TYPES = {
@@ -111,14 +112,24 @@ class Inspection < ApplicationRecord
111112
bungee_assessment: Assessments::BungeeAssessment
112113
}.freeze
113114

115+
PLAY_ZONE_ASSESSMENT_TYPES = {
116+
structure_assessment: Assessments::StructureAssessment,
117+
materials_assessment: Assessments::MaterialsAssessment,
118+
fan_assessment: Assessments::FanAssessment,
119+
user_height_assessment: Assessments::UserHeightAssessment,
120+
slide_assessment: Assessments::SlideAssessment,
121+
play_zone_assessment: Assessments::PlayZoneAssessment
122+
}.freeze
123+
114124
ALL_ASSESSMENT_TYPES =
115125
CASTLE_ASSESSMENT_TYPES
116126
.merge(PILLOW_ASSESSMENT_TYPES)
117127
.merge(PAT_TESTABLE_ASSESSMENT_TYPES)
118128
.merge(INFLATABLE_BALL_POOL_ASSESSMENT_TYPES)
119129
.merge(INFLATABLE_GAME_ASSESSMENT_TYPES)
120130
.merge(CATCH_BED_ASSESSMENT_TYPES)
121-
.merge(BUNGEE_RUN_ASSESSMENT_TYPES).freeze
131+
.merge(BUNGEE_RUN_ASSESSMENT_TYPES)
132+
.merge(PLAY_ZONE_ASSESSMENT_TYPES).freeze
122133

123134
USER_EDITABLE_PARAMS = %i[
124135
has_slide
@@ -153,7 +164,8 @@ class Inspection < ApplicationRecord
153164
bungee_run: %i[inspection_date] + DIMENSION_FIELDS,
154165
catch_bed: %i[inspection_date] + DIMENSION_FIELDS,
155166
inflatable_game: %i[inspection_date] + DIMENSION_FIELDS,
156-
pat_testable: %i[inspection_date]
167+
pat_testable: %i[inspection_date],
168+
play_zone: %i[inspection_date has_slide] + DIMENSION_FIELDS
157169
}.freeze
158170

159171
belongs_to :user
@@ -281,7 +293,8 @@ def complete?
281293
catch_bed: CATCH_BED_ASSESSMENT_TYPES,
282294
inflatable_ball_pool: INFLATABLE_BALL_POOL_ASSESSMENT_TYPES,
283295
inflatable_game: INFLATABLE_GAME_ASSESSMENT_TYPES,
284-
pat_testable: PAT_TESTABLE_ASSESSMENT_TYPES
296+
pat_testable: PAT_TESTABLE_ASSESSMENT_TYPES,
297+
play_zone: PLAY_ZONE_ASSESSMENT_TYPES
285298
}.freeze
286299

287300
sig { returns(T::Hash[Symbol, T.class_of(ApplicationRecord)]) }
@@ -296,6 +309,7 @@ def assessment_types
296309
sig { returns(T::Hash[Symbol, T.class_of(ApplicationRecord)]) }
297310
def applicable_assessments
298311
return castle_applicable_assessments if bouncy_castle?
312+
return play_zone_applicable_assessments if play_zone?
299313

300314
assessment_types
301315
end
@@ -318,6 +332,16 @@ def castle_applicable_assessments
318332
end
319333
end
320334

335+
sig { returns(T::Hash[Symbol, T.class_of(ApplicationRecord)]) }
336+
def play_zone_applicable_assessments
337+
PLAY_ZONE_ASSESSMENT_TYPES.select do |assessment_key, _|
338+
case assessment_key
339+
when :slide_assessment then has_slide?
340+
else true
341+
end
342+
end
343+
end
344+
321345
public
322346

323347
# Iterate over only applicable assessments with a block
@@ -344,7 +368,7 @@ def applicable_tabs
344368
applicable = applicable_assessments.keys.map { |k| k.to_s.chomp("_assessment") }
345369

346370
# Add tabs in the correct UI order
347-
ordered_tabs = %w[user_height slide structure anchorage materials fan enclosed pat ball_pool bungee catch_bed inflatable_game]
371+
ordered_tabs = %w[user_height slide structure anchorage materials fan enclosed pat ball_pool bungee catch_bed inflatable_game play_zone]
348372
ordered_tabs.each do |tab|
349373
tabs << tab if applicable.include?(tab)
350374
end

app/models/unit.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class Unit < ApplicationRecord
4646
catch_bed: "CATCH_BED",
4747
inflatable_ball_pool: "INFLATABLE_BALL_POOL",
4848
inflatable_game: "INFLATABLE_GAME",
49-
pat_testable: "PAT_TESTABLE"
49+
pat_testable: "PAT_TESTABLE",
50+
play_zone: "PLAY_ZONE"
5051
}
5152

5253
belongs_to :user
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
form_fields:
3+
- legend_i18n_key: markings
4+
fields:
5+
- partial: :pass_fail_comment
6+
field: :age_marking
7+
- partial: :pass_fail_comment
8+
field: :height_marking
9+
- legend_i18n_key: safety_checks
10+
fields:
11+
- partial: :pass_fail_comment
12+
field: :sight_line
13+
- partial: :pass_fail_comment
14+
field: :access
15+
- partial: :pass_fail_comment
16+
field: :suitable_matting
17+
- partial: :pass_fail_comment
18+
field: :traffic_flow
19+
- partial: :pass_fail_comment
20+
field: :air_juggler
21+
- partial: :pass_fail_comment
22+
field: :balls
23+
- partial: :pass_fail_comment
24+
field: :ball_pool_gaps
25+
- partial: :pass_fail_comment
26+
field: :fitted_sheet
27+
- legend_i18n_key: measurements
28+
fields:
29+
- partial: :number_pass_fail_comment
30+
field: :ball_pool_depth
31+
attributes:
32+
step: 1
33+
min: 0
34+
- partial: :number_pass_fail_comment
35+
field: :ball_pool_entry_height
36+
attributes:
37+
step: 1
38+
min: 0
39+
- partial: :number_pass_fail_comment
40+
field: :slide_gradient
41+
attributes:
42+
step: 1
43+
min: 0
44+
- partial: :number_pass_fail_comment
45+
field: :slide_platform_height
46+
attributes:
47+
step: 0.01
48+
min: 0
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
en:
3+
forms:
4+
play_zone:
5+
header: Play Zone
6+
sections:
7+
markings: Markings
8+
safety_checks: Safety Checks
9+
measurements: Measurements
10+
fields:
11+
age_marking: Marking to indicate age range
12+
height_marking: Marking to indicate max user height
13+
sight_line: Sight lines clear to observe playing areas
14+
access: Access, egress and connections safe
15+
suitable_matting: Suitable matting
16+
traffic_flow: Traffic flow design safe
17+
air_juggler: Air jugglers compliant
18+
balls: Balls compliant
19+
ball_pool_gaps: No gaps in ball pool
20+
fitted_sheet: Fitted base sheet
21+
ball_pool_depth: Ball pool depth (mm) max 450mm
22+
ball_pool_entry_height: Ball pool entry height (mm) max 630mm
23+
slide_gradient: Platform incline gradient (deg) max 64 deg
24+
slide_platform_height: Slide platform height (m) max 1.5m
25+
status:
26+
checks_passed: Fields completed
27+
completion: Assessment Completion
28+
submit: Save Assessment
29+
submit_continue: Save & Continue
30+
errors:
31+
header:
32+
one: '1 error prevented this assessment from being saved:'
33+
other: '%{count} errors prevented this assessment from being saved:'

config/locales/inspections.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ en:
271271
inflatable_game_incomplete: Inflatable Game Assessment incomplete
272272
materials_incomplete: Materials Assessment incomplete
273273
pat_incomplete: PAT Assessment incomplete
274+
play_zone_incomplete: Play Zone Assessment incomplete
274275
slide_incomplete: Slide Assessment incomplete
275276
structure_incomplete: Structure Assessment incomplete
276277
user_height_incomplete: User Height Assessment incomplete

config/locales/units.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ en:
7171
inflatable_ball_pool: Inflatable Ball Pool
7272
inflatable_game: Inflatable Game
7373
pat_testable: PAT Testable Appliance
74+
play_zone: Play Zone
7475
labels:
7576
inspection_date: Inspection Date
7677
dimensions: Dimensions
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# typed: false
2+
# frozen_string_literal: true
3+
4+
class CreatePlayZoneAssessments < ActiveRecord::Migration[8.0]
5+
def change
6+
create_table :play_zone_assessments, id: false do |t|
7+
t.string :inspection_id, limit: 12, null: false
8+
add_pass_fail_fields(t)
9+
add_measurement_fields(t)
10+
t.timestamps
11+
end
12+
13+
add_index :play_zone_assessments, :inspection_id,
14+
unique: true, name: "play_zone_assessments_pkey"
15+
add_foreign_key :play_zone_assessments, :inspections
16+
end
17+
18+
private
19+
20+
def add_pass_fail_fields(t)
21+
t.boolean :age_marking_pass
22+
t.text :age_marking_comment
23+
t.boolean :height_marking_pass
24+
t.text :height_marking_comment
25+
t.boolean :sight_line_pass
26+
t.text :sight_line_comment
27+
t.boolean :access_pass
28+
t.text :access_comment
29+
t.boolean :suitable_matting_pass
30+
t.text :suitable_matting_comment
31+
t.boolean :traffic_flow_pass
32+
t.text :traffic_flow_comment
33+
t.boolean :air_juggler_pass
34+
t.text :air_juggler_comment
35+
t.boolean :balls_pass
36+
t.text :balls_comment
37+
t.boolean :ball_pool_gaps_pass
38+
t.text :ball_pool_gaps_comment
39+
t.boolean :fitted_sheet_pass
40+
t.text :fitted_sheet_comment
41+
end
42+
43+
def add_measurement_fields(t)
44+
t.integer :ball_pool_depth
45+
t.boolean :ball_pool_depth_pass
46+
t.text :ball_pool_depth_comment
47+
t.integer :ball_pool_entry_height
48+
t.boolean :ball_pool_entry_height_pass
49+
t.text :ball_pool_entry_height_comment
50+
t.integer :slide_gradient
51+
t.boolean :slide_gradient_pass
52+
t.text :slide_gradient_comment
53+
t.decimal :slide_platform_height, precision: 8, scale: 2
54+
t.boolean :slide_platform_height_pass
55+
t.text :slide_platform_height_comment
56+
end
57+
end

0 commit comments

Comments
 (0)