You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
10 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. <template>
  2. <div class="panel panel-default scorecard" v-if="show">
  3. <div class="panel-heading">
  4. <div class="team">
  5. <span class="team-icon" :style="'background-color: #'+tweet.team_color"></span>
  6. <span class="team-name">{{ tweet.team_name }}</span>
  7. </div>
  8. <h2>{{ tweet.mission }}</h2>
  9. <button type="button" class="close" v-on:click="dismiss"><span>&times;</span></button>
  10. </div>
  11. <div class="panel-body">
  12. <div class="row">
  13. <div class="col-md-8">
  14. <div class="profile">
  15. <img :src="tweet.player_photo" :style="'border-color: #'+tweet.team_color">
  16. <span><a :href="'https://twitter.com/'+tweet.player_username">@{{ tweet.player_username }}</a></span>
  17. </div>
  18. <div class="tweet">
  19. <div class="text">{{ tweet.text }}</div>
  20. <div v-if="tweet.photos">
  21. <div :class="'multi-photo photos-'+tweet.photos.length" v-if="tweet.photos">
  22. <div v-for="img in tweet.photos" class="photo" :style="'background-image:url('+img+')'" :data-featherlight="img">
  23. <img :src="img">
  24. </div>
  25. </div>
  26. <div class="multi-photo-clear"></div>
  27. </div>
  28. </div>
  29. <div class="tweet-reply" v-if="showReplyBox">
  30. <div class="top">
  31. <textarea class="form-control" rows="2" v-model="replyText" style="margin-bottom: 4px;" :disabled="replyInProgress"></textarea>
  32. </div>
  33. <div class="bottom">
  34. <div class="fill"></div>
  35. <img src="/twitter.ico" width="16">
  36. <div class="remaining-chars">{{ replyTextCharsRemaining }}</div>
  37. <button class="btn btn-primary" :disabled="isTweetReplyDisabled" v-on:click="sendReply">Reply</button>
  38. </div>
  39. </div>
  40. <div class="tweet-actions">
  41. <button type="button" class="btn btn-success" v-on:click="scoreTweet" :disabled="isAcceptDisabled">Accept</button>
  42. <button type="button" class="btn btn-danger" v-on:click="rejectTweet">Reject</button>
  43. </div>
  44. </div>
  45. <div class="col-md-4">
  46. <!-- MISSION 1 #transitspy -->
  47. <template v-if="tweet.mission_id == 1">
  48. <p class="instructions">
  49. The photo must show the sign with the transit line
  50. </p>
  51. <div class="form-group">
  52. <select class="form-control" v-model="selectedTransitLine">
  53. <option value=""></option>
  54. <option v-for="line in lines" :value="line.id">{{ line.name }}</option>
  55. </select>
  56. </div>
  57. <div class="form-group">
  58. <input type="text" v-model="selectedNonTrimetLine" placeholder="Non-Trimet Line" class="form-control">
  59. </div>
  60. </template>
  61. <!-- MISSION 2 #intercept -->
  62. <template v-if="tweet.mission_id == 2">
  63. <p class="instructions">
  64. <ul>
  65. <li>Photo must show the sign with the transit center</li>
  66. <li>Bonus points if another team and their pennant are visible!</li>
  67. </ul>
  68. </p>
  69. <div class="form-group">
  70. <select class="form-control" v-model="selectedTransitCenter">
  71. <option value=""></option>
  72. <option v-for="stop in centers" :value="stop.id">{{ stop.name }}</option>
  73. </select>
  74. </div>
  75. <div class="form-group">
  76. <div class="checkbox">
  77. <label>
  78. <input type="checkbox" v-model="selectedPhotoHasAnotherTeam">
  79. Another team is in the photo
  80. </label>
  81. </div>
  82. </div>
  83. </template>
  84. <!-- MISSION 3 #airlair -->
  85. <template v-if="tweet.mission_id == 3">
  86. <p class="instructions">
  87. <ul>
  88. <li>Make sure this photo is on the tram or at the top tram station</li>
  89. <li>Reject if it shows the rooftop with the code!</li>
  90. </ul>
  91. </p>
  92. </template>
  93. <!-- MISSION 4 #transittea -->
  94. <template v-if="tweet.mission_id == 4">
  95. <p class="instructions">
  96. <ul>
  97. <li>The photo must include the radio</li>
  98. <li>Reject if it shows the decoded message</li>
  99. </ul>
  100. </p>
  101. </template>
  102. <!-- MISSION 5 #sing -->
  103. <template v-if="tweet.mission_id == 5">
  104. <p class="instructions">
  105. Accept a photo of either a team member singing, or a photo of tipping the bus driver
  106. </p>
  107. <div class="form-group">
  108. <label>
  109. <input type="checkbox" v-model="selectedM5Singing">
  110. Singing
  111. </label>
  112. <br>
  113. <label>
  114. <input type="checkbox" v-model="selectedM5Tipping">
  115. Tipping the driver
  116. </label>
  117. </div>
  118. </template>
  119. <!-- MISSION 6 #passport -->
  120. <template v-if="tweet.mission_id == 6">
  121. <p class="instructions">
  122. The photo must show all team members with their completed visas
  123. </p>
  124. </template>
  125. <!-- MISSION 7 #document -->
  126. <template v-if="tweet.mission_id == 7">
  127. <p class="instructions">
  128. Accept a photo that completes one of the below documents:
  129. </p>
  130. <div class="form-group">
  131. <div v-for="doc in documents" class="radio">
  132. <label>
  133. <input type="radio" name="selectedDocument" v-model="selectedDocument" :value="doc.id">
  134. {{ doc.description }}
  135. </label>
  136. </div>
  137. </div>
  138. </template>
  139. </div>
  140. </div>
  141. </div>
  142. </div>
  143. </template>
  144. <script>
  145. module.exports = {
  146. props: ['show', 'tweet'],
  147. data () {
  148. return {
  149. documents: [],
  150. centers: [],
  151. lines: [],
  152. replyText: '',
  153. replyTextCharsRemaining: 140,
  154. replyInProgress: false,
  155. showReplyBox: true,
  156. selectedDocument: null,
  157. selectedTransitCenter: null,
  158. selectedTransitLine: null,
  159. selectedNonTrimetLine: '',
  160. selectedPhotoHasAnotherTeam: false,
  161. selectedM5Singing: false,
  162. selectedM5Tipping: false
  163. }
  164. },
  165. computed: {
  166. isAcceptDisabled() {
  167. if(this.show) {
  168. switch(this.tweet.mission_id) {
  169. case 1:
  170. return this.selectedTransitLine == null && this.selectedNonTrimetLine == '';
  171. case 2:
  172. return this.selectedTransitCenter == null;
  173. case 3:
  174. case 4:
  175. case 6:
  176. // Nothing to check
  177. return false;
  178. case 5:
  179. return this.selectedM5Singing == false && this.selectedM5Tipping == false;
  180. case 7:
  181. return this.selectedDocument == null;
  182. default:
  183. return true;
  184. }
  185. } else {
  186. return true;
  187. }
  188. },
  189. isTweetReplyDisabled() {
  190. return this.replyText == '' || this.replyInProgress || this.replyTextCharsRemaining < 0;
  191. }
  192. },
  193. methods: {
  194. clearState() {
  195. this.selectedDocument = null;
  196. this.selectedTransitCenter = null;
  197. this.selectedTransitLine = null;
  198. this.selectedNonTrimetLine = '';
  199. this.selectedPhotoHasAnotherTeam = false;
  200. this.selectedM5Singing = false;
  201. this.selectedM5Tipping = false;
  202. this.replyText = '';
  203. this.showReplyBox = true;
  204. },
  205. dismiss() {
  206. this.clearState();
  207. this.$emit('dismiss');
  208. },
  209. rejectTweet() {
  210. $.post("/dashboard/reject-tweet", {
  211. tweet_id: this.tweet.tweet_id
  212. }, function() {
  213. this.clearState();
  214. this.$emit('complete');
  215. }.bind(this));
  216. },
  217. scoreTweet() {
  218. var score_data = {};
  219. switch(this.tweet.mission_id) {
  220. case 1:
  221. score_data['m1_complete'] = 1;
  222. score_data['m1_transit_line_id'] = this.selectedTransitLine;
  223. score_data['m1_non_trimet'] = this.selectedNonTrimetLine;
  224. break;
  225. case 2:
  226. score_data['m2_complete'] = this.selectedTransitCenter ? 1 : 0;
  227. score_data['m2_transit_center_id'] = this.selectedTransitCenter;
  228. score_data['m2_with_other_team'] = this.selectedPhotoHasAnotherTeam ? 1 : 0;
  229. break;
  230. case 3:
  231. score_data['m3_complete'] = 1;
  232. break;
  233. case 4:
  234. score_data['m4_complete'] = 1;
  235. break;
  236. case 5:
  237. score_data['m5_complete'] = this.selectedM5Singing ? 1 : 0;
  238. score_data['m5_tip'] = this.selectedM5Tipping ? 1 : 0;
  239. break;
  240. case 6:
  241. score_data['m6_complete'] = 1;
  242. break;
  243. case 7:
  244. score_data['m7_document_id'] = this.selectedDocument;
  245. break;
  246. }
  247. $.post("/dashboard/score-tweet", {
  248. tweet_id: this.tweet.tweet_id,
  249. score_data: score_data
  250. }, function(){
  251. this.clearState();
  252. this.$emit('complete');
  253. }.bind(this));
  254. },
  255. sendReply() {
  256. this.replyInProgress = true;
  257. $.post("/dashboard/reply", {
  258. tweet_id: this.tweet.tweet_id,
  259. text: this.replyText
  260. }, function(response){
  261. if(response.result == "ok") {
  262. this.replyText = '';
  263. }
  264. this.replyInProgress = false;
  265. }.bind(this));
  266. // setTimeout(function(){ this.replyInProgress = false; this.showReplyBox = false; }.bind(this), 1000);
  267. }
  268. },
  269. watch: {
  270. // https://vuejs.org/v2/guide/computed.html#Watchers
  271. show: function(val) {
  272. if(val) {
  273. // https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue
  274. Vue.nextTick(function() {
  275. $(".multi-photo .photo").featherlight();
  276. }.bind(this));
  277. }
  278. },
  279. replyText: function(val) {
  280. this.replyTextCharsRemaining = 140 - twitter.getTweetLength(val);
  281. }
  282. },
  283. created() {
  284. $.get("/dashboard/dropdowns", function(response){
  285. this.centers = response.transit_centers;
  286. this.lines = response.transit_lines;
  287. this.documents = response.documents;
  288. }.bind(this));
  289. }
  290. }
  291. </script>