App

Bundles

Stats
BundleMinifiedGzipBrotli
index.js12 kB4.74 kB4.31 kB

Source

export function DateEntry({
	label,
	date,
	errorMsg,
	setDate,
	disabled = false
}) {
	const inputId = `${label}-date`;
	return (
		<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}
				onInput={e => setDate(e.currentTarget.value)}
				disabled={disabled}
			/>
			{errorMsg && <p class="form-input-hint">{errorMsg}</p>}
		</div>
	);
}
export const oneWayFlight = "one-way";
export const returnFlight = "return";

export function TripType({ tripType, setTripType }) {
	return (
		<div class="form-group">
			<label class="form-label" for="trip-type">
				Trip type
			</label>
			<select
				id="trip-type"
				class="form-select"
				value={tripType}
				onInput={e => setTripType(e.currentTarget.value)}
			>
				<option value={oneWayFlight}>one-way flight</option>
				<option value={returnFlight}>return flight</option>
			</select>
		</div>
	);
}
import { render, Component } from "preact";
import { today, validateDate } from "../../../../lib/date";
import { TripType, oneWayFlight, returnFlight } from "./TripType";
import { DateEntry } from "./DateEntry";

const initialDate = today();

class App extends Component {
	constructor() {
		super();
		this.state = {
			tripType: oneWayFlight,
			departing: initialDate,
			departingError: null,
			returning: initialDate,
			returningError: null
		};
	}

	updateDate(dateType, newDate) {
		let errorMsg = null;
		try {
			validateDate(newDate);
		} catch (error) {
			errorMsg = error.message;
		}

		this.setState({
			[dateType]: newDate,
			[dateType + "Error"]: errorMsg
		});
	}

	bookFlight() {
		const type = this.state.tripType === returnFlight ? "return" : "one-way";

		let message = `You have booked a ${type} flight, departing ${this.state.departing}`;
		if (this.state.tripType == returnFlight) {
			message += ` and returning ${this.state.returning}`;
		}

		alert(message);
	}

	render(props, state) {
		let returningError = state.returningError;
		if (
			state.departingError == null &&
			returningError == null &&
			state.tripType == returnFlight &&
			state.returning < state.departing
		) {
			returningError = "Returning date must be on or after departing date.";
		}

		const isBookDisabled = state.departingError || returningError;

		return (
			<>
				<TripType
					tripType={state.tripType}
					setTripType={tripType => this.setState({ tripType })}
				/>
				<DateEntry
					label="Departing"
					date={state.departing}
					setDate={newDate => this.updateDate("departing", newDate)}
					errorMsg={state.departingError}
				/>
				<DateEntry
					label="Returning"
					date={state.returning}
					setDate={newDate => this.updateDate("returning", newDate)}
					errorMsg={returningError}
					disabled={state.tripType !== returnFlight}
				/>
				<div class="form-group">
					<button
						disabled={isBookDisabled}
						onClick={() => this.bookFlight()}
						class="btn btn-primary"
					>
						book
					</button>
				</div>
			</>
		);
	}
}

render(<App />, document.getElementById("app"));