diff --git a/src/lib/components/PlaceCard.svelte b/src/lib/components/PlaceCard.svelte
index 450762f..064bfbc 100644
--- a/src/lib/components/PlaceCard.svelte
+++ b/src/lib/components/PlaceCard.svelte
@@ -83,9 +83,9 @@
{#if fullPlace.desc}
{fullPlace.desc}
{/if}
-
+
{/if}
@@ -236,7 +236,7 @@
font-size: 0.9rem;
}
- .edit-time {
+ /* .edit-time {
background-color: var(--gray-200);
border: none;
padding: 0.5rem 1rem;
@@ -249,5 +249,5 @@
.edit-time:hover {
opacity: 0.75;
- }
+ } */
\ No newline at end of file
diff --git a/src/lib/components/WorldMap.svelte b/src/lib/components/WorldMap.svelte
index fdfbc50..7a764be 100644
--- a/src/lib/components/WorldMap.svelte
+++ b/src/lib/components/WorldMap.svelte
@@ -4,38 +4,91 @@
import { feature } from 'topojson-client';
import { Colors } from '../constants/Colors';
import '../../app.css';
+ import { ref, get } from 'firebase/database';
+ import { db } from '../../firebase';
let mapContainer: HTMLDivElement;
+ interface TripLocation {
+ name: string;
+ location: {
+ lat: number;
+ lng: number;
+ };
+ }
+
+ async function getPastTripLocations(): Promise {
+ try {
+ const tripsRef = ref(db, 'trips');
+ const snapshot = await get(tripsRef);
+
+ if (!snapshot.exists()) return [];
+
+ // Get today's date at midnight for comparison
+ const today = new Date();
+ today.setHours(0, 0, 0, 0);
+
+ // Create a Set to store unique locations
+ const uniqueLocations = new Map();
+
+ // Filter past trips and extract unique destinations
+ Object.values(snapshot.val()).forEach((trip: any) => {
+ const endDate = new Date(trip.endDate);
+ if (endDate < today && trip.destination?.location) {
+ const locationKey = `${trip.destination.location.lat},${trip.destination.location.lng}`;
+ if (!uniqueLocations.has(locationKey)) {
+ uniqueLocations.set(locationKey, {
+ name: trip.destination.name,
+ location: trip.destination.location
+ });
+ }
+ }
+ });
+
+ return Array.from(uniqueLocations.values());
+ } catch (error) {
+ console.error('Error fetching past trips:', error);
+ return [];
+ }
+ }
+
+ let cleanup: (() => void) | undefined;
+
onMount(() => {
- const width = mapContainer.clientWidth;
- const height = mapContainer.clientHeight;
+ let mounted = true;
- // Create SVG
- const svg = d3.select(mapContainer)
- .append('svg')
- .attr('width', '100%')
- .attr('height', '100%')
- .attr('viewBox', `0 0 ${width} ${height}`) // make a coordinate from (0, 0) to (width, height)
- .attr('preserveAspectRatio', 'xMidYMid meet') as d3.Selection; // center the map
+ async function initMap() {
+ if (!mounted) return;
- // Add a group for all map elements that will be transformed
- const g = svg.append('g');
+ const width = mapContainer.clientWidth;
+ const height = mapContainer.clientHeight;
- // Create projection
- const projection = d3.geoMercator()
- .scale(width / (2 * Math.PI))
- .translate([width / 2, height / 1.6]); // position the map, horizontally centered but is slighty upward
+ // Create SVG
+ const svg = d3.select(mapContainer)
+ .append('svg')
+ .attr('width', '100%')
+ .attr('height', '100%')
+ .attr('viewBox', `0 0 ${width} ${height}`)
+ .attr('preserveAspectRatio', 'xMidYMid meet') as d3.Selection;
- const path = d3.geoPath().projection(projection);
+ // Add a group for all map elements that will be transformed
+ const g = svg.append('g');
- // Tokyo coordinates [longitude, latitude]
- const tokyo: [number, number] = [139.6917, 35.6895];
+ // Create projection
+ const projection = d3.geoMercator()
+ .scale(width / (2 * Math.PI))
+ .translate([width / 2, height / 1.6]); // position the map, horizontally centered but is slighty upward
+
+ const path = d3.geoPath().projection(projection);
- const initMap = async () => {
try {
+ // Get past trip locations
+ const pastLocations = await getPastTripLocations();
+ if (!mounted) return;
+
// Load world map data
const response = await fetch('https://unpkg.com/world-atlas@2/countries-110m.json');
+ if (!mounted) return;
const world = await response.json();
// Convert TopoJSON to GeoJSON
@@ -53,13 +106,16 @@
.attr('stroke', Colors.gray.light50)
.attr('stroke-width', '0.5');
- // Add Tokyo marker
- g.append('circle')
- .attr('cx', projection(tokyo)![0])
- .attr('cy', projection(tokyo)![1])
+ // Add markers for past trip locations
+ g.selectAll('circle')
+ .data(pastLocations)
+ .enter()
+ .append('circle')
+ .attr('cx', d => projection([d.location.lng, d.location.lat])![0])
+ .attr('cy', d => projection([d.location.lng, d.location.lat])![1])
.attr('r', 5)
.attr('class', 'marker')
- .attr('fill', Colors.planner.med400);
+ .attr('fill', Colors.planner.med400)
// Add zoom behavior
const zoom = d3.zoom()
@@ -70,16 +126,20 @@
svg.call(zoom)
.call(zoom.transform, d3.zoomIdentity);
+
} catch (error) {
- console.error('Error loading map:', error);
+ console.error('Error initializing map:', error);
}
- };
+ }
initMap();
- return () => {
+ cleanup = () => {
+ mounted = false;
d3.select(mapContainer).selectAll('*').remove();
};
+
+ return cleanup;
});
diff --git a/src/routes/itinerary/[tid]/+page.svelte b/src/routes/itinerary/[tid]/+page.svelte
index 8e0d9f0..caf38b8 100644
--- a/src/routes/itinerary/[tid]/+page.svelte
+++ b/src/routes/itinerary/[tid]/+page.svelte
@@ -259,7 +259,7 @@
tripDates = dates;
// initialize expanded states for dates
- expandedDates = Object.fromEntries(dates.map(date => [date, false]));
+ expandedDates = Object.fromEntries(dates.map(date => [date, true]));
// initialize placesToVisit from database or empty array
placesToVisit = tripData.placesToVisit || [];