{"id":21106600,"url":"https://github.com/joeclos/hsl","last_synced_at":"2026-04-12T12:35:02.233Z","repository":{"id":157939954,"uuid":"616840190","full_name":"JoeClos/hsl","owner":"JoeClos","description":"App that displays journeys made with city bike in the Helsinki Capital area.","archived":false,"fork":false,"pushed_at":"2025-09-02T08:16:54.000Z","size":1232,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-01T10:42:47.134Z","etag":null,"topics":["express","mongodb","mui","node-js","reactjs"],"latest_commit_sha":null,"homepage":"https://hsl-ui.netlify.app/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JoeClos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-03-21T07:33:32.000Z","updated_at":"2025-09-02T08:16:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"2cc7e66a-d4a9-4204-b754-39f7930ef9ad","html_url":"https://github.com/JoeClos/hsl","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JoeClos/hsl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoeClos%2Fhsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoeClos%2Fhsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoeClos%2Fhsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoeClos%2Fhsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JoeClos","download_url":"https://codeload.github.com/JoeClos/hsl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoeClos%2Fhsl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31715492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T06:22:27.080Z","status":"ssl_error","status_checked_at":"2026-04-12T06:21:52.710Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","mongodb","mui","node-js","reactjs"],"created_at":"2024-11-20T00:27:34.222Z","updated_at":"2026-04-12T12:35:02.198Z","avatar_url":"https://github.com/JoeClos.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Helsinki City Bikes\n\nA friendly, responsive web app for exploring city bike **stations** and **journeys** in the Helsinki Capital area.\n\n\u003e This started as Solita’s [Dev Academy pre-assignment](https://github.com/solita/dev-academy-2023-exercise) and grew into a hobby project.    \n\u003e Live demo: **[HCB – Helsinki City Bikes](https://hsl-ui.netlify.app)**\n\n## 📸 Preview\n\n| Desktop View | Mobile View |\n| :---: | :---: |\n| ![Desktop](https://github.com/user-attachments/assets/3d75823a-77a5-4215-9b65-781d198818b0) | ![Mobile](https://github.com/user-attachments/assets/4e1eb096-8876-4174-8b74-5ac81776f74d) |\n\n---\n\n## Why this refactor?\n\nI rebuilt the app to make it **faster**, **easier to work on**, and **better on mobile**.\n\n### The big changes\n- **From CRA to Vite (React + Vite)**\n  - Vite starts the dev server almost instantly and produces smaller builds.\n  - New scripts:\n    - `npm run dev` – start the app in development\n    - `npm run build` – create a production build\n    - `npm run preview` – preview the production build locally\n\n- **Mobile-first, responsive UI**\n  - Works great on phones: bottom navigation, modal details, readable lists.\n  - Desktop gets tables, side-by-side layouts, and more screen real estate.\n  - The map renders reliably on all screen sizes.\n\n- **Clear project structure**\n  - Reusable components live in `src/components/`\n  - Screens live in `src/pages/`\n  - API helpers live in `src/service/`\n  - Easier to find things, easier to extend.\n\n- **Quality-of-life improvements**\n  - Consistent toasts for success/error messages.\n  - Modernized MUI usage (e.g., Grid v2, updated TextField API).\n  - Sorting, searching, pagination across lists.\n\n---\n\n\n## What you can do in the app\n\n- **Home:** Explore stations on an interactive map (with clustering).\n- **Journeys:** Browse trips with sorting (by Departure, Return, Distance, Duration) and pagination.\n- **Stations:** Search and browse stations with pagination and sorting.\n- **Single Station:** See details, a map pin, and totals of journeys from/to that station.\n- **Add Station:** Submit a new station with real-time validation and clear feedback.\n\n---\n\n\n## Tech Stack\n\n**UI**\n- React 18\n- Vite\n- Material UI (MUI)\n- React Leaflet (+ Marker Cluster)\n\n**API / DB**\n- Node.js + Express\n- MongoDB + Mongoose\n\n---\n\n## Data Sources\n\n**Journeys**\n- May–July 2021 trips:\n  - https://dev.hsl.fi/citybikes/od-trips-2021/2021-05.csv  \n  - https://dev.hsl.fi/citybikes/od-trips-2021/2021-06.csv  \n  - https://dev.hsl.fi/citybikes/od-trips-2021/2021-07.csv  \n\n**Stations**\n- https://opendata.arcgis.com/datasets/726277c507ef4914b0aec3cbcfcbfafc_0.csv\n\n**Import constraints**\n- Only journeys with `duration \u003e 10s` and `covered_distance \u003e 10m`\n- Skip journeys with undefined/null station ids\n- UI fetches up to `5000` journeys (client-side pagination)\n\n---\n\n\n- **State management**: React hooks (`useState`, `useEffect`, `useMemo`) — no external state lib.\n- **API layer**: Single axios instance; pages call `service/api` helpers.\n- **UI patterns**: Tables on desktop; card lists on mobile; consistent spacing/typography via MUI.\n\n---\n\n## Local Development\n\n\u003e Requires **Node 18+** (Vite 5 needs Node ≥ 18).\n\n### 1) Clone + install\n\n```bash\n# UI\ncd hsl/hsl-client\nnpm install\n\n# Server\ncd hsl/hsl-server\nnpm install\n````\n\n### 2) Run\n\n```bash\n# UI (Vite)\ncd hsl-client\nnpm run dev                 # http://localhost:5173\n\n# Server (Express)\ncd hsl-server\nnodemon app.js          # http://localhost:8000\n```\n\n## API Quick Reference\n\n### GET `/journeys`\n**Query params**\n- `limit` — max items to return (default: 5000)\n- `page` — page index starting at 1 (used with `limit`)\n- `display` — `list` (default) or `count`\n- `departureStationId` — filter by departure station id\n- `returnStationId` — filter by return station id\n\n**Server-side filters**\n- `duration \u003e 10` seconds  \n- `covered_distance \u003e 10` meters\n\n**Examples**\n```http\nGET /journeys?limit=5000\u0026page=1\nGET /journeys?display=count\u0026departureStationId=501\nGET /journeys?display=count\u0026returnStationId=501\n```\n\n### GET `/stations`\n```http\nGET /stations\n```\n\n### GET `/stations/:id`\n```http\nGET /stations/501\n```\n\n### POST `/addStation`\nCreate a new station.\n\n```json\n{\n  \"fid\": 123,\n  \"id\": 501,\n  \"nimi\": \"Kamppi (fi)\",\n  \"namn\": \"Kampen (sv)\",\n  \"name\": \"Kamppi (en)\",\n  \"osoite\": \"Urho Kekkosen katu 1\",\n  \"address\": \"Urho Kekkosen St 1\",\n  \"kaupunki\": \"Helsinki\",\n  \"stad\": \"Helsingfors\",\n  \"operaattor\": \"CityBike Finland\",\n  \"kapasiteet\": 28,\n  \"x\": 24.931,\n  \"y\": 60.170\n}\n```\n---\n\n\n## Final notes\n\n- This project is a learning playground—it began as an assignment and evolved into a hobby refactor focused on speed (Vite), structure (clear folders), and accessibility/responsiveness.\n- There’s room for more (date filters, server-side paging, maps for journeys, etc.). PRs and ideas welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoeclos%2Fhsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoeclos%2Fhsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoeclos%2Fhsl/lists"}