11'use client'
22
3+ import { useState } from 'react'
34import { X , ExternalLink , Circle } from 'lucide-react'
45
56interface GoogleGuideProps {
67 isOpen : boolean
78 onClose : ( ) => void
89}
910
10- const steps = [
11+ const methods = [
1112 {
12- number : 1 ,
13- title : 'Go to Google Takeout' ,
14- items : [
15- 'Visit takeout.google.com' ,
16- 'Deselect all, then select only "Location History"' ,
13+ label : 'From your phone (recommended)' ,
14+ steps : [
15+ {
16+ number : 1 ,
17+ title : 'Open Google Maps' ,
18+ items : [
19+ 'Tap your profile picture' ,
20+ 'Go to "Your Timeline"' ,
21+ ] ,
22+ } ,
23+ {
24+ number : 2 ,
25+ title : 'Export your data' ,
26+ items : [
27+ 'Tap ⋮ (more) → Settings → Export Timeline data' ,
28+ 'This downloads a location-history.json file' ,
29+ ] ,
30+ } ,
31+ {
32+ number : 3 ,
33+ title : 'Upload to Travelback' ,
34+ items : [
35+ 'Drop the JSON file here' ,
36+ 'Use the timeline slider to select a date range' ,
37+ ] ,
38+ } ,
1739 ] ,
18- action : {
19- label : 'Open Google Takeout' ,
20- href : 'https://takeout.google.com' ,
21- } ,
2240 } ,
2341 {
24- number : 2 ,
25- title : 'Choose export settings' ,
26- items : [
27- 'Select JSON format' ,
28- 'Choose "Export once"' ,
29- 'Click "Create export"' ,
30- ] ,
31- } ,
32- {
33- number : 3 ,
34- title : 'Download & extract' ,
35- items : [
36- 'Wait for the email from Google' ,
37- 'Download the zip file' ,
38- 'Extract and find "Records.json" or "Location History.json"' ,
39- ] ,
40- } ,
41- {
42- number : 4 ,
43- title : 'Upload to Travelback' ,
44- items : [
45- 'Drop the JSON file into Travelback' ,
46- 'Use the timeline slider to select a date range' ,
47- 'Play and export your journey!' ,
42+ label : 'From Google Takeout' ,
43+ steps : [
44+ {
45+ number : 1 ,
46+ title : 'Go to Google Takeout' ,
47+ items : [
48+ 'Visit takeout.google.com' ,
49+ 'Deselect all, then select "Location History"' ,
50+ ] ,
51+ action : {
52+ label : 'Open Google Takeout' ,
53+ href : 'https://takeout.google.com' ,
54+ } ,
55+ } ,
56+ {
57+ number : 2 ,
58+ title : 'Download & extract' ,
59+ items : [
60+ 'Create export → wait for email → download zip' ,
61+ 'Any of these files work: Records.json, Timeline Edits.json, or monthly Semantic Location History files (e.g. 2024_JANUARY.json)' ,
62+ ] ,
63+ } ,
64+ {
65+ number : 3 ,
66+ title : 'Upload to Travelback' ,
67+ items : [
68+ 'Drop any of the JSON files here' ,
69+ 'Use the timeline slider to select a date range' ,
70+ ] ,
71+ } ,
4872 ] ,
4973 } ,
5074]
5175
5276const tips = [
77+ 'Since 2024, Google stores Timeline data on-device — phone export usually has the most complete data' ,
5378 'Large files (100MB+) may take a moment to parse' ,
5479 'Use the timeline selector to zoom into specific trips' ,
55- 'Google Location History updates may be delayed' ,
5680]
5781
5882export default function GoogleGuide ( { isOpen, onClose } : GoogleGuideProps ) {
83+ const [ tab , setTab ] = useState ( 0 )
84+
5985 if ( ! isOpen ) return null
6086
87+ const active = methods [ tab ]
88+
6189 return (
6290 < div
6391 className = "absolute inset-0 z-20 flex items-center justify-center"
@@ -69,7 +97,7 @@ export default function GoogleGuide({ isOpen, onClose }: GoogleGuideProps) {
6997 < div className = "flex items-center justify-between px-5 py-4 pb-3 sticky top-0 z-10"
7098 style = { { background : 'inherit' , borderRadius : 'var(--r-glass) var(--r-glass) 0 0' } } >
7199 < h3 className = "text-lg font-bold" style = { { color : 'var(--t1)' } } >
72- Export Google Location History
100+ Export Google Timeline
73101 </ h3 >
74102 < button
75103 onClick = { onClose }
@@ -81,20 +109,34 @@ export default function GoogleGuide({ isOpen, onClose }: GoogleGuideProps) {
81109 </ button >
82110 </ div >
83111
84- { /* Steps */ }
112+ { /* Method tabs */ }
113+ < div className = "px-5 flex gap-2 mb-3" >
114+ { methods . map ( ( m , i ) => (
115+ < button
116+ key = { i }
117+ onClick = { ( ) => setTab ( i ) }
118+ className = "px-3 py-1.5 text-xs font-medium rounded-full cursor-pointer transition-colors"
119+ style = { {
120+ background : tab === i ? 'rgb(var(--gl))' : 'var(--bg-gi)' ,
121+ color : tab === i ? '#fff' : 'var(--t3)' ,
122+ } }
123+ >
124+ { m . label }
125+ </ button >
126+ ) ) }
127+ </ div >
128+
129+ { /* Steps for active tab */ }
85130 < div className = "px-5 pb-3 space-y-2" >
86- { steps . map ( ( step ) => (
131+ { active . steps . map ( ( step ) => (
87132 < div
88133 key = { step . number }
89134 className = "gi flex gap-3 px-3 py-2.5" style = { { borderRadius : '10px' } }
90135 >
91- { /* Number circle */ }
92136 < div className = "flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center"
93137 style = { { background : 'rgb(var(--gl))' } } >
94138 < span className = "text-white text-sm font-bold" > { step . number } </ span >
95139 </ div >
96-
97- { /* Content */ }
98140 < div className = "flex-1 min-w-0" >
99141 < p className = "font-semibold mb-1" style = { { color : 'var(--t1)' } } >
100142 { step . title }
@@ -106,7 +148,7 @@ export default function GoogleGuide({ isOpen, onClose }: GoogleGuideProps) {
106148 </ li >
107149 ) ) }
108150 </ ul >
109- { step . action && (
151+ { 'action' in step && step . action && (
110152 < a
111153 href = { step . action . href }
112154 target = "_blank"
0 commit comments