Subversion Repositories SmartDukaan

Rev

Rev 36670 | Rev 36698 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
36621 ranu 1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
	<meta charset="utf-8">
5
	<meta name="viewport" content="width=device-width, initial-scale=1">
6
	<title>Route Planner - Smart Dukaan</title>
7
	<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
8
	<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
9
	<style>
10
		* {
11
			margin: 0;
12
			padding: 0;
13
			box-sizing: border-box;
14
		}
15
 
16
		body {
17
			font-family: 'Inter', sans-serif;
18
			background: #0f172a;
19
			color: #e2e8f0;
20
			height: 100vh;
21
			overflow: hidden;
22
		}
23
 
24
		/* Top Bar */
25
		.top-bar {
26
			display: flex;
27
			align-items: center;
28
			gap: 12px;
29
			padding: 8px 16px;
30
			background: #1e293b;
31
			border-bottom: 1px solid #334155;
32
			height: 50px;
33
		}
34
 
35
		.top-bar h1 {
36
			font-size: 16px;
37
			font-weight: 600;
38
			color: #60a5fa;
39
			margin-right: 20px;
40
		}
41
 
42
		.top-bar select, .top-bar button {
43
			font-family: inherit;
44
			font-size: 13px;
45
			padding: 6px 10px;
46
			border-radius: 6px;
47
			border: 1px solid #475569;
48
			background: #1e293b;
49
			color: #e2e8f0;
50
		}
51
 
52
		.top-bar select:focus {
53
			outline: none;
54
			border-color: #60a5fa;
55
		}
56
 
57
		.top-bar button {
58
			cursor: pointer;
59
			font-weight: 500;
60
		}
61
 
62
		.top-bar .btn-primary {
63
			background: #3b82f6;
64
			border-color: #3b82f6;
65
			color: #fff;
66
		}
67
 
68
		.top-bar .btn-primary:hover {
69
			background: #2563eb;
70
		}
71
 
72
		/* Main Layout */
73
		.main-layout {
74
			display: flex;
75
			height: calc(100vh - 50px);
76
		}
77
 
78
		/* Left Panel */
79
		.left-panel {
80
			width: 300px;
81
			min-width: 300px;
82
			background: #1e293b;
83
			border-right: 1px solid #334155;
84
			display: flex;
85
			flex-direction: column;
86
			overflow: hidden;
87
		}
88
 
89
		.panel-tabs {
90
			display: flex;
91
			border-bottom: 1px solid #334155;
92
		}
93
 
94
		.panel-tab {
95
			flex: 1;
96
			padding: 10px;
97
			text-align: center;
98
			font-size: 12px;
99
			font-weight: 600;
100
			cursor: pointer;
101
			color: #94a3b8;
102
			border-bottom: 2px solid transparent;
103
			transition: all 0.2s;
104
		}
105
 
106
		.panel-tab.active {
107
			color: #60a5fa;
108
			border-bottom-color: #60a5fa;
109
		}
110
 
111
		.panel-tab:hover {
112
			color: #e2e8f0;
113
		}
114
 
115
		.panel-content {
116
			flex: 1;
117
			overflow-y: auto;
118
			padding: 10px;
119
		}
120
 
121
		/* Route List */
122
		.route-day {
123
			margin-bottom: 12px;
124
		}
125
 
126
		.route-day-header {
127
			font-size: 12px;
128
			font-weight: 600;
129
			color: #60a5fa;
130
			padding: 6px 8px;
131
			background: #0f172a;
132
			border-radius: 6px;
133
			display: flex;
134
			justify-content: space-between;
135
		}
136
 
137
		.route-stop {
138
			display: flex;
139
			align-items: center;
140
			gap: 8px;
141
			padding: 6px 8px;
142
			border-left: 2px solid #334155;
143
			margin-left: 12px;
144
			font-size: 12px;
145
		}
146
 
147
		.route-stop .stop-num {
148
			width: 20px;
149
			height: 20px;
150
			border-radius: 50%;
151
			background: #3b82f6;
152
			color: #fff;
153
			display: flex;
154
			align-items: center;
155
			justify-content: center;
156
			font-size: 10px;
157
			font-weight: 700;
158
			flex-shrink: 0;
159
		}
160
 
161
		.route-stop .stop-info {
162
			flex: 1;
163
		}
164
 
165
		.route-stop .stop-name {
166
			font-weight: 500;
167
			color: #e2e8f0;
168
		}
169
 
170
		.route-stop .stop-meta {
171
			color: #64748b;
172
			font-size: 11px;
173
		}
174
 
175
		.route-stop-home {
176
			border-left-color: #22c55e;
177
		}
178
 
179
		.route-stop-home .stop-num {
180
			background: #22c55e;
181
		}
182
 
183
		.route-stop-clickable:hover {
184
			background: #334155;
185
			border-radius: 4px;
186
		}
187
 
188
		.stop-remove {
189
			color: #64748b;
190
			font-size: 16px;
191
			font-weight: 700;
192
			cursor: pointer;
193
			padding: 0 4px;
194
			flex-shrink: 0;
195
			line-height: 1;
196
		}
197
 
198
		.stop-remove:hover {
199
			color: #ef4444;
200
		}
201
 
202
		/* Distance Segment between stops */
203
		.route-segment {
204
			display: flex;
205
			align-items: center;
206
			margin-left: 20px;
207
			padding: 2px 0;
208
		}
209
 
210
		.seg-line {
211
			width: 12px;
212
			border-top: 1px dashed #475569;
213
			margin-right: 6px;
214
		}
215
 
216
		.seg-line-home {
217
			border-top-color: #22c55e;
218
		}
219
 
220
		.seg-dist {
221
			font-size: 10px;
222
			color: #60a5fa;
223
			font-weight: 500;
224
		}
225
 
226
		/* Day Summary */
227
		.day-summary {
228
			font-size: 11px;
229
			color: #94a3b8;
230
			padding: 4px 8px;
231
			margin-left: 12px;
232
		}
233
 
234
		/* Calendar */
235
		.cal-grid {
236
			width: 100%;
237
			border-collapse: collapse;
238
		}
239
 
240
		.cal-grid th {
241
			padding: 6px;
242
			font-size: 11px;
243
			color: #64748b;
244
			text-align: center;
245
		}
246
 
247
		.cal-grid td {
248
			padding: 4px;
249
			text-align: center;
250
			font-size: 12px;
251
			height: 70px;
252
			vertical-align: top;
253
			border: 1px solid #334155;
254
			position: relative;
255
			cursor: pointer;
256
		}
257
 
258
		.cal-grid td:hover {
259
			background: #1e293b;
260
		}
261
 
262
		.cal-grid td.blocked {
263
			background: #0f172a;
264
			color: #475569;
265
			cursor: not-allowed;
266
		}
267
 
268
		.cal-grid td.holiday {
269
			background: #422006;
270
		}
271
 
272
		.cal-grid td.today {
273
			border: 2px solid #3b82f6;
274
		}
275
 
276
		.cal-date {
277
			font-weight: 600;
278
			margin-bottom: 2px;
279
		}
280
 
281
		.cal-chip {
282
			display: block;
283
			font-size: 9px;
284
			padding: 1px 4px;
285
			border-radius: 3px;
286
			color: #fff;
287
			margin: 1px 0;
288
			white-space: nowrap;
289
			overflow: hidden;
290
			text-overflow: ellipsis;
291
		}
292
 
293
		.cal-chip.running {
294
			box-shadow: 0 0 0 2px #ef4444;
295
		}
296
 
297
		.cal-chip.completed {
298
			opacity: 0.4;
299
		}
300
 
36632 ranu 301
        .cal-chip-remove {
302
            margin-left: 4px;
303
            cursor: pointer;
304
            font-weight: 700;
305
            font-size: 11px;
306
            opacity: 0.7;
307
        }
308
 
309
        .cal-chip-remove:hover {
310
            opacity: 1;
311
            color: #fca5a5;
312
        }
313
 
314
        .cal-grid td.past {
315
            background: #0c1222 !important;
316
            color: #334155 !important;
317
            cursor: not-allowed !important;
318
        }
319
 
320
        .cal-grid td.past .cal-date {
321
            color: #334155;
322
        }
323
 
324
        .cal-grid td.sunday {
325
            background: #1a1a2e;
326
        }
327
 
328
        .cal-grid td.sunday .cal-date {
329
            color: #ef4444;
330
        }
331
 
36621 ranu 332
		.cal-holiday-label {
333
			font-size: 9px;
334
			color: #fbbf24;
335
		}
336
 
337
		/* Beat Cards in Calendar Panel */
338
		.beat-card {
339
			padding: 10px;
340
			margin-bottom: 8px;
341
			border-radius: 8px;
342
			border: 1px solid #334155;
343
			cursor: pointer;
344
			transition: all 0.2s;
345
		}
346
 
347
		.beat-card:hover {
348
			border-color: #60a5fa;
349
		}
350
 
351
		.beat-card.selected {
352
			border-color: #3b82f6;
353
			box-shadow: 0 0 0 1px #3b82f6;
354
		}
355
 
356
		.beat-card .beat-name {
357
			font-weight: 600;
358
			font-size: 13px;
359
			display: flex;
360
			align-items: center;
361
			gap: 6px;
362
		}
363
 
364
		.beat-card .beat-meta {
365
			font-size: 11px;
366
			color: #64748b;
367
			margin-top: 4px;
368
		}
369
 
370
		.beat-card .beat-actions {
371
			margin-top: 8px;
372
			display: flex;
373
			gap: 6px;
374
		}
375
 
376
		.beat-card .btn-sm {
377
			font-size: 11px;
378
			padding: 3px 8px;
379
			border-radius: 4px;
380
			border: none;
381
			cursor: pointer;
382
			font-weight: 500;
383
		}
384
 
385
		.btn-schedule {
386
			background: #3b82f6;
387
			color: #fff;
388
		}
389
 
390
		.btn-repeat {
391
			background: #22c55e;
392
			color: #fff;
393
		}
394
 
395
		.btn-schedule:hover {
396
			background: #2563eb;
397
		}
398
 
399
		.btn-repeat:hover {
400
			background: #16a34a;
401
		}
402
 
403
		.status-badge {
404
			font-size: 10px;
405
			padding: 2px 6px;
406
			border-radius: 10px;
407
			font-weight: 600;
408
		}
409
 
410
		.status-running {
411
			background: #ef4444;
412
			color: #fff;
413
		}
414
 
415
		.status-scheduled {
416
			background: #3b82f6;
417
			color: #fff;
418
		}
419
 
420
		.status-completed {
421
			background: #475569;
422
			color: #94a3b8;
423
		}
424
 
425
		/* Map */
426
		.map-container {
427
			flex: 1;
428
			position: relative;
429
		}
430
 
431
		#beat-map {
432
			width: 100%;
433
			height: 100%;
434
		}
435
 
436
		/* Bottom Bar */
437
		.bottom-bar {
438
			position: absolute;
439
			bottom: 0;
440
			left: 0;
441
			right: 0;
442
			display: flex;
443
			align-items: center;
444
			justify-content: space-between;
445
			padding: 8px 16px;
446
			background: rgba(15, 23, 42, 0.9);
447
			backdrop-filter: blur(8px);
448
			border-top: 1px solid #334155;
449
			font-size: 12px;
450
			z-index: 10;
451
		}
452
 
453
		.bottom-bar .day-info {
454
			display: flex;
455
			gap: 20px;
456
		}
457
 
458
		.progress-wrap {
459
			width: 200px;
460
			height: 8px;
461
			background: #334155;
462
			border-radius: 4px;
463
			overflow: hidden;
464
		}
465
 
466
		.progress-fill {
467
			height: 100%;
468
			border-radius: 4px;
469
			transition: width 0.3s;
470
		}
471
 
472
		/* Action Buttons */
473
		.bottom-bar .action-btns button {
474
			font-family: inherit;
475
			font-size: 12px;
476
			padding: 6px 14px;
477
			border-radius: 6px;
478
			border: none;
479
			cursor: pointer;
480
			font-weight: 500;
481
			margin-left: 8px;
482
		}
483
 
484
		.btn-end-day {
485
			background: #f59e0b;
486
			color: #0f172a;
487
		}
488
 
489
		.btn-finish {
490
			background: #22c55e;
491
			color: #fff;
492
		}
493
 
494
		.btn-end-day:hover {
495
			background: #d97706;
496
		}
497
 
498
		.btn-finish:hover {
499
			background: #16a34a;
500
		}
501
 
502
		/* Modal Overlay */
503
		.modal-overlay {
504
			display: none;
505
			position: fixed;
506
			top: 0;
507
			left: 0;
508
			right: 0;
509
			bottom: 0;
510
			background: rgba(0, 0, 0, 0.6);
511
			z-index: 100;
512
			justify-content: center;
513
			align-items: center;
514
		}
515
 
516
		.modal-overlay.show {
517
			display: flex;
518
		}
519
 
520
		.modal-box {
521
			background: #1e293b;
522
			border: 1px solid #334155;
523
			border-radius: 12px;
524
			padding: 24px;
525
			min-width: 400px;
526
			max-width: 600px;
527
			max-height: 80vh;
528
			overflow-y: auto;
529
		}
530
 
531
		.modal-box h3 {
532
			font-size: 16px;
533
			font-weight: 600;
534
			margin-bottom: 16px;
535
			color: #f1f5f9;
536
		}
537
 
538
		.modal-box input, .modal-box select {
539
			font-family: inherit;
540
			width: 100%;
541
			padding: 8px 12px;
542
			border: 1px solid #475569;
543
			border-radius: 6px;
544
			background: #0f172a;
545
			color: #e2e8f0;
546
			margin-bottom: 10px;
547
			font-size: 13px;
548
		}
549
 
550
		.modal-box .modal-actions {
551
			display: flex;
552
			justify-content: flex-end;
553
			gap: 8px;
554
			margin-top: 16px;
555
		}
556
 
557
		.modal-box .modal-actions button {
558
			font-family: inherit;
559
			padding: 8px 16px;
560
			border-radius: 6px;
561
			border: none;
562
			cursor: pointer;
563
			font-weight: 500;
564
			font-size: 13px;
565
		}
566
 
567
		.modal-cancel {
568
			background: #475569;
569
			color: #e2e8f0;
570
		}
571
 
572
		.modal-confirm {
573
			background: #3b82f6;
574
			color: #fff;
575
		}
576
 
577
		/* Info Window custom */
578
		.marker-popup {
579
			font-family: 'Inter', sans-serif;
580
			padding: 8px;
581
			min-width: 200px;
582
		}
583
 
584
		.marker-popup h4 {
36632 ranu 585
            font-size: 14px;
586
            font-weight: 700;
587
            color: #1e293b;
588
            margin-bottom: 6px;
36621 ranu 589
		}
590
 
591
		.marker-popup .popup-meta {
592
			font-size: 11px;
593
			color: #666;
594
			margin-bottom: 8px;
595
		}
596
 
597
		.marker-popup .popup-distance {
598
			font-size: 12px;
599
			font-weight: 500;
600
			color: #3b82f6;
601
			margin-bottom: 8px;
602
		}
603
 
604
		.marker-popup button {
605
			font-size: 11px;
606
			padding: 4px 10px;
607
			border: none;
608
			border-radius: 4px;
609
			cursor: pointer;
610
			margin-right: 4px;
611
			font-weight: 500;
612
		}
613
 
614
		.popup-next {
615
			background: #3b82f6;
616
			color: #fff;
617
		}
618
 
619
		.popup-last {
620
			background: #f59e0b;
621
			color: #0f172a;
622
		}
623
 
624
		.popup-nextday {
625
			background: #8b5cf6;
626
			color: #fff;
627
		}
628
 
36668 ranu 629
		/* Partners list */
630
		.partner-row {
631
			display: flex;
632
			align-items: center;
633
			gap: 8px;
634
			padding: 6px 8px;
635
			border-radius: 6px;
636
			cursor: pointer;
637
			font-size: 12px;
638
			border-bottom: 1px solid #1a2334;
639
		}
640
 
641
		.partner-row:hover {
642
			background: #1a2334;
643
		}
644
 
645
		.partner-row.in-route {
646
			background: rgba(34, 197, 94, 0.08);
647
		}
648
 
649
		.partner-row input[type="checkbox"] {
650
			accent-color: #22c55e;
651
			flex-shrink: 0;
652
		}
653
 
654
		.partner-row .pr-info {
655
			flex: 1;
656
			min-width: 0;
657
		}
658
 
659
		.partner-row .pr-code {
660
			font-weight: 600;
661
			color: #e2e8f0;
662
		}
663
 
664
		.partner-row .pr-name {
665
			color: #94a3b8;
666
			font-size: 11px;
667
			white-space: nowrap;
668
			overflow: hidden;
669
			text-overflow: ellipsis;
670
		}
671
 
672
		.partner-row .pr-day {
673
			font-size: 10px;
674
			color: #22c55e;
675
			font-weight: 600;
676
			flex-shrink: 0;
677
		}
678
 
36621 ranu 679
		/* Nav Month */
680
		.month-nav {
681
			display: flex;
682
			align-items: center;
683
			gap: 12px;
684
			padding: 10px;
685
			border-bottom: 1px solid #334155;
686
		}
687
 
688
		.month-nav button {
689
			background: none;
690
			border: 1px solid #475569;
691
			color: #e2e8f0;
692
			padding: 4px 10px;
693
			border-radius: 4px;
694
			cursor: pointer;
695
			font-size: 12px;
696
		}
697
 
698
		.month-nav span {
699
			font-weight: 600;
700
			font-size: 14px;
701
		}
702
	</style>
703
</head>
704
<body>
705
 
706
<!-- Top Bar -->
707
<div class="top-bar">
708
	<h1>Route Planner</h1>
709
	<select id="bp-category" style="width:100px;">
710
		<option value="4">Sales</option>
711
	</select>
712
	<select id="bp-level" style="width:80px;">
713
		<option value="">Level</option>
714
		#foreach($et in $escalationTypes)
715
			<option value="$et">$et</option>
716
		#end
717
	</select>
718
	<select id="bp-auth-user" style="width:180px;">
719
		<option value="">Select User</option>
720
	</select>
721
	<button class="btn-primary" id="bp-load">Load</button>
722
	<div style="flex:1;"></div>
723
	<span id="bp-user-label" style="font-size:12px;color:#94a3b8;"></span>
724
</div>
725
 
726
<!-- Main Layout -->
727
<div class="main-layout">
728
	<!-- Left Panel -->
729
	<div class="left-panel">
730
		<div class="panel-tabs">
731
			<div class="panel-tab active" data-tab="route">Route</div>
36668 ranu 732
			<div class="panel-tab" data-tab="partners">Partners</div>
36621 ranu 733
			<div class="panel-tab" data-tab="calendar">Calendar</div>
734
		</div>
735
 
736
		<!-- Route Tab Content -->
737
		<div class="panel-content" id="panel-route">
738
			<div id="route-list">
739
				<p style="color:#64748b;font-size:12px;text-align:center;padding:40px 10px;">
740
					Select a user and click Load to start planning.
741
				</p>
742
			</div>
743
		</div>
744
 
36668 ranu 745
		<!-- Partners Tab Content -->
746
		<div class="panel-content" id="panel-partners" style="display:none;">
747
			<div style="position:sticky;top:0;background:#1e293b;padding-bottom:8px;z-index:5;">
748
				<input type="text" id="partners-search" placeholder="Search code / name / city..."
749
					   style="width:100%;padding:6px 10px;border:1px solid #475569;border-radius:6px;background:#0f172a;color:#e2e8f0;font-size:13px;font-family:inherit;">
750
				<div style="font-size:11px;color:#94a3b8;margin-top:6px;display:flex;justify-content:space-between;">
751
					<span>Tick to add to current day</span>
752
					<span id="partners-count">0 / 0</span>
753
				</div>
754
			</div>
755
			<div id="partners-list"></div>
756
		</div>
757
 
36621 ranu 758
		<!-- Calendar Tab Content -->
759
		<div class="panel-content" id="panel-calendar" style="display:none;">
760
			<div class="month-nav">
761
				<button id="cal-prev">&lt;</button>
762
				<span id="cal-month-label"></span>
763
				<button id="cal-next">&gt;</button>
764
			</div>
765
			<div id="cal-beat-cards"></div>
766
		</div>
767
	</div>
768
 
769
	<!-- Map -->
770
	<div class="map-container">
771
		<div id="beat-map"></div>
772
 
773
		<!-- Bottom Bar (on map) -->
774
		<div class="bottom-bar" id="bottom-bar" style="display:none;">
775
			<div class="day-info">
776
				<span id="bb-day-label">Day 1</span>
777
				<span id="bb-stops">0 stops</span>
778
				<span id="bb-distance">0 km</span>
779
				<span id="bb-time">0h 0m</span>
780
				<div class="progress-wrap">
781
					<div class="progress-fill" id="bb-progress" style="width:0%;background:#22c55e;"></div>
782
				</div>
783
			</div>
784
			<div class="action-btns">
785
				<button class="btn-finish" id="btn-finish">Finish Plan</button>
786
			</div>
787
		</div>
788
 
789
		<!-- Calendar Grid (overlays map when calendar tab active) -->
790
		<div id="cal-grid-container"
791
			 style="display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:#0f172a;overflow-y:auto;padding:20px;">
792
			<div id="cal-grid-content"></div>
793
		</div>
794
	</div>
795
</div>
796
 
797
<!-- Home Location Modal -->
798
<div class="modal-overlay" id="modal-home">
799
	<div class="modal-box">
800
		<h3>Set Home Location</h3>
801
		<p style="font-size:12px;color:#94a3b8;margin-bottom:12px;">Search or click on map to set the auth user's
802
			home/base location.</p>
803
		<input type="text" id="home-search" placeholder="Search location...">
804
		<div id="home-map" style="height:250px;border-radius:8px;border:1px solid #334155;margin-bottom:12px;"></div>
805
		<div class="modal-actions">
806
			<button class="modal-cancel" id="home-cancel">Cancel</button>
807
			<button class="modal-confirm" id="home-confirm">Confirm Home</button>
808
		</div>
809
	</div>
810
</div>
811
 
812
<!-- Day Break Modal -->
813
<div class="modal-overlay" id="modal-daybreak">
814
	<div class="modal-box">
815
		<h3>End of Day</h3>
816
		<p id="daybreak-info" style="font-size:13px;margin-bottom:12px;"></p>
817
		<div style="margin-bottom:12px;">
818
			<label style="display:block;padding:8px;cursor:pointer;border-radius:6px;border:1px solid #334155;margin-bottom:6px;">
819
				<input type="radio" name="stay" value="HOME" checked> Go back home (base location)
820
			</label>
821
			<label style="display:block;padding:8px;cursor:pointer;border-radius:6px;border:1px solid #334155;">
822
				<input type="radio" name="stay" value="HOTEL"> Stay at hotel / other location
823
			</label>
824
		</div>
825
		<div id="hotel-fields" style="display:none;">
826
			<input type="text" id="hotel-search" placeholder="Search hotel/location...">
827
			<div id="hotel-map" style="height:200px;border-radius:8px;border:1px solid #334155;"></div>
828
		</div>
829
		<div class="modal-actions">
830
			<button class="modal-cancel" id="daybreak-cancel">Cancel</button>
831
			<button class="modal-confirm" id="daybreak-confirm">Continue to Next Day</button>
832
		</div>
833
	</div>
834
</div>
835
 
836
<!-- Calendar Schedule Modal -->
837
<div class="modal-overlay" id="modal-cal-schedule">
838
	<div class="modal-box" style="min-width:500px;">
839
		<h3 id="cal-sched-title">Schedule Beat</h3>
840
		<div id="cal-sched-grid"></div>
841
		<div id="cal-sched-info" style="font-size:12px;color:#94a3b8;margin-top:10px;"></div>
842
		<div class="modal-actions">
843
			<button class="modal-cancel" id="cal-sched-cancel">Cancel</button>
844
			<button class="modal-confirm" id="cal-sched-confirm">Confirm Schedule</button>
845
		</div>
846
	</div>
847
</div>
848
 
849
<script>
850
	var context = "${rc.contextPath}";
851
</script>
852
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc&libraries=places&v=weekly"></script>
36681 ranu 853
<script src="${rc.contextPath}/resources/js/beat-plan-app.js?v=20260526b"></script>
36621 ranu 854
</body>
855
</html>