Browse Source

adds tweet queue to dashboard

master
Aaron Parecki 7 years ago
parent
commit
e28797017a
No known key found for this signature in database GPG Key ID: 276C2817346D6056
22 changed files with 867 additions and 152 deletions
  1. +58
    -0
      app/Events/NewTweetEvent.php
  2. +19
    -3
      app/Http/Controllers/DashboardController.php
  3. +10
    -18
      app/Http/Controllers/TwitterController.php
  4. +15
    -0
      app/Mission.php
  5. +21
    -2
      app/Tweet.php
  6. +1
    -0
      composer.json
  7. +404
    -1
      composer.lock
  8. +1
    -1
      database/migrations/2017_07_02_182117_create_tweet_queue.php
  9. +31
    -0
      database/migrations/2017_07_02_210344_create_missions.php
  10. +32
    -0
      database/migrations/2017_07_02_211355_tweet_mission_id.php
  11. +1
    -0
      database/seeds/DatabaseSeeder.php
  12. +26
    -0
      database/seeds/MissionSeeder.php
  13. +29
    -3
      public/css/app.css
  14. +107
    -107
      public/js/app.js
  15. +5
    -4
      resources/assets/js/app.js
  16. +0
    -8
      resources/assets/js/components/TeamList.vue
  17. +61
    -0
      resources/assets/js/components/TweetQueue.vue
  18. +33
    -3
      resources/assets/sass/app.scss
  19. +7
    -1
      resources/views/dashboard.blade.php
  20. +1
    -1
      resources/views/teams.blade.php
  21. +4
    -0
      routes/channels.php
  22. +1
    -0
      routes/web.php

+ 58
- 0
app/Events/NewTweetEvent.php View File

@ -0,0 +1,58 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Tweet;
class NewTweetEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $tweet_id;
public $tweet_date;
public $team_name;
public $team_color;
public $player_username;
public $player_photo;
public $text;
public $photos;
public $mission;
public $mission_id;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Tweet $tweet)
{
$this->tweet_id = $tweet->id;
$this->tweet_date = strtotime($tweet->tweet_date);
$this->team_name = $tweet->team->name;
$this->team_color = $tweet->team->color;
$this->player_username = $tweet->player->twitter;
$this->player_photo = $tweet->player->photo;
$this->text = $tweet->text;
$this->photos = json_decode($tweet->photo);
$this->mission = $tweet->mission->hashtag;
$this->mission_id = $tweet->mission_id;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return ['tweet-queue'];
}
}

+ 19
- 3
app/Http/Controllers/DashboardController.php View File

@ -4,7 +4,7 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Twitter;
use App\Tweet;
use App\Tweet, App\Events\NewTweetEvent;
class DashboardController extends Controller
{
@ -25,12 +25,28 @@ class DashboardController extends Controller
*/
public function index()
{
return view('home', [
return view('dashboard', [
]);
}
public function queue() {
$queue = Tweet::queued();
Tweet::claimed_timeout();
$tweets = Tweet::queued()->get();
$queue = [];
foreach($tweets as $tweet) {
$queue[] = new NewTweetEvent($tweet);
}
return response()->json(['queue'=>$queue]);
}
public function claim_tweet(Request $request) {
$tweet = Tweet::where('id', $request->input('tweet_id'))->first();
if($tweet) {
$tweet->claimed_at = date('Y-m-d H:i:s');
$tweet->save();
}
return response()->json(['result'=>'ok']);
}
}

+ 10
- 18
app/Http/Controllers/TwitterController.php View File

@ -4,7 +4,8 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Log;
use App\Player, App\Team, App\Tweet, App\TransitCenter, App\TransitLine, App\Document;
use App\Player, App\Team, App\Tweet, App\TransitCenter, App\TransitLine, App\Document, App\Mission;
use App\Events\NewTweetEvent;
class TwitterController extends BaseController
{
@ -41,33 +42,24 @@ class TwitterController extends BaseController
}
// Find the mission hashtag
if(strpos($text, '#transitspy') !== false)
$mission = 1;
elseif(strpos($text, '#intercept') !== false)
$mission = 2;
elseif(strpos($text, '#airlair') !== false)
$mission = 3;
elseif(strpos($text, '#transittea') !== false)
$mission = 4;
elseif(strpos($text, '#sing') !== false)
$mission = 5;
elseif(strpos($text, '#passport') !== false)
$mission = 6;
elseif(strpos($text, '#document') !== false)
$mission = 7;
else
$mission = 0;
$mission_id = 0;
foreach(Mission::all() as $mission) {
if(strpos($text, $mission->hashtag) !== false) {
$mission_id = $mission->id;
}
}
$tweet = new Tweet;
$tweet->player_id = $player ? $player->id : 0;
$tweet->team_id = $player ? $player->team->id : 0;
$tweet->text = $text;
$tweet->photo = json_encode($photos);
$tweet->mission = $mission;
$tweet->mission_id = $mission_id;
$tweet->tweet_date = date('Y-m-d H:i:s', strtotime($data['created_at']));
$tweet->save();
// TODO: Broadcast this to the web interface
event(new NewTweetEvent($tweet));
return $data['id_str'];
}

+ 15
- 0
app/Mission.php View File

@ -0,0 +1,15 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Mission extends Model
{
protected $fillable = [
'hashtag',
];
public function tweets() {
return $this->hasMany('App\Tweet');
}
}

+ 21
- 2
app/Tweet.php View File

@ -2,18 +2,37 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use DB;
class Tweet extends Model
{
protected $fillable = [
'player_id', 'team_id', 'text', 'photo', 'claimed_at', 'processed', 'mission', 'tweet_date',
'player_id', 'team_id', 'text', 'photo', 'claimed_at', 'processed', 'mission_id', 'tweet_date',
'm1_transit_line_id', 'm1_non_trimet',
'm2_transit_center_id', 'm2_with_other_team',
'm3_complete', 'm4_complete', 'm5_complete', 'm5_tip',
'm6_complete', 'm7_document_id'
];
public function team() {
return $this->belongsTo('\App\Team');
}
public function player() {
return $this->belongsTo('\App\Player');
}
public function mission() {
return $this->belongsTo('\App\Mission');
}
public static function claimed_timeout() {
DB::table('tweets')
->where('claimed_at', '<', date('Y-m-d H:i:s', time()-60)) // find tweets claimed longer than a minute ago
->update(['claimed_at' => null]);
}
public static function queued() {
return Tweet::whereNull('claimed_at')->where('processed', 0)->where('mission', '>', 0)->get();
return Tweet::whereNull('claimed_at')->where('processed', 0)->where('mission_id', '>', 0);
}
}

+ 1
- 0
composer.json View File

@ -6,6 +6,7 @@
"type": "project",
"require": {
"php": ">=5.6.4",
"doctrine/dbal": "^2.5",
"laravel/framework": "5.4.*",
"laravel/tinker": "~1.0",
"mnabialek/laravel-sql-logger": "^1.1",

+ 404
- 1
composer.lock View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "9e8221d9785f2844cfd20e63de3a382d",
"content-hash": "5681db78f7fa8c08618795173764986e",
"packages": [
{
"name": "dnoegel/php-xdg-base-dir",
@ -39,6 +39,355 @@
"description": "implementation of xdg base directory specification for php",
"time": "2014-10-24T07:27:01+00:00"
},
{
"name": "doctrine/annotations",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "54cacc9b81758b14e3ce750f205a393d52339e97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97",
"reference": "54cacc9b81758b14e3ce750f205a393d52339e97",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": "^5.6 || ^7.0"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"time": "2017-02-24T16:22:25+00:00"
},
{
"name": "doctrine/cache",
"version": "v1.6.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3",
"reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3",
"shasum": ""
},
"require": {
"php": "~5.5|~7.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0",
"predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2016-10-29T11:16:17+00:00"
},
{
"name": "doctrine/collections",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "1a4fb7e902202c33cce8c55989b945612943c2ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba",
"reference": "1a4fb7e902202c33cce8c55989b945612943c2ba",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"require-dev": {
"doctrine/coding-standard": "~0.1@dev",
"phpunit/phpunit": "^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Collections\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"array",
"collections",
"iterator"
],
"time": "2017-01-03T10:49:41+00:00"
},
{
"name": "doctrine/common",
"version": "v2.7.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "930297026c8009a567ac051fd545bf6124150347"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/930297026c8009a567ac051fd545bf6124150347",
"reference": "930297026c8009a567ac051fd545bf6124150347",
"shasum": ""
},
"require": {
"doctrine/annotations": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/inflector": "1.*",
"doctrine/lexer": "1.*",
"php": "~5.6|~7.0"
},
"require-dev": {
"phpunit/phpunit": "^5.4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common Library for Doctrine projects",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"collections",
"eventmanager",
"persistence",
"spl"
],
"time": "2017-01-13T14:02:13+00:00"
},
{
"name": "doctrine/dbal",
"version": "v2.5.12",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "7b9e911f9d8b30d43b96853dab26898c710d8f44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/7b9e911f9d8b30d43b96853dab26898c710d8f44",
"reference": "7b9e911f9d8b30d43b96853dab26898c710d8f44",
"shasum": ""
},
"require": {
"doctrine/common": ">=2.4,<2.8-dev",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"symfony/console": "2.*||^3.0"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\DBAL\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Database Abstraction Layer",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"persistence",
"queryobject"
],
"time": "2017-02-08T12:53:47+00:00"
},
{
"name": "doctrine/inflector",
"version": "v1.1.0",
@ -106,6 +455,60 @@
],
"time": "2015-11-06T14:35:42+00:00"
},
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
],
"time": "2014-09-09T13:34:57+00:00"
},
{
"name": "erusev/parsedown",
"version": "1.6.2",

+ 1
- 1
database/migrations/2017_07_02_182117_create_tweet_queue.php View File

@ -21,7 +21,7 @@ class CreateTweetQueue extends Migration
$table->integer('team_id');
$table->text('text');
$table->json('photo');
$table->text('photo');
$table->datetime('claimed_at')->nullable();
$table->boolean('processed')->default(0);

+ 31
- 0
database/migrations/2017_07_02_210344_create_missions.php View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMissions extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('missions', function (Blueprint $table) {
$table->increments('id');
$table->string('hashtag', 255);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('missions');
}
}

+ 32
- 0
database/migrations/2017_07_02_211355_tweet_mission_id.php View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class TweetMissionId extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tweets', function (Blueprint $table) {
$table->renameColumn('mission', 'mission_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tweets', function (Blueprint $table) {
$table->renameColumn('mission_id', 'mission');
});
}
}

+ 1
- 0
database/seeds/DatabaseSeeder.php View File

@ -14,5 +14,6 @@ class DatabaseSeeder extends Seeder
$this->call(DocumentSeeder::class);
$this->call(TransitCenterSeeder::class);
$this->call(TransitLineSeeder::class);
$this->call(MissionSeeder::class);
}
}

+ 26
- 0
database/seeds/MissionSeeder.php View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Seeder;
class MissionSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$missions = [
'#transitspy',
'#intercept',
'#airlair',
'#transittea',
'#sing',
'#passport',
'#document',
];
foreach($missions as $i=>$m)
DB::table('missions')->insert(['id' => $i+1, 'hashtag' => $m]);
}
}

+ 29
- 3
public/css/app.css View File

@ -8372,9 +8372,11 @@ button.close {
}
.profile img {
width: 30px;
height: 30px;
border-radius: 15px;
width: 40px;
height: 40px;
border-radius: 20px;
border-width: 5px;
border-style: solid;
}
.player-list ul {
@ -8386,6 +8388,30 @@ button.close {
.player-list li {
margin: 0;
padding: 4px 0;
}
.tweet-queue .tweet {
border-bottom: 1px #ccc solid;
padding: 4px;
cursor: pointer;
}
.tweet-queue .tweet .mission {
font-weight: bold;
margin-top: 3px;
}
.tweet-queue .tweet .text {
margin-top: 6px;
font-size: 10px;
line-height: 12px;
max-height: 36px;
overflow: hidden;
white-space: pre-wrap;
}
.tweet-queue .tweet:hover {
background: #e4f1f7;
}

+ 107
- 107
public/js/app.js View File

@ -894,11 +894,12 @@ window.Vue = __webpack_require__(38);
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example', __webpack_require__(39));
Vue.component('team-list', __webpack_require__(42));
Vue.component('tweet-queue', __webpack_require__(56));
var data = { queue: [] };
var app = new Vue({
el: '#app'
el: '#app',
data: data
});
$.ajaxSetup({
@ -46409,15 +46410,37 @@ module.exports = Vue$3;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
/***/ }),
/* 39 */
/* 39 */,
/* 40 */,
/* 41 */,
/* 42 */,
/* 43 */,
/* 44 */,
/* 45 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/* 46 */,
/* 47 */,
/* 48 */,
/* 49 */,
/* 50 */,
/* 51 */,
/* 52 */,
/* 53 */,
/* 54 */,
/* 55 */,
/* 56 */
/***/ (function(module, exports, __webpack_require__) {
var disposed = false
var Component = __webpack_require__(8)(
/* script */
__webpack_require__(40),
__webpack_require__(57),
/* template */
__webpack_require__(41),
__webpack_require__(58),
/* styles */
null,
/* scopeId */
@ -46425,9 +46448,9 @@ var Component = __webpack_require__(8)(
/* moduleIdentifier (server only) */
null
)
Component.options.__file = "/Users/aaronpk/Code/spy30/resources/assets/js/components/Example.vue"
Component.options.__file = "/Users/aaronpk/Code/spy30/resources/assets/js/components/TweetQueue.vue"
if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key.substr(0, 2) !== "__"})) {console.error("named exports are not supported in *.vue files.")}
if (Component.options.functional) {console.error("[vue-loader] Example.vue: functional components are not supported with templates, they should use render functions.")}
if (Component.options.functional) {console.error("[vue-loader] TweetQueue.vue: functional components are not supported with templates, they should use render functions.")}
/* hot reload */
if (false) {(function () {
@ -46436,9 +46459,9 @@ if (false) {(function () {
if (!hotAPI.compatible) return
module.hot.accept()
if (!module.hot.data) {
hotAPI.createRecord("data-v-ffb61a8e", Component.options)
hotAPI.createRecord("data-v-1798c0a1", Component.options)
} else {
hotAPI.reload("data-v-ffb61a8e", Component.options)
hotAPI.reload("data-v-1798c0a1", Component.options)
}
module.hot.dispose(function (data) {
disposed = true
@ -46449,15 +46472,9 @@ module.exports = Component.exports
/***/ }),
/* 40 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
/* 57 */
/***/ (function(module, exports) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
//
//
//
//
//
//
//
@ -46471,113 +46488,96 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
//
//
/* harmony default export */ __webpack_exports__["default"] = ({
mounted: function mounted() {
console.log('Component mounted.');
}
});
/***/ }),
/* 41 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = {
data: function data() {
return {
queue: []
};
},
module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
return _vm._m(0)
},staticRenderFns: [function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
return _c('div', {
staticClass: "container"
}, [_c('div', {
staticClass: "row"
}, [_c('div', {
staticClass: "col-md-8 col-md-offset-2"
}, [_c('div', {
staticClass: "panel panel-default"
}, [_c('div', {
staticClass: "panel-heading"
}, [_vm._v("Example Component")]), _vm._v(" "), _c('div', {
staticClass: "panel-body"
}, [_vm._v("\n I'm an example component!\n ")])])])])])
}]}
module.exports.render._withStripped = true
if (false) {
module.hot.accept()
if (module.hot.data) {
require("vue-hot-reload-api").rerender("data-v-ffb61a8e", module.exports)
}
}
methods: {
loadQueue: function loadQueue() {
$.get('/dashboard/queue', function (tweets) {
var _this = this;
/***/ }),
/* 42 */
/***/ (function(module, exports, __webpack_require__) {
for (var i in tweets.queue) {
this.queue.push(tweets.queue[i]);
}
var disposed = false
var Component = __webpack_require__(8)(
/* script */
__webpack_require__(43),
/* template */
__webpack_require__(44),
/* styles */
null,
/* scopeId */
null,
/* moduleIdentifier (server only) */
null
)
Component.options.__file = "/Users/aaronpk/Code/spy30/resources/assets/js/components/TeamList.vue"
if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key.substr(0, 2) !== "__"})) {console.error("named exports are not supported in *.vue files.")}
if (Component.options.functional) {console.error("[vue-loader] TeamList.vue: functional components are not supported with templates, they should use render functions.")}
// Listen for new items on the queue
Echo.channel('tweet-queue').listen('NewTweetEvent', function (e) {
console.log(e);
_this.queue.push(e);
});
}.bind(this));
},
clickedTweet: function clickedTweet(event) {
var tweet_id = $(event.target).parents(".tweet").data('tweet-id');
console.log(this.queue);
// Get the index of the clicked element
for (var i in this.queue) {
if (parseInt(this.queue[i].tweet_id) == parseInt(tweet_id)) {
var queueIndex = i;
}
}
console.log("Removing item at index " + queueIndex);
this.queue.splice(queueIndex, 1);
/* hot reload */
if (false) {(function () {
var hotAPI = require("vue-hot-reload-api")
hotAPI.install(require("vue"), false)
if (!hotAPI.compatible) return
module.hot.accept()
if (!module.hot.data) {
hotAPI.createRecord("data-v-67ad3e48", Component.options)
} else {
hotAPI.reload("data-v-67ad3e48", Component.options)
// Mark this as claimed
$.post('/dashboard/claim-tweet', {
tweet_id: tweet_id
}, function (response) {});
}
},
created: function created() {
this.loadQueue();
}
module.hot.dispose(function (data) {
disposed = true
})
})()}
module.exports = Component.exports
/***/ }),
/* 43 */
/***/ (function(module, exports) {
//
//
//
//
//
};
/***/ }),
/* 44 */
/* 58 */
/***/ (function(module, exports, __webpack_require__) {
module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
return _c('div', {
staticClass: "team"
})
staticClass: "tweet-queue"
}, _vm._l((_vm.queue), function(tweet) {
return _c('div', {
staticClass: "tweet",
attrs: {
"data-tweet-id": tweet.tweet_id
},
on: {
"click": _vm.clickedTweet
}
}, [_c('div', {
staticClass: "profile"
}, [_c('img', {
style: ('border-color: #' + tweet.team_color),
attrs: {
"src": tweet.player_photo
}
}), _vm._v(" "), _c('span', [_c('a', {
attrs: {
"href": 'https://twitter.com/' + tweet.player_username
}
}, [_vm._v("@" + _vm._s(tweet.player_username))])])]), _vm._v(" "), _c('div', {
staticClass: "mission",
attrs: {
"data-mission-id": tweet.mission_id
}
}, [_vm._v(_vm._s(tweet.mission))]), _vm._v(" "), _c('div', {
staticClass: "text"
}, [_vm._v(_vm._s(tweet.text))])])
}))
},staticRenderFns: []}
module.exports.render._withStripped = true
if (false) {
module.hot.accept()
if (module.hot.data) {
require("vue-hot-reload-api").rerender("data-v-67ad3e48", module.exports)
require("vue-hot-reload-api").rerender("data-v-1798c0a1", module.exports)
}
}
/***/ }),
/* 45 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ })
/******/ ]);

+ 5
- 4
resources/assets/js/app.js View File

@ -15,11 +15,12 @@ window.Vue = require('vue');
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example', require('./components/Example.vue'));
Vue.component('team-list', require('./components/TeamList.vue'));
Vue.component('tweet-queue', require('./components/TweetQueue.vue'));
const app = new Vue({
el: '#app'
var data = {queue: []};
var app = new Vue({
el: '#app',
data: data
});
$.ajaxSetup({

+ 0
- 8
resources/assets/js/components/TeamList.vue View File

@ -1,8 +0,0 @@
<template>
<div class="team">
</div>
</template>
<script>
</script>

+ 61
- 0
resources/assets/js/components/TweetQueue.vue View File

@ -0,0 +1,61 @@
<template>
<div class="tweet-queue">
<div v-for="tweet in queue" v-on:click="clickedTweet" class="tweet" :data-tweet-id="tweet.tweet_id">
<div class="profile">
<img :src="tweet.player_photo" :style="'border-color: #'+tweet.team_color">
<span><a :href="'https://twitter.com/'+tweet.player_username">@{{ tweet.player_username }}</a></span>
</div>
<div class="mission" :data-mission-id="tweet.mission_id">{{ tweet.mission }}</div>
<div class="text">{{ tweet.text }}</div>
</div>
</div>
</template>
<script>
module.exports = {
data () {
return {
queue: []
}
},
methods: {
loadQueue () {
$.get('/dashboard/queue', function(tweets){
for(var i in tweets.queue) {
this.queue.push(tweets.queue[i]);
}
// Listen for new items on the queue
Echo.channel('tweet-queue')
.listen('NewTweetEvent', (e) => {
console.log(e);
this.queue.push(e);
});
}.bind(this));
},
clickedTweet(event) {
var tweet_id = $(event.target).parents(".tweet").data('tweet-id');
console.log(this.queue);
// Get the index of the clicked element
for(var i in this.queue) {
if(parseInt(this.queue[i].tweet_id) == parseInt(tweet_id)) {
var queueIndex = i;
}
}
console.log("Removing item at index "+queueIndex);
this.queue.splice(queueIndex, 1);
// Mark this as claimed
$.post('/dashboard/claim-tweet', {
tweet_id: tweet_id
}, function(response) {
});
}
},
created() {
this.loadQueue();
}
}
</script>

+ 33
- 3
resources/assets/sass/app.scss View File

@ -27,9 +27,11 @@
.profile {
img {
width: 30px;
height: 30px;
border-radius: 15px;
width: 40px;
height: 40px;
border-radius: 20px;
border-width: 5px;
border-style: solid;
}
span {
@ -46,6 +48,34 @@
}
li {
margin: 0;
padding: 4px 0;
}
}
.tweet-queue {
.tweet {
border-bottom: 1px #ccc solid;
padding: 4px;
cursor:pointer;
.mission {
font-weight: bold;
margin-top: 3px;
}
.text {
margin-top: 6px;
font-size: 10px;
line-height: 12px;
max-height: 36px;
overflow: hidden;
white-space: pre-wrap;
}
}
.tweet:hover {
background: #e4f1f7;
}
}

resources/views/home.blade.php → resources/views/dashboard.blade.php View File

@ -3,7 +3,13 @@
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="col-xs-4 col-md-4">
<div class="panel panel-default">
<div class="panel-heading">Queue</div>
<tweet-queue></tweet-queue>
</div>
</div>
<div class="col-xs-8 col-md-8">
<div class="panel panel-default">
<div class="panel-heading">Dashboard</div>

+ 1
- 1
resources/views/teams.blade.php View File

@ -23,7 +23,7 @@
@foreach($team->players as $player)
<li>
<div class="profile">
<img src="{{ $player->photo }}">
<img src="{{ $player->photo }}" style="border-color: #{{ $team->color }};">
<span><a href="https://twitter.com/{{ $player->twitter }}">{{ '@'.$player->twitter }}</a></span>
</div>
</li>

+ 4
- 0
routes/channels.php View File

@ -14,3 +14,7 @@
Broadcast::channel('App.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
// Broadcast::channel('tweet-queue', function($user) {
// return true;
// })

+ 1
- 0
routes/web.php View File

@ -19,6 +19,7 @@ Auth::routes();
Route::get('/dashboard', 'DashboardController@index')->name('dashboard');
Route::get('/dashboard/queue', 'DashboardController@queue')->name('queue');
Route::post('/dashboard/claim-tweet', 'DashboardController@claim_tweet');
Route::get('/teams', 'TeamController@index')->name('teams');
Route::post('/teams/new', 'TeamController@create_team');

Loading…
Cancel
Save