Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
36642 ranu 1
<html>
2
<head>
3
    <meta charset="UTF-8">
4
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
36807 aman 5
    <title>Store Verification - SmartDukaan</title>
36642 ranu 6
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
7
    <style>
8
        body {
36807 aman 9
            background: #f5f6f8;
36686 ranu 10
            font-family: 'Segoe UI', Roboto, sans-serif;
36807 aman 11
            color: #2b2b2b;
36642 ranu 12
        }
13
 
36807 aman 14
        /* ---------- Top navbar ---------- */
15
        .top-nav {
36642 ranu 16
            background: #fff;
36807 aman 17
            border-bottom: 1px solid #ececec;
18
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
19
            padding: 14px 22px;
20
            display: flex;
21
            align-items: center;
22
            justify-content: space-between;
23
            position: sticky;
24
            top: 0;
25
            z-index: 10;
36642 ranu 26
        }
27
 
36807 aman 28
        .nav-home {
29
            display: inline-flex;
30
            align-items: center;
31
            gap: 8px;
32
            color: #2b2b2b;
33
            font-weight: 600;
34
            font-size: 15px;
35
            text-decoration: none;
36642 ranu 36
        }
37
 
36807 aman 38
        .nav-home:hover {
39
            color: #e1212a;
40
            text-decoration: none;
41
        }
42
 
43
        .nav-brand {
44
            display: inline-flex;
36686 ranu 45
            align-items: center;
36807 aman 46
            text-decoration: none;
36686 ranu 47
        }
48
 
36807 aman 49
        .nav-brand .brand-logo {
50
            height: 30px;
51
            width: auto;
52
            display: block;
53
        }
54
 
55
        .nav-help {
36686 ranu 56
            display: inline-flex;
57
            align-items: center;
36807 aman 58
            gap: 8px;
59
            font-size: 14px;
60
            color: #555;
61
            white-space: nowrap;
36686 ranu 62
        }
63
 
36807 aman 64
        .nav-call {
65
            display: inline-flex;
66
            align-items: center;
67
            gap: 7px;
68
            text-decoration: none;
69
            color: #555;
70
        }
71
 
72
        .nav-call:hover {
73
            text-decoration: none;
74
        }
75
 
76
        .nav-call .call-word {
77
            color: #555;
78
            font-weight: 600;
79
        }
80
 
81
        .nav-help .phone {
82
            color: #e1212a;
36686 ranu 83
            font-weight: 700;
36642 ranu 84
        }
85
 
36807 aman 86
        @media (max-width: 575px) {
87
            .top-nav {
88
                padding: 10px 12px;
89
            }
90
 
91
            .nav-brand .brand-logo {
92
                height: 22px;
93
            }
94
 
95
            .nav-help .q-label,
96
            .nav-call .call-word {
97
                display: none;
98
            }
99
 
100
            .nav-call {
101
                gap: 5px;
102
            }
103
 
104
            .nav-help .phone {
105
                font-size: 13px;
106
            }
107
 
108
            .subhead {
109
                padding: 12px 14px 0;
110
            }
36642 ranu 111
        }
112
 
36807 aman 113
        /* ---------- Sub-header home button ---------- */
114
        .subhead {
115
            padding: 16px 22px 0;
36642 ranu 116
        }
117
 
36807 aman 118
        .btn-home {
119
            display: inline-flex;
120
            align-items: center;
121
            gap: 7px;
122
            background: #fff;
123
            color: #374151;
124
            border: 1px solid #e3e6ea;
125
            border-radius: 9px;
126
            padding: 8px 14px;
127
            font-size: 14px;
128
            font-weight: 600;
129
            text-decoration: none;
130
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
36642 ranu 131
        }
132
 
36807 aman 133
        .btn-home:hover {
134
            background: #f1f3f5;
135
            color: #374151;
136
            text-decoration: none;
36642 ranu 137
        }
138
 
36807 aman 139
        /* ---------- Greeting ---------- */
140
        .greeting {
141
            text-align: center;
142
            font-size: 19px;
143
            color: #2b2b2b;
144
            margin: 26px 16px 18px;
145
        }
146
 
147
        /* ---------- Card ---------- */
148
        .geo-card {
149
            max-width: 720px;
150
            margin: 0 auto 36px;
151
            background: #fff;
152
            border-radius: 14px;
153
            box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
154
            overflow: hidden;
155
        }
156
 
157
        .card-head {
158
            padding: 22px 28px 18px;
159
            border-bottom: 1px solid #eee;
160
        }
161
 
162
        .card-head h4 {
163
            margin: 0 0 6px;
164
            font-weight: 700;
165
            font-size: 22px;
166
        }
167
 
168
        .card-head p {
169
            margin: 0;
170
            color: #6b7280;
171
            font-size: 14px;
172
        }
173
 
174
        .card-body-geo {
175
            padding: 26px 28px 28px;
176
        }
177
 
178
        @media (max-width: 575px) {
179
            .card-head, .card-body-geo {
180
                padding-left: 18px;
181
                padding-right: 18px;
182
            }
183
        }
184
 
185
        /* ---------- Step indicator + labels ---------- */
36642 ranu 186
        .step-indicator {
187
            display: flex;
188
            justify-content: center;
189
            gap: 8px;
36807 aman 190
            margin-bottom: 10px;
36642 ranu 191
        }
192
 
36807 aman 193
        .step-caption {
194
            text-align: center;
195
            font-size: 13px;
196
            font-weight: 600;
197
            color: #8b93a1;
198
            margin-bottom: 24px;
199
        }
200
 
36642 ranu 201
        .step-dot {
36807 aman 202
            width: 28px;
203
            height: 5px;
204
            border-radius: 3px;
205
            background: #e3e6ea;
36642 ranu 206
            transition: background 0.3s;
207
        }
208
 
209
        .step-dot.done {
36807 aman 210
            background: #22c55e;
36642 ranu 211
        }
212
 
213
        .step-dot.current {
36807 aman 214
            background: #e1212a;
36642 ranu 215
        }
216
 
36807 aman 217
        .section-label {
218
            font-size: 12px;
219
            font-weight: 700;
220
            letter-spacing: 0.6px;
221
            text-transform: uppercase;
222
            color: #8b93a1;
223
            margin-bottom: 12px;
224
        }
225
 
226
        .section-label .step-no {
227
            color: #e1212a;
228
        }
229
 
230
        /* Hindi line shown right under its English counterpart */
231
        .hindi {
232
            display: block;
233
            margin-top: 6px;
234
        }
235
 
236
        /* divider between the two steps on the same page */
237
        .step-divider {
36642 ranu 238
            border: none;
36807 aman 239
            border-top: 1px solid #eef0f3;
240
            margin: 26px 0;
241
        }
242
 
243
        .step-section.locked {
244
            opacity: 0.6;
245
            pointer-events: none;
246
        }
247
 
248
        /* ---------- Form fields ---------- */
249
        .field-label {
36686 ranu 250
            font-weight: 600;
36807 aman 251
            font-size: 15px;
252
            margin-bottom: 8px;
253
            display: block;
36642 ranu 254
        }
255
 
36807 aman 256
        .field-label .req {
257
            color: #e1212a;
258
            margin-left: 2px;
36642 ranu 259
        }
260
 
36807 aman 261
        .input-geo {
262
            width: 100%;
263
            background: #f1f3f5;
264
            border: 1px solid #f1f3f5;
265
            border-radius: 10px;
266
            padding: 13px 16px;
267
            font-size: 15px;
268
            transition: border-color 0.2s, background 0.2s;
36642 ranu 269
        }
270
 
36807 aman 271
        .input-geo:focus {
272
            outline: none;
273
            background: #fff;
274
            border-color: #e1212a;
275
            box-shadow: 0 0 0 0.18rem rgba(225, 33, 42, 0.15);
276
        }
277
 
278
        .input-geo:disabled {
279
            color: #6b7280;
280
        }
281
 
282
        .mobile-row {
283
            position: relative;
284
        }
285
 
286
        .mobile-row .input-geo {
287
            width: 100%;
288
        }
289
 
290
        /* reserve room on the right for the in-field badge once verified */
291
        .input-geo.field-verified {
292
            padding-right: 104px;
293
        }
294
 
295
        .verified-pill {
296
            position: absolute;
297
            right: 8px;
298
            top: 50%;
299
            transform: translateY(-50%);
300
            display: none;
301
            align-items: center;
302
            gap: 6px;
303
            background: #e8f7ee;
304
            color: #16a34a;
36642 ranu 305
            border-radius: 8px;
36807 aman 306
            padding: 6px 12px;
36642 ranu 307
            font-size: 13px;
36807 aman 308
            font-weight: 600;
309
            white-space: nowrap;
36642 ranu 310
        }
311
 
36807 aman 312
        .verified-pill.show {
313
            display: inline-flex;
314
            animation: badgeIn 0.4s ease both;
36642 ranu 315
        }
316
 
36807 aman 317
        @keyframes badgeIn {
318
            from {
319
                opacity: 0;
320
                transform: translateY(-50%) translateX(8px);
321
            }
322
            to {
323
                opacity: 1;
324
                transform: translateY(-50%) translateX(0);
325
            }
36642 ranu 326
        }
327
 
36807 aman 328
        /* soft reveal used for Step 2 appearing */
329
        @keyframes softReveal {
330
            from {
331
                opacity: 0;
332
                transform: translateY(10px);
333
            }
334
            to {
335
                opacity: 1;
336
                transform: translateY(0);
337
            }
36642 ranu 338
        }
339
 
36807 aman 340
        .reveal-soft {
341
            animation: softReveal 0.45s ease both;
36642 ranu 342
        }
343
 
36807 aman 344
        /* the tick draws itself once the badge appears */
345
        .verified-pill svg path {
346
            stroke-dasharray: 24;
347
            stroke-dashoffset: 24;
36642 ranu 348
        }
349
 
36807 aman 350
        .verified-pill.show svg path {
351
            animation: drawTick 0.45s ease-out 0.15s forwards;
36642 ranu 352
        }
353
 
36807 aman 354
        @keyframes drawTick {
36642 ranu 355
            to {
36807 aman 356
                stroke-dashoffset: 0;
36642 ranu 357
            }
358
        }
359
 
36807 aman 360
        /* ---------- Success / thank-you ---------- */
361
        .success-wrap {
362
            min-height: 380px;
363
            display: flex;
364
            flex-direction: column;
365
            align-items: center;
366
            justify-content: center;
367
            gap: 30px;
368
            padding: 44px 24px;
369
            text-align: center;
36642 ranu 370
        }
36689 ranu 371
 
36807 aman 372
        /* circle draws a full 360, then the tick ticks left -> right; repeats 3x every 4s */
373
        .success-circle {
374
            stroke-dasharray: 151;
375
            stroke-dashoffset: 151;
376
            animation: drawCircle 4s ease-in-out 3 forwards;
377
        }
378
 
379
        .success-check {
380
            stroke-dasharray: 32;
381
            stroke-dashoffset: 32;
382
            animation: drawCheck 4s ease-in-out 3 forwards;
383
        }
384
 
385
        @keyframes drawCircle {
386
            0% {
387
                stroke-dashoffset: 151;
388
            }
389
            25% {
390
                stroke-dashoffset: 0;
391
            }
392
            100% {
393
                stroke-dashoffset: 0;
394
            }
395
        }
396
 
397
        @keyframes drawCheck {
398
            0%, 25% {
399
                stroke-dashoffset: 32;
400
            }
401
            45% {
402
                stroke-dashoffset: 0;
403
            }
404
            100% {
405
                stroke-dashoffset: 0;
406
            }
407
        }
408
 
409
        .success-msg {
410
            margin: 0;
411
            font-size: 22px;
412
            font-weight: 700;
413
            color: #16a34a;
414
        }
415
 
416
        .success-msg-hi {
417
            margin: 6px 0 0;
418
            font-size: 16px;
419
            color: #4b5563;
420
        }
421
 
422
        /* ---------- Capture (combined location + photo) ---------- */
423
        .capture-help {
424
            color: #6b7280;
425
            font-size: 14px;
426
            margin: 0 0 16px;
427
        }
428
 
429
        /* "Take Store Photo" + "Close" controls row */
430
        .camera-controls {
431
            display: flex;
432
            gap: 10px;
433
            align-items: stretch;
434
            margin-bottom: 18px;
435
        }
436
 
437
        .btn-camera-open {
438
            flex: 1;
439
            display: flex;
440
            flex-direction: row;
441
            align-items: center;
442
            justify-content: center;
443
            gap: 9px;
444
            background: #ef5a68;
445
            color: #fff;
446
            border: none;
447
            border-radius: 12px;
448
            padding: 15px 18px;
449
            cursor: pointer;
450
            box-shadow: 0 2px 10px rgba(239, 90, 104, 0.3);
451
        }
452
 
453
        .btn-camera-open .sep {
454
            opacity: 0.5;
455
            font-weight: 400;
456
        }
457
 
458
        .btn-camera-close {
459
            display: inline-flex;
460
            align-items: center;
461
            justify-content: center;
462
            gap: 6px;
463
            background: #fff;
464
            color: #455a64;
465
            border: 1px solid #cfd6dd;
466
            border-radius: 12px;
467
            padding: 0 22px;
468
            font-size: 15px;
469
            font-weight: 600;
470
            cursor: pointer;
471
            white-space: nowrap;
472
        }
473
 
474
        .btn-camera-close .close-x {
475
            display: none;
476
        }
477
 
478
        /* mobile: collapse Close to a compact icon-only ✕ — placed AFTER the
479
           base rules above so it wins the cascade on small screens */
480
        @media (max-width: 575px) {
481
            .btn-camera-close {
482
                padding: 0 14px;
483
            }
484
 
485
            .btn-camera-close .close-label {
486
                display: none;
487
            }
488
 
489
            .btn-camera-close .close-x {
490
                display: block;
491
            }
492
        }
493
 
494
        .btn-camera-close:hover {
495
            background: #f1f3f5;
496
        }
497
 
498
        .btn-camera-open:hover {
499
            filter: brightness(0.96);
500
            color: #fff;
501
        }
502
 
503
        .btn-camera-open .label-en {
504
            font-size: 15px;
505
            font-weight: 700;
506
            line-height: 1.2;
507
        }
508
 
509
        .btn-camera-open .label-hi {
510
            font-size: 14px;
511
            font-weight: 500;
512
            opacity: 0.95;
513
        }
514
 
36689 ranu 515
        .camera-wrap {
516
            position: relative;
517
            background: #000;
36807 aman 518
            border-radius: 12px;
36689 ranu 519
            overflow: hidden;
520
            aspect-ratio: 4 / 3;
36807 aman 521
            margin-bottom: 14px;
36689 ranu 522
        }
523
 
524
        .camera-wrap video,
525
        .camera-wrap img {
526
            width: 100%;
527
            height: 100%;
528
            object-fit: cover;
529
            display: block;
530
        }
531
 
532
        .camera-wrap .cam-overlay {
533
            position: absolute;
534
            inset: 0;
535
            display: flex;
536
            align-items: center;
537
            justify-content: center;
538
            color: #fff;
539
            font-size: 13px;
36807 aman 540
            background: rgba(0, 0, 0, 0.55);
36689 ranu 541
            text-align: center;
542
            padding: 16px;
543
        }
544
 
36807 aman 545
        .capture-row {
546
            display: flex;
547
            align-items: center;
548
            justify-content: center;
549
            gap: 16px;
550
            margin-bottom: 16px;
551
        }
552
 
36689 ranu 553
        .btn-capture {
554
            background: #fff;
36807 aman 555
            color: #e1212a;
556
            border: 3px solid #e1212a;
36689 ranu 557
            border-radius: 50%;
558
            width: 64px;
559
            height: 64px;
560
            display: inline-flex;
561
            align-items: center;
562
            justify-content: center;
563
            cursor: pointer;
564
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
565
        }
566
 
567
        .btn-capture:disabled {
568
            opacity: 0.5;
569
            cursor: not-allowed;
570
        }
571
 
572
        .btn-capture .inner {
573
            width: 48px;
574
            height: 48px;
575
            border-radius: 50%;
36807 aman 576
            background: linear-gradient(135deg, #f7931e 0%, #e1212a 100%);
36689 ranu 577
        }
578
 
579
        .btn-retake {
580
            background: transparent;
581
            border: 1px solid #b0bec5;
582
            color: #455a64;
583
            border-radius: 8px;
36807 aman 584
            padding: 9px 16px;
36689 ranu 585
            cursor: pointer;
36807 aman 586
            font-size: 14px;
587
        }
588
 
589
        .capture-status {
590
            border-radius: 10px;
591
            padding: 12px 16px;
592
            font-size: 14px;
593
            margin-bottom: 18px;
594
            display: none;
595
        }
596
 
597
        .capture-status.ok {
598
            display: block;
599
            background: #e8f7ee;
600
            color: #16a34a;
601
        }
602
 
603
        .capture-status.err {
604
            display: block;
605
            background: #fce4ec;
606
            color: #c62828;
607
        }
608
 
609
        /* ---------- Buttons ---------- */
610
        .btn-primary-geo {
611
            background: #475569;
612
            color: #fff;
613
            border: none;
614
            border-radius: 10px;
615
            padding: 14px 24px;
616
            font-size: 16px;
617
            width: 100%;
618
            cursor: pointer;
619
            font-weight: 600;
620
            box-shadow: 0 2px 6px rgba(71, 85, 105, 0.20);
621
        }
622
 
623
        .btn-primary-geo:hover {
624
            background: #334155;
625
            color: #fff;
626
        }
627
 
628
        .btn-primary-geo:disabled {
629
            background: #b0bec5;
630
            box-shadow: none;
631
            cursor: not-allowed;
632
        }
633
 
634
        .btn-submit {
635
            background: #ef5a68;
636
            color: #fff;
637
            border: none;
638
            border-radius: 10px;
639
            padding: 15px 24px;
640
            font-size: 16px;
641
            width: 100%;
642
            cursor: pointer;
643
            font-weight: 700;
644
            box-shadow: 0 2px 10px rgba(239, 90, 104, 0.3);
645
        }
646
 
647
        .btn-submit:hover {
648
            filter: brightness(0.96);
649
            color: #fff;
650
        }
651
 
652
        .btn-submit:disabled {
653
            background: #f1a8b0;
654
            box-shadow: none;
655
            cursor: not-allowed;
656
        }
657
 
658
        .inline-err {
659
            background: #fce4ec;
660
            color: #c62828;
661
            border-radius: 8px;
662
            padding: 11px 14px;
663
            font-size: 14px;
664
            margin-bottom: 14px;
665
            display: none;
666
        }
667
 
668
        /* ---------- Consent ---------- */
669
        .consent-box {
670
            border: 1px solid #e3e6ea;
671
            background: #fafbfc;
672
            border-radius: 10px;
673
            padding: 16px 18px;
674
            margin-bottom: 22px;
675
            display: flex;
676
            gap: 12px;
677
            align-items: flex-start;
678
        }
679
 
680
        .consent-box input[type="checkbox"] {
681
            width: 18px;
682
            height: 18px;
683
            margin-top: 2px;
684
            flex-shrink: 0;
685
            cursor: pointer;
686
            accent-color: #e1212a;
687
        }
688
 
689
        .consent-box label {
690
            margin: 0;
691
            font-size: 13.5px;
692
            color: #4b5563;
693
            line-height: 1.5;
694
            cursor: pointer;
695
        }
696
 
697
        /* ---------- Spinner ---------- */
698
        .spinner {
699
            display: inline-block;
700
            width: 18px;
701
            height: 18px;
702
            border: 3px solid #fff;
703
            border-top-color: transparent;
704
            border-radius: 50%;
705
            animation: spin 0.8s linear infinite;
706
            vertical-align: middle;
707
        }
708
 
709
        @keyframes spin {
710
            to {
711
                transform: rotate(360deg);
712
            }
713
        }
714
 
715
        /* ---------- Footer ---------- */
716
        .footer-help {
717
            text-align: center;
718
            font-size: 14px;
719
            color: #4b5563;
720
            padding: 20px 16px 2px;
721
        }
722
 
723
        .footer-call {
724
            display: inline-flex;
725
            align-items: center;
726
            gap: 6px;
727
            color: #e1212a;
728
            font-weight: 700;
729
            text-decoration: none;
730
            margin-left: 6px;
731
        }
732
 
733
        .footer-call:hover {
734
            text-decoration: none;
735
        }
736
 
737
        .geo-footer {
738
            text-align: center;
739
            color: #9aa1ab;
36689 ranu 740
            font-size: 13px;
36807 aman 741
            padding: 8px 16px 30px;
742
            line-height: 1.6;
36689 ranu 743
        }
36642 ranu 744
    </style>
745
</head>
746
<body>
747
 
36807 aman 748
<!-- ===== Top navbar ===== -->
749
<div class="top-nav">
750
    <a href="https://smartdukaan.com/" class="nav-brand">
751
        <img src="$rc.contextPath/resources/images/sd-logo.jpg" alt="SmartDukaan" class="brand-logo">
752
    </a>
753
    <span class="nav-help">
754
        <span class="q-label">Any questions?</span>
755
        <a href="tel:1800270273" class="nav-call">
756
            <span class="call-word">Call</span>
757
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#e1212a" stroke-width="2"
758
                 stroke-linecap="round" stroke-linejoin="round"><path
759
                    d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
760
            <span class="phone">1800 270 273</span>
761
        </a>
762
    </span>
763
</div>
764
 
765
<div class="subhead">
766
    <a href="https://smartdukaan.com/" class="btn-home">
767
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
768
             stroke-linecap="round" stroke-linejoin="round">
769
            <path d="M3 9.5L12 3l9 6.5"/>
770
            <path
771
                    d="M5 10v10h14V10"/>
772
            <path d="M9 20v-6h6v6"/>
773
        </svg>
774
        Home
775
    </a>
776
</div>
777
 
778
    #if($leadName && $leadName.trim() != "")
779
    <p class="greeting">Greetings, <strong>$leadName</strong>!</p>
780
    #else
781
    <p class="greeting">Greetings!</p>
782
    #end
783
 
36642 ranu 784
<div class="geo-card">
36807 aman 785
    <div class="card-head">
786
        <h4>Store Verification Form</h4>
787
        <p>Please provide your details for our Area Sales Manager to schedule a visit</p>
36642 ranu 788
    </div>
36807 aman 789
    <div class="card-body-geo">
36642 ranu 790
        <div class="step-indicator">
791
            <div class="step-dot current" id="dot1"></div>
792
            <div class="step-dot" id="dot2"></div>
793
        </div>
36807 aman 794
        <div class="step-caption" id="stepCaption">Step 1 of 2</div>
36642 ranu 795
 
36807 aman 796
        <!-- ===== STEP 1: Mobile verification (stays on the page) ===== -->
797
        <div class="step-section" id="step1Section">
798
            <div class="section-label"><span class="step-no">Step 1.</span> Verify Mobile Number</div>
799
            <label class="field-label" for="mobileNumber">Mobile Number <span class="req">*</span></label>
800
            <div class="mobile-row">
801
                <input type="tel" class="input-geo" id="mobileNumber" maxlength="10"
802
                       placeholder="Enter 10-digit registered mobile number" autocomplete="off">
803
                <div class="verified-pill" id="mobileVerified">
804
                    <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"
805
                         stroke-linecap="round" stroke-linejoin="round">
806
                        <path d="M4 12L9 17L20 6"/>
807
                    </svg>
808
                    Verified
809
                </div>
36642 ranu 810
            </div>
36807 aman 811
            <div id="mobileError" class="inline-err mt-3"></div>
812
            <button class="btn-primary-geo mt-3" id="btnVerifyMobile">Verify &amp; Continue</button>
36642 ranu 813
        </div>
814
 
36807 aman 815
        <!-- ===== STEP 2: Single combined capture — photo + auto location ===== -->
816
        <div class="step-section" id="step2Section" style="display:none;">
817
            <hr class="step-divider">
818
            <div class="section-label"><span class="step-no">Step 2.</span> Capture Your Store Photo</div>
819
            <p class="capture-help">
820
                Tap the button below to open your camera and take a live photo of your store front.
821
                Your location is recorded automatically with the photo.
822
                <span class="hindi">नीचे दिए गए बटन पर टैप करके कैमरा खोलें और अपनी दुकान के सामने की लाइव फोटो लें। आपकी लोकेशन फोटो के साथ अपने-आप रिकॉर्ड हो जाती है।</span>
36642 ranu 823
            </p>
36689 ranu 824
 
36807 aman 825
            <div class="camera-controls">
826
                <button type="button" class="btn-camera-open" id="btnOpenCamera">
827
                    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
828
                         stroke-linecap="round" stroke-linejoin="round">
829
                        <path
830
                                d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
831
                        <circle
832
                                cx="12" cy="13" r="4"/>
833
                    </svg>
834
                    <span class="label-en">Take a Photo</span>
835
                    <span class="sep">|</span>
836
                    <span class="label-hi">दुकान की फोटो लें</span>
36689 ranu 837
                </button>
36807 aman 838
                <button type="button" class="btn-camera-close" id="btnCloseCamera" style="display:none;"
839
                        aria-label="Close camera">
840
                    <svg class="close-x" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
841
                         stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
842
                        <line x1="18" y1="6" x2="6"
843
                              y2="18"/>
844
                        <line x1="6" y1="6" x2="18" y2="18"/>
845
                    </svg>
846
                    <span class="close-label">Close</span>
36689 ranu 847
                </button>
848
            </div>
849
 
36807 aman 850
            <div id="cameraStage" style="display:none;">
851
                <div class="camera-wrap" id="cameraWrap">
852
                    <video id="cameraVideo" autoplay playsinline muted></video>
853
                    <img id="photoPreview" alt="Captured photo" style="display:none;">
854
                    <div class="cam-overlay" id="cameraOverlay">Starting camera...</div>
855
                </div>
36689 ranu 856
 
36807 aman 857
                <div class="capture-row">
858
                    <button type="button" class="btn-capture" id="btnCapture" disabled>
859
                        <span class="inner"></span>
860
                    </button>
861
                    <button type="button" class="btn-retake" id="btnRetake" style="display:none;">Retake</button>
862
                </div>
863
            </div>
864
 
865
            <div id="captureStatus" class="capture-status"></div>
866
 
867
            <!-- Consent -->
868
            <div class="consent-box">
869
                <input type="checkbox" id="consentCheck">
870
                <label for="consentCheck">
871
                    I acknowledge that the information provided above is accurate and I consent to SmartDukaan's
872
                    Area Sales Manager visiting my store at the location specified. I understand that this
873
                    information will be used for onboarding purposes only.
874
                    <span class="hindi">मैं स्वीकार करता/करती हूँ कि ऊपर दी गई जानकारी सही है, और मैं SmartDukaan के एरिया सेल्स मैनेजर को बताए गए स्थान पर मेरी दुकान पर आने की सहमति देता/देती हूँ। मुझे पता है कि इस जानकारी का उपयोग केवल ऑनबोर्डिंग के लिए किया जाएगा।</span>
875
                </label>
876
            </div>
877
 
878
            <div id="submitError" class="inline-err"></div>
879
 
36642 ranu 880
            <input type="hidden" id="latitude" value="">
881
            <input type="hidden" id="longitude" value="">
36689 ranu 882
            <input type="hidden" id="imageDocumentId" value="0">
36642 ranu 883
 
36807 aman 884
            <button class="btn-submit" id="btnSubmit" disabled>Submit Details</button>
36642 ranu 885
        </div>
886
    </div>
887
</div>
888
 
36807 aman 889
<div class="footer-help">
890
    Need help? Call
891
    <a href="tel:1800270273" class="footer-call">
892
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
893
             stroke-linecap="round" stroke-linejoin="round">
894
            <path
895
                    d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/>
896
        </svg>
897
        1800 270 273
898
    </a>
899
</div>
900
<div class="geo-footer">
901
    &copy; 2026 SmartDukaan. All rights reserved.<br>
902
    Transforming mobile retail across India
903
</div>
904
 
36689 ranu 905
<!-- Hidden canvas used to grab a still frame from the live video stream -->
906
<canvas id="captureCanvas" style="display:none;"></canvas>
907
 
36642 ranu 908
<input type="hidden" id="leadId" value="$leadId">
909
 
910
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
911
<script>
912
    var contextPath = "$rc.contextPath";
36689 ranu 913
    var mediaStream = null; // live camera stream
914
 
36807 aman 915
    function markStepsAfterVerify() {
916
        $('#dot1').removeClass('current').addClass('done');
917
        $('#dot2').addClass('current');
918
        $('#stepCaption').text('Step 2 of 2');
36642 ranu 919
    }
920
 
36807 aman 921
    // ===== STEP 1: Verify mobile against the lead record =====
36642 ranu 922
    $('#btnVerifyMobile').click(function () {
923
        var mobile = $('#mobileNumber').val().trim();
924
        if (!mobile || mobile.length < 10) {
925
            $('#mobileError').text('Please enter a valid 10-digit mobile number').show();
926
            return;
927
        }
928
        var btn = $(this);
929
        btn.prop('disabled', true).html('<span class="spinner"></span> Verifying...');
930
        $('#mobileError').hide();
931
 
932
        $.ajax({
933
            url: contextPath + '/lead-geo/verify-mobile',
934
            method: 'POST',
935
            data: {leadId: $('#leadId').val(), mobileNumber: mobile},
936
            success: function (resp) {
937
                if (resp.response && resp.response.verified) {
36807 aman 938
                    // Lock step 1, reveal step 2 on the same page
939
                    $('#mobileNumber').prop('disabled', true).addClass('field-verified');
940
                    btn.hide();
941
                    $('#mobileVerified').addClass('show');
942
                    markStepsAfterVerify();
943
                    $('#step2Section').css('display', 'block').addClass('reveal-soft');
36642 ranu 944
                } else {
945
                    $('#mobileError').text('Verification failed. Please try again.').show();
36807 aman 946
                    btn.prop('disabled', false).text('Verify & Continue');
36642 ranu 947
                }
948
            },
949
            error: function (xhr) {
950
                var msg = 'Verification failed';
951
                try {
952
                    msg = JSON.parse(xhr.responseText).message || msg;
953
                } catch (e) {
954
                }
955
                $('#mobileError').text(msg).show();
36807 aman 956
                btn.prop('disabled', false).text('Verify & Continue');
36642 ranu 957
            }
958
        });
959
    });
960
 
36807 aman 961
    $('#mobileNumber').keypress(function (e) {
962
        if (e.which === 13) $('#btnVerifyMobile').click();
963
    });
964
 
965
    // Open the camera only when the user taps "Take Store Photo".
966
    // The button stays visible and a "Close" button appears so the user
967
    // stays in control of the camera.
968
    $('#btnOpenCamera').click(function () {
969
        $('#cameraStage').show();
970
        $('#btnCloseCamera').show();
971
        startCamera();
972
    });
973
 
974
    $('#btnCloseCamera').click(function () {
975
        stopCamera();
976
        $('#cameraStage').hide();
977
        $(this).hide();
978
    });
979
 
980
    // ===== STEP 2: Live camera — live capture only (no gallery picker). =====
981
    // Geolocation is grabbed silently at the instant the photo is captured,
982
    // so location and photo are a single combined action.
36689 ranu 983
    function startCamera() {
36807 aman 984
        var overlay = $('#cameraOverlay').show().text('Starting camera...');
985
        $('#photoPreview').hide();
986
        $('#cameraVideo').show();
36689 ranu 987
        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
988
            overlay.text('Your browser does not support live camera. Please open this link in Chrome/Safari on your phone.');
36642 ranu 989
            return;
990
        }
36689 ranu 991
        navigator.mediaDevices.getUserMedia({
992
            video: {facingMode: {ideal: 'environment'}}, // prefer rear camera
993
            audio: false
994
        }).then(function (stream) {
995
            mediaStream = stream;
996
            var video = document.getElementById('cameraVideo');
997
            video.srcObject = stream;
998
            video.onloadedmetadata = function () {
999
                overlay.hide();
1000
                $('#btnCapture').prop('disabled', false);
1001
            };
1002
        }).catch(function (err) {
1003
            var msg = 'Camera access denied. ';
1004
            if (err && err.name === 'NotAllowedError') msg += 'Please allow camera permission and reload.';
1005
            else if (err && err.name === 'NotFoundError') msg += 'No camera was found on this device.';
1006
            else if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
1007
                msg = 'Live camera requires HTTPS. Please open this link over a secure connection.';
1008
            }
1009
            overlay.text(msg);
1010
        });
1011
    }
36642 ranu 1012
 
36689 ranu 1013
    function stopCamera() {
1014
        if (mediaStream) {
1015
            mediaStream.getTracks().forEach(function (t) {
1016
                t.stop();
1017
            });
1018
            mediaStream = null;
1019
        }
1020
    }
36642 ranu 1021
 
36807 aman 1022
    // Capture frame + silently grab geolocation (single combined action)
36689 ranu 1023
    $('#btnCapture').click(function () {
1024
        var btn = $(this);
1025
        btn.prop('disabled', true);
36807 aman 1026
        $('#captureStatus').attr('class', 'capture-status ok').text('Capturing photo and your location...');
36689 ranu 1027
 
1028
        var video = document.getElementById('cameraVideo');
1029
        var canvas = document.getElementById('captureCanvas');
1030
        canvas.width = video.videoWidth;
1031
        canvas.height = video.videoHeight;
1032
        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
1033
 
36807 aman 1034
        // Show still preview, hide live video, allow retake
36689 ranu 1035
        var dataUrl = canvas.toDataURL('image/jpeg', 0.9);
1036
        $('#photoPreview').attr('src', dataUrl).show();
1037
        $('#cameraVideo').hide();
1038
        $('#btnRetake').show();
1039
 
1040
        canvas.toBlob(function (blob) {
1041
            if (!blob) {
1042
                btn.prop('disabled', false);
36807 aman 1043
                $('#captureStatus').attr('class', 'capture-status err').text('Could not capture photo. Try again.');
36689 ranu 1044
                return;
1045
            }
1046
            // Upload photo + grab geolocation in parallel
1047
            var uploadDone = uploadPhoto(blob);
1048
            var geoDone = captureGeo();
1049
            $.when(uploadDone, geoDone).done(function () {
36807 aman 1050
                $('#captureStatus').attr('class', 'capture-status ok')
1051
                        .html('&#10004; Store photo and location captured.');
36689 ranu 1052
                stopCamera();
36807 aman 1053
                refreshSubmitState();
36689 ranu 1054
            }).fail(function (msg) {
1055
                btn.prop('disabled', false);
36807 aman 1056
                $('#captureStatus').attr('class', 'capture-status err').text(msg || 'Capture failed. Try again.');
36689 ranu 1057
            });
1058
        }, 'image/jpeg', 0.9);
36642 ranu 1059
    });
1060
 
36689 ranu 1061
    $('#btnRetake').click(function () {
1062
        $('#photoPreview').hide();
1063
        $('#cameraVideo').show();
1064
        $(this).hide();
1065
        $('#imageDocumentId').val('0');
1066
        $('#latitude').val('');
1067
        $('#longitude').val('');
36807 aman 1068
        $('#captureStatus').attr('class', 'capture-status').hide();
1069
        refreshSubmitState();
36689 ranu 1070
        if (!mediaStream) startCamera();
1071
        else $('#btnCapture').prop('disabled', false);
36642 ranu 1072
    });
1073
 
36689 ranu 1074
    function uploadPhoto(blob) {
1075
        var d = $.Deferred();
36642 ranu 1076
        var formData = new FormData();
36689 ranu 1077
        formData.append('file', blob, 'store-photo.jpg');
36642 ranu 1078
        $.ajax({
1079
            url: contextPath + '/lead-geo/upload-image',
1080
            method: 'POST',
1081
            data: formData,
1082
            processData: false,
1083
            contentType: false,
1084
            success: function (resp) {
1085
                if (resp.response && resp.response.document_id) {
1086
                    $('#imageDocumentId').val(resp.response.document_id);
36689 ranu 1087
                    d.resolve();
1088
                } else {
1089
                    d.reject('Upload failed.');
36642 ranu 1090
                }
1091
            },
1092
            error: function () {
36689 ranu 1093
                d.reject('Upload failed. Please try again.');
36642 ranu 1094
            }
1095
        });
36689 ranu 1096
        return d.promise();
1097
    }
36642 ranu 1098
 
36689 ranu 1099
    function captureGeo() {
1100
        var d = $.Deferred();
1101
        if (!navigator.geolocation) {
1102
            d.reject('Geolocation not supported.');
1103
            return d.promise();
1104
        }
1105
        navigator.geolocation.getCurrentPosition(
1106
                function (pos) {
1107
                    $('#latitude').val(pos.coords.latitude);
1108
                    $('#longitude').val(pos.coords.longitude);
1109
                    d.resolve();
1110
                },
1111
                function (err) {
1112
                    var msg = 'Unable to get location. ';
1113
                    if (err.code === 1) msg += 'Please allow location permission.';
1114
                    else if (err.code === 2) msg += 'Location unavailable.';
1115
                    else if (err.code === 3) msg += 'Timed out. Try again.';
1116
                    d.reject(msg);
1117
                },
1118
                {enableHighAccuracy: true, timeout: 15000, maximumAge: 0}
1119
        );
1120
        return d.promise();
1121
    }
1122
 
36807 aman 1123
    // ===== Submit gating: photo + location + consent all required =====
1124
    function refreshSubmitState() {
1125
        var hasLocation = $('#latitude').val() !== '' && $('#longitude').val() !== '';
1126
        var hasImage = $('#imageDocumentId').val() !== '0';
1127
        var consented = $('#consentCheck').is(':checked');
1128
        $('#btnSubmit').prop('disabled', !(hasLocation && hasImage && consented));
1129
    }
1130
 
1131
    $('#consentCheck').change(refreshSubmitState);
1132
 
1133
    // ===== Submit =====
36642 ranu 1134
    $('#btnSubmit').click(function () {
1135
        var btn = $(this);
1136
        btn.prop('disabled', true).html('<span class="spinner"></span> Submitting...');
36807 aman 1137
        $('#submitError').hide();
36642 ranu 1138
 
1139
        $.ajax({
1140
            url: contextPath + '/lead-geo/submit',
1141
            method: 'POST',
1142
            data: {
1143
                leadId: $('#leadId').val(),
1144
                mobileNumber: $('#mobileNumber').val().trim(),
1145
                latitude: $('#latitude').val(),
1146
                longitude: $('#longitude').val(),
1147
                imageDocumentId: $('#imageDocumentId').val()
1148
            },
1149
            success: function (resp) {
36807 aman 1150
                $('.greeting').remove();
1151
                $('.geo-card').html(
1152
                        '<div class="success-wrap">' +
1153
                        '<svg class="success-svg" width="120" height="120" viewBox="0 0 52 52" fill="none">' +
1154
                        '<circle class="success-circle" cx="26" cy="26" r="24" fill="none" stroke="#22c55e"' +
1155
                        ' stroke-width="3" stroke-linecap="round" transform="rotate(-90 26 26)"></circle>' +
1156
                        '<path class="success-check" d="M16 27L23 34L37 19" fill="none" stroke="#22c55e" stroke-width="4"' +
1157
                        ' stroke-linecap="round" stroke-linejoin="round"></path>' +
36686 ranu 1158
                        '</svg>' +
36807 aman 1159
                        '<div>' +
1160
                        '<h4 class="success-msg">Thank you for verification</h4>' +
1161
                        '<p class="success-msg-hi">सत्यापन के लिए धन्यवाद</p>' +
1162
                        '</div>' +
36642 ranu 1163
                        '</div>'
1164
                );
36689 ranu 1165
                stopCamera();
36642 ranu 1166
            },
1167
            error: function () {
36807 aman 1168
                btn.prop('disabled', false).text('Submit Details');
1169
                $('#submitError').text('Submission failed. Please try again.').show();
36642 ranu 1170
            }
1171
        });
1172
    });
1173
</script>
1174
</body>
1175
</html>