From e28797017a7ac7d120ab89682db23f23b484bea6 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 2 Jul 2017 15:17:28 -0700 Subject: [PATCH] adds tweet queue to dashboard --- app/Events/NewTweetEvent.php | 58 +++ app/Http/Controllers/DashboardController.php | 22 +- app/Http/Controllers/TwitterController.php | 28 +- app/Mission.php | 15 + app/Tweet.php | 23 +- composer.json | 1 + composer.lock | 405 +++++++++++++++++- .../2017_07_02_182117_create_tweet_queue.php | 2 +- .../2017_07_02_210344_create_missions.php | 31 ++ .../2017_07_02_211355_tweet_mission_id.php | 32 ++ database/seeds/DatabaseSeeder.php | 1 + database/seeds/MissionSeeder.php | 26 ++ public/css/app.css | 32 +- public/js/app.js | 214 ++++----- resources/assets/js/app.js | 9 +- resources/assets/js/components/TeamList.vue | 8 - resources/assets/js/components/TweetQueue.vue | 61 +++ resources/assets/sass/app.scss | 36 +- .../{home.blade.php => dashboard.blade.php} | 8 +- resources/views/teams.blade.php | 2 +- routes/channels.php | 4 + routes/web.php | 1 + 22 files changed, 867 insertions(+), 152 deletions(-) create mode 100644 app/Events/NewTweetEvent.php create mode 100644 app/Mission.php create mode 100644 database/migrations/2017_07_02_210344_create_missions.php create mode 100644 database/migrations/2017_07_02_211355_tweet_mission_id.php create mode 100644 database/seeds/MissionSeeder.php delete mode 100644 resources/assets/js/components/TeamList.vue create mode 100644 resources/assets/js/components/TweetQueue.vue rename resources/views/{home.blade.php => dashboard.blade.php} (57%) diff --git a/app/Events/NewTweetEvent.php b/app/Events/NewTweetEvent.php new file mode 100644 index 0000000..7a85a3e --- /dev/null +++ b/app/Events/NewTweetEvent.php @@ -0,0 +1,58 @@ +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']; + } +} diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 005f773..480c3a9 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -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']); + } } diff --git a/app/Http/Controllers/TwitterController.php b/app/Http/Controllers/TwitterController.php index 25d81e3..a4baaf5 100644 --- a/app/Http/Controllers/TwitterController.php +++ b/app/Http/Controllers/TwitterController.php @@ -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']; } diff --git a/app/Mission.php b/app/Mission.php new file mode 100644 index 0000000..4e508c4 --- /dev/null +++ b/app/Mission.php @@ -0,0 +1,15 @@ +hasMany('App\Tweet'); + } +} diff --git a/app/Tweet.php b/app/Tweet.php index d74072f..f6b8545 100644 --- a/app/Tweet.php +++ b/app/Tweet.php @@ -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); } } diff --git a/composer.json b/composer.json index 3c56fbe..68a2542 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/composer.lock b/composer.lock index 5933a94..7024619 100644 --- a/composer.lock +++ b/composer.lock @@ -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", diff --git a/database/migrations/2017_07_02_182117_create_tweet_queue.php b/database/migrations/2017_07_02_182117_create_tweet_queue.php index aa199ab..7eb603a 100644 --- a/database/migrations/2017_07_02_182117_create_tweet_queue.php +++ b/database/migrations/2017_07_02_182117_create_tweet_queue.php @@ -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); diff --git a/database/migrations/2017_07_02_210344_create_missions.php b/database/migrations/2017_07_02_210344_create_missions.php new file mode 100644 index 0000000..8a27aa3 --- /dev/null +++ b/database/migrations/2017_07_02_210344_create_missions.php @@ -0,0 +1,31 @@ +increments('id'); + $table->string('hashtag', 255); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('missions'); + } +} diff --git a/database/migrations/2017_07_02_211355_tweet_mission_id.php b/database/migrations/2017_07_02_211355_tweet_mission_id.php new file mode 100644 index 0000000..c1fa506 --- /dev/null +++ b/database/migrations/2017_07_02_211355_tweet_mission_id.php @@ -0,0 +1,32 @@ +renameColumn('mission', 'mission_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('tweets', function (Blueprint $table) { + $table->renameColumn('mission_id', 'mission'); + }); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 248cc0a..a65b11c 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -14,5 +14,6 @@ class DatabaseSeeder extends Seeder $this->call(DocumentSeeder::class); $this->call(TransitCenterSeeder::class); $this->call(TransitLineSeeder::class); + $this->call(MissionSeeder::class); } } diff --git a/database/seeds/MissionSeeder.php b/database/seeds/MissionSeeder.php new file mode 100644 index 0000000..6683ee9 --- /dev/null +++ b/database/seeds/MissionSeeder.php @@ -0,0 +1,26 @@ +$m) + DB::table('missions')->insert(['id' => $i+1, 'hashtag' => $m]); + } +} diff --git a/public/css/app.css b/public/css/app.css index 539b107..4792ac5 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -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; } diff --git a/public/js/app.js b/public/js/app.js index 1e9e697..c8425e9 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -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 - /***/ }) /******/ ]); \ No newline at end of file diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index 6508912..23aecae 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -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({ diff --git a/resources/assets/js/components/TeamList.vue b/resources/assets/js/components/TeamList.vue deleted file mode 100644 index 29d3234..0000000 --- a/resources/assets/js/components/TeamList.vue +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/resources/assets/js/components/TweetQueue.vue b/resources/assets/js/components/TweetQueue.vue new file mode 100644 index 0000000..e3b471c --- /dev/null +++ b/resources/assets/js/components/TweetQueue.vue @@ -0,0 +1,61 @@ + + \ No newline at end of file diff --git a/resources/assets/sass/app.scss b/resources/assets/sass/app.scss index d3498aa..1095dcd 100644 --- a/resources/assets/sass/app.scss +++ b/resources/assets/sass/app.scss @@ -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; + } + } diff --git a/resources/views/home.blade.php b/resources/views/dashboard.blade.php similarity index 57% rename from resources/views/home.blade.php rename to resources/views/dashboard.blade.php index d6de122..bed5543 100644 --- a/resources/views/home.blade.php +++ b/resources/views/dashboard.blade.php @@ -3,7 +3,13 @@ @section('content')
-
+
+
+
Queue
+ +
+
+
Dashboard
diff --git a/resources/views/teams.blade.php b/resources/views/teams.blade.php index b4a45d7..3b2af4a 100644 --- a/resources/views/teams.blade.php +++ b/resources/views/teams.blade.php @@ -23,7 +23,7 @@ @foreach($team->players as $player)
  • diff --git a/routes/channels.php b/routes/channels.php index f16a20b..a569806 100644 --- a/routes/channels.php +++ b/routes/channels.php @@ -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; +// }) diff --git a/routes/web.php b/routes/web.php index d4ff3ec..e957bbc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -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');