diff --git a/frameworks/solid-js/src/7GUIs-flight-booker/DateEntry.jsx b/frameworks/solid-js/src/7GUIs-flight-booker/DateEntry.jsx new file mode 100644 index 0000000..7b5da67 --- /dev/null +++ b/frameworks/solid-js/src/7GUIs-flight-booker/DateEntry.jsx @@ -0,0 +1,31 @@ +/** + * @typedef DateEntryProps + * @property {string} label + * @property {string} date + * @property {(newDate: string) => void} setDate + * @property {string | null} errorMsg + * @property {boolean} [disabled] + */ + +/** + * @param {DateEntryProps} props + */ +export function DateEntry(props) { + const inputId = `${props.label}-date`; + return ( +
+ + props.setDate(e.currentTarget.value)} + disabled={props.disabled} + /> + {props.errorMsg &&

{props.errorMsg}

} +
+ ); +} diff --git a/frameworks/solid-js/src/7GUIs-flight-booker/TripType.jsx b/frameworks/solid-js/src/7GUIs-flight-booker/TripType.jsx new file mode 100644 index 0000000..8b12848 --- /dev/null +++ b/frameworks/solid-js/src/7GUIs-flight-booker/TripType.jsx @@ -0,0 +1,24 @@ +export const ONE_WAY_FLIGHT = "one-way"; +export const RETURN_FLIGHT = "return"; + +/** + * @param {{ tripType: string; setTripType(value: string): void; }} props + */ +export function TripType(props) { + return ( +
+ + +
+ ); +} diff --git a/frameworks/solid-js/src/7GUIs-flight-booker/index.jsx b/frameworks/solid-js/src/7GUIs-flight-booker/index.jsx new file mode 100644 index 0000000..c1c61ea --- /dev/null +++ b/frameworks/solid-js/src/7GUIs-flight-booker/index.jsx @@ -0,0 +1,98 @@ +import { createMemo, createSignal } from "solid-js"; +import { render } from "solid-js/web"; +import { today, validateDate } from "../../../../lib/date"; +import { TripType, RETURN_FLIGHT, ONE_WAY_FLIGHT } from "./TripType"; +import { DateEntry } from "./DateEntry"; + +const initialDate = today(); + +/** + * @typedef {import('solid-js').Accessor} Accessor + * @template T + */ + +/** + * @param {string} initialDate + * @returns {[Accessor, Accessor, (string) => void]} + */ +function useDate(initialDate) { + const [date, setDate] = createSignal(initialDate); + const [error, setError] = createSignal(null); + + /** @type {(newDate: string) => void} */ + function updateDate(newDate) { + setDate(newDate); + + try { + validateDate(newDate); + setError(null); + } catch (error) { + setError(error.message); + } + } + + return [date, error, updateDate]; +} + +function App() { + const [tripType, setTripType] = createSignal(ONE_WAY_FLIGHT); + const [departing, departingError, setDeparting] = useDate(initialDate); + const [returning, returningError, setReturning] = useDate(initialDate); + + const finalReturningError = createMemo(() => { + if ( + departingError() == null && + returningError() == null && + tripType() == RETURN_FLIGHT && + returning() < departing() + ) { + return "Returning date must be on or after departing date."; + } else { + return returningError(); + } + }); + + function bookFlight() { + const type = tripType() === RETURN_FLIGHT ? "return" : "one-way"; + + let message = `You have booked a ${type} flight, departing ${departing()}`; + if (tripType() == RETURN_FLIGHT) { + message += ` and returning ${returning()}`; + } + + alert(message); + } + + return ( + <> + setTripType(value)} + /> + setDeparting(newDate)} + errorMsg={departingError()} + /> + setReturning(newDate)} + errorMsg={finalReturningError()} + disabled={tripType() !== RETURN_FLIGHT} + /> +
+ +
+ + ); +} + +render(App, document.getElementById("app")); diff --git a/frameworks/solid-js/src/7GUIs-timer/index.jsx b/frameworks/solid-js/src/7GUIs-timer/index.jsx index 8be9ec4..0b8946e 100644 --- a/frameworks/solid-js/src/7GUIs-timer/index.jsx +++ b/frameworks/solid-js/src/7GUIs-timer/index.jsx @@ -1,6 +1,5 @@ import { createSignal, - onMount, onCleanup, createMemo, createRenderEffect diff --git a/sizes.json b/sizes.json index fadf878..895babb 100644 --- a/sizes.json +++ b/sizes.json @@ -184,11 +184,17 @@ "gzip": 3021, "brotli": 2736 }, + "7GUIs-flight-booker": { + "raw": 24511, + "minified": 10295, + "gzip": 4085, + "brotli": 3669 + }, "7GUIs-timer": { - "raw": 20167, - "minified": 8336, - "gzip": 3447, - "brotli": 3108 + "raw": 19713, + "minified": 8099, + "gzip": 3348, + "brotli": 3028 } }, "svelte": {