/ support / ebsSupport / client / activity.template.mjs
activity.template.mjs
  1  import { html } from "uhtml/reactive"
  2  import * as constants from "./constants.mjs"
  3  import * as access from "./access.mjs"
  4  
  5  function copyToClipboard(val) {
  6    navigator.clipboard.writeText(val)
  7  }
  8  
  9  const SessionTable = (rows) => (html`
 10  <div class="table support-sessions">
 11    <div class="table-header">
 12      <p class="table-value session-channel">Channel</p>  
 13      <p class="table-value session-start">Start</p>  
 14      <p class="table-value session-duration">Duration</p>  
 15      <p class="table-value session-bits">Bits</p>  
 16      <p class="table-value session-users">Users</p>  
 17      <p class="table-value session-viewers">Viewers</p>  
 18      <p class="table-value session-questions">Questions</p>  
 19    </div>
 20    ${rows.map((r) => SessionTableRow(r))}
 21  </div>`)
 22  
 23  const SessionTableRow = (row) => {
 24    const channelLink = `https://twitch.tv/${row.twitch_userName}`
 25    ,         vodLink = row.vod ? html`<a class="table-value-button" href="${row.vod}">VOD</a>` : html`<span ?hidden=${true}></span>`
 26    return html`
 27      <div class="table-row">
 28        <div class="table-value session-channel table-value-double">
 29          <p class="session-channel-name">
 30            <a href="${channelLink}">${row.twitch_userName}</a>
 31          </p>
 32          <p class="session-channel-id table-value-button" onclick="${() => { copyToClipboard(row.channel_id) }}">${row.channel_id}</p>
 33        </div>
 34        <p class="table-value session-start table-value-double">
 35          <span>${new Date(row.open).toDateString()}</span>
 36          ${vodLink}
 37        </p>
 38        <p class="table-value session-duration">${Math.floor((row.close - row.open) / 60000)}m</p>
 39        <p class="table-value session-bits">${row.bits}</p>
 40        <p class="table-value session-users">${row.subscribers + row.viewers}</p>
 41        <p class="table-value session-viewers">${row.avg_viewers > 0 ? row.avg_viewers : ""}</p>
 42        <p class="table-value session-questions">${row.questions}</p>
 43      </div>`
 44  }
 45  
 46  const ConfigTable = (rows) => (html`
 47  <div class="table support-configs">
 48    <div class="table-header">
 49      <p class="table-value config-channel">Channel</p>
 50      <p class="table-value config-mode">Mode</p>
 51      <p class="table-value config-points">Points</p>
 52      <p class="table-value config-submit">Submit</p>
 53      <p class="table-value config-upvote">Upvote</p>
 54      <p class="table-value config-suspensions">Suspended</p>
 55    </div>
 56    ${rows.map((r) => ConfigTableRow(r))}
 57  </div>`)
 58  
 59  function MultiBadges(active) {
 60    const badges = []
 61    for (const multi of constants.ALL_MULTI) {
 62      let badgeClass = `config-multi config-multi-x${multi} ${active.has(multi) ? " config-multi-active" : " "}`
 63      badges.push(html`<span class="${badgeClass}">${multi}</span>`)
 64    }
 65  
 66    return badges
 67  }
 68  
 69  const ConfigTableRow = (row) => {
 70    const channelLink = `https://twitch.tv/${row.twitch_userName}`
 71    ,     activeUpvoteMultis = new Set(row.enabled_upvote_multipliers.split(" "))
 72    ,     activeSubmissionMultis = new Set(row.enabled_submission_multipliers.split(" "))
 73    ,     sessionLength = row.session_mode != "ENDLESS" ? html`<span>${row.session_length + "m"}</span>` : html`<span ?hidden=${true}></span>`
 74    ,     isLiveClass = row.isLive ? "config-live" : ""
 75    ,     rowClass = row.hasNoConfig ? "table-row config-empty" : "table-row"
 76  
 77    const viewerAllowedClass = row.exclude_viewers ? "config-points-notAllowed" : ""
 78  
 79    return html`
 80      <div class="${rowClass}">
 81        <div class="table-value config-channel table-value-double">
 82          <p class="config-channel-name">
 83            <a href="${channelLink}" class="${isLiveClass}">${row.twitch_userName}</a>
 84          </p>
 85          <p class="session-channel-id table-value-button" onclick="${() => { copyToClipboard(row.channel_id) }}">${row.channel_id}</p>
 86        </div>
 87        <p class="table-value table-value-double config-mode">
 88          <span>${row.session_mode == "ENDLESS" ? "Endless" : "Countdown"}</span>
 89          ${sessionLength}
 90        </p>
 91        <p class="table-value config-points">
 92          <span class="${viewerAllowedClass}">${row.viewer_points}</span>
 93          <span>${row.subscriber_points}</span>
 94        </p>
 95        <p class="table-value config-submit">${MultiBadges(activeSubmissionMultis)}</p>
 96        <p class="table-value config-upvote">${MultiBadges(activeUpvoteMultis)}</p>
 97        <p class="table-value config-suspensions">${row.suspended.split(" ").length - 1}</p>
 98      </div>`
 99  }
100  
101  export const ActivityView = (state) => {
102    const { isLoading, lastUpdated, sessions, configs } = state
103  
104    const isLoadingClass = isLoading.value ? "activity loading" : "activity"
105    ,      updateHandler = () => { access.GetActivityData(state, "latest") }
106    
107    return html`
108    <div class=${isLoadingClass}>
109      <div class="activity-tools">
110        <p class="activity-tools-lastUpdated">
111          <span class="activity-tools-lastUpdated-label">Last Updated</span>
112          <span class="activity-tools-lastUpdated-time">${lastUpdated.value.toLocaleTimeString()}</span>
113        </p>
114        <button class="activity-tools-update" onclick=${updateHandler}></button>
115      </div>
116    
117      <h3 class="activity-headline">Sessions</h3>
118      ${SessionTable(Array.from(sessions.value.values()))}
119      <h3 class="activity-headline">Configs</h3>
120      ${ConfigTable(Array.from(configs.value.values()))}
121    </div>`
122  }