Rev 37508 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<style>.nm-wrapper {background: #f5f7fa;padding: 20px;}/* ─── Custom month-grid calendar ─────────────────────────────────── */.nc-header {display: flex;align-items: center;gap: 10px;margin-bottom: 12px;}.nc-title {font-size: 18px;font-weight: 600;color: #111;flex: 1;text-align: center;}.nc-nav-btn {background: #fff;border: 1px solid #d1d5db;border-radius: 6px;padding: 6px 12px;cursor: pointer;font-size: 14px;}.nc-nav-btn:hover {background: #f9fafb;}.nc-nav-btn.today {padding: 6px 14px;}.nc-grid {width: 100%;border-collapse: collapse;table-layout: fixed;}.nc-grid th {background: #f3f4f6;padding: 8px;font-size: 11px;font-weight: 600;letter-spacing: 0.5px;color: #6b7280;text-transform: uppercase;border: 1px solid #e5e7eb;text-align: left;}.nc-grid td {vertical-align: top;border: 1px solid #e5e7eb;height: 110px;padding: 4px;background: #fff;}.nc-grid td.nc-other-month {background: #fafbfc;color: #9ca3af;}.nc-grid td.nc-today .nc-day-num {background: #2563eb;color: #fff;border-radius: 999px;width: 24px;height: 24px;display: inline-flex;align-items: center;justify-content: center;}.nc-day-num {font-size: 12px;font-weight: 600;color: #374151;margin-bottom: 4px;padding: 0 4px;}.nc-events {display: flex;flex-direction: column;gap: 2px;overflow-y: auto;max-height: 82px;}.nc-event {font-size: 11px;padding: 2px 6px;border-radius: 4px;color: #fff;cursor: pointer;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.nc-event:hover {opacity: 0.9;}.nc-more {font-size: 10px;color: #6b7280;padding: 2px 6px;cursor: pointer;}.nm-crumb {color: #374151;font-size: 14px;margin: 4px 0 16px;padding: 8px 12px;background: #fff;border-radius: 6px;border: 1px solid #e5e7eb;}.nm-crumb a {color: #2563eb;}/* Tabs */.nm-tabs {display: flex;gap: 4px;border-bottom: 1px solid #e5e7eb;margin-bottom: 16px;}.nm-tab {padding: 10px 18px;color: #6b7280;cursor: pointer;text-decoration: none;border-bottom: 2px solid transparent;font-weight: 500;font-size: 14px;}.nm-tab:hover {color: #111827;text-decoration: none;}.nm-tab.active {color: #2563eb;border-bottom-color: #2563eb;}.nm-tab-badge {background: #e5e7eb;color: #374151;padding: 2px 8px;border-radius: 10px;font-size: 11px;margin-left: 6px;}.nm-tab-content {display: none;}.nm-tab-content.active {display: block;}.nm-card {background: #fff;border: 1px solid #e5e7eb;border-radius: 8px;padding: 20px;margin-bottom: 16px;}.nm-card-title {font-size: 18px;font-weight: 600;margin: 0 0 4px 0;color: #111827;}.nm-section-label {font-size: 11px;letter-spacing: 0.5px;color: #6b7280;font-weight: 600;margin: 20px 0 12px 0;text-transform: uppercase;}.nm-section-label:first-child {margin-top: 0;}.nm-format-row {display: flex;gap: 12px;margin-bottom: 16px;}.nm-format {flex: 1;border: 1px solid #e5e7eb;border-radius: 8px;padding: 14px;cursor: pointer;background: #fff;display: flex;align-items: center;gap: 12px;}.nm-format.active {border-color: #2563eb;box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);}.nm-format .nm-format-icon {width: 34px;height: 34px;border-radius: 8px;background: #eff6ff;color: #2563eb;display: flex;align-items: center;justify-content: center;font-size: 16px;}.nm-format-name {font-weight: 600;font-size: 14px;color: #111827;}.nm-format-sub {font-size: 12px;color: #6b7280;}.nm-format-full {flex-basis: 100%;text-decoration: none;}.nm-format-full:hover {border-color: #2563eb;box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);text-decoration: none;}.nm-format-full .nm-format-arrow {margin-left: auto;color: #2563eb;font-size: 18px;}.nm-field {margin-bottom: 16px;}.nm-field-label {display: block;font-size: 13px;font-weight: 500;color: #374151;margin-bottom: 6px;}.nm-field-label .nm-req {color: #dc2626;}.nm-input, .nm-select, .nm-textarea {width: 100%;padding: 8px 10px;border: 1px solid #d1d5db;border-radius: 6px;font-size: 14px;background: #fff;color: #111827;}.nm-textarea {min-height: 84px;resize: vertical;}.nm-input:focus, .nm-select:focus, .nm-textarea:focus {outline: 2px solid #93c5fd;border-color: #2563eb;}.nm-charcount {float: right;font-size: 12px;color: #6b7280;}.nm-two-col {display: grid;grid-template-columns: 1fr 1fr;gap: 16px;}.nm-help {font-size: 12px;color: #6b7280;margin-top: 4px;}.nm-actions {display: flex;gap: 10px;justify-content: flex-end;padding-top: 8px;}.nm-btn {padding: 9px 16px;border-radius: 6px;font-size: 14px;font-weight: 500;border: 1px solid transparent;cursor: pointer;}.nm-btn-outline {background: #fff;border-color: #d1d5db;color: #374151;}.nm-btn-outline:hover {background: #f9fafb;}.nm-btn-primary {background: #2563eb;color: #fff;}.nm-btn-primary:hover {background: #1d4ed8;}.nm-panel {display: none;}.nm-panel.active {display: block;}.nm-preview {display: none;}.nm-preview.active {display: block;}.nm-preview-label {font-size: 11px;letter-spacing: 0.6px;color: #6b7280;font-weight: 600;margin-bottom: 10px;text-transform: uppercase;}/* Push preview */.nm-phone {background: linear-gradient(160deg, #6b7ba0, #a97b8e);border-radius: 20px;padding: 34px 18px 22px 18px;min-height: 360px;position: relative;overflow: hidden;}.nm-phone-notch {position: absolute;top: 12px;left: 50%;transform: translateX(-50%);width: 78px;height: 22px;background: #111;border-radius: 12px;}.nm-phone-time {text-align: center;color: #fff;font-weight: 300;font-size: 44px;margin-top: 26px;}.nm-phone-date {text-align: center;color: #fff;font-size: 14px;margin-top: -4px;}.nm-noti-card {background: rgba(255, 255, 255, 0.96);border-radius: 12px;padding: 12px;margin-top: 60px;}.nm-noti-head {display: flex;align-items: center;gap: 8px;}.nm-noti-app-icon {width: 28px;height: 28px;background: #4a80c8;border-radius: 7px;color: #fff;display: flex;align-items: center;justify-content: center;font-weight: 700;font-size: 12px;}.nm-noti-app-name {font-size: 12px;font-weight: 600;color: #333;text-transform: uppercase;letter-spacing: 0.5px;flex: 1;}.nm-noti-when {font-size: 12px;color: #666;}.nm-noti-title {font-weight: 700;font-size: 14px;color: #111;margin-top: 6px;line-height: 1.3;}.nm-noti-body {font-size: 13px;color: #444;margin-top: 3px;line-height: 1.35;}/* Popup preview */.nm-popup-screen {background: #111827;border-radius: 20px;min-height: 360px;position: relative;padding: 22px;display: flex;align-items: center;justify-content: center;overflow: hidden;}/* Faux app background — a gradient + mock UI blocks that get blurred so the popupsits on top of "something that looks like the app" instead of a solid black slab. */.nm-popup-bg {position: absolute;inset: 0;background: linear-gradient(135deg, #eef2ff 0%, #dbeafe 40%, #ede9fe 100%);filter: blur(6px);}.nm-popup-bg::before, .nm-popup-bg::after {content: '';position: absolute;left: 8%;right: 8%;background: rgba(255, 255, 255, 0.85);border-radius: 12px;}.nm-popup-bg::before {top: 12%;height: 40px;}.nm-popup-bg::after {bottom: 12%;height: 120px;}.nm-popup-dim {position: absolute;inset: 0;background: rgba(17, 24, 39, 0.55);}.nm-popup-card {background: #fff;border-radius: 14px;padding: 18px;width: 92%;box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);position: relative;z-index: 1;}.nm-popup-image {width: 100%;max-height: 140px;object-fit: cover;border-radius: 10px;margin-bottom: 12px;display: block;}.nm-popup-close {position: absolute;top: 12px;right: 12px;background: #4b5563;color: #fff;width: 22px;height: 22px;border-radius: 50%;display: flex;align-items: center;justify-content: center;font-size: 14px;cursor: default;}.nm-popup-title {font-weight: 700;font-size: 15px;color: #111;}.nm-popup-body {font-size: 13px;color: #4b5563;margin-top: 6px;line-height: 1.4;}.nm-popup-cta {display: block;background: #2563eb;color: #fff;padding: 10px;border-radius: 10px;text-align: center;margin-top: 14px;font-weight: 600;font-size: 14px;}/* Story preview */.nm-story-screen {background: #111;border-radius: 20px;min-height: 360px;position: relative;padding: 18px;color: #fff;display: flex;flex-direction: column;}.nm-story-head {display: flex;align-items: center;gap: 8px;}.nm-story-body {flex: 1;display: flex;align-items: center;justify-content: center;color: #6b7280;font-size: 13px;text-align: center;padding: 10px;}.nm-story-title {font-weight: 700;font-size: 15px;margin-top: 8px;}.nm-story-msg {font-size: 12px;color: #d1d5db;margin-top: 4px;line-height: 1.4;}.nm-story-cta {border: 1px solid #fff;border-radius: 26px;padding: 10px;text-align: center;margin-top: 12px;font-weight: 600;font-size: 13px;}.nm-preview-cap {text-align: center;font-size: 12px;color: #6b7280;margin-top: 8px;}/* Desktop: keep the Live Preview + Summary column pinned as the form scrolls.Bootstrap 3 rows use floats, so cols don't match heights — sticky then hasno room to move within its parent. Force flex on the compose row socol-lg-4 stretches to match col-lg-8, giving sticky the scroll room it needs. */@media (min-width: 992px) {.nm-compose-row {display: flex;flex-wrap: wrap;}.nm-compose-row > [class*="col-"] {display: flex;flex-direction: column;}.nm-preview-sticky {position: sticky;top: 16px;align-self: flex-start; /* pin to top of the flex col, don't stretch */}}/* Mobile: preview column is hidden inline; floating button opens it as a modal. */.nm-preview-fab {display: none;position: fixed;right: 16px;bottom: 16px;z-index: 1030;background: #2563eb;color: #fff;border: 0;border-radius: 999px;padding: 12px 18px;font-weight: 600;font-size: 13px;box-shadow: 0 6px 18px rgba(37, 99, 235, 0.35);}@media (max-width: 991px) {.nm-preview-col {display: none;}.nm-compose-form-col {flex: 0 0 100%;max-width: 100%;}.nm-preview-fab {display: inline-flex;align-items: center;gap: 6px;}}.nm-summary-row {display: flex;justify-content: space-between;padding: 8px 0;font-size: 13px;border-bottom: 1px solid #f3f4f6;}.nm-summary-row:last-child {border-bottom: none;}.nm-summary-key {color: #6b7280;}.nm-summary-val {color: #111827;font-weight: 500;text-align: right;}.nm-summary-badge {background: #eff6ff;color: #2563eb;padding: 2px 8px;border-radius: 10px;font-size: 12px;}.nm-chip {display: inline-block;margin: 3px 4px;padding: 4px 10px;background: #eef2ff;color: #3730a3;border-radius: 12px;font-size: 13px;}.nm-chip .nm-chip-x {color: #b91c1c;margin-left: 6px;cursor: pointer;}/* Dropzone */.nm-dropzone {border: 2px dashed #d1d5db;border-radius: 10px;padding: 20px;text-align: center;cursor: pointer;background: #fafbfc;transition: background 0.15s, border-color 0.15s;}.nm-dropzone:hover {background: #f3f4f6;}.nm-dropzone.nm-dropzone-hover {background: #eff6ff;border-color: #2563eb;}.nm-dropzone-label {color: #6b7280;font-size: 13px;}.nm-dropzone-label i {font-size: 26px;color: #9ca3af;margin-bottom: 8px;display: block;}.nm-dropzone-label b {color: #111827;font-weight: 600;display: block;margin-bottom: 2px;font-size: 14px;}.nm-file-input {display: none;}.nm-thumb-list {list-style: none;padding-left: 0;margin-top: 10px;display: flex;flex-wrap: wrap;gap: 8px;}.nm-thumb {position: relative;width: 80px;height: 80px;border-radius: 8px;overflow: hidden;background: #f3f4f6;border: 1px solid #e5e7eb;}.nm-thumb img {width: 100%;height: 100%;object-fit: cover;}.nm-thumb-spinner {position: absolute;inset: 0;display: flex;align-items: center;justify-content: center;color: #6b7280;font-size: 20px;}.nm-thumb-x {position: absolute;top: 2px;right: 2px;background: rgba(0, 0, 0, 0.6);color: #fff;width: 20px;height: 20px;border-radius: 50%;display: flex;align-items: center;justify-content: center;font-size: 14px;cursor: pointer;}.nm-empty {text-align: center;padding: 60px 20px;color: #6b7280;background: #fff;border: 1px solid #e5e7eb;border-radius: 8px;}.nm-empty i {font-size: 36px;color: #d1d5db;margin-bottom: 12px;display: block;}</style><section class="nm-wrapper"><div class="nm-crumb"><i class="fa fa-home"></i> <a href="${rc.contextPath}/dashboard">Home</a> /<i class="fa fa-bell-o"></i> Notifications Manager</div><!-- Tabs --><div class="nm-tabs"><a href="javascript:void(0)" class="nm-tab active" data-tab="compose">Compose</a><a href="javascript:void(0)" class="nm-tab" data-tab="calendar">Calendar View</a>#* Content Library and Bulk Send tabs — feature under construction, hidden for now.<a href="javascript:void(0)" class="nm-tab" data-tab="library">Content Library <span class="nm-tab-badge" id="nmDraftCount">0</span></a><a href="javascript:void(0)" class="nm-tab" data-tab="bulk">Bulk Send</a>*#</div><!-- ─── Compose tab ─────────────────────────────────────────────── --><div class="nm-tab-content active" data-tab-content="compose"><!-- Format selector — full page width, spans over the two-column layout below.4 equal cards (Banner is a placeholder — COMING SOON). --><div class="nm-card"><div class="nm-format-row"><div class="nm-format active" data-format="PUSH"><div class="nm-format-icon"><i class="fa fa-bell"></i></div><div><div class="nm-format-name">Push notification</div><div class="nm-format-sub">Phone notification tray</div></div></div><div class="nm-format" data-format="IN_APP_POPUP"><div class="nm-format-icon"><i class="fa fa-square-o"></i></div><div><div class="nm-format-name">In-app pop-up</div><div class="nm-format-sub">Modal over the app</div></div></div><div class="nm-format" data-format="STORY"><div class="nm-format-icon"><i class="fa fa-mobile"></i></div><div><div class="nm-format-name">Story</div><div class="nm-format-sub">Home-screen stories strip</div></div></div><div class="nm-format" style="cursor:not-allowed;opacity:0.75;position:relative;"><div class="nm-format-icon"><i class="fa fa-image"></i></div><div><div class="nm-format-name">Banner Management</div><div class="nm-format-sub">Home-screen full-width banner</div></div><span style="position:absolute;top:6px;right:6px;color:#f59e0b;font-size:9px;font-weight:700;padding:2px 6px;border-radius:10px;background:#fef3c7;letter-spacing:0.4px;">COMING SOON</span></div></div></div><div class="row nm-compose-row"><!-- Left column: form --><div class="col-lg-8 col-md-8 nm-compose-form-col"><!-- Recipients (shared) --><div class="nm-card"><h4 class="nm-card-title" id="nmDetailsTitle">Notification details</h4><div class="nm-section-label">Recipients</div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Partner Name</label><select class="nm-select" id="fofo-users" name="fofo-users" multiple="multiple">#foreach($fofoId in $customRetailersMap.keySet())<option value="$fofoId">$customRetailersMap.get($fofoId).getBusinessName()</option>#end</select></div><div class="nm-field"><label class="nm-field-label">State Name</label><select class="nm-select" id="state-users" name="state-users" multiple="multiple">#foreach($warehouseMap in $warehouseMap.entrySet())<option value="$warehouseMap.getKey()">$warehouseMap.getValue()</option>#end</select></div><div class="nm-field"><label class="nm-field-label">Internal User</label><select class="nm-select" id="internal-users" name="internal-users" multiple="multiple">#foreach($userId in $userMap.keySet())<option value="$userId">$userMap.get($userId).getEmailId()</option>#end</select></div><div class="nm-field"><label class="nm-field-label">Campaign Group <span style="color:#6b7280;font-weight:400;">(optional)</span></label><select class="nm-select" id="nmCampaignGroup"><option value="">— None (ungrouped) —</option><option value="__new__">+ Create new campaign group…</option></select><div class="nm-help">Group related notifications together (e.g. all Monsoon Restock sends).Optional.</div></div><div class="nm-field"><label class="nm-field-label">Send label <span style="color:#6b7280;font-weight:400;">(what to call this specific send)</span></label><input class="nm-input" id="campaignName" name="campaignName" type="text"placeholder="e.g. Morning wave"></div></div></div><!-- Content --><div class="nm-card"><div class="nm-section-label">Content</div><div class="nm-field"><label class="nm-field-label">Title <span class="nm-req">*</span><span class="nm-charcount"><span id="titleCount">0</span>/80</span></label><input class="nm-input" id="title" name="title" type="text" maxlength="80"placeholder="Short attention-grabbing title"></div><div class="nm-field"><label class="nm-field-label">Message <span class="nm-req">*</span><span class="nm-charcount"><span id="messageCount">0</span>/240</span></label><textarea class="nm-textarea" id="message" name="message" maxlength="240"placeholder="Body of the notification"></textarea></div><!-- Push: multi-image + attachment --><div class="nm-panel active" data-panel="PUSH"><div class="nm-field"><label class="nm-field-label">Images <span style="color:#6b7280;font-weight:400;">(optional · shown as a carousel)</span></label><div class="nm-dropzone" data-target="pushImages" data-multi="true"><input type="file" class="nm-file-input" accept="image/*" multiple><div class="nm-dropzone-label"><i class="fa fa-upload"></i><b>Upload images</b>Drag & drop or click to browse · PNG, JPG up to 5 MB each</div></div><ul class="nm-thumb-list" data-target="pushImages"></ul></div><div class="nm-field"><label class="nm-field-label">Attachment <span style="color:#6b7280;font-weight:400;">(optional)</span></label><label class="nm-btn nm-btn-outline" style="display:inline-block;cursor:pointer;"><i class="fa fa-paperclip"></i> Attach document<input type="file" id="notifyDocument" name="notifyDocument" style="display:none;"></label><div class="nm-help">A PDF or image partners can open from the notification.</div></div></div><!-- Popup: single image --><div class="nm-panel" data-panel="IN_APP_POPUP"><div class="nm-field"><label class="nm-field-label">Pop-up image <span style="color:#6b7280;font-weight:400;">(optional)</span></label><div class="nm-dropzone" data-target="popupImage" data-multi="false"><input type="file" class="nm-file-input" accept="image/*"><div class="nm-dropzone-label"><i class="fa fa-upload"></i><b>Upload pop-up image</b>Drag & drop or click to browse · PNG, JPG up to 5 MB</div></div><ul class="nm-thumb-list" data-target="popupImage"></ul></div></div><!-- Story: multi-card carousel --><div class="nm-panel" data-panel="STORY"><div class="nm-field"><label class="nm-field-label">Story cards <span style="color:#6b7280;font-weight:400;">(shown as a carousel)</span></label><div class="nm-dropzone" data-target="storyCards" data-multi="true"><input type="file" class="nm-file-input" accept="image/*" multiple><div class="nm-dropzone-label"><i class="fa fa-upload"></i><b>Upload story cards</b>Drag & drop or click to browse · PNG, JPG up to 5 MB each</div></div><ul class="nm-thumb-list" data-target="storyCards"></ul></div></div><!-- Shared: Link a live scheme / offer / product --><div class="nm-field" style="border-top:1px solid #f3f4f6;padding-top:16px;margin-top:16px;"><label class="nm-field-label">Link a live scheme / offer / product <spanstyle="color:#6b7280;font-weight:400;">(optional)</span></label><div class="nm-two-col"><select class="nm-select" id="linkableType"><option value="">— Pick a type —</option><option value="SCHEME">Scheme</option><option value="OFFER">Offer</option><option value="PRODUCT">Product</option></select><div><!-- Populated for SCHEME / OFFER (dropdown of active items) --><select class="nm-select" id="linkablePicker" style="display:none;"><option value="">— Loading —</option></select><!-- Populated for PRODUCT (Bootstrap typeahead against /entity) --><div id="linkableSearchWrap" style="display:none;"><input class="nm-input" id="linkableSearchInput" type="text"placeholder="Type at least 2 letters to search products…"autocomplete="off" data-provide="typeahead"></div></div></div><ul id="linkedEntitiesList" style="list-style:none;padding-left:0;margin-top:10px;"></ul><div class="nm-help">Tapping the notification takes the partner straight to the attachedentity.</div></div></div><!-- Tap behaviour --><div class="nm-card"><div class="nm-section-label">Tap behaviour</div><div class="nm-panel" data-panel="IN_APP_POPUP"><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Button label</label><input class="nm-input" id="buttonLabelPopup" type="text" placeholder="e.g. View offer"></div><div class="nm-field"><label class="nm-field-label">Buttons to show</label><div><label style="font-weight:400;font-size:13px;"><input type="checkbox" id="showCta" checked style="margin-right:6px;">CTA button —the main action</label></div><div style="margin-top:6px;"><label style="font-weight:400;font-size:13px;"><input type="checkbox" id="showClose" checked style="margin-right:6px;">Close × —partner can dismiss it</label></div></div></div></div><div class="nm-panel" data-panel="STORY"><div class="nm-field"><label class="nm-field-label">Button label</label><input class="nm-input" id="buttonLabelStory" type="text" placeholder="e.g. View offer"></div></div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Action when tapped</label><select class="nm-select" id="type" name="type"><option value="url" selected>Open a link (web page)</option><option value="none">None (no action)</option><option value="native">Open native screen</option><option value="update">Trigger app update</option></select></div><div class="nm-field" id="nmLinkField"><label class="nm-field-label">Link to open</label><select class="nm-select" id="selectedUrl" onchange="nmChangeUrl()"><option value="" selected disabled>Pick a link</option><optgroup label="Partner app (React)"><option value="/home">Home</option><option value="/dashboard">Dashboard</option><option value="/sell">Sell Mode</option><option value="/buy/deals">Buy Deals</option><option value="/buy/brands">Brands</option><option value="/buy/hot-deals">Hot Deals</option><option value="/buy/clearance">Clearance</option><option value="/buy/cart">Cart</option><option value="/schemes">Schemes / Earn</option><option value="/orders">Orders</option><option value="/notifications">Notifications</option></optgroup><optgroup label="Legacy fofo URLs"><option value="https://app.smartdukaan.com/pages/home/dashboard">app.smartdukaan.com/pages/home/dashboard</option><option value="https://app.smartdukaan.com/pages/home/notifications">app.smartdukaan.com/pages/home/notifications</option><option value="https://app.smartdukaan.com/pages/home/services">app.smartdukaan.com/pages/home/services</option><option value="https://app.smartdukaan.com/pages/home/recharge">app.smartdukaan.com/pages/home/recharge</option><option value="https://app.smartdukaan.com/pages/home/damageProtectioninfo">app.smartdukaan.com/pages/home/damageProtectioninfo</option></optgroup><option value="other">other (enter below)</option></select><input class="nm-input" id="url" name="url" type="text" placeholder="https://..."style="margin-top:6px;display:none;"></div></div></div><!-- Push: Delivery --><div class="nm-card nm-panel active" data-panel="PUSH"><div class="nm-section-label">Delivery</div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Category</label><select class="nm-select" id="nmCategory" name="category"><option value="" selected disabled>Select category</option><option value="ANNOUNCE">Announce</option><option value="NOTIFICATION">Notification</option><option value="REMINDER">Reminder</option><option value="ALERT">Alert</option></select><div class="nm-help">Drives the colour tag on the calendar.</div></div><div class="nm-field"><label class="nm-field-label">Notification life span</label><select class="nm-select" id="nmHasExpiry"><option value="no" selected>Lifetime (no expiry)</option><option value="yes">Set an expiry date</option></select><div class="nm-help">Some notifications should stay in the partner's app forever. Pick "Setan expiry" only when it should auto-remove.</div></div><div class="nm-field" id="nmExpiryDateField" style="display:none;"><label class="nm-field-label">Expiry Date <span class="nm-req">*</span></label><input class="nm-input" id="expireSat" name="dateTime" type="text"><div class="nm-help">After this date it stops showing in the partner's app.</div></div></div></div><!-- Popup: Display rules --><div class="nm-card nm-panel" data-panel="IN_APP_POPUP"><div class="nm-section-label">Display rules</div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Category</label><select class="nm-select" id="nmCategoryPopup" name="category"><option value="" selected disabled>Select category</option><option value="ANNOUNCE">Announce</option><option value="NOTIFICATION">Notification</option><option value="REMINDER">Reminder</option><option value="ALERT">Alert</option></select></div><div class="nm-field"><label class="nm-field-label">Show on page (route) <span class="nm-req">*</span></label><select class="nm-select" id="showOnPage"><option value="" selected disabled>Select page</option><option value="/home">/home (Home)</option><option value="/dashboard">/dashboard (Dashboard)</option><option value="/buy/brands/mobile">/buy/brands/mobile (Buy mode)</option><option value="/sell">/sell (Sell mode)</option><option value="/sell/checkout">/sell/checkout (Sell cart)</option><option value="/buy/cart">/buy/cart (Buy bag)</option><option value="/wallet">/wallet (My money)</option></select><div class="nm-help">Pick the exact page where the pop-up should appear. Required so itdoesn't leak onto every screen.</div></div><div class="nm-field"><label class="nm-field-label">How long it stays up</label><select class="nm-select" id="autoCloseSeconds"><option value="">Until the partner closes it</option><option value="5">5 seconds</option><option value="10">10 seconds</option><option value="30">30 seconds</option></select></div><div class="nm-field"><label class="nm-field-label">Live from</label><input class="nm-input" id="popupLiveFrom" type="date"></div><div class="nm-field"><label class="nm-field-label">Live until <span class="nm-req">*</span></label><input class="nm-input" id="popupLiveUntil" type="date"><div class="nm-help">After this date the pop-up stops appearing.</div></div></div></div><!-- Story: Publishing --><div class="nm-card nm-panel" data-panel="STORY"><div class="nm-section-label">Publishing</div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Category</label><select class="nm-select" id="nmCategoryStory" name="category"><option value="" selected disabled>Select category</option><option value="ANNOUNCE">Announce</option><option value="NOTIFICATION">Notification</option><option value="REMINDER">Reminder</option><option value="ALERT">Alert</option></select></div><div class="nm-field"><label class="nm-field-label">Story category</label><select class="nm-select" id="postInCategory"><option value="" selected disabled>Select category</option><option value="all-brands-listing">All brands listing (mobile brands)</option><option value="price-change">Price change</option><option value="announcement">Announcement</option><option value="offer">Offer</option></select></div><div class="nm-field"><label class="nm-field-label">Play duration per card</label><select class="nm-select" id="playDurationSeconds"><option value="3">3 seconds</option><option value="5" selected>5 seconds</option><option value="8">8 seconds</option><option value="10">10 seconds</option></select></div><div class="nm-field"><label class="nm-field-label">Expires after</label><select class="nm-select" id="expiresAfterPolicy"><option value="FIXED_HOURS">24 hours from publish</option><option value="ON_DATE">On a set date</option></select></div><div class="nm-field"><label class="nm-field-label">Live from</label><input class="nm-input" id="storyLiveFrom" type="date"></div><div class="nm-field" id="storyExpiryOnDateField" style="display:none;"><label class="nm-field-label">Expires on</label><input class="nm-input" id="storyExpiryOnDate" type="date"></div></div></div><!-- Actions --><div class="nm-card"><div class="nm-actions"><button class="nm-btn nm-btn-outline" id="nmResetBtn" type="button"><iclass="fa fa-refresh"></i> Reset</button><button class="nm-btn nm-btn-outline" id="nmScheduleBtn" type="button"><iclass="fa fa-clock-o"></i> Schedule</button><button class="nm-btn nm-btn-primary create-notification-button" type="button"><i class="fa fa-paper-plane"></i> <span id="nmPrimaryCtaLabel">Send now</span></button></div></div></div><!-- Right column: preview + summary. Hidden on mobile; the floating"Preview" button opens it in a bottom-sheet modal instead. --><div class="col-lg-4 col-md-4 nm-preview-col"><div class="nm-preview-sticky"><div class="nm-card"><div class="nm-preview-label">Live preview</div><div class="nm-preview active" data-preview="PUSH"><div class="nm-phone"><div class="nm-phone-notch"></div><div class="nm-phone-time" id="nmPhoneTime">5:31</div><div class="nm-phone-date" id="nmPhoneDate">Tuesday, 14 Jul</div><div class="nm-noti-card"><div class="nm-noti-head"><div class="nm-noti-app-icon">SD</div><div class="nm-noti-app-name">SMARTDUKAAN</div><div class="nm-noti-when">now</div></div><div class="nm-noti-title" id="nmPreviewTitlePush">Restock offer: up to 40% marginthis week</div><div class="nm-noti-body" id="nmPreviewBodyPush">Order now and earn extra margin onstaples. Free logistics on orders above ₹5,000. Tap to view the catalogue.</div></div></div><div class="nm-preview-cap">Partner app · lock-screen push</div></div><div class="nm-preview" data-preview="IN_APP_POPUP"><div class="nm-popup-screen"><!-- Blurred faux app background (dims when the popup covers it) --><div class="nm-popup-bg"></div><div class="nm-popup-dim"></div><div class="nm-popup-card"><div class="nm-popup-close" id="nmPopupPreviewClose">×</div><img class="nm-popup-image" id="nmPreviewImagePopup" src="" alt=""style="display:none;"/><div class="nm-popup-title" id="nmPreviewTitlePopup">Restock offer: up to 40% marginthis week</div><div class="nm-popup-body" id="nmPreviewBodyPopup">Order now and earn extra marginon staples. Free logistics on orders above ₹5,000. Tap to view the catalogue.</div><div class="nm-popup-cta" id="nmPreviewCtaPopup">View offer</div></div></div><div class="nm-preview-cap">Partner app · in-app pop-up</div></div><div class="nm-preview" data-preview="STORY"><div class="nm-story-screen"><div class="nm-story-head"><div class="nm-noti-app-icon">SD</div><div><div style="font-size:12px;font-weight:600;">SmartDukaan</div><div style="font-size:11px;color:#9ca3af;">Just now</div></div></div><div class="nm-story-body">Upload a photo or video to fill the story</div><div><div class="nm-story-title" id="nmPreviewTitleStory">Restock offer: up to 40% marginthis week</div><div class="nm-story-msg" id="nmPreviewBodyStory">Order now and earn extra margin onstaples. Free logistics on orders above ₹5,000. Tap to view the catalogue.</div><div class="nm-story-cta" id="nmPreviewCtaStory">View offer ↑</div></div></div><div class="nm-preview-cap">Partner app · home-screen story</div></div></div><div class="nm-card"><h4 class="nm-card-title" style="margin-bottom:8px;">Summary</h4><div class="nm-summary-row"><span class="nm-summary-key">Format</span><span class="nm-summary-val"><span id="nmSummaryFormat" class="nm-summary-badge">Push notification</span></span></div><div class="nm-summary-row"><span class="nm-summary-key">Recipients</span><span class="nm-summary-val" id="nmSummaryRecipients">Not selected</span></div><div class="nm-summary-row"><span class="nm-summary-key">Campaign</span><span class="nm-summary-val" id="nmSummaryCampaign">—</span></div><div class="nm-summary-row"><span class="nm-summary-key">Category</span><span class="nm-summary-val" id="nmSummaryCategory">Not set</span></div><div class="nm-summary-row"><span class="nm-summary-key">On tap</span><span class="nm-summary-val" id="nmSummaryTap"style="word-break:break-all;max-width:60%;">—</span></div><div class="nm-summary-row"><span class="nm-summary-key">Expires</span><span class="nm-summary-val" id="nmSummaryExpires">—</span></div><div class="nm-summary-row"><span class="nm-summary-key">Scheduled</span><span class="nm-summary-val" id="nmSummarySchedule">Send now</span></div></div></div><!-- /.nm-preview-sticky --></div></div></div><!-- ─── Calendar tab ────────────────────────────────────────────── --><div class="nm-tab-content" data-tab-content="calendar"><div class="nm-card"><div style="margin-bottom:12px;font-size:13px;color:#6b7280;"><b style="color:#111;">Legend:</b><span style="display:inline-block;width:10px;height:10px;background:#3a87ad;border-radius:2px;margin:0 4px 0 12px;"></span>Scheduled<span style="display:inline-block;width:10px;height:10px;background:#5cb85c;border-radius:2px;margin:0 4px 0 12px;"></span>Dispatched<span style="display:inline-block;width:10px;height:10px;background:#999;border-radius:2px;margin:0 4px 0 12px;"></span>Cancelled<span style="display:inline-block;width:10px;height:10px;background:#d9534f;border-radius:2px;margin:0 4px 0 12px;"></span>Failed</div><div id="notification-calendar"><div class="nc-header"><button class="nc-nav-btn" id="ncPrev">‹</button><button class="nc-nav-btn today" id="ncToday">Today</button><button class="nc-nav-btn" id="ncNext">›</button><div class="nc-title" id="ncTitle">—</div></div><table class="nc-grid"><thead><tr><th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th></tr></thead><tbody id="ncBody"></tbody></table></div></div><!-- Upcoming Scheduled Notifications table --><div class="nm-card" style="margin-top:16px;"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;"><div><b style="color:#111;font-size:15px;">Upcoming Scheduled Notifications</b><div style="font-size:12px;color:#6b7280;margin-top:2px;">Content, audience and status for every future PUSH fire in the next<select id="nslDays" style="border:1px solid #e5e7eb;border-radius:4px;padding:2px 4px;"><option value="7">7</option><option value="30" selected>30</option><option value="60">60</option><option value="90">90</option></select>days.</div></div><button type="button" id="nslRefresh" class="nm-btn nm-btn-outline">Refresh</button></div><div style="overflow-x:auto;"><table class="table table-striped" id="nslTable" style="margin:0;font-size:13px;"><thead><tr><th style="white-space:nowrap;">When</th><th>Group</th><th>Content</th><th>Category</th><th style="text-align:right;white-space:nowrap;">Audience</th><th>Status</th><th style="text-align:right;">Actions</th></tr></thead><tbody id="nslBody"><tr><td colspan="7" style="text-align:center;color:#9ca3af;padding:24px;">Loading…</td></tr></tbody></table></div></div><!-- Recent Notifications (everything you've created, all formats) --><div class="nm-card" style="margin-top:16px;"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;"><div><b style="color:#111;font-size:15px;">Recent Notifications</b><div style="font-size:12px;color:#6b7280;margin-top:2px;">Every notification (Push, Pop-up, Story) you've created in the last<select id="nrlDays" style="border:1px solid #e5e7eb;border-radius:4px;padding:2px 4px;"><option value="7">7</option><option value="30" selected>30</option><option value="60">60</option><option value="90">90</option></select>days. Most recent first.</div></div><button type="button" id="nrlRefresh" class="nm-btn nm-btn-outline">Refresh</button></div><div style="overflow-x:auto;"><table class="table table-striped" id="nrlTable" style="margin:0;font-size:13px;"><thead><tr><th style="white-space:nowrap;">Created</th><th>Format</th><th>Group</th><th>Content</th><th>Category</th><th>Delivery</th><th style="text-align:right;white-space:nowrap;">Audience</th><th style="text-align:right;">Actions</th></tr></thead><tbody id="nrlBody"><tr><td colspan="8" style="text-align:center;color:#9ca3af;padding:24px;">Loading…</td></tr></tbody></table></div></div></div>#* Content Library + Bulk Send tab bodies — hidden while the tabs themselves are commented out.<!-- ─── Content Library tab (placeholder) ───────────────────────── --><div class="nm-tab-content" data-tab-content="library"><div class="nm-empty"><i class="fa fa-folder-open-o"></i><b style="color:#111;font-size:16px;">Content Library</b><div style="margin-top:6px;">Saved drafts will appear here. Coming soon.</div></div></div><!-- ─── Bulk Send tab (placeholder) ─────────────────────────────── --><div class="nm-tab-content" data-tab-content="bulk"><div class="nm-empty"><i class="fa fa-upload"></i><b style="color:#111;font-size:16px;">Bulk Send</b><div style="margin-top:6px;">Upload a CSV to send notifications in bulk. Coming soon.</div></div></div>*#<!-- Mobile-only floating "Preview" button. On desktop the preview panel isalways visible on the right (and sticky-pinned as you scroll). --><button type="button" id="nmPreviewFab" class="nm-preview-fab"><i class="fa fa-mobile"></i> Preview</button></section><!-- Mobile preview modal — receives the .nm-preview-sticky node on open so wedon't duplicate the preview DOM (all the existing jQuery selectors keep working). --><div id="nmMobilePreviewModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content" style="background:white;"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title">Live preview</h4></div><div class="modal-body" id="nmMobilePreviewBody" style="max-height:80vh;overflow-y:auto;"></div></div></div></div><!-- Create Campaign Group modal --><div id="nmGroupModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content" style="background:white;"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title">Create Campaign Group</h4></div><div class="modal-body"><div class="nm-field"><label class="nm-field-label">Name <span class="nm-req">*</span></label><input class="nm-input" id="nmGroupName" type="text" placeholder="e.g. Monsoon Restock Drive"></div><div class="nm-field"><label class="nm-field-label">Description <spanstyle="color:#6b7280;font-weight:400;">(optional)</span></label><textarea class="nm-textarea" id="nmGroupDesc" placeholder="Short note about what this group is for"style="min-height:60px;"></textarea></div><div class="nm-two-col"><div class="nm-field"><label class="nm-field-label">Starts on <spanstyle="color:#6b7280;font-weight:400;">(optional)</span></label><input class="nm-input" id="nmGroupStarts" type="date"></div><div class="nm-field"><label class="nm-field-label">Ends on <spanstyle="color:#6b7280;font-weight:400;">(optional)</span></label><input class="nm-input" id="nmGroupEnds" type="date"></div></div></div><div class="modal-footer"><button type="button" class="nm-btn nm-btn-outline" data-dismiss="modal">Cancel</button><button type="button" id="nmCreateGroupBtn" class="nm-btn nm-btn-primary">Create</button></div></div></div></div><!-- Schedule modal --><div id="nmScheduleModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content" style="background:white;"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title">Schedule Notification</h4></div><div class="modal-body"><p style="color:#6b7280;font-size:13px;">Add one or more send times. The notification will fan out at each scheduled moment.</p><div style="display:flex;gap:8px;"><input id="scheduleDateInput" type="datetime-local" class="nm-input" style="flex:1;"><button id="addScheduleDate" type="button" class="nm-btn nm-btn-outline">Add date</button></div><ul id="scheduleDatesList" style="list-style:none;padding-left:0;margin-top:12px;min-height:32px;"></ul></div><div class="modal-footer"><button type="button" class="nm-btn nm-btn-outline" data-dismiss="modal">Close</button><button type="button" id="nmSubmitScheduleBtn" class="nm-btn nm-btn-primary">Schedule & save</button></div></div></div></div><!-- Full campaign detail modal (content + audience list + schedules) --><div id="campaignDetailModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog modal-lg"><div class="modal-content" style="background:white;"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title" id="cdmTitle">Campaign detail</h4></div><div class="modal-body" id="cdmBody" style="max-height:70vh;overflow-y:auto;"><div style="text-align:center;color:#9ca3af;padding:24px;">Loading…</div></div><div class="modal-footer"><button type="button" class="nm-btn nm-btn-outline" data-dismiss="modal">Close</button></div></div></div></div><!-- Calendar event detail modal --><div id="scheduleDetailModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content" style="background:white;"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title">Scheduled Notification</h4></div><div class="modal-body"><p><strong>Campaign:</strong> <span id="ncDetailCampaign"></span></p><p><strong>Scheduled at:</strong> <span id="ncDetailWhen"></span></p><p><strong>Status:</strong> <span id="ncDetailStatus"></span></p><p><strong>Schedule ID:</strong> <span id="ncDetailScheduleId"></span></p><div id="ncAddScheduleBox"style="display:none;margin-top:16px;padding:12px;border:1px solid #e5e7eb;border-radius:6px;background:#f9fafb;"><p style="margin:0 0 8px;font-weight:600;">Add another schedule for this campaign</p><div style="display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end;"><div style="flex:1;min-width:140px;"><label style="display:block;font-size:12px;color:#6b7280;margin-bottom:4px;">Date</label><input type="date" id="ncAddDate" class="form-control"/></div><div style="flex:1;min-width:140px;"><label style="display:block;font-size:12px;color:#6b7280;margin-bottom:4px;">Time</label><input type="time" id="ncAddTime" class="form-control"/></div><button type="button" id="ncAddSaveBtn" class="nm-btn nm-btn-primary">Save</button></div><p id="ncAddErr" style="display:none;color:#dc2626;font-size:12px;margin:8px 0 0;"></p></div></div><div class="modal-footer"><button type="button" class="nm-btn nm-btn-outline" data-dismiss="modal">Close</button><button type="button" id="ncAddScheduleBtn" class="nm-btn nm-btn-outline" style="display:none;">+ Addanother schedule</button><button type="button" id="ncCancelBtn" class="nm-btn nm-btn-outline"style="color:#dc2626;border-color:#fecaca;">Cancel Schedule</button></div></div></div></div><script>$(function () {var mopts = {includeSelectAllOption: true, multiple: true, maxHeight: 200,buttonWidth: '100%', numberDisplayed: 1, enableFiltering: true, enableCaseInsensitiveFiltering: true};$('#fofo-users').multiselect($.extend({}, mopts, {nonSelectedText: 'Select partner'}));$('#state-users').multiselect($.extend({}, mopts, {nonSelectedText: 'Select state'}));$('#internal-users').multiselect($.extend({}, mopts, {nonSelectedText: 'Select user'}));$('input[name="dateTime"]').daterangepicker(getSingleDatePicker());function tickPreviewClock() {var d = new Date();var hh = d.getHours(), mm = String(d.getMinutes()).padStart(2, '0');$('#nmPhoneTime').text(hh + ':' + mm);$('#nmPhoneDate').text(d.toLocaleDateString(undefined, {weekday: 'long', day: 'numeric', month: 'short'}));}tickPreviewClock();setInterval(tickPreviewClock, 30000);});function nmChangeUrl() {if ($('#selectedUrl').val() === 'other') {$('#url').show();} else {$('#url').hide();}}</script>