Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
37526 amit 1
<section class="wrapper">
2
<div class="ocs-root">
3
 
4
  <style>
5
  /* Scoped to .ocs-root so it cannot leak into the admin theme. Colours use rgb()
6
     and selectors use classes, never id-hashes - Velocity would try to parse a
7
     leading "#" as a directive. */
8
  .ocs-root {
9
    --ocs-surface: rgb(255, 255, 255);
10
    --ocs-border: rgb(226, 232, 240);
11
    --ocs-text: rgb(15, 23, 42);
12
    --ocs-muted: rgb(100, 116, 139);
13
    --ocs-accent: rgb(79, 70, 229);
14
    --ocs-accent-soft: rgb(238, 242, 255);
15
    --ocs-ok: rgb(22, 163, 74);
16
    --ocs-ok-soft: rgb(240, 253, 244);
17
    --ocs-warn: rgb(180, 83, 9);
18
    --ocs-warn-soft: rgb(255, 251, 235);
19
    --ocs-danger: rgb(190, 18, 60);
20
    --ocs-danger-soft: rgb(255, 241, 242);
21
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
22
    color: var(--ocs-text);
23
    font-size: 13px;
24
    line-height: 1.5;
25
    padding: 18px 22px 32px;
26
    box-sizing: border-box;
27
  }
28
  .ocs-root *, .ocs-root *::before, .ocs-root *::after { box-sizing: border-box; }
29
 
30
  .ocs-head { display: flex; align-items: flex-start; justify-content: space-between;
31
              gap: 16px; flex-wrap: wrap; margin-bottom: 8px; }
32
  .ocs-title { font-size: 20px; font-weight: 650; letter-spacing: -0.01em; margin: 0; }
33
  .ocs-sub { color: var(--ocs-muted); margin: 4px 0 0; font-size: 12.5px; max-width: 70ch; }
34
 
35
  .ocs-note { background: var(--ocs-warn-soft); border: 1px solid rgb(253, 230, 138);
36
              color: var(--ocs-warn); border-radius: 8px; padding: 9px 12px;
37
              font-size: 12.5px; margin: 14px 0 18px; }
38
 
39
  .ocs-tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--ocs-border);
40
              margin-bottom: 16px; }
41
  .ocs-tab { border: 0; background: none; padding: 8px 14px; font-size: 13px;
42
             color: var(--ocs-muted); cursor: pointer; border-bottom: 2px solid transparent; }
43
  .ocs-tab.is-on { color: var(--ocs-accent); border-bottom-color: var(--ocs-accent);
44
                   font-weight: 600; }
45
 
46
  .ocs-card { background: var(--ocs-surface); border: 1px solid var(--ocs-border);
47
              border-radius: 10px; padding: 16px 18px; margin-bottom: 18px; }
48
  .ocs-card h3 { margin: 0 0 4px; font-size: 14px; font-weight: 650; }
49
  .ocs-card p.ocs-hint { margin: 0 0 14px; color: var(--ocs-muted); font-size: 12.5px;
50
                         max-width: 78ch; }
51
 
52
  .ocs-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
53
  .ocs-field { display: flex; flex-direction: column; gap: 4px; }
54
  .ocs-field label { font-size: 11.5px; color: var(--ocs-muted); text-transform: uppercase;
55
                     letter-spacing: 0.04em; }
56
  .ocs-field input, .ocs-field select {
57
      border: 1px solid var(--ocs-border); border-radius: 7px; padding: 6px 9px;
58
      font-size: 13px; min-width: 170px; background: var(--ocs-surface);
59
      color: var(--ocs-text); height: 32px; }
60
  .ocs-field-wide input { min-width: 260px; }
61
 
62
  .ocs-btn { border: 1px solid var(--ocs-border); background: var(--ocs-surface);
63
             color: var(--ocs-text); border-radius: 7px; padding: 6px 13px;
64
             font-size: 12.5px; cursor: pointer; height: 32px; }
65
  .ocs-btn:hover { border-color: var(--ocs-accent); color: var(--ocs-accent); }
66
  .ocs-btn-primary { background: var(--ocs-accent); border-color: var(--ocs-accent);
67
                     color: rgb(255, 255, 255); }
68
  .ocs-btn-primary:hover { color: rgb(255, 255, 255); opacity: 0.92; }
69
  .ocs-btn-danger { color: var(--ocs-danger); }
70
  .ocs-btn-danger:hover { border-color: var(--ocs-danger); color: var(--ocs-danger); }
71
  .ocs-btn-sm { height: 26px; padding: 2px 9px; font-size: 12px; }
72
 
73
  table.ocs-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
74
  table.ocs-table th { text-align: left; font-weight: 600; color: var(--ocs-muted);
75
                       font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em;
76
                       padding: 8px 10px; border-bottom: 1px solid var(--ocs-border);
77
                       white-space: nowrap; }
78
  table.ocs-table td { padding: 8px 10px; border-bottom: 1px solid var(--ocs-border);
79
                       vertical-align: middle; }
80
  table.ocs-table tr.ocs-off td { background: rgb(250, 250, 251); color: var(--ocs-muted); }
81
  .ocs-scroll { overflow-x: auto; }
82
 
83
  .ocs-pill { display: inline-block; border-radius: 999px; padding: 1px 8px;
84
              font-size: 11.5px; font-weight: 600; }
85
  .ocs-pill-on { background: var(--ocs-ok-soft); color: var(--ocs-ok); }
86
  .ocs-pill-off { background: var(--ocs-danger-soft); color: var(--ocs-danger); }
87
  .ocs-pill-alias { background: var(--ocs-accent-soft); color: var(--ocs-accent); }
88
  .ocs-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
89
              font-size: 12px; }
90
  .ocs-muted { color: var(--ocs-muted); }
91
  .ocs-empty { text-align: center; color: var(--ocs-muted); padding: 22px; }
92
 
93
  .ocs-msg { border-radius: 8px; padding: 9px 12px; font-size: 12.5px; margin-bottom: 14px;
94
             display: none; }
95
  .ocs-msg-ok { background: var(--ocs-ok-soft); color: var(--ocs-ok);
96
                border: 1px solid rgb(187, 247, 208); }
97
  .ocs-msg-bad { background: var(--ocs-danger-soft); color: var(--ocs-danger);
98
                 border: 1px solid rgb(254, 205, 211); }
99
 
100
  .ocs-export { width: 100%; min-height: 220px; font-family: ui-monospace, Menlo, monospace;
101
                font-size: 12px; border: 1px solid var(--ocs-border); border-radius: 8px;
102
                padding: 10px; display: none; }
103
  </style>
104
 
105
  <div class="ocs-head">
106
    <div>
107
      <h2 class="ocs-title">Offer circular &mdash; scope config</h2>
108
      <p class="ocs-sub">Which OEM divisions get ingested from the monthly circular, and
109
         which alternate labels mean a division that already exists. This is the only
110
         authority on scope &mdash; the parser has no built-in list.</p>
111
    </div>
112
    <div>
113
      <button class="ocs-btn" type="button" data-ocs-export>Export as SQL</button>
114
      <button class="ocs-btn" type="button" data-ocs-reload>Reload</button>
115
    </div>
116
  </div>
117
 
118
  <div class="ocs-note">
119
    Changes here take effect on the <strong>next ingest</strong>. Scope is read when a
120
    circular is parsed, so editing it does not alter a circular that is already published
121
    &mdash; re-ingest that circular from the review screen to apply it.
122
  </div>
123
 
124
  <div class="ocs-msg ocs-msg-ok" data-ocs-ok></div>
125
  <div class="ocs-msg ocs-msg-bad" data-ocs-bad></div>
126
 
127
  <div class="ocs-tabs">
128
    <button class="ocs-tab is-on" type="button" data-ocs-tab="divisions">Divisions</button>
129
    <button class="ocs-tab" type="button" data-ocs-tab="aliases">Label aliases</button>
130
  </div>
131
 
132
  <div data-ocs-panel="divisions">
133
    <div class="ocs-card">
134
      <h3>Add or edit a division</h3>
135
      <p class="ocs-hint">The label must match the circular's &ldquo;OEM Name&rdquo; cell
136
         exactly. Saving an existing label edits it. A division needs a category so the
137
         matcher knows which catalog bucket to search; a brand may be missing (Google has
138
         no catalog brand row), in which case its products stay unresolved.</p>
139
      <div class="ocs-form">
140
        <div class="ocs-field ocs-field-wide">
141
          <label>OEM label (verbatim)</label>
142
          <input type="text" data-ocs-d-label placeholder="Samsung Tabs" />
143
        </div>
144
        <div class="ocs-field">
145
          <label>Display name</label>
146
          <input type="text" data-ocs-d-display placeholder="Samsung Tablets" />
147
        </div>
148
        <div class="ocs-field">
149
          <label>Brand</label>
150
          <select data-ocs-d-brand><option value="">- none -</option></select>
151
        </div>
152
        <div class="ocs-field">
153
          <label>Category</label>
154
          <select data-ocs-d-category><option value="">- none -</option></select>
155
        </div>
156
        <div class="ocs-field">
157
          <label>In scope</label>
158
          <select data-ocs-d-inscope>
159
            <option value="true">Yes - ingest it</option>
160
            <option value="false">No - drop it</option>
161
          </select>
162
        </div>
163
        <div class="ocs-field ocs-field-wide">
164
          <label>Reason (required when out of scope)</label>
165
          <input type="text" data-ocs-d-reason placeholder="Laptops - out of scope" />
166
        </div>
167
        <button class="ocs-btn ocs-btn-primary" type="button" data-ocs-d-save>Save division</button>
168
        <button class="ocs-btn" type="button" data-ocs-d-clear>Clear</button>
169
      </div>
170
    </div>
171
 
172
    <div class="ocs-card">
173
      <h3>Divisions</h3>
174
      <p class="ocs-hint">Taking a division out of scope never deletes anything &mdash;
175
         offers already ingested keep their history. It changes what the next ingest keeps.</p>
176
      <div class="ocs-scroll">
177
        <table class="ocs-table">
178
          <thead>
179
            <tr>
180
              <th>OEM label</th><th>Display name</th><th>Brand</th><th>Category</th>
181
              <th>Scope</th><th>Reason</th><th>Offers</th><th>Aliases</th><th></th>
182
            </tr>
183
          </thead>
184
          <tbody data-ocs-divisions>
185
            <tr><td colspan="9" class="ocs-empty">Loading&hellip;</td></tr>
186
          </tbody>
187
        </table>
188
      </div>
189
    </div>
190
  </div>
191
 
192
  <div data-ocs-panel="aliases" style="display:none">
193
    <div class="ocs-card">
194
      <h3>Add a label alias</h3>
195
      <p class="ocs-hint">Use this when the circular prints a different spelling of a
196
         division that already exists &mdash; &ldquo;XIAOMI CE&rdquo; for
197
         &ldquo;Xiaomi CE&rdquo;, say. An alias only says two labels mean the same
198
         division; it carries no brand or category of its own, so the scope decision stays
199
         in one place. If the label needs a <em>different</em> category, it is a division,
200
         not an alias.</p>
201
      <div class="ocs-form">
202
        <div class="ocs-field ocs-field-wide">
203
          <label>Label as printed</label>
204
          <input type="text" data-ocs-a-label placeholder="XIAOMI CE" />
205
        </div>
206
        <div class="ocs-field">
207
          <label>Means this division</label>
208
          <select data-ocs-a-division><option value="">- pick one -</option></select>
209
        </div>
210
        <div class="ocs-field ocs-field-wide">
211
          <label>Note (optional)</label>
212
          <input type="text" data-ocs-a-note placeholder="Sep'26 circular prints it upper case" />
213
        </div>
214
        <button class="ocs-btn ocs-btn-primary" type="button" data-ocs-a-save>Save alias</button>
215
      </div>
216
    </div>
217
 
218
    <div class="ocs-card">
219
      <h3>Label aliases</h3>
220
      <div class="ocs-scroll">
221
        <table class="ocs-table">
222
          <thead>
223
            <tr><th>Label as printed</th><th>Means</th><th>Note</th><th>Added by</th><th></th></tr>
224
          </thead>
225
          <tbody data-ocs-aliases>
226
            <tr><td colspan="5" class="ocs-empty">Loading&hellip;</td></tr>
227
          </tbody>
228
        </table>
229
      </div>
230
    </div>
231
  </div>
232
 
233
  <textarea class="ocs-export" data-ocs-export-box readonly></textarea>
234
 
235
</div>
236
 
237
<script type="text/javascript">
238
    // This page can be opened directly, so it cannot rely on admin.vm having already
239
    // set the global "context".
240
    window.ocsContext = "${rc.contextPath}";
241
 
242
    // Standalone bootstrap - same reason as the review screen. Injected as a fragment
243
    // jQuery is already present and this does nothing; opened by URL the fragment
244
    // arrives alone with no include-scripts.vm, and the screen would never initialise.
245
    (function () {
246
        var base = window.ocsContext || '';
247
        function addScript(src, next) {
248
            var s = document.createElement('script');
249
            s.src = src;
250
            s.onload = next;
251
            document.head.appendChild(s);
252
        }
253
        // The script registers everything inside $(function(){...}), which runs on the
254
        // NEXT tick - so at this script's onload the init function does not exist yet.
255
        // Calling it here directly is a silent no-op that leaves the screen on "Loading".
256
        // Defer through jQuery's ready queue instead: our callback is registered after
257
        // the file's own, so it runs after it.
258
        function start() {
259
            if (!window.jQuery) { return; }
260
            window.jQuery(function () {
261
                if (window.initOfferCircularScope) { window.initOfferCircularScope(); }
262
            });
263
        }
264
        if (!window.jQuery) {
265
            addScript(base + '/resources/js/jquery-3.2.1.min.js', function () {
266
                addScript(base + '/resources/js/offer-circular-scope.js?v=${version}', start);
267
            });
268
        } else if (!window.initOfferCircularScope) {
269
            addScript(base + '/resources/js/offer-circular-scope.js?v=${version}', start);
270
        } else {
271
            start();
272
        }
273
    })();
274
</script>
275
</section>