import React, { useState } from 'react' import { FormLayoutSection, Input, Textarea, Button, Checkbox, Icon, NativeSelect, Tooltip, } from '@ocv-web/ui' import { categoryMap, certaintyMap, eventCodeKeysFilter, eventCodes, eventResponses, severityMap, urgencyMap, weaCertaintyMap, weaHandling, weaSeverityMap, weaUrgencyMap, } from '../../config' import { useSettings } from '../../api/settings' import { fipsCodeList, stateFips } from '../../api/settings/fips' export interface IFormData { watchWEA: boolean watchWEASpanish: boolean watchNWEM: boolean watchRecurring: boolean watchSchedule: boolean watchScheduleHide: boolean watchWEAHandle: string errors: any register: any setValue?: any setError?: any // submitStatus: string mapModalState: React.Dispatch<React.SetStateAction<any>> locationPoints: number locationShapes: number notificationType: string } export const FormData: React.FC<IFormData> = ({ watchWEA, watchWEASpanish, watchNWEM, watchRecurring, watchSchedule, watchScheduleHide, watchWEAHandle, errors, register, setValue, setError, mapModalState, locationPoints, locationShapes, notificationType, // submitStatus, }) => { const [charactersWEAShort, setCharactersWEAShort] = useState(0) const [charactersWEALong, setCharactersWEALong] = useState(0) const [charactersWEASpanish, setCharactersWEASpanish] = useState(0) const [charactersWEALongSpanish, setCharactersWEALongSpanish] = useState(0) const [charactersTitle, setCharactersTitle] = useState(0) const [charactersDescription, setCharactersDescription] = useState(0) const [charactersInstructions, setCharactersInstructions] = useState(0) const { data } = useSettings() const FIPSList = JSON.parse(data?.Results?.[0]?.FIPSList || '[]') const findFipsCodeName = fipsCode => { const foundEntry = fipsCodeList.find(entry => entry['FIPS code'] === fipsCode) return foundEntry ? foundEntry.name : 'Unknown' } const findFipsCodeState = fipsCode => { const fipsDigit = fipsCode?.slice(0, 3) const foundEntry = stateFips.find(entry => entry['Digit'] === fipsDigit) return foundEntry ? foundEntry.name : 'Unknown' } const [selectedOptions, setSelectedOptions] = useState([]) const handleSelect = fipsCode => { console.log('Checkbox clicked:', fipsCode) setValue('CountyFIPS', prevSelected => { const isSelected = prevSelected.includes(fipsCode) const selectedFipsCodes = isSelected ? prevSelected.filter(selected => selected !== fipsCode) : [...prevSelected, fipsCode] setSelectedOptions(prevOptions => { if (prevOptions.includes(fipsCode)) { return prevOptions.filter(code => code !== fipsCode) } else { return [...prevOptions, fipsCode] } }) return JSON.stringify(Object.values(selectedFipsCodes)) }) } // React.useEffect(() => { // if (submitStatus === 'success') { // setCharactersWEAShort(0) // setCharactersWEALong(0) // setCharactersWEASpanish(0) // setCharactersTitle(0) // setCharactersWEALongSpanish(0) // setCharactersDescription(0) // setCharactersInstructions(0) // } // }, [submitStatus]) // const validateSixDigits = value => { // if (value.length !== 6 || isNaN(value)) { // return 'County FIPS must be a 6-digit numeric code.' // } // return true // } return ( <> <FormLayoutSection title="Compose Your Message" description="Notify your contacts about the information." className="Message" > <div className="space-y-5"> {notificationType === 'IPAWS' && watchWEA && ( <Input id="WEAShortText" name="WEAShortText" type="text" placeholder="Add your WEA Short Text" label="WEA Short Text" labelTooltipComponent={ <Tooltip content="This is the text that appears in one-way radio broadcasts that send to cell phones or mobile devices based on the recipient's proximity to the selected cell tower" className="-mt-0.5" direction="left" /> } limit={90} onChange={e => { const value = e.target.value setCharactersWEAShort(value.length) }} currentCount={charactersWEAShort} required={watchWEA} error={errors.WEAShortText} ref={register({ required: true, maxLength: { value: 90, message: 'The short text must be between 1 - 90 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> )} {notificationType === 'IPAWS' && watchWEA && ( <Textarea id="WEALongText" name="WEALongText" placeholder="Add your WEA Long Text" label="WEA Long Text" labelTooltipComponent={ <Tooltip content="This is the text that appears in one-way radio broadcasts that send to cell phones or mobile devices based on the recipient's proximity to the selected cell tower (use if more than 90 characters are needed)" className="-mt-0.5" direction="left" /> } limit={360} onChange={e => { const value = e.target.value setCharactersWEALong(value.length) }} currentCount={charactersWEALong} error={errors.weaLongText} ref={register({ maxLength: { value: 360, message: 'The character length must be between 1 - 360 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> )} {notificationType === 'IPAWS' && watchWEA && ( <Checkbox name="WEASpanish" ref={register}> Add WEA Spanish Translation </Checkbox> )} {notificationType === 'IPAWS' && watchWEA && watchWEASpanish && ( <Input id="WEAShortTextSpanish" name="WEAShortTextSpanish" type="text" placeholder="Add your WEA Short Text (Spanish)" label="WEA Short Text (Spanish)" labelTooltipComponent={ <Tooltip content="This is the spanish translation of the text that appears in one-way radio broadcasts that send to cell phones or mobile devices based on the recipient's proximity to the selected cell tower" className="-mt-0.5" direction="left" /> } limit={90} onChange={e => { const value = e.target.value setCharactersWEASpanish(value.length) }} required={watchWEASpanish} error={errors.WEAShortTextSpanish} currentCount={charactersWEASpanish} ref={register({ required: true, maxLength: { value: 90, message: 'The short text must be between 1 - 90 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> )} {notificationType === 'IPAWS' && watchWEA && watchWEASpanish && ( <Textarea id="WEALongTextSpanish" name="WEALongTextSpanish" placeholder="Add your WEA Long Text (Spanish)" label="WEA Long Text (Spanish)" labelTooltipComponent={ <Tooltip content="This is the spanish translation of the text that appears in one-way radio broadcasts that send to cell phones or mobile devices based on the recipient's proximity to the selected cell tower (use if more than 90 characters are needed)" className="-mt-0.5" direction="left" /> } limit={360} onChange={e => { const value = e.target.value setCharactersWEALongSpanish(value.length) }} currentCount={charactersWEALongSpanish} error={errors.weaLongTextSpanish} ref={register({ maxLength: { value: 360, message: 'The character length must be between 1 - 360 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> )} <Input id="Title" type="text" name="Title" placeholder="New Alert" label="Headline (Title)" labelTooltipComponent={ <Tooltip content="This is the text headline of the alert message" className="-mt-0.5" direction="left" /> } limit={140} onChange={e => { const value = e.target.value setCharactersTitle(value.length) }} required error={errors.Title} currentCount={charactersTitle} ref={register({ required: watchNWEM, maxLength: { value: 140, message: 'The character length must be between 1 - 140 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> <Textarea id="Description" name="Description" placeholder="Instructions to follow" label="Description" labelTooltipComponent={ <Tooltip content="This is the text describing the subject event of the alert message" className="-mt-0.5" direction="left" /> } rows={4} limit={1800} onChange={e => { const value = e.target.value setCharactersDescription(value.length) }} currentCount={charactersDescription} required error={errors.Description} ref={register({ required: true, maxLength: { value: 1800, message: 'The character length must be between 1 - 1,800 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> {notificationType === 'IPAWS' && ( <Textarea id="Instructions" name="Instructions" placeholder="Long description of alert" label="Instructions" labelTooltipComponent={ <Tooltip content="This is the optional extended description of the subject event of the alert message" className="-mt-0.5" direction="left" /> } rows={4} limit={1800} onChange={e => { const value = e.target.value setCharactersInstructions(value.length) }} currentCount={charactersInstructions} ref={register({ maxLength: { value: 1800, message: 'The character length must be between 1 - 1,800 characters', }, pattern: { value: /^[^{}|\\^~[\]]{0,}$/m, message: 'The message cannot include any of the following characters: {, }, |, \\, ^, ~, [, or ]', }, })} /> )} {/* <div className="flex flex-col"> <p className="block mb-1 text-sm font-semibold text-gray-700 dark:text-gray-100"> Attachments (Max 10MB) </p> <Button>Upload Media</Button> </div> */} </div> </FormLayoutSection> {notificationType === 'IPAWS' && ( <> <FormLayoutSection className="Message-Details" title="Message Details"> <div className="mb-5"> <NativeSelect id="AlertCategory" ref={register({ required: true })} name="AlertCategory" label="Alert Category" labelTooltipComponent={ <Tooltip content="This is the category of the alert message" direction="left" /> } required onChange={event => { if (event.target.value === 'Select Alert Category') { setError('AlertCategory', { type: 'manual', message: 'Please select the Alert Category', }) } }} onBlur={event => { if (event.target.value === 'Select Alert Category') { setError('AlertCategory', { type: 'manual', message: 'Please select the Alert Category', }) } }} > <option defaultValue="">Select Alert Category</option> {Object.keys(categoryMap).map(category => ( <option key={category} value={categoryMap[category].name}> {categoryMap[category].name} </option> ))} </NativeSelect> <p style={{ color: 'red' }}> {errors.AlertCategory && errors.AlertCategory.message} </p> </div> <div className="mb-5"> <NativeSelect id="Severity" ref={register({ required: true })} name="Severity" label="Severity" labelTooltipComponent={ <Tooltip content="This is the code denoting the severity of the subject event of the alert message" direction="left" /> } required onChange={event => { if (event.target.value === 'Select Severity') { setError('Severity', { type: 'manual', message: 'Please select the Severity', }) } }} onBlur={event => { if (event.target.value === 'Select Severity') { setError('Severity', { type: 'manual', message: 'Please select the Severity', }) } }} > <option defaultValue="">Select Severity</option> {Object.keys(watchWEA ? weaSeverityMap : severityMap).map(severity => ( <option key={severity} value={severity}> {severity} </option> ))} </NativeSelect> <p style={{ color: 'red' }}>{errors.Severity && errors.Severity.message}</p> </div> <div className="mb-5"> <NativeSelect id="Urgency" ref={register({ required: true })} name="Urgency" label="Urgency" labelTooltipComponent={ <Tooltip content="This is the code denoting the urgency of the subject event of the alert message" direction="left" /> } required onChange={event => { if (event.target.value === 'Select Urgency') { setError('Urgency', { type: 'manual', message: 'Please select the Urgency', }) } }} onBlur={event => { if (event.target.value === 'Select Urgency') { setError('Urgency', { type: 'manual', message: 'Please select the Urgency', }) } }} > <option defaultValue="">Select Urgency</option> {Object.keys(watchWEA ? weaUrgencyMap : urgencyMap).map(urgency => ( <option key={urgency} value={urgency}> {urgency} </option> ))} </NativeSelect> <p style={{ color: 'red' }}>{errors.Urgency && errors.Urgency.message}</p> </div> <div className="mb-5"> <NativeSelect id="Certainty" ref={register({ required: true })} name="Certainty" label="Certainty" labelTooltipComponent={ <Tooltip content="This is the code denoting the certainty of the subject event of the alert message" direction="left" /> } required onChange={event => { if (event.target.value === 'Select Certainty') { setError('Certainty', { type: 'manual', message: 'Please select the Certainty', }) } }} onBlur={event => { if (event.target.value === 'Select Certainty') { setError('Certainty', { type: 'manual', message: 'Please select the Certainty', }) } }} > <option defaultValue="">Select Certainty</option> {Object.keys(watchWEA ? weaCertaintyMap : certaintyMap).map(certainty => ( <option key={certainty} value={certainty}> {certainty} </option> ))} </NativeSelect> <p style={{ color: 'red' }}> {errors.Certainty && errors.Certainty.message} </p> </div> </FormLayoutSection> <FormLayoutSection className="Advanced-Options" title="Advanced Options"> {watchWEA && ( <div className="mb-5"> <NativeSelect id="WEAHandling" ref={register({ required: true })} name="WEAHandling" label="WEA Handling" labelTooltipComponent={ <Tooltip content="This is the code determining the type of handling required for this alert" direction="left" /> } required onChange={event => { if (event.target.value === 'Select WEA Handling') { setError('WEAHandling', { type: 'manual', message: 'Please select the WEA Handling', }) } }} onBlur={event => { if (event.target.value === 'Select WEA Handling') { setError('WEAHandling', { type: 'manual', message: 'Please select the WEA Handling', }) } }} > <option defaultValue="">Select WEA Handling</option> {Object.keys(weaHandling).map(handle => ( <option key={handle} value={handle}> {weaHandling[handle]} </option> ))} </NativeSelect> <p style={{ color: 'red' }}> {errors.WEAHandling && errors.WEAHandling.message} </p> </div> )} <div className="mb-5"> <NativeSelect id="EventCode" required ref={register({ required: true })} name="EventCode" label="Event Code" labelTooltipComponent={ <Tooltip content="This is a system-specific code identifying the event type of the alert message" direction="left" /> } onChange={event => { if (event.target.value === 'Select Event Code') { setError('EventCode', { type: 'manual', message: 'Please select the Event Code', }) } }} onBlur={event => { if (event.target.value === 'Select Event Code') { setError('EventCode', { type: 'manual', message: 'Please select the Event Code', }) } }} > <option defaultValue="">Select Event Code</option> {eventCodeKeysFilter(watchWEA, watchNWEM, watchWEAHandle).map(code => ( <option key={code} value={code} >{`${code} - ${eventCodes[code].name}`}</option> ))} </NativeSelect> <p style={{ color: 'red' }}> {errors.EventCode && errors.EventCode.message} </p> </div> <div className="mb-5"> <NativeSelect id="EventResponse" ref={register({ required: true })} name="EventResponse" label="Event Response" labelTooltipComponent={ <Tooltip content="This is the event denoting the type of alert message" direction="left" /> } required onChange={event => { if (event.target.value === 'Select Event Response') { setError('EventResponse', { type: 'manual', message: 'Please select the Event Response', }) } }} onBlur={event => { if (event.target.value === 'Select Event Response') { setError('EventResponse', { type: 'manual', message: 'Please select the Event Response', }) } }} > <option defaultValue="">Select Event Response</option> {Object.keys(eventResponses).map(response => ( <option key={response} value={response}> {response} </option> ))} </NativeSelect> <p style={{ color: 'red' }}> {errors.EventResponse && errors.EventResponse.message} </p> </div> </FormLayoutSection> </> )} <FormLayoutSection className="Location-Info" title="Location Info"> {/* {FIPSList.map(fipsCode => ( <div key={fipsCode}> <input type="checkbox" id={fipsCode} name="CountyFIPS" value={fipsCode} ref={register} // Make sure you have register function from react-hook-form onChange={() => selectedOptions.includes(fipsCode)} defaultChecked={selectedOptions.includes(fipsCode)} /> <label htmlFor={fipsCode}> {fipsCode} - {findFipsCodeName(fipsCode)}, {findFipsCodeState(fipsCode)} </label> </div> ))} */} <div className="mb-5"> <p className="block text-sm font-semibold text-gray-700 dark:text-gray-100"> Validation Info:{' '} <span className="text-sm font-semibold text-red-500"> {locationPoints > 100 && 'More than 100 points added please remove locations.'}{' '} {locationShapes > 10 && 'More than 10 shapes added please remove locations.'} </span> </p> <p className="text-sm font-semibold text-gray-700 dark:text-gray-100"> {locationPoints} Points - {locationShapes} Shapes </p> </div> {!locationShapes && ( <div className="px-4 py-3 bg-yellow-700 rounded-md mb-5"> <p className="text-md font-semibold text-gray-100"> Note: If no shape is selected, the notification will go to the entire FIPS Code. </p> </div> )} {/* {notificationType === 'IPAWS' && ( // <Input // id="CountyFIPS" // name="CountyFIPS" // type="number" // onBlur={e => // e.target.removeEventListener('wheel', function (e) { // e.preventDefault() // }) // } // onFocus={e => // e.target.addEventListener( // 'wheel', // function (e) { // e.preventDefault() // }, // { passive: false } // ) // } // label="County FIPS(s):" // labelTooltipComponent={ // <Tooltip // content="This is a 6-digit numeric code identifying the geographic area for where you want to send the alert - the 5-digit numeric code must be prefaced with an additional zero" // direction="left" // /> // } // placeholder="######" // required // ref={register({ // required: true, // validate: validateSixDigits, // })} // error={errors.FIPS ? errors.FIPS.message : ''} // /> // )} // {errors.CountyFIPS && ( // <p style={{ color: 'red' }}>{errors.CountyFIPS.message}</p>*/} <div className="mb-5"> <NativeSelect id="CountyFIPS" ref={register({ required: true })} name="CountyFIPS" label="County FIPS(s):" labelTooltipComponent={ <Tooltip content="This is a 6-digit numeric code identifying the geographic area for where you want to send the alert - the 5-digit numeric code must be prefaced with an additional zero" direction="left" /> } required onChange={event => { if (event.target.value === 'Select FIPS Code') { setError('CountyFIPS', { type: 'manual', message: 'Please select the FIPS Code', }) } }} onBlur={event => { if (event.target.value === 'Select FIPS Code') { setError('CountyFIPS', { type: 'manual', message: 'Please select the FIPS Code', }) } }} > <option defaultValue="">Select FIPS Code</option> {FIPSList.map((fipsCode, index) => ( <option key={index} value={fipsCode}> {fipsCode} - {findFipsCodeName(fipsCode)}, {findFipsCodeState(fipsCode)} </option> ))} {!FIPSList.length && ( <option defaultValue="">No FIPS Codes. Please add in settings.</option> )} </NativeSelect> <p style={{ color: 'red' }}>{errors.CountyFIPS && errors.CountyFIPS.message}</p> </div> {/* <MultiSelect options={FIPSList} onSelect={handleSelect} ref></MultiSelect> )} */} <div className="flex flex-col"> <p className="block mb-1 text-sm font-semibold text-gray-700 dark:text-gray-100"> Choose a Geographic Location </p> <Button onClick={mapModalState} icon={<Icon className="mr-2 -ml-1" name="globe" />} > Choose Location </Button> </div> </FormLayoutSection> <FormLayoutSection className="Scheduling-Options" title="Scheduling Options"> <div className="space-y-5"> {notificationType === 'MAXX' && ( <Checkbox name="ScheduleNotification" ref={register}> Schedule Notification for Later? </Checkbox> )} {watchSchedule && ( <> <Input type="datetime-local" id="ScheduleDate" name="ScheduledDate" ref={register} placeholder="mm/dd/yyyy hh/mm PM" label="Scheduled Date" onBlur={e => e.target.removeEventListener('wheel', function (e) { e.preventDefault() }) } onFocus={e => e.target.addEventListener( 'wheel', function (e) { e.preventDefault() }, { passive: false } ) } /> <Checkbox name="ScheduleHide" ref={register}> Schedule Hide? </Checkbox> {watchScheduleHide && ( <Input type="datetime-local" id="ScheduleHideDate" name="ScheduledHideDate" ref={register} placeholder="mm/dd/yyyy hh/mm AM" label="Scheduled Hide" onBlur={e => e.target.removeEventListener('wheel', function (e) { e.preventDefault() }) } onFocus={e => e.target.addEventListener( 'wheel', function (e) { e.preventDefault() }, { passive: false } ) } /> )} <Checkbox name="ScheduleRecurring" ref={register}> Is this a recurring Notification? </Checkbox> {watchRecurring && ( <NativeSelect id="Frequency" name="Frequency" label="Frequency"> <option value="Does Not Repeat">Does Not Repeat</option> <option value="Daily">Daily</option> <option value="Weekly">Weekly</option> <option value="Monthly">Monthly</option> <option value="Weekdays">Weekdays</option> <option value="Weekends">Weekends</option> </NativeSelect> )} </> )} <div className="grid grid-cols-1 sm:grid-cols-2 sm:gap-x-4 sm:gap-y-0 gap-y-1"> <div className="mb-1 sm:col-span-2"> <div className="inline-flex justify-between w-full"> <h3>Expires in</h3> <Tooltip content="This is the expire time of the information of the alert message." direction="left" /> </div> </div> <Input id="ExpiresInHours" name="ExpiresInHours" type="number" label="Hours" placeholder="" required onBlur={e => e.target.removeEventListener('wheel', function (e) { e.preventDefault() }) } onFocus={e => e.target.addEventListener( 'wheel', function (e) { e.preventDefault() }, { passive: false } ) } error={errors.ExpiresInHours ? errors.ExpiresInHours.message : ''} ref={register({ required: true, min: { value: 0, message: 'The hours value must be greater than or equal to 0.', }, // max: { // value: 24, // message: 'The hours value must be less than or equal to 24.', // }, pattern: { value: /^-?\d+$/, message: 'This must be a whole number.', }, })} /> <NativeSelect id="ExpiresInMinutes" name="ExpiresInMinutes" label="Minutes" required ref={register({ required: true })} > <option value={0}>0</option> <option value={15}>15</option> <option value={30}>30</option> <option value={30}>45</option> </NativeSelect> {errors.ExpiresInMinutes && ( <p style={{ color: 'red' }}>{errors.ExpiresInMinutes.message}</p> )} </div> </div> </FormLayoutSection> </> ) } export default FormData
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter