diff --git a/README.md b/README.md index eb427c15a..a2ed0c375 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ The internal staff-facing Vue 2 application. Staff use it for queue management, The public-facing Vue 2 application for booking appointments, viewing booked appointments, managing account settings, handling sign-in flows, and viewing walk-in queue status. +### `appointment-booking` + +The new under development public-facing React 19 + TypeScript application for booking appointments at Service BC locations. It will eventually replace `appointment-frontend`. See [`appointment-booking/README.md`](./appointment-booking/README.md) for setup instructions. + ### `notifications-api` A separate Flask service for outbound notifications. It exposes authenticated `POST /api/v1/notifications/sms` and `POST /api/v1/notifications/email` endpoints and supports pluggable delivery providers, including GC Notify, CHES, and logging/custom implementations. @@ -41,7 +45,7 @@ This legacy Flask service accepts feedback submissions and forwards them to the ## Technology Stack - Backend: Python, Flask, Flask-RESTX, SQLAlchemy, Flask-Migrate, Flask-SocketIO, Marshmallow, Gunicorn, and Gevent. -- Frontend: Vue 2, TypeScript, Vue Router, Vuex, Vuetify, BootstrapVue, Buefy, and Axios. +- Frontend: Vue 2 , React 19 + TypeScript + Vite , Vue Router, Vuex, Vuetify, BootstrapVue, Buefy, and Axios. - Data and integrations: PostgreSQL, Redis-backed real-time/message queue usage, MinIO for object storage, Keycloak/OIDC authentication, optional Snowplow analytics, and GC Notify/CHES/custom notification providers. - Serving/runtime: Nginx serves built frontend assets in containerized deployments. @@ -77,6 +81,7 @@ It also provisions project-local Python environments for both `api` and `notific - `5000`: queue management API - `5002`: notifications API +- `5173`: appointment booking frontend (React) - `8080`: staff frontend - `8081`: appointment frontend - `8085`: Keycloak auth server @@ -112,6 +117,9 @@ The devcontainer installs dependencies automatically for `api`, `notifications-a cd ./appointment-frontend npm install + + cd ./appointment-booking + npm install ``` 3. Create the required local config files: @@ -188,6 +196,15 @@ cd ./appointment-frontend npm run serve -- --port 8081 ``` +Appointment booking frontend (React): + +```bash +cd ./appointment-booking +npm run dev +``` + +Opens at `http://localhost:5173`. See [`appointment-booking/README.md`](./appointment-booking/README.md) for Docker and environment variable details. + #### Local Config Files These are the main local files you should expect to have in place when running the application locally: diff --git a/api/config.py b/api/config.py index aee3ac5e1..b23d3c755 100644 --- a/api/config.py +++ b/api/config.py @@ -219,7 +219,7 @@ class LocalConfig(BaseConfig): SERVER_NAME = None SESSION_COOKIE_DOMAIN = None - CORS_ALLOWED_ORIGINS = ["http://localhost:8080", "http://localhost:8081"] + CORS_ALLOWED_ORIGINS = ["http://localhost:8080", "http://localhost:8081", "http://localhost:5173", "http://localhost:5174"] SQLALCHEMY_ECHO = False SECRET_KEY = "pancakes" diff --git a/appointment-booking/.gitignore b/appointment-booking/.gitignore index a547bf36d..5945dc6d8 100644 --- a/appointment-booking/.gitignore +++ b/appointment-booking/.gitignore @@ -11,6 +11,7 @@ node_modules dist dist-ssr *.local +ci_output.txt # Editor directories and files .vscode/* diff --git a/appointment-booking/Dockerfile b/appointment-booking/Dockerfile index 4ae2c78f7..7e1358bfc 100644 --- a/appointment-booking/Dockerfile +++ b/appointment-booking/Dockerfile @@ -1,42 +1,20 @@ -# Multi-stage build for appointment-booking SSR app # Stage 1: Builder FROM node:22-alpine AS builder WORKDIR /app -# Copy package files COPY package*.json ./ - -# Install dependencies RUN npm ci -# Copy source COPY . . - -# Build client and server RUN npm run build # Stage 2: Runtime -FROM node:22-alpine - -WORKDIR /app - -# Install only production dependencies -COPY package*.json ./ -RUN npm ci --omit=dev - -# Copy built artifacts from builder -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/server.js ./server.js -COPY --from=builder /app/public ./public - -# Health check -HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ - CMD node -e "require('http').get('http://localhost:5173/config/runtime-config.json', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" || exit 1 +FROM nginx:1.25.3 -# Expose port -EXPOSE 5173 +COPY nginx.conf /etc/nginx/nginx.conf +RUN mkdir /app +COPY --from=builder /app/dist /app -# Run production server -ENV NODE_ENV=production -CMD ["node", "server.js"] +EXPOSE 8080 +CMD ["nginx", "-g", "daemon off;"] diff --git a/appointment-booking/README.md b/appointment-booking/README.md index 9ae9e8f5e..e5da5630b 100644 --- a/appointment-booking/README.md +++ b/appointment-booking/README.md @@ -1,6 +1,6 @@ # Appointment Booking App -A React 19 + TypeScript appointment booking interface built for BC Gov, featuring server-side rendering (SSR), automated tests, and OpenShift deployment readiness. +A React 19 + TypeScript appointment booking interface built for BC Gov. ## Prerequisites @@ -21,18 +21,14 @@ npm install ### Start the frontend ```bash -# Default: proxies /api/v1 to http://localhost:5000 +# Proxies /api/v1 to http://localhost:5000 (default) npm run dev -# If your local API runs on a different port (e.g. 5100 on macOS where port 5000 is reserved by mDNS): +# If your local API runs on port 5100 npm run dev:local ``` -Open `http://localhost:5173`. If that port is in use, the server automatically falls back to `5174`. - -### Frontend-only (without backend) - -The frontend starts without a running backend. API calls to `/api/v1/*` will fail gracefully until the backend is running. +Open `http://localhost:5173`. The frontend starts without a running backend — API calls will fail gracefully until the backend is running. ### Run Checks @@ -40,84 +36,57 @@ The frontend starts without a running backend. API calls to `/api/v1/*` will fai # Run everything at once (lint + type-check + test + build + license) npm run ci:check -# Optional: run checks individually +# Individually npm run test -npm run test:watch npm run lint npm run type-check -npm run license-check ``` ### Build for Production ```bash -# Compile TypeScript, build client & server npm run build - # Output in ./dist/ -# - dist/client/ (browser assets) -# - dist/server/ (SSR entry point) - -# Run production build locally -NODE_ENV=production node server.js -# Opens at http://localhost:5173 ``` --- ## Docker -### Build Image - -```bash -docker build -t appointment-booking:latest . -``` +### Run with Docker Compose (recommended) -### Run Container +From the repository root: ```bash -docker run -p 5173:5173 \ - -e API_BASE_URL=http://api-service/api/v1 \ - -e NODE_ENV=production \ - appointment-booking:latest +docker compose --profile api up --build ``` -**Note:** Use `host.docker.internal` on macOS/Windows to access localhost from container. On Linux, use the Docker network or actual IP. +Starts the frontend, API, database, and Keycloak. Open `http://localhost:5173`. + +> Note: running Docker compose will occupy port 5173. If you then run `npm run dev`, Vite will fall back to port 5174. -### Run with Docker Compose +### Build and run manually ```bash -docker-compose up appointment-booking +docker build -t appointment-booking . +docker run -p 5173:8080 appointment-booking ``` -(Assumes compose.yaml exists with service definition) - --- -## Environment Variables - -| Variable | Default | Purpose | -|----------|---------|---------| -| `NODE_ENV` | `development` | Controls production vs development mode | -| `PORT` | `5173` | Server listen port | -| `FALLBACK_PORT` | `PORT + 1` | Fallback port when `PORT` is already in use (dev) | -| `API_PROXY_TARGET` | `http://localhost:5000` | Backend URL for Vite's `/api/v1` dev proxy (**dev only**) | -| `API_BASE_URL` | `/api/v1` | API base URL served to the client via runtime config (**production**) | -| `REQUEST_TIMEOUT_MS` | `10000` | API request timeout in milliseconds | +## Runtime Config -### Runtime Config +The app fetches `/config/runtime-config.json` on startup to get its configuration. The default file is at [`public/config/runtime-config.json`](./public/config/runtime-config.json) and is served as a static file by nginx. -The app loads configuration from `/config/runtime-config.json` endpoint (served by `server.js`): +In OpenShift, a ConfigMap mounts over this file to provide environment-specific values without rebuilding the image. ```json { - "apiBaseUrl": "/api/v1", + "apiBaseUrl": "http://localhost:5000/api/v1", "requestTimeoutMs": 10000 } ``` -This endpoint reads from environment variables at startup, allowing Kubernetes ConfigMaps/Secrets to drive configuration without rebuilding the image. - --- ## License @@ -125,24 +94,3 @@ This endpoint reads from environment variables at startup, allowing Kubernetes C MIT + Apache-2.0 (for BC Gov design system components) See `LICENSE` file and run `npm run license-check` to verify all dependencies comply. - ---- - -## Contributing - -1. Create a feature branch -2. Make changes and run tests: `npm run test` -3. Lint and format: `npm run lint && npm run format` -4. Push and open a PR -5. GitHub Actions runs quality checks automatically -6. Merge once checks pass - ---- - -## Links - -- **BC Gov Design System:** https://github.com/bcgov/design-system -- **React Docs:** https://react.dev -- **Vite Docs:** https://vite.dev -- **TypeScript Docs:** https://www.typescriptlang.org -- **OpenShift Docs:** https://docs.openshift.com diff --git a/appointment-booking/ci_output.txt b/appointment-booking/ci_output.txt deleted file mode 100644 index 495fe04a8..000000000 --- a/appointment-booking/ci_output.txt +++ /dev/null @@ -1,510 +0,0 @@ - -> appointment-booking@0.0.0 ci:check -> npm run lint && npm run type-check && npm run test && npm run build && npm run license-check - - -> appointment-booking@0.0.0 lint -> eslint . - - -> appointment-booking@0.0.0 type-check -> tsc --noEmit - - -> appointment-booking@0.0.0 test -> vitest run - - - RUN  v4.1.6 /Users/vveenu/Documents/GitHub/queue-management/appointment-booking - - ✓ src/services/api-client.service.test.ts (2 tests) 5ms - ✓ src/App.test.tsx (1 test) 52ms - - Test Files  2 passed (2) - Tests  3 passed (3) - Start at  16:12:08 - Duration  781ms (transform 45ms, setup 296ms, import 43ms, tests 57ms, environment 963ms) - - -> appointment-booking@0.0.0 build -> tsc -b && npm run build:client && npm run build:server - - -> appointment-booking@0.0.0 build:client -> vite build --outDir dist/client - -vite v8.0.12 building client environment for production... - transforming...✓ 26 modules transformed. -rendering chunks... -computing gzip size... -dist/client/index.html 0.48 kB │ gzip: 0.30 kB -dist/client/assets/BCSans-LightItalic-dN5bWDr3.woff2 200.23 kB -dist/client/assets/BCSans-Italic-_P9wZbgV.woff2 201.80 kB -dist/client/assets/BCSans-Bold-Ciclm6eX.woff2 209.33 kB -dist/client/assets/BCSans-BoldItalic-bEalI5bL.woff2 215.60 kB -dist/client/assets/BCSans-Light-DTetth3X.woff2 223.74 kB -dist/client/assets/BCSans-Regular-DKwZ9GnR.woff2 253.98 kB -dist/client/assets/BCSans-LightItalic-C2AxY9aU.woff 356.58 kB -dist/client/assets/BCSans-Italic-BSFPKGgR.woff 359.68 kB -dist/client/assets/BCSans-Bold-BmoTexmK.woff 360.36 kB -dist/client/assets/BCSans-BoldItalic-Dg_86UDa.woff 378.33 kB -dist/client/assets/BCSans-Light-CmVrKSZi.woff 388.54 kB -dist/client/assets/BCSans-Regular-CMx_o1HH.woff 486.61 kB -dist/client/assets/index-CeFoQ9g5.css 9.34 kB │ gzip: 2.11 kB -dist/client/assets/index-DfOt3hr1.js 356.99 kB │ gzip: 95.59 kB - -✓ built in 111ms - -> appointment-booking@0.0.0 build:server -> vite build --ssr src/entry-server.tsx --outDir dist/server - -vite v8.0.12 building ssr environment for production... - transforming...✓ 10 modules transformed. -rendering chunks... -computing gzip size... -dist/server/entry-server.js 5.01 kB │ gzip: 1.79 kB - -✓ built in 19ms - -> appointment-booking@0.0.0 license-check -> license-checker --production --onlyAllow "MIT;Apache-2.0;ISC;BSD-2-Clause;BSD-3-Clause;0BSD" --excludePackages "appointment-booking@0.0.0;@bcgov/bc-sans@2.1.0" - -(node:65471) [DEP0170] DeprecationWarning: The URL git+ssh://git@github.com:bcgov/bc-sans.git is invalid. Future versions of Node.js will throw an error. -(Use `node --trace-deprecation ...` to show where the warning was created) -├─ @adobe/react-spectrum-ui@1.2.1 -│ ├─ licenses: Apache-2.0 -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum-ui -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum-ui/LICENSE -├─ @adobe/react-spectrum-workflow@2.3.5 -│ ├─ licenses: Apache-2.0 -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum-workflow -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum-workflow/LICENSE -├─ @adobe/react-spectrum@3.47.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum/LICENSE -├─ @babel/runtime@7.29.2 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/babel/babel -│ ├─ publisher: The Babel Team -│ ├─ url: https://babel.dev/team -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@babel/runtime -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@babel/runtime/LICENSE -├─ @bcgov/design-system-react-components@0.7.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/bcgov/design-system -│ ├─ publisher: Tyler Krys -│ ├─ email: Tyler.Krys@gov.bc.ca -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-system-react-components -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-system-react-components/README.md -├─ @bcgov/design-tokens@3.2.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/bcgov/design-system -│ ├─ publisher: Tyler Krys -│ ├─ email: Tyler.Krys@gov.bc.ca -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-system-react-components/node_modules/@bcgov/design-tokens -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-system-react-components/node_modules/@bcgov/design-tokens/README.md -├─ @bcgov/design-tokens@4.0.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/bcgov/design-system -│ ├─ publisher: Tyler Krys -│ ├─ email: Tyler.Krys@gov.bc.ca -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-tokens -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@bcgov/design-tokens/README.md -├─ @formatjs/ecma402-abstract@2.3.6 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ publisher: Long Ho -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/ecma402-abstract -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/ecma402-abstract/LICENSE.md -├─ @formatjs/fast-memoize@2.2.7 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ publisher: Long Ho -│ ├─ email: holevietlong@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/fast-memoize -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/fast-memoize/LICENSE.md -├─ @formatjs/icu-messageformat-parser@2.11.4 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/icu-messageformat-parser -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/icu-messageformat-parser/LICENSE.md -├─ @formatjs/icu-skeleton-parser@1.8.16 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/icu-skeleton-parser -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/icu-skeleton-parser/LICENSE.md -├─ @formatjs/intl-localematcher@0.6.2 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ publisher: Long Ho -│ ├─ email: holevietlong@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/intl-localematcher -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@formatjs/intl-localematcher/LICENSE.md -├─ @internationalized/date@3.12.1 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum/tree/main/packages/@internationalized/date -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/date -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/date/LICENSE -├─ @internationalized/message@3.1.9 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/message -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/message/LICENSE -├─ @internationalized/number@3.6.6 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/number -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/number/LICENSE -├─ @internationalized/string@3.2.8 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/string -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@internationalized/string/LICENSE -├─ @react-aria/autocomplete@3.0.0-rc.6 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/autocomplete -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/autocomplete/LICENSE -├─ @react-aria/button@3.15.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/button -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/button/LICENSE -├─ @react-aria/collections@3.1.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/collections -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/collections/LICENSE -├─ @react-aria/combobox@3.16.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/combobox -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/combobox/LICENSE -├─ @react-aria/dnd@3.12.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/dnd -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/dnd/LICENSE -├─ @react-aria/focus@3.22.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/focus -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/focus/LICENSE -├─ @react-aria/i18n@3.13.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/i18n -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/i18n/LICENSE -├─ @react-aria/interactions@3.28.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/interactions -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/interactions/LICENSE -├─ @react-aria/listbox@3.16.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/listbox -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/listbox/LICENSE -├─ @react-aria/live-announcer@3.5.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/live-announcer -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/live-announcer/LICENSE -├─ @react-aria/overlays@3.32.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/overlays -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/overlays/LICENSE -├─ @react-aria/searchfield@3.9.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/searchfield -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/searchfield/LICENSE -├─ @react-aria/ssr@3.10.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/ssr -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/ssr/LICENSE -├─ @react-aria/textfield@3.19.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/textfield -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/textfield/LICENSE -├─ @react-aria/toolbar@3.0.0-beta.24 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/toolbar -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/toolbar/LICENSE -├─ @react-aria/utils@3.34.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/utils -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/utils/LICENSE -├─ @react-aria/virtualizer@4.2.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/virtualizer -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-aria/virtualizer/LICENSE -├─ @react-spectrum/button@3.18.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/button -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/button/LICENSE -├─ @react-spectrum/combobox@3.17.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/combobox -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/combobox/LICENSE -├─ @react-spectrum/form@3.8.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/form -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/form/LICENSE -├─ @react-spectrum/provider@3.11.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/provider -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/provider/LICENSE -├─ @react-spectrum/searchfield@3.9.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/searchfield -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/searchfield/LICENSE -├─ @react-spectrum/table@3.18.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/table -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-spectrum/table/LICENSE -├─ @react-stately/autocomplete@3.0.0-beta.4 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/autocomplete -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/autocomplete/LICENSE -├─ @react-stately/combobox@3.14.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/combobox -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/combobox/LICENSE -├─ @react-stately/grid@3.12.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/grid -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/grid/LICENSE -├─ @react-stately/layout@4.7.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/layout -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/layout/LICENSE -├─ @react-stately/searchfield@3.6.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/searchfield -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/searchfield/LICENSE -├─ @react-stately/selection@3.21.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/selection -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/selection/LICENSE -├─ @react-stately/table@3.16.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/table -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/table/LICENSE -├─ @react-stately/utils@3.12.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/utils -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/utils/LICENSE -├─ @react-stately/virtualizer@4.5.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/virtualizer -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-stately/virtualizer/LICENSE -├─ @react-types/autocomplete@3.0.0-alpha.38 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/autocomplete -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/autocomplete/LICENSE -├─ @react-types/button@3.16.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/button -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/button/LICENSE -├─ @react-types/combobox@3.15.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/combobox -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/combobox/LICENSE -├─ @react-types/form@3.8.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/form -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/form/LICENSE -├─ @react-types/grid@3.4.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/grid -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/grid/LICENSE -├─ @react-types/searchfield@3.7.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/searchfield -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/searchfield/LICENSE -├─ @react-types/shared@3.34.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/shared -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/shared/LICENSE -├─ @react-types/table@3.14.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/table -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@react-types/table/LICENSE -├─ @spectrum-icons/ui@3.7.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@spectrum-icons/ui -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@spectrum-icons/ui/LICENSE -├─ @spectrum-icons/workflow@4.3.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@spectrum-icons/workflow -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@spectrum-icons/workflow/LICENSE -├─ @swc/helpers@0.5.21 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/swc-project/swc -│ ├─ publisher: 강동윤 -│ ├─ email: kdy1997.dev@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@swc/helpers -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@swc/helpers/LICENSE -├─ aria-hidden@1.2.6 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/theKashey/aria-hidden -│ ├─ publisher: Anton Korzunov -│ ├─ email: thekashey@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/aria-hidden -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/aria-hidden/LICENSE -├─ client-only@0.0.1 -│ ├─ licenses: MIT -│ └─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/client-only -├─ clsx@2.1.1 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/lukeed/clsx -│ ├─ publisher: Luke Edwards -│ ├─ email: luke.edwards05@gmail.com -│ ├─ url: https://lukeed.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/clsx -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/clsx/license -├─ csstype@3.2.3 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/frenic/csstype -│ ├─ publisher: Fredrik Nicol -│ ├─ email: fredrik.nicol@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/csstype -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/csstype/LICENSE -├─ decimal.js@10.6.0 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/MikeMcl/decimal.js -│ ├─ publisher: Michael Mclaughlin -│ ├─ email: M8ch88l@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/decimal.js -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/decimal.js/LICENCE.md -├─ dom-helpers@5.2.1 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/react-bootstrap/dom-helpers -│ ├─ publisher: Jason Quense -│ ├─ email: monastic.panic@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/dom-helpers -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/dom-helpers/LICENSE -├─ intl-messageformat@10.7.18 -│ ├─ licenses: BSD-3-Clause -│ ├─ repository: https://github.com/formatjs/formatjs -│ ├─ publisher: Eric Ferraiuolo -│ ├─ email: eferraiuolo@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/intl-messageformat -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/intl-messageformat/LICENSE.md -├─ js-tokens@4.0.0 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/lydell/js-tokens -│ ├─ publisher: Simon Lydell -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/js-tokens -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/js-tokens/LICENSE -├─ loose-envify@1.4.0 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/zertosh/loose-envify -│ ├─ publisher: Andres Suarez -│ ├─ email: zertosh@gmail.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/loose-envify -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/loose-envify/LICENSE -├─ object-assign@4.1.1 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/sindresorhus/object-assign -│ ├─ publisher: Sindre Sorhus -│ ├─ email: sindresorhus@gmail.com -│ ├─ url: sindresorhus.com -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/object-assign -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/object-assign/license -├─ prop-types@15.8.1 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/facebook/prop-types -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/prop-types -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/prop-types/LICENSE -├─ react-aria-components@1.16.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-aria-components -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-aria-components/LICENSE -├─ react-aria-components@1.17.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum/node_modules/react-aria-components -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/@adobe/react-spectrum/node_modules/react-aria-components/LICENSE -├─ react-aria@3.48.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-aria -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-aria/LICENSE -├─ react-dom@19.2.6 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/facebook/react -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-dom -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-dom/LICENSE -├─ react-is@16.13.1 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/facebook/react -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-is -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-is/LICENSE -├─ react-stately@3.46.0 -│ ├─ licenses: Apache-2.0 -│ ├─ repository: https://github.com/adobe/react-spectrum -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-stately -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-stately/LICENSE -├─ react-transition-group@4.4.5 -│ ├─ licenses: BSD-3-Clause -│ ├─ repository: https://github.com/reactjs/react-transition-group -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-transition-group -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react-transition-group/LICENSE -├─ react@19.2.6 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/facebook/react -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/react/LICENSE -├─ scheduler@0.27.0 -│ ├─ licenses: MIT -│ ├─ repository: https://github.com/facebook/react -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/scheduler -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/scheduler/LICENSE -├─ tslib@2.8.1 -│ ├─ licenses: 0BSD -│ ├─ repository: https://github.com/Microsoft/tslib -│ ├─ publisher: Microsoft Corp. -│ ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/tslib -│ └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/tslib/LICENSE.txt -└─ use-sync-external-store@1.6.0 - ├─ licenses: MIT - ├─ repository: https://github.com/facebook/react - ├─ path: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/use-sync-external-store - └─ licenseFile: /Users/vveenu/Documents/GitHub/queue-management/appointment-booking/node_modules/use-sync-external-store/LICENSE - diff --git a/appointment-booking/index.html b/appointment-booking/index.html index f3e7ef759..9f7a58db0 100644 --- a/appointment-booking/index.html +++ b/appointment-booking/index.html @@ -7,7 +7,7 @@ appointment-booking -
- +
+ diff --git a/appointment-booking/nginx.conf b/appointment-booking/nginx.conf new file mode 100644 index 000000000..40bfd5899 --- /dev/null +++ b/appointment-booking/nginx.conf @@ -0,0 +1,50 @@ +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /tmp/nginx.pid; + +events { + worker_connections 4096; +} + +http { + include /etc/nginx/mime.types; + client_body_temp_path /tmp/client_temp; + proxy_temp_path /tmp/proxy_temp_path; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + default_type application/octet-stream; + server_tokens off; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + + server { + listen 8080; + server_name _; + + add_header Strict-Transport-Security "max-age=31536000;"; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Content-Type-Options "nosniff"; + add_header X-Frame-Options "DENY"; + add_header Cache-Control "no-cache,no-store,must-revalidate"; + add_header Pragma "no-cache"; + + root /app; + index index.html; + error_log /dev/stdout info; + access_log /dev/stdout; + + location / { + try_files $uri $uri/ /index.html; + } + + location /nginx_status { + stub_status on; + allow all; + access_log off; + } + } +} diff --git a/appointment-booking/package.json b/appointment-booking/package.json index 941256440..0944c0690 100644 --- a/appointment-booking/package.json +++ b/appointment-booking/package.json @@ -4,19 +4,16 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "node server.js", - "dev:local": "API_PROXY_TARGET=http://localhost:5100 node server.js", - "build": "tsc -b && npm run build:client && npm run build:server", - "build:client": "vite build --outDir dist/client", - "build:server": "vite build --ssr src/entry-server.tsx --outDir dist/server", + "dev": "vite", + "dev:local": "API_PROXY_TARGET=http://localhost:5100 vite", + "build": "tsc -b && vite build", "test": "vitest run", "test:watch": "vitest", "lint": "eslint .", "format": "prettier --write src", "format:check": "prettier --check src", - "start": "NODE_ENV=production node server.js", "type-check": "tsc --noEmit", - "preview": "npm run start", + "preview": "vite preview", "license-check": "license-checker --production --onlyAllow \"MIT;Apache-2.0;ISC;BSD-2-Clause;BSD-3-Clause;0BSD\" --excludePackages \"appointment-booking@0.0.0;@bcgov/bc-sans@2.1.0\"", "ci:check": "npm run lint && npm run type-check && npm run test && npm run build && npm run license-check" }, diff --git a/appointment-booking/public/config/runtime-config.json b/appointment-booking/public/config/runtime-config.json new file mode 100644 index 000000000..69a036936 --- /dev/null +++ b/appointment-booking/public/config/runtime-config.json @@ -0,0 +1,4 @@ +{ + "apiBaseUrl": "http://localhost:5000/api/v1", + "requestTimeoutMs": 10000 +} diff --git a/appointment-booking/server.js b/appointment-booking/server.js deleted file mode 100644 index 34913e765..000000000 --- a/appointment-booking/server.js +++ /dev/null @@ -1,142 +0,0 @@ -import fs from 'node:fs/promises' -import http from 'node:http' -import path from 'node:path' -import { fileURLToPath, pathToFileURL } from 'node:url' - -const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const isProd = process.env.NODE_ENV === 'production' -const preferredPort = Number(process.env.PORT || 5173) -const fallbackPort = Number(process.env.FALLBACK_PORT || preferredPort + 1) - -let vite -if (!isProd) { - const { createServer } = await import('vite') - vite = await createServer({ - appType: 'custom', - root: __dirname, - server: { middlewareMode: true }, - }) -} - -const prodTemplate = isProd - ? await fs.readFile(path.resolve(__dirname, 'dist/client/index.html'), 'utf-8') - : '' - -const distClientDir = path.resolve(__dirname, 'dist/client') - -function send(res, statusCode, body, headers = {}) { - res.writeHead(statusCode, headers) - res.end(body) -} - -function getRuntimeConfig() { - return { - apiBaseUrl: process.env.API_BASE_URL || process.env.VITE_API_BASE_URL || '/api/v1', - requestTimeoutMs: Number(process.env.REQUEST_TIMEOUT_MS || 10000), - } -} - -async function renderPage(url, res) { - let template - let render - - if (!isProd) { - template = await fs.readFile(path.resolve(__dirname, 'index.html'), 'utf-8') - template = await vite.transformIndexHtml(url, template) - render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render - } else { - template = prodTemplate - render = (await import(pathToFileURL(path.resolve(__dirname, 'dist/server/entry-server.js')).href)).render - } - - const { appHtml } = await render(url) - const html = template.replace('', appHtml) - - send(res, 200, html, { 'Content-Type': 'text/html; charset=utf-8' }) -} - -async function tryServeStatic(urlPath, res) { - if (!isProd) { - return false - } - - const normalizedPath = decodeURIComponent(urlPath.split('?')[0]) - const requestedFile = normalizedPath === '/' ? '/index.html' : normalizedPath - const absolutePath = path.resolve(distClientDir, `.${requestedFile}`) - - if (!absolutePath.startsWith(distClientDir)) { - send(res, 403, 'Forbidden') - return true - } - - try { - const file = await fs.readFile(absolutePath) - const extension = path.extname(absolutePath) - const contentType = mimeTypes[extension] || 'application/octet-stream' - send(res, 200, file, { 'Content-Type': contentType }) - return true - } catch { - return false - } -} - -const server = http.createServer(async (req, res) => { - const url = req.url || '/' - - if (url.startsWith('/config/runtime-config.json')) { - send(res, 200, JSON.stringify(getRuntimeConfig()), { - 'Cache-Control': 'no-store', - 'Content-Type': 'application/json; charset=utf-8', - }) - return - } - - if (!isProd && vite) { - return vite.middlewares(req, res, async () => { - try { - await renderPage(url, res) - } catch (error) { - vite.ssrFixStacktrace(error) - send(res, 500, 'Internal Server Error') - } - }) - } - - try { - const served = await tryServeStatic(url, res) - if (served) { - return - } - - await renderPage(url, res) - } catch { - send(res, 500, 'Internal Server Error') - } -}) - -let isRetryingWithFallbackPort = false - -function startServer(onPort) { - server.listen(onPort, () => { - // Keep startup logging concise for local dev and container logs. - console.log(`SSR server running on http://localhost:${onPort}`) - }) -} - -server.on('error', (error) => { - if ( - error && - error.code === 'EADDRINUSE' && - !isRetryingWithFallbackPort && - preferredPort !== fallbackPort - ) { - isRetryingWithFallbackPort = true - console.warn(`Port ${preferredPort} is already in use. Falling back to ${fallbackPort}.`) - startServer(fallbackPort) - return - } - - throw error -}) - -startServer(preferredPort) \ No newline at end of file diff --git a/appointment-booking/src/assets/img/gov3_bc_logo.png b/appointment-booking/src/assets/img/gov3_bc_logo.png deleted file mode 100644 index 08a9f2168..000000000 Binary files a/appointment-booking/src/assets/img/gov3_bc_logo.png and /dev/null differ diff --git a/appointment-booking/src/assets/img/gov3_bc_logo_mobile.png b/appointment-booking/src/assets/img/gov3_bc_logo_mobile.png deleted file mode 100644 index 262b7e8ea..000000000 Binary files a/appointment-booking/src/assets/img/gov3_bc_logo_mobile.png and /dev/null differ diff --git a/appointment-booking/src/components/common/Layout.tsx b/appointment-booking/src/components/common/Layout.tsx index 6001a5dc2..f6187dbac 100644 --- a/appointment-booking/src/components/common/Layout.tsx +++ b/appointment-booking/src/components/common/Layout.tsx @@ -1,8 +1,8 @@ import { Footer, Header } from '@bcgov/design-system-react-components' -import React from 'react' +import type { ReactNode } from 'react' interface LayoutProps { - children: React.ReactNode + children: ReactNode } export function Layout({ children }: LayoutProps) { diff --git a/appointment-booking/src/components/common/Page.tsx b/appointment-booking/src/components/common/Page.tsx index e668a60b7..14a2cd12d 100644 --- a/appointment-booking/src/components/common/Page.tsx +++ b/appointment-booking/src/components/common/Page.tsx @@ -1,8 +1,8 @@ -import React from 'react' +import type { ReactNode } from 'react' interface PageProps { title: string - children: React.ReactNode + children: ReactNode } export function Page({ title, children }: PageProps) { diff --git a/appointment-booking/src/entry-server.tsx b/appointment-booking/src/entry-server.tsx deleted file mode 100644 index 3d919428f..000000000 --- a/appointment-booking/src/entry-server.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { StrictMode } from 'react' -import { renderToString } from 'react-dom/server' -import App from './App' - -export function render(url: string) { - void url - - const appHtml = renderToString( - - - , - ) - - return { appHtml } -} diff --git a/appointment-booking/src/entry-client.tsx b/appointment-booking/src/main.tsx similarity index 68% rename from appointment-booking/src/entry-client.tsx rename to appointment-booking/src/main.tsx index ef8d2b9ee..43168c1bb 100644 --- a/appointment-booking/src/entry-client.tsx +++ b/appointment-booking/src/main.tsx @@ -1,12 +1,11 @@ import '@bcgov/design-tokens/css/variables.css' import '@bcgov/bc-sans/css/BC_Sans.css' import { StrictMode } from 'react' -import { hydrateRoot } from 'react-dom/client' +import { createRoot } from 'react-dom/client' import './index.css' import App from './App' -hydrateRoot( - document.getElementById('app')!, +createRoot(document.getElementById('app')!).render( , diff --git a/compose.yaml b/compose.yaml index a5c474004..6ef7cb034 100644 --- a/compose.yaml +++ b/compose.yaml @@ -42,10 +42,12 @@ services: timeout: 5s retries: 10 start_period: 5s - image: postgres:16.2 + image: postgres:16 restart: unless-stopped volumes: - postgres-data:/var/lib/postgresql/data + ports: + - "5432:5432" x11: environment: @@ -86,6 +88,13 @@ services: volumes: - ./keycloak-local:/opt/keycloak/data/import:ro + appointment-booking: + build: + context: ./appointment-booking + dockerfile: Dockerfile + ports: + - "5173:8080" + api: profiles: - api