From e314a4f2b3c3ea295284bf520e9fe06d7641a76d Mon Sep 17 00:00:00 2001 From: Yosuke Inoue <24513446@student.uwa.edu.au> Date: Tue, 17 Feb 2026 16:39:34 +0000 Subject: [PATCH 1/3] display map by using openstreetmap --- client/package-lock.json | 51 ++++++++++++++++++ client/package.json | 3 ++ client/public/leaflet/marker-icon-2x.png | Bin 0 -> 2464 bytes client/public/leaflet/marker-icon.png | Bin 0 -> 1466 bytes client/public/leaflet/marker-shadow.png | Bin 0 -> 618 bytes client/src/components/map/EventMap.tsx | 43 +++++++++++++++ client/src/components/map/osm.ts | 28 ++++++++++ client/src/hooks/useEvent.ts | 1 + client/src/pages/_app.tsx | 1 + client/src/pages/events/[id].tsx | 17 ++++++ .../0010_event_openstreetmap_url.py | 18 +++++++ server/game_dev/models.py | 16 ++++-- server/game_dev/serializers.py | 16 ++++-- 13 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 client/public/leaflet/marker-icon-2x.png create mode 100644 client/public/leaflet/marker-icon.png create mode 100644 client/public/leaflet/marker-shadow.png create mode 100644 client/src/components/map/EventMap.tsx create mode 100644 client/src/components/map/osm.ts create mode 100644 server/game_dev/migrations/0010_event_openstreetmap_url.py diff --git a/client/package-lock.json b/client/package-lock.json index 98daa111..3409ed81 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -17,10 +17,12 @@ "clsx": "^2.1.1", "framer-motion": "^12.23.24", "is-inside-container": "^1.0.0", + "leaflet": "^1.9.4", "lucide-react": "^0.516.0", "next": "15.4.10", "react": "19.1.0", "react-dom": "19.1.0", + "react-leaflet": "^5.0.0", "react-social-icons": "^6.25.0", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7" @@ -31,6 +33,7 @@ "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.29.0", "@tanstack/eslint-plugin-query": "^5.78.0", + "@types/leaflet": "^1.9.21", "@types/node": "^24.0.3", "@types/react": "19.1.8", "@types/react-dom": "19.1.6", @@ -1329,6 +1332,17 @@ } } }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1429,6 +1443,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1443,6 +1464,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/leaflet": { + "version": "1.9.21", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", + "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/node": { "version": "24.0.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz", @@ -4694,6 +4725,12 @@ "node": ">=0.10" } }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5799,6 +5836,20 @@ "dev": true, "license": "MIT" }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, "node_modules/react-social-icons": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/react-social-icons/-/react-social-icons-6.25.0.tgz", diff --git a/client/package.json b/client/package.json index 0e4b8880..72ee2685 100644 --- a/client/package.json +++ b/client/package.json @@ -27,10 +27,12 @@ "clsx": "^2.1.1", "framer-motion": "^12.23.24", "is-inside-container": "^1.0.0", + "leaflet": "^1.9.4", "lucide-react": "^0.516.0", "next": "15.4.10", "react": "19.1.0", "react-dom": "19.1.0", + "react-leaflet": "^5.0.0", "react-social-icons": "^6.25.0", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7" @@ -41,6 +43,7 @@ "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.29.0", "@tanstack/eslint-plugin-query": "^5.78.0", + "@types/leaflet": "^1.9.21", "@types/node": "^24.0.3", "@types/react": "19.1.8", "@types/react-dom": "19.1.6", diff --git a/client/public/leaflet/marker-icon-2x.png b/client/public/leaflet/marker-icon-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88f9e501888c9c6cb29ad340d9a888627dd1b6d8 GIT binary patch literal 2464 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 e-I|>x8~*?ZhF3snGbtJX0000cOl4 literal 0 HcmV?d00001 diff --git a/client/public/leaflet/marker-icon.png b/client/public/leaflet/marker-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..950edf24677ded147df13b26f91baa2b0fa70513 GIT binary patch literal 1466 zcmV;r1x5OaP)P001cn1^@s6z>|W`000GnNklGNuHDcIX17Zdjl&3`L?0sTjIws<{((Dh&g-s0<@jYQyl?D*X^?%13;ml^gy> ziMrY_^1WI=(g@LMizu=zCoA>C`6|QEq1eV92k*7m>G65*&@&6)aC&e}G zI)pf-Za|N`DT&Cn1J|o`19mumxW~hiKiKyc-P`S@q)rdTo84@QI@;0yXrG%9uhI>A zG5QHb6s4=<6xy{1 z@NMxEkryp{LS44%z$3lP^cX!9+2-;CTt3wM4(k*#C{aiIiLuB>jJj;KPhPzIC00bL zU3a#;aJld94lCW=`4&aAy8M7PY=HQ>O%$YEP4c4UY#CRxfgbE~(|uiI=YS8q;O9y6 zmIkXzR`}p7ti|PrM3a}WMnR=3NVnWdAAR>b9X@)DKL6=YsvmH%?I24wdq?Gh54_;# z$?_LvgjEdspdQlft#4CQ z`2Zyvy?*)N1Ftw|{_hakhG9WjS?Az@I@+IZ8JbWewR!XUK4&6346+d#~gsE0SY(LX8&JfY>Aj)RxGy96nwhs2rv zzW6pTnMpFkDSkT*a*6Dx|u@ds6ISVn0@^RmIsKZ5Y;bazbc;tTSq(kg(=481ODrPyNB6n z-$+U}(w$m6U6H$w17Bw+wDaFIe~GvNMYvnw31MpY0eQKT9l>SU``8k7w4)z!GZKMI z#_cEKq7k~i%nlK@6c-K?+R;B#5$?T#YpKD`t_4bAs^#E+@5QW$@OX3*`;(#{U^d-vY)&xEE>n5lYl&T?Amke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7sOnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{ zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/client/src/components/map/EventMap.tsx b/client/src/components/map/EventMap.tsx new file mode 100644 index 00000000..0e0aac5a --- /dev/null +++ b/client/src/components/map/EventMap.tsx @@ -0,0 +1,43 @@ +import "leaflet/dist/leaflet.css"; + +import L from "leaflet"; +import { MapContainer, Marker, Popup,TileLayer } from "react-leaflet"; + +const iconProto = L.Icon.Default.prototype as unknown as { + _getIconUrl?: unknown; +}; + +delete iconProto._getIconUrl; + +L.Icon.Default.mergeOptions({ + iconRetinaUrl: "/leaflet/marker-icon-2x.png", + iconUrl: "/leaflet/marker-icon.png", + shadowUrl: "/leaflet/marker-shadow.png", +}); + +type Props = { + lat: number; + lon: number; + name?: string; +}; + +export default function EventMap({ lat, lon, name }: Props) { + return ( +
+ + + + {name ?? "Event location"} + + +
+ ); +} diff --git a/client/src/components/map/osm.ts b/client/src/components/map/osm.ts new file mode 100644 index 00000000..a70f8cc4 --- /dev/null +++ b/client/src/components/map/osm.ts @@ -0,0 +1,28 @@ +export function parseOpenStreetMapUrl( + osmUrl: string, +): { lat: number; lon: number } | null { + try { + const url = new URL(osmUrl); + + // Pattern 1: ?mlat=..&mlon=.. + const mlat = url.searchParams.get("mlat"); + const mlon = url.searchParams.get("mlon"); + if (mlat && mlon) { + const lat = Number(mlat); + const lon = Number(mlon); + if (Number.isFinite(lat) && Number.isFinite(lon)) return { lat, lon }; + } + + // Pattern 2: #map=zoom/lat/lon + const match = url.hash.match(/#map=\d+\/(-?\d+(\.\d+)?)\/(-?\d+(\.\d+)?)/); + if (match) { + const lat = Number(match[1]); + const lon = Number(match[3]); + if (Number.isFinite(lat) && Number.isFinite(lon)) return { lat, lon }; + } + + return null; + } catch { + return null; + } +} diff --git a/client/src/hooks/useEvent.ts b/client/src/hooks/useEvent.ts index 27794c6b..10d48547 100644 --- a/client/src/hooks/useEvent.ts +++ b/client/src/hooks/useEvent.ts @@ -12,6 +12,7 @@ type ApiEvent = { startTime: string | null; location: string; cover_image: string | null; + openstreetmap_url: string | null; }; type UiEvent = Omit & { diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx index ca3770d2..e1e19af9 100644 --- a/client/src/pages/_app.tsx +++ b/client/src/pages/_app.tsx @@ -1,4 +1,5 @@ import "@/styles/globals.css"; +import "leaflet/dist/leaflet.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; diff --git a/client/src/pages/events/[id].tsx b/client/src/pages/events/[id].tsx index 8e8d8803..be475e91 100644 --- a/client/src/pages/events/[id].tsx +++ b/client/src/pages/events/[id].tsx @@ -1,8 +1,14 @@ +import dynamic from "next/dynamic"; import Image from "next/image"; import { useRouter } from "next/router"; +import { parseOpenStreetMapUrl } from "@/components/map/osm"; import { useEvent } from "@/hooks/useEvent"; +const EventMap = dynamic(() => import("@/components/map/EventMap"), { + ssr: false, +}); + function formatDateTime(dateString: string): string { try { const date = new Date(dateString); @@ -59,6 +65,9 @@ export default function EventPage() { ); } + const coords = event.openstreetmap_url + ? parseOpenStreetMapUrl(event.openstreetmap_url) + : null; return (
@@ -89,6 +98,14 @@ export default function EventPage() { /> + {coords && ( +
+
+ +
+ + )}
); } diff --git a/server/game_dev/migrations/0010_event_openstreetmap_url.py b/server/game_dev/migrations/0010_event_openstreetmap_url.py new file mode 100644 index 00000000..f0a52b48 --- /dev/null +++ b/server/game_dev/migrations/0010_event_openstreetmap_url.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.14 on 2026-02-16 09:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("game_dev", "0009_merge_20260131_1044"), + ] + + operations = [ + migrations.AddField( + model_name="event", + name="openstreetmap_url", + field=models.URLField(blank=True, max_length=500), + ), + ] diff --git a/server/game_dev/models.py b/server/game_dev/models.py index 8b81b7bd..4c12bac2 100644 --- a/server/game_dev/models.py +++ b/server/game_dev/models.py @@ -4,7 +4,8 @@ class Member(models.Model): name = models.CharField(max_length=200) active = models.BooleanField(default=True) - profile_picture = models.ImageField(upload_to="profiles/", null=True, blank=True) + profile_picture = models.ImageField( + upload_to="profiles/", null=True, blank=True) about = models.CharField(max_length=256, blank=True) pronouns = models.CharField(max_length=20, blank=True) @@ -19,6 +20,7 @@ class Event(models.Model): publicationDate = models.DateField() cover_image = models.ImageField(upload_to="events/", null=True) location = models.CharField(max_length=256) + openstreetmap_url = models.URLField(max_length=500, blank=True) def __str__(self): return self.name @@ -26,8 +28,10 @@ def __str__(self): # GameContributor table: links Game, Member, and role (composite PK) class GameContributor(models.Model): - game = models.ForeignKey('Game', on_delete=models.CASCADE, related_name='game_contributors') - member = models.ForeignKey('Member', on_delete=models.CASCADE, related_name='member_games') + game = models.ForeignKey( + 'Game', on_delete=models.CASCADE, related_name='game_contributors') + member = models.ForeignKey( + 'Member', on_delete=models.CASCADE, related_name='member_games') role = models.CharField(max_length=100) class Meta: @@ -62,14 +66,16 @@ class CompletionStatus(models.IntegerChoices): ) thumbnail = models.ImageField(upload_to="games/", null=True) - event = models.ForeignKey(Event, on_delete=models.SET_NULL, null=True, blank=True) + event = models.ForeignKey( + Event, on_delete=models.SET_NULL, null=True, blank=True) def __str__(self): return str(self.name) class GameShowcase(models.Model): - game = models.ForeignKey('Game', on_delete=models.CASCADE, related_name='game_showcases') + game = models.ForeignKey( + 'Game', on_delete=models.CASCADE, related_name='game_showcases') description = models.TextField() def __str__(self): diff --git a/server/game_dev/serializers.py b/server/game_dev/serializers.py index a9e5c811..c4b66014 100644 --- a/server/game_dev/serializers.py +++ b/server/game_dev/serializers.py @@ -13,12 +13,14 @@ class Meta: "publicationDate", "cover_image", "location", + "openstreetmap_url", ] # This is child serializer of GameSerializer class GameContributorSerializer(serializers.ModelSerializer): - member_id = serializers.IntegerField(source="member.id") # to link contributors to their member/[id] page + # to link contributors to their member/[id] page + member_id = serializers.IntegerField(source="member.id") name = serializers.CharField(source="member.name") class Meta: @@ -35,7 +37,8 @@ class GamesSerializer(serializers.ModelSerializer): class Meta: model = Game - fields = ('id', 'name', 'description', 'completion', 'active', 'hostURL', 'itchEmbedID', 'thumbnail', 'event', "contributors") + fields = ('id', 'name', 'description', 'completion', 'active', + 'hostURL', 'itchEmbedID', 'thumbnail', 'event', "contributors") # Contributor serializer for name and role @@ -54,13 +57,16 @@ class Meta: class GameshowcaseSerializer(serializers.ModelSerializer): game_id = serializers.IntegerField(source='game.id', read_only=True) game_name = serializers.CharField(source='game.name', read_only=True) - game_description = serializers.CharField(source='game.description', read_only=True) - game_cover_thumbnail = serializers.ImageField(source='game.thumbnail', read_only=True) + game_description = serializers.CharField( + source='game.description', read_only=True) + game_cover_thumbnail = serializers.ImageField( + source='game.thumbnail', read_only=True) contributors = serializers.SerializerMethodField() class Meta: model = GameShowcase - fields = ('game_id', 'game_name', 'game_description', 'description', 'contributors', 'game_cover_thumbnail') + fields = ('game_id', 'game_name', 'game_description', + 'description', 'contributors', 'game_cover_thumbnail') def get_contributors(self, obj): # Always fetch contributors from GameContributor for the related game From 28c1923d6e560b2d8c49cdc4a3eea4c7b8e51559 Mon Sep 17 00:00:00 2001 From: Yosuke Inoue <24513446@student.uwa.edu.au> Date: Tue, 17 Feb 2026 17:02:03 +0000 Subject: [PATCH 2/3] create marge file for migration --- .../game_dev/migrations/0014_merge_20260218_0101.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 server/game_dev/migrations/0014_merge_20260218_0101.py diff --git a/server/game_dev/migrations/0014_merge_20260218_0101.py b/server/game_dev/migrations/0014_merge_20260218_0101.py new file mode 100644 index 00000000..979db69f --- /dev/null +++ b/server/game_dev/migrations/0014_merge_20260218_0101.py @@ -0,0 +1,13 @@ +# Generated by Django 5.1.14 on 2026-02-17 17:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("game_dev", "0010_event_openstreetmap_url"), + ("game_dev", "0013_merge_20260214_1347"), + ] + + operations = [] From eaa88840182c54c5fd23e62aa9c9800deb1b8811 Mon Sep 17 00:00:00 2001 From: Yosuke Inoue <24513446@student.uwa.edu.au> Date: Tue, 17 Feb 2026 17:11:05 +0000 Subject: [PATCH 3/3] fixed prettier error --- client/src/components/map/EventMap.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/map/EventMap.tsx b/client/src/components/map/EventMap.tsx index 0e0aac5a..add6dfb4 100644 --- a/client/src/components/map/EventMap.tsx +++ b/client/src/components/map/EventMap.tsx @@ -1,7 +1,7 @@ import "leaflet/dist/leaflet.css"; import L from "leaflet"; -import { MapContainer, Marker, Popup,TileLayer } from "react-leaflet"; +import { MapContainer, Marker, Popup, TileLayer } from "react-leaflet"; const iconProto = L.Icon.Default.prototype as unknown as { _getIconUrl?: unknown;