| 1 |
import {SubmitHandler, useForm} from 'react-hook-form'; |
| 2 |
import {__} from '@wordpress/i18n'; |
| 3 |
import styles from './EventFormModal.module.scss'; |
| 4 |
import FormModal from '../FormModal'; |
| 5 |
import EventTicketsApi from '../api'; |
| 6 |
|
| 7 |
/** |
| 8 |
* Get the next sharp hour |
| 9 |
* |
| 10 |
* @since 3.6.0 |
| 11 |
*/ |
| 12 |
const getNextSharpHour = (hoursToAdd: number) => { |
| 13 |
const date = new Date(); |
| 14 |
date.setHours(date.getHours() + hoursToAdd, 0, 0, 0); |
| 15 |
|
| 16 |
return date; |
| 17 |
}; |
| 18 |
|
| 19 |
/** |
| 20 |
* Format a given date to be used in datetime inputs |
| 21 |
* |
| 22 |
* @since 3.6.0 |
| 23 |
*/ |
| 24 |
const getDateString = (date: Date) => { |
| 25 |
const offsetInMilliseconds = date.getTimezoneOffset() * 60 * 1000; |
| 26 |
const dateWithOffset = new Date(date.getTime() - offsetInMilliseconds); |
| 27 |
|
| 28 |
return removeTimezoneFromDateISOString(dateWithOffset.toISOString()); |
| 29 |
}; |
| 30 |
|
| 31 |
/** |
| 32 |
* Remove timezone from date string |
| 33 |
* |
| 34 |
* @since 3.6.0 |
| 35 |
*/ |
| 36 |
const removeTimezoneFromDateISOString = (date: string) => { |
| 37 |
return date.slice(0, -5); |
| 38 |
}; |
| 39 |
|
| 40 |
/** |
| 41 |
* Event Form Modal component |
| 42 |
* |
| 43 |
* @since 3.20.0 Added placeholder to event description field |
| 44 |
* @since 3.6.0 |
| 45 |
*/ |
| 46 |
export default function EventFormModal({isOpen, handleClose, apiSettings, title, event}: EventModalProps) { |
| 47 |
const API = new EventTicketsApi(apiSettings); |
| 48 |
|
| 49 |
const { |
| 50 |
register, |
| 51 |
handleSubmit, |
| 52 |
formState: {errors, isDirty}, |
| 53 |
} = useForm<Inputs>({ |
| 54 |
defaultValues: { |
| 55 |
title: event?.title ?? '', |
| 56 |
description: event?.description ?? '', |
| 57 |
startDateTime: getDateString( |
| 58 |
event?.startDateTime?.date ? new Date(event?.startDateTime?.date) : getNextSharpHour(1) |
| 59 |
), |
| 60 |
endDateTime: getDateString( |
| 61 |
event?.endDateTime?.date ? new Date(event?.endDateTime?.date) : getNextSharpHour(2) |
| 62 |
), |
| 63 |
}, |
| 64 |
}); |
| 65 |
|
| 66 |
const onSubmit: SubmitHandler<Inputs> = async (inputs) => { |
| 67 |
try { |
| 68 |
inputs.startDateTime = getDateString(new Date(inputs.startDateTime)); |
| 69 |
inputs.endDateTime = getDateString(new Date(inputs.endDateTime)); |
| 70 |
|
| 71 |
const endpoint = event?.id ? `/event/${event.id}` : ''; |
| 72 |
const response = await API.fetchWithArgs(endpoint, inputs, 'POST'); |
| 73 |
|
| 74 |
handleClose(response); |
| 75 |
} catch (error) { |
| 76 |
console.error('Error submitting event event', error); |
| 77 |
} |
| 78 |
}; |
| 79 |
|
| 80 |
return ( |
| 81 |
<FormModal |
| 82 |
isOpen={isOpen} |
| 83 |
handleClose={handleClose} |
| 84 |
title={title} |
| 85 |
handleSubmit={handleSubmit(onSubmit)} |
| 86 |
errors={errors} |
| 87 |
className={styles.eventForm} |
| 88 |
> |
| 89 |
<div className="givewp-event-tickets__form-row"> |
| 90 |
<label htmlFor="title">{__('Event Name', 'give')}</label> |
| 91 |
<input |
| 92 |
type="text" |
| 93 |
{...register('title', {required: __('The event must have a name!', 'give')})} |
| 94 |
aria-invalid={errors.title ? 'true' : 'false'} |
| 95 |
placeholder={__('Enter event name', 'give')} |
| 96 |
/> |
| 97 |
</div> |
| 98 |
<div className="givewp-event-tickets__form-row"> |
| 99 |
<label htmlFor="description">{__('Description', 'give')}</label> |
| 100 |
<textarea |
| 101 |
{...register('description')} |
| 102 |
rows={4} |
| 103 |
placeholder={__('Briefly describe the details of your event', 'give')} |
| 104 |
/> |
| 105 |
</div> |
| 106 |
<div className="givewp-event-tickets__form-row givewp-event-tickets__form-row--half"> |
| 107 |
<div className="givewp-event-tickets__form-column"> |
| 108 |
<label htmlFor="startDateTime">{__('Start date and time', 'give')}</label> |
| 109 |
<input |
| 110 |
type="datetime-local" |
| 111 |
{...register('startDateTime', {required: __('The event must have a start date!', 'give')})} |
| 112 |
aria-invalid={errors.startDateTime ? 'true' : 'false'} |
| 113 |
/> |
| 114 |
</div> |
| 115 |
<div className="givewp-event-tickets__form-column"> |
| 116 |
<label htmlFor="endDateTime">{__('End date and time', 'give')}</label> |
| 117 |
<input type="datetime-local" {...register('endDateTime')} /> |
| 118 |
</div> |
| 119 |
</div> |
| 120 |
|
| 121 |
<button |
| 122 |
type="submit" |
| 123 |
className={`button button-primary ${!isDirty ? 'disabled' : ''}`} |
| 124 |
aria-disabled={!isDirty} |
| 125 |
disabled={!isDirty} |
| 126 |
> |
| 127 |
{event?.id ? __('Save changes', 'give') : __('Save event', 'give')} |
| 128 |
</button> |
| 129 |
</FormModal> |
| 130 |
); |
| 131 |
} |
| 132 |
|
| 133 |
type Event = { |
| 134 |
id?: number; |
| 135 |
title: string; |
| 136 |
description: string; |
| 137 |
startDateTime: { |
| 138 |
date: string; |
| 139 |
timezone_type: number; |
| 140 |
timezone: string; |
| 141 |
}; |
| 142 |
endDateTime: { |
| 143 |
date: string; |
| 144 |
timezone_type: number; |
| 145 |
timezone: string; |
| 146 |
}; |
| 147 |
createdAt: string; |
| 148 |
updatedAt: string; |
| 149 |
}; |
| 150 |
|
| 151 |
type Inputs = { |
| 152 |
title: string; |
| 153 |
description: string; |
| 154 |
startDateTime: string; |
| 155 |
endDateTime: string; |
| 156 |
}; |
| 157 |
|
| 158 |
interface EventModalProps { |
| 159 |
isOpen: boolean; |
| 160 |
handleClose: (response?: any) => void; |
| 161 |
apiSettings: { |
| 162 |
apiRoot: string; |
| 163 |
apiNonce: string; |
| 164 |
}; |
| 165 |
title: string; |
| 166 |
event?: Event; |
| 167 |
} |
| 168 |
|