@@ -32,30 +32,31 @@ const PDCModal: React.FC<PDCModalProps> = ({ isOpen, onClose, flight, onIssuePDC
3232 'standard'
3333 ) ;
3434 const [ error , setError ] = useState < string | null > ( null ) ;
35+ const [ customRemarks , setCustomRemarks ] = useState < string > ( '' ) ;
3536
3637 const generateRandomSquawk = ( ) : string => {
3738 return Array . from ( { length : 4 } , ( ) =>
3839 Math . floor ( Math . random ( ) * 8 )
3940 ) . join ( '' ) ;
4041 } ;
4142
42- const generateRandomIdentifier = ( ) : string => {
43- const squawk = getSquawk ( ) ;
43+ const [ autoSquawk ] = useState ( ( ) => generateRandomSquawk ( ) ) ;
44+
45+ const [ autoIdentifier ] = useState ( ( ) => {
46+ // Generate identifier from squawk and callsign
47+ const squawk = flight ?. squawk || autoSquawk ;
4448 const firstThreeNumbers = squawk . substring ( 0 , 3 ) ;
45-
49+
4650 let firstLetter = 'A' ;
4751 if ( flight ?. callsign ) {
4852 const letters = flight . callsign . match ( / [ A - Z ] / i) ;
4953 if ( letters && letters . length > 0 ) {
5054 firstLetter = letters [ 0 ] . toUpperCase ( ) ;
5155 }
5256 }
53-
54- return firstThreeNumbers + firstLetter ;
55- } ;
5657
57- const [ autoSquawk ] = useState ( ( ) => generateRandomSquawk ( ) ) ;
58- const [ autoIdentifier ] = useState ( ( ) => generateRandomIdentifier ( ) ) ;
58+ return firstThreeNumbers + firstLetter ;
59+ } ) ;
5960
6061 useEffect ( ( ) => {
6162 localStorage . setItem (
@@ -70,6 +71,32 @@ const PDCModal: React.FC<PDCModalProps> = ({ isOpen, onClose, flight, onIssuePDC
7071 }
7172 } , [ isOpen , flight ] ) ;
7273
74+ // Pre-fill remarks with default text when modal opens
75+ useEffect ( ( ) => {
76+ if ( isOpen && flight ) {
77+ const sidText = flight . sid || 'DCT' ;
78+ const isVFR = flight . flight_type === 'VFR' ;
79+ const isRadarVectors = sidText === 'RADAR VECTORS' ;
80+ const clearedAlt = flight . clearedFL || '030' ;
81+ const freqs = getFrequencies ( ) ;
82+
83+ let climbInstruction ;
84+ if ( isVFR || isRadarVectors ) {
85+ climbInstruction = `CLEARED ${ sidText } ` ;
86+ } else {
87+ climbInstruction = `CLEARED ${ sidText } DEPARTURE CLIMB VIA SID` ;
88+ }
89+
90+ const defaultRemarks = `${ climbInstruction } EXP ${ flight . cruisingFL || clearedAlt } 10 MIN AFT DP` ;
91+ setCustomRemarks ( defaultRemarks ) ;
92+ }
93+
94+ // Reset remarks when modal closes
95+ if ( ! isOpen ) {
96+ setCustomRemarks ( '' ) ;
97+ }
98+ } , [ isOpen , flight ] ) ;
99+
73100 const fetchAirportFrequencies = async ( icao : string ) => {
74101 if ( ! icao ) return ;
75102
@@ -141,9 +168,14 @@ const PDCModal: React.FC<PDCModalProps> = ({ isOpen, onClose, flight, onIssuePDC
141168 departure : customFreqs . departure || '122.800'
142169 } ;
143170 }
171+
172+
173+ const clearanceFreq = airportFreqs . clearanceDelivery || airportFreqs . ground || '122.800' ;
174+ const departureFreq = airportFreqs . departure || airportFreqs . tower || '122.800' ;
175+
144176 return {
145- clearance : airportFreqs . clearanceDelivery || '122.800' ,
146- departure : airportFreqs . departure || '122.800'
177+ clearance : clearanceFreq ,
178+ departure : departureFreq
147179 } ;
148180 } ;
149181
@@ -156,23 +188,15 @@ const PDCModal: React.FC<PDCModalProps> = ({ isOpen, onClose, flight, onIssuePDC
156188 const sidText = flight . sid || 'DCT' ;
157189 const freqs = getFrequencies ( ) ;
158190 const clearedAlt = flight . clearedFL || '030' ;
159- const isVFR = flight . flight_type === 'VFR' ;
160- const isRadarVectors = sidText === 'RADAR VECTORS' ;
161-
162- let climbInstruction ;
163- if ( isVFR || isRadarVectors ) {
164- climbInstruction = `CLEARED ${ sidText } ` ;
165- } else {
166- climbInstruction = `CLEARED ${ sidText } DEPARTURE CLIMB VIA SID` ;
167- }
168191
169192 if ( pdcFormat === 'simplified' ) {
170193 return `PDC FOR ${ flight . callsign }
171194CLEARED TO ${ flight . arrival } VIA ${ sidText }
172195CLIMB AND MAINTAIN ${ clearedAlt }
173196SQUAWK ${ squawk }
174- CONTACT DEPARTURE ${ freqs . departure }
175- CONTACT CLEARANCE ${ freqs . clearance } TO PUSH` ;
197+ DEPARTURE ${ freqs . departure }
198+ CLEARANCE ${ freqs . clearance }
199+ IDENTIFIER ${ identifier } ${ customRemarks ? `\nREMARKS: ${ customRemarks } ` : '' } ` ;
176200 }
177201
178202 return `ACARS: PDC | CALLSIGN: ${
@@ -181,19 +205,29 @@ CONTACT CLEARANCE ${freqs.clearance} TO PUSH`;
181205DEPARTURE: ${ flight . departure } | DESTINATION: ${ flight . arrival } |
182206ROUTE: ${ flight . departure } .${ sidText } ..${ flight . arrival } |
183207ALTITUDE: ${ clearedAlt } | TRANSPONDER: ${ squawk } | REMARKS:
184- ${ climbInstruction } EXP ${ flight . cruisingFL || clearedAlt } 10
185- MIN AFT DP DPFRQ ${ freqs . departure } | CTC ${ freqs . clearance } TO PUSH
208+ ${ customRemarks } , DPFRQ ${ freqs . departure } CTC ${ freqs . clearance } TO PUSH
186209IDENTIFIER: ${ identifier } ` ;
187210 } ;
188211
189212 const handleCustomFreqChange = (
190213 type : keyof AirportFrequencies ,
191214 value : string
192215 ) => {
193- setCustomFreqs ( ( prev ) => ( { ...prev , [ type ] : value } ) ) ;
216+ const filtered = value . replace ( / [ ^ 0 - 9 . ] / g, '' ) ;
217+ setCustomFreqs ( ( prev ) => ( { ...prev , [ type ] : filtered } ) ) ;
194218 setUseCustomFreqs ( true ) ;
195219 } ;
196220
221+ const handleSquawkChange = ( value : string ) => {
222+ const filtered = value . replace ( / [ ^ 0 - 7 ] / g, '' ) . slice ( 0 , 4 ) ;
223+ setCustomSquawk ( filtered ) ;
224+ } ;
225+
226+ const handleIdentifierChange = ( value : string ) => {
227+ const filtered = value . replace ( / [ ^ A - Z 0 - 9 ] / gi, '' ) . slice ( 0 , 4 ) . toUpperCase ( ) ;
228+ setCustomIdentifier ( filtered ) ;
229+ } ;
230+
197231 const copyToClipboard = async ( ) => {
198232 if ( ! flight ) return ;
199233
@@ -366,6 +400,24 @@ IDENTIFIER: ${identifier}`;
366400 </ div >
367401 </ div >
368402 </ div >
403+ { /* Remarks */ }
404+ < div className = "space-y-3" >
405+ < h3 className = "text-lg font-semibold text-blue-300" >
406+ Remarks
407+ </ h3 >
408+ < div >
409+ < textarea
410+ value = { customRemarks }
411+ onChange = { ( e ) => setCustomRemarks ( e . target . value ) }
412+ placeholder = "Enter PDC remarks..."
413+ className = "w-full bg-zinc-800 border border-zinc-700 text-white rounded-lg p-3 font-mono text-sm min-h-[80px] resize-y focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
414+ maxLength = { 250 }
415+ />
416+ < p className = "text-xs text-gray-500 mt-1" >
417+ Edit Remarks
418+ </ p >
419+ </ div >
420+ </ div >
369421
370422 { /* Frequencies */ }
371423 < div className = "space-y-3" >
@@ -392,9 +444,9 @@ IDENTIFIER: ${identifier}`;
392444 value = {
393445 useCustomFreqs
394446 ? customFreqs . clearanceDelivery ||
395- ''
447+ ''
396448 : airportFreqs . clearanceDelivery ||
397- '122.800'
449+ '122.800'
398450 }
399451 onChange = { ( value ) =>
400452 handleCustomFreqChange (
@@ -416,7 +468,7 @@ IDENTIFIER: ${identifier}`;
416468 useCustomFreqs
417469 ? customFreqs . departure || ''
418470 : airportFreqs . departure ||
419- '122.800'
471+ '122.800'
420472 }
421473 onChange = { ( value ) =>
422474 handleCustomFreqChange (
@@ -462,12 +514,17 @@ IDENTIFIER: ${identifier}`;
462514 ? customSquawk
463515 : flight . squawk || autoSquawk
464516 }
465- onChange = { setCustomSquawk }
517+ onChange = { handleSquawkChange }
466518 placeholder = "e.g. 1234"
467519 className = "w-full bg-zinc-800 border border-zinc-700 font-mono"
468520 maxLength = { 4 }
469521 disabled = { ! useCustomSquawk }
470522 />
523+ { useCustomSquawk && (
524+ < p className = "text-xs text-gray-500 mt-1" >
525+ Only digits 0-7 allowed
526+ </ p >
527+ ) }
471528 </ div >
472529 < div >
473530 < div className = "flex items-center justify-between mb-2" >
@@ -497,16 +554,20 @@ IDENTIFIER: ${identifier}`;
497554 ? customIdentifier
498555 : autoIdentifier
499556 }
500- onChange = { setCustomIdentifier }
557+ onChange = { handleIdentifierChange }
501558 placeholder = "e.g. AB12"
502559 className = "w-full bg-zinc-800 border border-zinc-700 font-mono"
503560 maxLength = { 4 }
504561 disabled = { ! useCustomIdentifier }
505562 />
563+ { useCustomIdentifier && (
564+ < p className = "text-xs text-gray-500 mt-1" >
565+ Letters and numbers only
566+ </ p >
567+ ) }
506568 </ div >
507569 </ div >
508570 </ div >
509-
510571 { /* Warning */ }
511572 < div className = "bg-amber-900/20 p-3 rounded-lg border border-amber-700 text-amber-300 text-xs" >
512573 < div className = "flex items-start" >
0 commit comments