App
Source
import { html } from "lit";
export function DateEntry(label, date, errorMsg, setDate, disabled = false) {
const inputId = label + "-date";
let errorMarkup;
if (errorMsg) {
errorMarkup = html` <p class="form-input-hint">${errorMsg}</p> `;
}
return html`
<div class=${"form-group" + (errorMsg ? " has-error" : "")}>
<label class="form-label" for=${inputId}>${label}</label
><input
id=${inputId}
class="form-input"
type="text"
value=${date}
@input=${e => setDate(e.target.value)}
?disabled=${disabled}
/>
${errorMarkup}
</div>
`;
}
import { html } from "lit";
export const oneWayFlight = "one-way";
export const returnFlight = "return";
export function TripType(tripType, setTripType) {
return html`
<div class="form-group">
<label class="form-label" for="trip-type">Trip type</label
><select
id="trip-type"
class="form-select"
value=${tripType}
@input=${e => setTripType(e.target.value)}
>
<option value=${oneWayFlight}>one-way flight</option>
<option value=${returnFlight}>return flight</option>
</select>
</div>
`;
}
import { html, render } from "lit";
import { today, validateDate } from "../../../../lib/date";
import { DateEntry } from "./DateEntry";
import { TripType, returnFlight, oneWayFlight } from "./TripType";
/**
* @typedef {(e: Event) => void} EventHandler
*
* @param {string} tripType
* @param {EventHandler} setTripType
* @param {string} departing
* @param {string} departingError
* @param {EventHandler} setDeparting
* @param {string} returning
* @param {string} returningError
* @param {EventHandler} setReturning
* @param {boolean} isBookDisabled
* @param {EventHandler} bookFlight
*/
function FlightBooker(
tripType,
setTripType,
departing,
departingError,
setDeparting,
returning,
returningError,
setReturning,
isBookDisabled,
bookFlight
) {
return html`
${TripType(tripType, setTripType)}
${DateEntry("Departing", departing, departingError, setDeparting)}
${DateEntry(
"Returning",
returning,
returningError,
setReturning,
tripType !== returnFlight
)}
<div class="form-group">
<button
?disabled=${isBookDisabled}
@click=${bookFlight}
class="btn btn-primary"
>
book
</button>
</div>
`;
}
/**
* @param {string} date
* @returns {string | null}
*/
function getErrorMessage(date) {
try {
validateDate(date);
return null;
} catch (error) {
return error.message;
}
}
const container = document.getElementById("app");
/**
* @param {string} tripType
* @param {string} departing
* @param {string} returning
*/
function update(tripType, departing, returning) {
let departingError = getErrorMessage(departing);
let returningError = getErrorMessage(returning);
if (
departingError == null &&
returningError == null &&
tripType == returnFlight &&
returning < departing
) {
returningError = "Returning date must be on or after departing date.";
}
const isBookDisabled = Boolean(departingError || returningError);
const setTripType = newTripType => update(newTripType, departing, returning);
const setDeparting = newDate => update(tripType, newDate, returning);
const setReturning = newDate => update(tripType, departing, newDate);
function bookFlight() {
const type = tripType === returnFlight ? "return" : "one-way";
let message = `You have booked a ${type} flight, departing ${departing}`;
if (tripType == returnFlight) {
message += ` and returning ${returning}`;
}
alert(message);
}
render(
FlightBooker(
tripType,
setTripType,
departing,
departingError,
setDeparting,
returning,
returningError,
setReturning,
isBookDisabled,
bookFlight
),
container
);
}
const initialDate = today();
update(oneWayFlight, initialDate, initialDate);