diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index c02c3ed..a6e4de5 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -952,6 +952,19 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package-lock.json b/package-lock.json index 0d02bf3..7d8399c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "devDependencies": { "htm": "^3.1.1", "preact": "^10.29.2", - "tailwindcss": "^3.4.17" + "tailwindcss": "^3.4.17", + "typescript": "^6.0.3" } }, "node_modules/@alloc/quick-lru": { @@ -960,6 +961,19 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 7b263b4..210a1a1 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "devDependencies": { "htm": "^3.1.1", "preact": "^10.29.2", - "tailwindcss": "^3.4.17" + "tailwindcss": "^3.4.17", + "typescript": "^6.0.3" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..668cc8b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "checkJs": true, + "allowJs": true, + "noEmit": true, + "strict": true, + "lib": ["dom", "es2022"], + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "paths": { + "https://esm.sh/preact@10": ["./node_modules/preact/src/index.d.ts"], + "https://esm.sh/preact@10/hooks": ["./node_modules/preact/hooks/src/index.d.ts"], + "https://esm.sh/htm@3/preact": ["./node_modules/htm/preact/index.d.ts"] + } + }, + "include": [ + "web/modules/custom/riverside_pt/js/**/*.js", + "web/modules/custom/riverside_pt/js/globals.d.ts" + ] +} diff --git a/web/modules/custom/riverside_pt/js/components/rpt-appt-type.js b/web/modules/custom/riverside_pt/js/components/rpt-appt-type.js index 8c693d2..27fd45b 100644 --- a/web/modules/custom/riverside_pt/js/components/rpt-appt-type.js +++ b/web/modules/custom/riverside_pt/js/components/rpt-appt-type.js @@ -16,6 +16,7 @@ const CHECK = html` @@ -372,11 +390,11 @@ function BookingPanel({ service, settings }) { ${slots.length > 0 ? html`

Select a time on ${(function () { - var p = slots[0].start.split("T")[0].split("-"); + var p = slots[0] ? slots[0].start.split("T")[0].split("-") : ["","",""]; return parseInt(p[1]) + "/" + parseInt(p[2]) + "/" + p[0]; })()}:

- ${slots.map(function (slot) { + ${slots.map(function (/** @type {RiversidePtEvent} */ slot) { return html`
@@ -422,7 +440,7 @@ function BookingPanel({ service, settings }) { autocomplete="family-name" required value=${formData.lastName} - onInput=${function (e) { handleFormChange("lastName", e.target.value); }} + onInput=${function (/** @type {any} */ e) { handleFormChange("lastName", e.target.value); }} class=${CX.formInput} />
@@ -437,7 +455,7 @@ function BookingPanel({ service, settings }) { autocomplete="email" required value=${formData.email} - onInput=${function (e) { handleFormChange("email", e.target.value); }} + onInput=${function (/** @type {any} */ e) { handleFormChange("email", e.target.value); }} class=${CX.formInput} /> @@ -452,7 +470,7 @@ function BookingPanel({ service, settings }) { autocomplete="tel" required value=${formatPhone(formData.phone)} - onInput=${function (e) { + onInput=${function (/** @type {any} */ e) { handleFormChange("phone", formatPhone(e.target.value)); }} class=${CX.formInput} @@ -470,7 +488,7 @@ function BookingPanel({ service, settings }) { name="comments" autocomplete="off" value=${formData.comments} - onInput=${function (e) { handleFormChange("comments", e.target.value); }} + onInput=${function (/** @type {any} */ e) { handleFormChange("comments", e.target.value); }} class=${CX.formTextarea} > @@ -491,7 +509,7 @@ function BookingPanel({ service, settings }) {

${confirmedAppointment.firstName} ${confirmedAppointment.lastName}

${confirmedAppointment.email}

-

${TYPES.find(function (t) { return t.id === confirmedAppointment.service; }).label}

+

${(TYPES.find(function (/** @type {{id:string,label:string}} */ t) { return t.id === confirmedAppointment.service; }) || {}).label}

${formatAppointmentDate(confirmedAppointment.start)}

We'll contact you shortly to confirm your appointment.

@@ -506,8 +524,11 @@ function BookingPanel({ service, settings }) { // Owns service selection and the type selector UI. Keys BookingPanel by // service so it mounts fresh on every change — no reset effects, no races. // Starts with null so no service is pre-selected. +/** + * @param {{ settings: RiversidePtSettings }} props + */ function Booking({ settings }) { - const [service, setService] = useState(null); + const [service, setService] = useState(/** @type {string | null} */ (null)); return html`
@@ -519,7 +540,7 @@ function Booking({ settings }) {