Mon Jan 09 2017
Copied to clipboard! Copy reply
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
<template>
  <main>

    <h2 class="ui header">Create &amp; schedule a flip</h2>


    <div class="ui massive red message" v-if='editMode && !found && !isFetching'>
      <i class="warning circle icon"></i>
      Could not find this flip.
    </div>

    <form class="ui form"  @submit.prevent='handleSubmit' v-if='(editMode && found) || !editMode'>

      <!--  BASIC INFO -->
      <div class="ui attached message">
        <h3 class="ui  header">Basic info</h3>
      </div>

      <div class="ui attached segment">
        <div class="three fields">

          <!-- name -->
          <div class="required field">
            <label>Flip Name</label>
            <i>Just a name so you can edit this later if needed</i>
            <input type="text" v-model='name' placeholder="black friday">
          </div>

          <!-- promosoet -->
          <div class="required field">
            <label>Sitewide promoset</label>
            <i>Will apply to catalog pages</i>
            <select class="ui search selection dropdown"
            data-promoset
            v-model='promoset'>
              <option value="">select a promo</option>
              <option :value=promo v-for='promo in promosets'>{{ promo }}</option>
            </select>
          </div>

          <!--  date -->
          <div class="required field">
            <label>Flip Date</label>
            <i>Date &amp; time for this flip</i>
            <div class="ui calendar">
              <div class="ui left icon input">
                <i class="calendar icon"></i>
                <input type="text" name="date" placeholder="select date &amp; time">
              </div>
            </div>
          </div>

        </div>
      </div>


      <!-- CONSTANT LANDING PAGES -->
      <div class="ui attached message">
        <h3 class="ui header">Landing Pages</h3>
      </div>

      <div class="ui attached segment" :class="{'loading': !constants}">
        <p>
          Below are our <b>"constant"</b> landing pages.
          Specify which page they will "mirror" next   flip.
        </p>
        <div class="ui grid">
          <div class="four wide column" v-for="(page,key) in constants">
            <div class="field">
              <label>{{ page.label }}</label>
              <select class="ui search selection dropdown" :name='page.label' v-model='page.value' data-constant>
                <option :value="null">select a page</option>
                <option :value=p v-for='p in nonConstants'>{{ p }}</option>
              </select>
            </div>
          </div>
        </div>


      </div>

      <!-- ASSETS -->
      <div class="ui attached message">
        <h3 class="ui  header">Sitewide Images &amp; Criteo</h3>
      </div>

      <div class="ui attached segment ">
        <p>Select assets to upload. You can select more than one.</p>
        <div class="field">
          <input type="file" multiple>
        </div>
      </div>



      <!-- <div class="ui  bottom attached tiny info  message" style="display:none">
        <i class="warning icon"></i><b>Typically used assets are</b>:
        <div>
            <div class="ui horizontal list">
              <div class="item">mdot-rto.jpg</div>
              <div class="item">us-buynow.jpg</div>
              <div class="item">us-freedemo.jpg</div>
              <div class="item">us-freedemo-mobile.jpg</div>
            </div>
            <div class="ui horizontal list">
              <div class="item">us-hslpbanner.jpg</div>
              <div class="item">es-buynow.jpg</div>
              <div class="item">es-homepage-bg.png</div>
              <div class="item">es-catalog.jpg</div>
            </div>
          </div>
      </div> -->

      <!-- RTOs -->
      <div class="ui attached message" style="">
        <h3>Desktop and Mobile RTO (catalog)</h3>
      </div>

      <div class="ui attached segment" style="">

        <!-- mobile rto -->
        <div class="two fields" style="align-items: center">
          <!--  toggle on|off -->
          <div class="four wide field">
            <div class="ui toggle checkbox" :class='{"checked" : config.mobile.rto.on}'>
              <input type="checkbox"
              name="mobile-rto"
              class="hidden"
              v-model='config.mobile.rto.on'
              @change='handleRtoToggle'>
              <label>Show m. RTO?</label>
            </div>
          </div>

          <!-- url -->
          <div class="fourteen wide field" v-bind:style="{opacity: config.mobile.rto.on ? 1: 0}">
            <input
            type="text"
            name="mobile-rto-url"
            placeholder="Mobile RTO url"
            v-model="config.mobile.rto.url" />
          </div>
        </div>

        <!-- desktop rto -->
        <div class="two fields" style="align-items: center">
          <!-- toggle on|off -->
          <div class="four wide field">
            <div class="ui toggle checkbox">
              <input type="checkbox"
              name="desktop-rto"
              class="hidden"
              v-model='config.desktop.rto.on'
              @change='handleRtoToggle'>
              <label>Show desktop RTO?</label>
            </div>
          </div>

          <!-- url -->
          <div class="fourteen wide field" v-bind:style="{opacity: config.desktop.rto.on ? 1: 0}">
            <input
            type="text"
            name="desktop-rto-url"
            placeholder="Desktop RTO url"
            v-model="config.desktop.rto.url" />
          </div>
        </div>
      </div>


      <div class="ui attached message" style="">
        <div class="required field">
          <label>Router</label>
          <input type="text" name="router" placeholder="router link" v-model="router">
        </div>
      </div>



      <div class="ui yellow large message" v-if="exists">
        <i class="warning circle icon"></i>
        A flip scheduled on this date already exists. <b>You will be overwriting the old one.</b>
      </div>

      <div class="ui small header">
        <div class="ui grid">
          <div class="thirteen wide column">
            <div
              class="ui  message"
              :class="{'negative' : formResult.result == 0,'positive' : formResult.result == 1}"
              v-if="formResult.result !== null">
                <div class="header">
                  <i class="warning circle icon"></i>
                  <span v-html="formResult.message"></span>
                </div>
              </div>
          </div>
          <div class="three wide column">
            <button class="ui fluid big teal button" :class="{'loading': isSubmitting}">{{btnText}}</button>
          </div>

        </div>
      </div>

    </form>

  </main>
</template>


<script>

  'use strict';

  export default {
    name: 'CreateFlip',

    data() {
      return {

        // Flip name
        name: "",

        // Flip's sitewide promoset
        promoset: "",

        // Flip raw date to pass to server
        rawdate: "",

        // Constant landing pages: sitewide, sale, etc
        constants: [],

        // Pages that aren't constants (come and go by campaign)
        nonConstants: [],

        // Configs for M. and Desktop
        config: {
          desktop: {
            rto: {
              on: false,
              url: ''
            }
          },
          mobile: {
            rto: {
              on: false,
              url: ''
            }
          }
        },

        // Value for router
        router: '',

        // Promosets
        promosets: [],

        // True if theres a flip on chosen date.
        exists: false,

        // Is the form being submitted?
        isSubmitting: false,

        // True when form is validated
        canSubmit: false,

        isFetching: false,

        // True if we are editing (id/<date> in url)
        editMode: false,

        // Will be false if in edit mode but flip not found
        found: null,

        // Store results from submission to show user
        formResult: {
          result: null,
          message: null
        }
      }
    },

    updated() {
      $(this.$el).find('select.dropdown').dropdown()
      //$(this.$el).find('.ui.calendar').calendar('set date', this.rawdate)
    },

    computed: {
      btnText() {
        return this.editMode ? 'Update' : 'Submit'
      }
    },

    created() {

      // Fetch info for our dropdowns
      $.getJSON(`${window.server}/pages`, r => {
        this.nonConstants = r.filter(p => !p.metadata.constant).map(p => p.name)
        this.constants = r.filter(p => p.metadata.constant).map(p => ({label:p.name, value:null}))
      })

      $.getJSON(`${window.server}/promosets`, r => this.promosets = Object.keys(r))
    },



    mounted() {

      const self = this

      // Define required form fields - visual purposes only
      $(this.$el).find('form').form({
        fields: {
         'name': 'empty',
         'promoset-dropdown': 'empty',
         'date': 'empty',
         "router": 'empty'
        }
      })

      // Initiate calendar picker

      $(this.$el).find('.ui.calendar').calendar({
        onChange(date, text) {
          console.log('ok?')
          //self.rawdate = date
        },
        onHide() {
          console.log('ok')
          self.checkIfExists()
        }
      }).calendar('set startDate', new Date())

      // Start semantic-ui's elements
      $(this.$el).find('.ui.toggle.checkbox').checkbox()


      /*
       * Initiate dropdowns. For some reason the pages one doesn't
       * work on mounted(), so I put them both here.
       */

      if (this.$route.params.id) {
        this.editMode = true
        this.isFetching = true
        const id = this.$route.params.id

        $.getJSON(`${window.server}/flips`, r => {
          this.isFetching = false
          r = r.filter(f => f.rawdate == id)[0]
          if (undefined === r) {
            this.found = false
            return
          }
          this.found = true
          this.name = r.name
          this.rawdate = r.rawdate
          this.promoset = r.promoset
          this.config = r.config
          this.router = r.router
          $(this.$el).find('select[data-promoset]').dropdown('set value', this.promoset)
          $.each($(this.$el).find('select[data-constant]'), (i, e) => {
            $(e).dropdown('set value', r.constants[e.name])
          })

        })

      }
    },


    methods: {

      /*
       * When a date is changed, we check to see if there's
       * already a flip on that datetime, and let user know.
       */

      checkIfExists() {
        $.getJSON(`${window.server}/flips`, r => {
          if (r.map(f => f.date).includes(this.rawdate)) {
            this.exists = true
          }
        })
      },


      /*
       * When we toggle an RTO checkbox, we show/hide
       * the url input to its right
       */

      handleRtoToggle(e) {
        const isChecked = $(e.target).parent().hasClass('checked')
        $(e.target).parents('.wide.field').siblings('.wide.field').animate({
          opacity: isChecked
        })
      },


      /*
       * Submit our form. No need to bind every single input to a state data.
       * So we use jquery to grab the values of the form.
       *
       *  @param {bool} overwrite
       *    If true, request url will have ?overwrite=true, causing
       *    the server to overwrite a campaign if it exists
       *
       */

      handleSubmit(e) {

        if (this.isSubmitting) return

        this.isSubmitting = true

        const
          self              = this
          , constants       = {}
          , name            = this.name.trim()
          , promoset        = this.promoset.trim()
          , date            = this.rawdate
          , router          = this.router.trim()
          , config          = this.config
          , assets          = [...document.querySelector('input[type=file]').files]
          ;

        // Create constant pages map. ie, {sale: 'blackridayaii'}
        $.each($(this.$el).find('select[data-constant]'), (i, select) => {
          constants[select.name] = select.value
        })

        // Validate required fields
        if (!name || !promoset || !date || !router) {
          return this.isSubmitting = false
        }

        // Pack above data to send to server
        const formdata = new FormData()
        formdata.append('name', name)
        formdata.append('promoset', promoset)
        formdata.append('date', this.rawdate)
        formdata.append('constants', JSON.stringify(constants))
        formdata.append('config',  JSON.stringify(config))
        formdata.append('router',  router)
        assets.forEach(ass => formdata.append('assets[]', ass, ass.name))

        const requestUrl = `${window.server}/flip`
        const method = this.editMode ? 'PUT' : 'POST'
        const url = `${window.server}/flip/${this.editMode ?  this.$route.params.id : ''}`
        const request = new XMLHttpRequest()

        request.open(method, url, true)
        request.send(formdata)

        request.onload = function() {
          if (request.status >= 200 && request.status < 400) {
            const response = JSON.parse(request.responseText)
            self.formResult = {
              result: response.result,
              message: response.payload
            }

            /*
             * Since the date in the url is sent to the server, and the server
             * identifies old flip to remove based on that date, we must update
             * the url immediately. This is because if the user updates the flip
             * date in the ui calendar, the server needs to know what the
             * previous one was - and it does so by looking at the url param
             */

            var base = window.document.location.href.split('/')
            base.pop()
            base.push(date)
            base = base.join('/')
            try {
              history.pushState("", "", base);
            } catch(e) {
              window.location.hef = base
            }
          } else {
            self.formResult = { result: 0, message: 'Error on the server.' }
          }
          self.isSubmitting = false
        }

        request.onerror = function() {
          self.formResult = { result: 0, message: 'Could not reach server.' }
          self.isSubmitting = false
        }
      }
    }
  }



</script>