Subversion Repositories SmartDukaan

Rev

Rev 37034 | Rev 37039 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37034 Rev 37038
Line 178... Line 178...
178
  .img-x:hover{background:rgba(255,255,255,.3)}
178
  .img-x:hover{background:rgba(255,255,255,.3)}
179
  .modal-back.show{display:flex}
179
  .modal-back.show{display:flex}
180
  .modal{background:#fff;border-radius:14px;max-width:780px;width:100%;padding:20px 22px;box-shadow:0 20px 60px rgba(10,20,50,.3);position:relative}
180
  .modal{background:#fff;border-radius:14px;max-width:780px;width:100%;padding:20px 22px;box-shadow:0 20px 60px rgba(10,20,50,.3);position:relative}
181
  .modal h3{margin:0 0 2px;font-size:17px;text-align:center}
181
  .modal h3{margin:0 0 2px;font-size:17px;text-align:center}
182
  .modal > .desc{text-align:center}
182
  .modal > .desc{text-align:center}
183
  .modal .x{position:absolute;top:14px;right:16px;cursor:pointer;color:var(--soft);font-size:22px;line-height:1;border:0;background:none}
183
  .modal .x,.rh-panel .x{position:absolute;top:14px;right:16px;cursor:pointer;color:var(--soft);font-size:22px;line-height:1;border:0;background:none}
184
  /* journey totals bar */
184
  /* journey totals bar */
185
  .jstats{display:flex;gap:9px;margin:12px 0 2px;flex-wrap:wrap}
185
  .jstats{display:flex;gap:9px;margin:12px 0 2px;flex-wrap:wrap}
186
  .js{flex:1;min-width:104px;background:#f8f9fc;border:1px solid var(--line2);border-radius:10px;padding:9px 10px;text-align:center}
186
  .js{flex:1;min-width:104px;background:#f8f9fc;border:1px solid var(--line2);border-radius:10px;padding:9px 10px;text-align:center}
187
  .js .jv{font-size:15.5px;font-weight:760;color:var(--ink);font-variant-numeric:tabular-nums}
187
  .js .jv{font-size:15.5px;font-weight:760;color:var(--ink);font-variant-numeric:tabular-nums}
188
  .js .jl{font-size:10px;color:var(--soft);text-transform:uppercase;letter-spacing:.04em;margin-top:3px;font-weight:600}
188
  .js .jl{font-size:10px;color:var(--soft);text-transform:uppercase;letter-spacing:.04em;margin-top:3px;font-weight:600}
Line 204... Line 204...
204
  .tlrow.left .tlremark{justify-content:flex-start}
204
  .tlrow.left .tlremark{justify-content:flex-start}
205
  .tlremark .rk{max-width:100%;background:#fbfcfe;border:1px solid var(--line2);border-left:3px solid #c7d0e8;border-radius:8px;padding:7px 10px;font-size:11.5px;color:#4a5468;line-height:1.45;word-break:break-word}
205
  .tlremark .rk{max-width:100%;background:#fbfcfe;border:1px solid var(--line2);border-left:3px solid #c7d0e8;border-radius:8px;padding:7px 10px;font-size:11.5px;color:#4a5468;line-height:1.45;word-break:break-word}
206
  .tlrow.right .tlremark .rk{text-align:right}
206
  .tlrow.right .tlremark .rk{text-align:right}
207
  .tlrow.left .tlremark .rk{text-align:left}
207
  .tlrow.left .tlremark .rk{text-align:left}
208
  .tlremark .rkl{font-size:9px;text-transform:uppercase;letter-spacing:.05em;color:var(--soft);font-weight:700;margin-bottom:3px}
208
  .tlremark .rkl{font-size:9px;text-transform:uppercase;letter-spacing:.05em;color:var(--soft);font-weight:700;margin-bottom:3px}
-
 
209
  .tlremark .rkhist{display:inline-block;margin-top:6px;background:none;border:0;padding:0;color:var(--brand);font-size:10.5px;font-weight:700;cursor:pointer}
-
 
210
  .tlremark .rkhist:hover{text-decoration:underline}
-
 
211
  /* past-discussions drawer */
-
 
212
  .rh-back{position:fixed;inset:0;background:rgba(15,22,40,.42);z-index:1200;display:none}
-
 
213
  .rh-back.show{display:block}
-
 
214
  .rh-panel{position:absolute;top:0;right:0;height:100%;width:min(400px,92vw);background:#fff;box-shadow:-8px 0 30px rgba(20,30,60,.18);display:flex;flex-direction:column;padding:18px 18px 14px;transform:translateX(100%);transition:transform .22s ease}
-
 
215
  .rh-back.show .rh-panel{transform:translateX(0)}
-
 
216
  .rh-panel h3{margin:0 0 2px;font-size:15px;color:var(--ink)}
-
 
217
  .rh-panel .desc{margin:0;font-size:12px;color:var(--soft)}
-
 
218
  .rh-list{flex:1;overflow-y:auto;margin-top:12px;display:flex;flex-direction:column;gap:9px}
-
 
219
  .rhitem{background:#fbfcfe;border:1px solid var(--line2);border-left:3px solid #c7d0e8;border-radius:9px;padding:9px 11px}
-
 
220
  .rhtop{display:flex;justify-content:space-between;align-items:center;gap:8px}
-
 
221
  .rhdate{font-size:11px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
-
 
222
  .rhb{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:1px 6px;border-radius:5px;white-space:nowrap}
-
 
223
  .rhb.ok{background:#e7f7ec;color:#1a7a3c}
-
 
224
  .rhb.def{background:#fff4e6;color:#e8590c}
-
 
225
  .rhexec{font-size:10px;color:var(--soft);font-weight:600;margin:3px 0 4px}
-
 
226
  .rhtext{font-size:12px;color:#4a5468;line-height:1.45;word-break:break-word;white-space:pre-wrap}
-
 
227
  .rhloading,.rhempty{color:var(--soft);font-size:12px;text-align:center;padding:24px 8px}
-
 
228
  .rh-more{margin-top:10px;background:var(--brand);color:#fff;border:0;border-radius:8px;padding:9px;font-weight:650;font-size:12.5px;cursor:pointer;display:none}
-
 
229
  .rh-more:disabled{opacity:.6;cursor:default}
209
  .tlcard .tm{flex:none;width:62px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#fff;font-weight:750;font-size:13px;padding:6px 4px;line-height:1.05}
230
  .tlcard .tm{flex:none;width:62px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#fff;font-weight:750;font-size:13px;padding:6px 4px;line-height:1.05}
210
  .tlcard .tm small{font-weight:600;font-size:8.5px;opacity:.9;text-transform:uppercase;letter-spacing:.04em;margin-top:3px}
231
  .tlcard .tm small{font-weight:600;font-size:8.5px;opacity:.9;text-transform:uppercase;letter-spacing:.04em;margin-top:3px}
211
  .tlcard .bd{padding:8px 11px;flex:1;min-width:0}
232
  .tlcard .bd{padding:8px 11px;flex:1;min-width:0}
212
  .tlcard .bd .ti{font-size:12.5px;font-weight:700;color:var(--ink);line-height:1.25;word-break:break-word}
233
  .tlcard .bd .ti{font-size:12.5px;font-weight:700;color:var(--ink);line-height:1.25;word-break:break-word}
213
  .tlcard .bd .stt{display:inline-block;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:1px 6px;border-radius:5px;margin-top:5px;color:#fff}
234
  .tlcard .bd .stt{display:inline-block;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:1px 6px;border-radius:5px;margin-top:5px;color:#fff}
Line 280... Line 301...
280
<div class="img-back" id="bj-img-back">
301
<div class="img-back" id="bj-img-back">
281
  <button class="img-x" id="bj-img-x" title="Close">&times;</button>
302
  <button class="img-x" id="bj-img-x" title="Close">&times;</button>
282
  <img id="bj-img" alt="Attachment">
303
  <img id="bj-img" alt="Attachment">
283
</div>
304
</div>
284
 
305
 
-
 
306
<!-- past-discussions drawer — slides in from the right, above the journey modal -->
-
 
307
<div class="rh-back" id="bj-rh-back" onclick="if(event.target===this)closeRemarkHistory()">
-
 
308
  <div class="rh-panel" id="bj-rh-panel">
-
 
309
    <button class="x" onclick="closeRemarkHistory()">&times;</button>
-
 
310
    <h3 id="bj-rh-title"></h3>
-
 
311
    <p class="desc" id="bj-rh-sub"></p>
-
 
312
    <div class="rh-list" id="bj-rh-list"></div>
-
 
313
    <button class="rh-more" id="bj-rh-more" onclick="bjLoadRemarkHistory()">Load more</button>
-
 
314
  </div>
-
 
315
</div>
-
 
316
 
285
<script>
317
<script>
286
var CTX = '${rc.contextPath}';
318
var CTX = '${rc.contextPath}';
287
var BASE = CTX + '/beat-journey';
319
var BASE = CTX + '/beat-journey';
288
var LENS = 'today';
320
var LENS = 'today';
289
var TODAY = '$today';
321
var TODAY = '$today';
Line 1501... Line 1533...
1501
          '<span class="stt" style="background:'+s.c+'">'+s.l+'</span>'+
1533
          '<span class="stt" style="background:'+s.c+'">'+s.l+'</span>'+
1502
          (tt==='lead' ? '<span class="stt unplanned">Unplanned</span>' : '')+
1534
          (tt==='lead' ? '<span class="stt unplanned">Unplanned</span>' : '')+
1503
          '<div class="mt">'+meta+'</div>'+extra+'</div>'+
1535
          '<div class="mt">'+meta+'</div>'+extra+'</div>'+
1504
      '</div>';
1536
      '</div>';
1505
  // remark sits on the opposite half of the timeline (empty spacer when none)
1537
  // remark sits on the opposite half of the timeline (empty spacer when none)
-
 
1538
  var rk='';
-
 
1539
  if(!x._punch && x.remarks){
1506
  var rk=(!x._punch && x.remarks) ? '<div class="rk"><div class="rkl">Remark</div>'+esc(x.remarks)+'</div>' : '';
1540
    rk='<div class="rk"><div class="rkl">Remark</div>'+esc(x.remarks);
-
 
1541
    if(x.taskId && x.taskId>0){
-
 
1542
      // one big-string timeline -> global fn + primitive args (partner name escaped for the attribute)
-
 
1543
      rk+='<button type="button" class="rkhist" onclick="bjOpenRemarkHistory('+x.taskId+',\''+js(x.taskType||'')+'\',\''+js(tlTitle(x))+'\')">&#128220; Past discussions</button>';
-
 
1544
    }
-
 
1545
    rk+='</div>';
-
 
1546
  }
1507
  var remark='<div class="tlremark">'+rk+'</div>';
1547
  var remark='<div class="tlremark">'+rk+'</div>';
1508
  var halves = side==='left' ? (card+remark) : (remark+card);
1548
  var halves = side==='left' ? (card+remark) : (remark+card);
1509
  return '<div class="tlrow '+side+'">'+
1549
  return '<div class="tlrow '+side+'">'+
1510
      '<div class="node" style="background:'+s.c+'">'+s.ic+'</div>'+
1550
      '<div class="node" style="background:'+s.c+'">'+s.ic+'</div>'+
1511
      halves+'</div>';
1551
      halves+'</div>';
Line 1513... Line 1553...
1513
function closeModal(){ el('bj-modal-back').classList.remove('show'); }
1553
function closeModal(){ el('bj-modal-back').classList.remove('show'); }
1514
// Image lightbox — opens an attachment larger, stacked above the journey modal.
1554
// Image lightbox — opens an attachment larger, stacked above the journey modal.
1515
function bjOpenImage(src){ if(!src) return; el('bj-img').src=src; el('bj-img-back').classList.add('show'); }
1555
function bjOpenImage(src){ if(!src) return; el('bj-img').src=src; el('bj-img-back').classList.add('show'); }
1516
function bjCloseImage(){ el('bj-img-back').classList.remove('show'); el('bj-img').removeAttribute('src'); }
1556
function bjCloseImage(){ el('bj-img-back').classList.remove('show'); el('bj-img').removeAttribute('src'); }
1517
 
1557
 
-
 
1558
/* ===================== REMARK HISTORY DRAWER ===================== */
-
 
1559
// All prior discussions for one partner/lead (task_id + task_type), across every
-
 
1560
// executive and date, newest first. Paged via /beat-journey/remark-history.
-
 
1561
function bjOpenRemarkHistory(taskId, taskType, name){
-
 
1562
  if(!taskId || taskId<=0) return;
-
 
1563
  window._rh = { taskId:taskId, taskType:taskType, name:name, offset:0, limit:8, items:[], loading:false, total:0 };
-
 
1564
  el('bj-rh-title').innerHTML='&#128220; '+esc(name);
-
 
1565
  el('bj-rh-sub').textContent='Past discussions across all executives';
-
 
1566
  el('bj-rh-list').innerHTML='<div class="rhloading"><div class="spinner"></div>Loading&hellip;</div>';
-
 
1567
  el('bj-rh-more').style.display='none';
-
 
1568
  el('bj-rh-back').classList.add('show');
-
 
1569
  bjLoadRemarkHistory();
-
 
1570
}
-
 
1571
function closeRemarkHistory(){ el('bj-rh-back').classList.remove('show'); window._rh=null; }
-
 
1572
function bjLoadRemarkHistory(){
-
 
1573
  var s=window._rh; if(!s || s.loading) return;          // block re-entrant fetches
-
 
1574
  s.loading=true;
-
 
1575
  var more=el('bj-rh-more'); more.disabled=true; more.textContent='Loading…';
-
 
1576
  var u=CTX+'/beat-journey/remark-history?taskId='+s.taskId
-
 
1577
        +'&taskType='+encodeURIComponent(s.taskType||'')
-
 
1578
        +'&offset='+s.offset+'&limit='+s.limit;
-
 
1579
  fetch(u,{headers:{'Accept':'application/json'}})
-
 
1580
    .then(function(r){ return r.json(); })
-
 
1581
    .then(function(d){
-
 
1582
      var st=window._rh; if(!st || st.taskId!==s.taskId) return;  // drawer changed mid-flight
-
 
1583
      st.total=d.total||0;
-
 
1584
      (d.items||[]).forEach(function(it){ st.items.push(it); });
-
 
1585
      st.offset += (d.items||[]).length;
-
 
1586
      st.loading=false;
-
 
1587
      bjRenderRemarkHistory(!!d.hasMore);
-
 
1588
    })
-
 
1589
    .catch(function(){
-
 
1590
      var st=window._rh; if(st) st.loading=false;
-
 
1591
      el('bj-rh-list').innerHTML='<div class="rhempty">Could not load past discussions.</div>';
-
 
1592
      el('bj-rh-more').style.display='none';
-
 
1593
    });
-
 
1594
}
-
 
1595
function bjRenderRemarkHistory(hasMore){
-
 
1596
  var s=window._rh; if(!s) return;
-
 
1597
  if(!s.items.length){
-
 
1598
    el('bj-rh-list').innerHTML='<div class="rhempty">No earlier discussions for this partner.</div>';
-
 
1599
    el('bj-rh-more').style.display='none';
-
 
1600
    return;
-
 
1601
  }
-
 
1602
  var h='';
-
 
1603
  s.items.forEach(function(it){
-
 
1604
    var mt=(it.markType||'').toUpperCase();
-
 
1605
    var badge = mt.indexOf('CHECKOUT')>=0 ? '<span class="rhb ok">visited</span>'
-
 
1606
              : (mt==='DEFERRED' ? '<span class="rhb def">deferred</span>' : '');
-
 
1607
    var when = esc(it.date||'')+(it.time?' &middot; '+esc(hhmm(it.time)):'');
-
 
1608
    h+='<div class="rhitem">'
-
 
1609
      +'<div class="rhtop"><span class="rhdate">'+when+'</span>'+badge+'</div>'
-
 
1610
      +'<div class="rhexec">'+esc(it.exec||'')+'</div>'
-
 
1611
      +'<div class="rhtext">'+esc(it.remark||'')+'</div></div>';
-
 
1612
  });
-
 
1613
  el('bj-rh-list').innerHTML=h;
-
 
1614
  var more=el('bj-rh-more');
-
 
1615
  more.disabled=false; more.textContent='Load more';
-
 
1616
  more.style.display = hasMore ? 'block' : 'none';
-
 
1617
}
-
 
1618
 
1518
/* ============================ APPROVAL ============================ */
1619
/* ============================ APPROVAL ============================ */
1519
function loadApproval(){
1620
function loadApproval(){
1520
  spinner();
1621
  spinner();
1521
  var from=el('bj-start').value, to=el('bj-end').value;
1622
  var from=el('bj-start').value, to=el('bj-end').value;
1522
  var u=CTX+'/beat-report/approval/data?fromDate='+encodeURIComponent(from)+'&toDate='+encodeURIComponent(to)+qs();
1623
  var u=CTX+'/beat-report/approval/data?fromDate='+encodeURIComponent(from)+'&toDate='+encodeURIComponent(to)+qs();