11document . addEventListener ( 'DOMContentLoaded' , ( ) => {
2+ // Optional debug fingerprint (can remove later)
3+ // console.log('production-create.js loaded', new Date().toISOString());
24
35 // ── Thumbnail preview ─────────────────────────────────────────
46 const thumbInput = document . getElementById ( 'thumbnailInput' ) ;
@@ -7,81 +9,126 @@ document.addEventListener('DOMContentLoaded', () => {
79 const uploadLabel = document . getElementById ( 'uploadLabel' ) ;
810 const clearBtn = document . getElementById ( 'clearThumbnail' ) ;
911
10- thumbInput ?. addEventListener ( 'change' , e => {
11- const file = e . target . files [ 0 ] ;
12- if ( ! file ) return ;
13- if ( ! file . type . startsWith ( 'image/' ) ) { alert ( 'Please select an image file.' ) ; thumbInput . value = '' ; return ; }
14- if ( file . size > 10 * 1024 * 1024 ) { alert ( 'Max file size is 10 MB.' ) ; thumbInput . value = '' ; return ; }
15- const reader = new FileReader ( ) ;
16- reader . onload = ev => {
17- thumbImg . src = ev . target . result ;
18- thumbPreview . style . display = '' ;
19- uploadLabel . style . display = 'none' ;
20- } ;
21- reader . readAsDataURL ( file ) ;
22- } ) ;
12+ if ( thumbInput && thumbPreview && thumbImg && uploadLabel ) {
13+ thumbInput . addEventListener ( 'change' , ( e ) => {
14+ const input = /** @type {HTMLInputElement } */ ( e . target ) ;
15+ const file = input . files && input . files [ 0 ] ;
16+ if ( ! file ) return ;
17+
18+ if ( ! file . type || ! file . type . startsWith ( 'image/' ) ) {
19+ alert ( 'Please select an image file.' ) ;
20+ input . value = '' ;
21+ return ;
22+ }
2323
24- clearBtn ?. addEventListener ( 'click' , ( ) => {
25- thumbInput . value = '' ;
26- thumbPreview . style . display = 'none' ;
27- uploadLabel . style . display = '' ;
28- } ) ;
24+ if ( file . size > 10 * 1024 * 1024 ) {
25+ alert ( 'Max file size is 10 MB.' ) ;
26+ input . value = '' ;
27+ return ;
28+ }
29+
30+ const reader = new FileReader ( ) ;
31+ reader . onload = ( ev ) => {
32+ const result = ev . target && ev . target . result ;
33+ if ( ! result ) return ;
34+
35+ thumbImg . src = String ( result ) ;
36+ thumbPreview . style . display = '' ;
37+ uploadLabel . style . display = 'none' ;
38+ } ;
39+ reader . readAsDataURL ( file ) ;
40+ } ) ;
41+
42+ if ( clearBtn ) {
43+ clearBtn . addEventListener ( 'click' , ( ) => {
44+ thumbInput . value = '' ;
45+ thumbPreview . style . display = 'none' ;
46+ uploadLabel . style . display = '' ;
47+ } ) ;
48+ }
49+ }
2950
3051 // ── Description counter ───────────────────────────────────────
3152 const descField = document . getElementById ( 'descriptionTextarea' ) ;
3253 const descCounter = document . getElementById ( 'descriptionCounter' ) ;
33- descField ?. addEventListener ( 'input' , ( ) =>
34- descCounter . textContent = descField . value . length ) ;
54+
55+ if ( descField && descCounter ) {
56+ descField . addEventListener ( 'input' , ( ) => {
57+ descCounter . textContent = String ( descField . value . length ) ;
58+ } ) ;
59+ // init if server pre-filled
60+ descCounter . textContent = String ( descField . value . length ) ;
61+ }
3562
3663 // ── Default start date ────────────────────────────────────────
3764 const startDate = document . querySelector ( '[name="StatusStartDate"]' ) ;
38- if ( startDate && ! startDate . value )
65+ if ( startDate && ! startDate . value ) {
66+ // YYYY-MM-DD (works for <input type="date">)
3967 startDate . value = new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
68+ }
4069
4170 // ── Cascading phase → status select ───────────────────────────
4271 const phaseSelect = document . getElementById ( 'phaseSelect' ) ;
4372 const statusSelect = document . getElementById ( 'statusTypeSelect' ) ;
44- const optgroups = statusSelect . querySelectorAll ( 'optgroup[data-phase]' ) ;
45-
46- phaseSelect ?. addEventListener ( 'change' , ( ) => {
47- const chosen = phaseSelect . value ;
48-
49- // Instead of toggling optgroup display (not reliable across browsers),
50- // show/hide individual <option> elements. This ensures only options
51- // relevant to the selected phase appear in the dropdown.
52- const placeholder = statusSelect . querySelector ( 'option[value=""]' ) ;
53-
54- // Iterate optgroups and their options
55- optgroups . forEach ( og => {
56- const match = og . dataset . phase === chosen ;
57- og . querySelectorAll ( 'option' ) . forEach ( opt => {
58- // Keep the placeholder option visible regardless
59- if ( opt . value === '' ) return ;
60-
61- // Use `hidden` and `disabled` so options are removed from the list
62- // and cannot be selected in browsers that don't respect optgroup styling.
63- opt . hidden = ! match ;
64- opt . disabled = ! match ;
73+
74+ if ( ! phaseSelect || ! statusSelect ) {
75+ console . warn ( 'CreateProduction: missing selects. phaseSelect/statusTypeSelect not found.' ) ;
76+ } else {
77+ const optgroups = statusSelect . querySelectorAll ( 'optgroup[data-phase]' ) ;
78+
79+ const applyPhase = ( ) => {
80+ const chosen = phaseSelect . value ;
81+ const placeholder = statusSelect . querySelector ( 'option[value=""]' ) ;
82+
83+ // If there are no optgroups, something is off in the markup
84+ if ( ! optgroups || optgroups . length === 0 ) {
85+ console . warn ( 'CreateProduction: no optgroups[data-phase] found under statusTypeSelect.' ) ;
86+ }
87+
88+ optgroups . forEach ( ( og ) => {
89+ const match = og . dataset . phase === chosen ;
90+
91+ // IMPORTANT: don't rely on optgroup display toggling; hide/disable options instead
92+ og . querySelectorAll ( 'option' ) . forEach ( ( opt ) => {
93+ if ( opt . value === '' ) return ; // keep placeholder visible
94+ opt . hidden = ! match ;
95+ opt . disabled = ! match ;
96+ } ) ;
6597 } ) ;
66- } ) ;
6798
68- if ( ! chosen ) {
69- // No phase chosen → disable status select and clear its value
70- statusSelect . value = '' ;
71- statusSelect . disabled = true ;
72- if ( placeholder ) placeholder . textContent = '— Select Phase first —' ;
73- } else {
74- statusSelect . disabled = false ;
75- statusSelect . value = '' ; // reset to "please choose" state
76- if ( placeholder ) placeholder . textContent = '— Select Status —' ;
77- }
78- } ) ;
99+ if ( ! chosen ) {
100+ statusSelect . value = '' ;
101+ statusSelect . disabled = true ;
102+ if ( placeholder ) placeholder . textContent = '— Select Phase first —' ;
103+ } else {
104+ statusSelect . disabled = false ;
105+ statusSelect . value = '' ; // reset selection on phase change
106+ if ( placeholder ) placeholder . textContent = '— Select Status —' ;
107+ }
108+ } ;
109+
110+ phaseSelect . addEventListener ( 'change' , applyPhase ) ;
111+
112+ // Init state on load (handles browser autofill / preselected values)
113+ applyPhase ( ) ;
114+ }
79115
80116 // ── Unsaved changes warning ───────────────────────────────────
81- let dirty = false ;
82- document . querySelectorAll ( '#createProductionForm input, #createProductionForm textarea, #createProductionForm select' )
83- . forEach ( el => el . addEventListener ( 'change' , ( ) => dirty = true ) ) ;
84- window . addEventListener ( 'beforeunload' , e => { if ( dirty ) { e . preventDefault ( ) ; e . returnValue = '' ; } } ) ;
85- document . getElementById ( 'createProductionForm' )
86- ?. addEventListener ( 'submit' , ( ) => dirty = false ) ;
117+ const form = document . getElementById ( 'createProductionForm' ) ;
118+ if ( form ) {
119+ let dirty = false ;
120+
121+ form . querySelectorAll ( 'input, textarea, select' ) . forEach ( ( el ) => {
122+ el . addEventListener ( 'change' , ( ) => ( dirty = true ) ) ;
123+ el . addEventListener ( 'input' , ( ) => ( dirty = true ) ) ;
124+ } ) ;
125+
126+ window . addEventListener ( 'beforeunload' , ( e ) => {
127+ if ( ! dirty ) return ;
128+ e . preventDefault ( ) ;
129+ e . returnValue = '' ;
130+ } ) ;
131+
132+ form . addEventListener ( 'submit' , ( ) => ( dirty = false ) ) ;
133+ }
87134} ) ;
0 commit comments