add messages support

This commit is contained in:
Kacper Donat 2018-09-11 20:58:37 +02:00
parent 205bcaa588
commit 3ce3f6d3d2
16 changed files with 149 additions and 18 deletions

View File

@ -0,0 +1,6 @@
<ul class="messages list-unstyled">
<li class="messages__message alert" :class="`alert-${type(message)}`" v-for="message in messages">
<fa :icon="icon(message)" fixed-width></fa>
{{ message.message }}
</li>
</ul>

View File

@ -34,7 +34,21 @@
padding-bottom: .5rem; padding-bottom: .5rem;
} }
%flex { .flex {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.section__title {
@extend .alert;
@extend .alert-dark;
font-size: medium;
background: transparent;
padding-top: .5rem;
padding-bottom: .5rem;
&:hover {
background: none;
}
}

View File

@ -8,7 +8,7 @@
} }
.departure__stop { .departure__stop {
@extend %flex; @extend .flex;
width: 100%; width: 100%;
.stop { .stop {
@ -27,12 +27,10 @@
} }
.departures__actions { .departures__actions {
display: flex; @extend .flex;
align-items: center;
.departures__auto-refresh { .departures__auto-refresh {
display: flex; @extend .flex;
align-items: center;
} }
.form-control { .form-control {

View File

@ -1,5 +1,5 @@
.line { .line {
@extend %flex; @extend .flex;
.line__symbol { .line__symbol {
min-width: 4rem; min-width: 4rem;
@ -7,7 +7,7 @@
} }
.track { .track {
@extend %flex; @extend .flex;
flex-shrink: 0; flex-shrink: 0;
flex-grow: 0; flex-grow: 0;

View File

@ -1,5 +1,5 @@
.stop, .stop-group__header { .stop, .stop-group__header {
@extend %flex; @extend .flex;
flex-wrap: wrap; flex-wrap: wrap;
} }

View File

@ -15,11 +15,23 @@ window['Popper'] = Popper;
// dependencies // dependencies
import 'bootstrap' import 'bootstrap'
import Vue from 'vue'; import { Vue } from "vue-property-decorator";
// here goes "public" API // here goes "public" API
window['czydojade'] = { window['czydojade'] = {
components components
}; };
window['app'] = new Vue({ el: '#app' }); window['app'] = new Vue({
el: '#app',
data: {
messages: {
count: 0,
visible: true
}
}, methods: {
handleMessagesUpdate(messages) {
this.messages.count = messages.length;
}
}
});

View File

@ -0,0 +1,5 @@
import Vue from 'vue'
export class Application extends Vue {
private messages: boolean = true;
}

View File

@ -2,3 +2,4 @@ export * from './utils'
export * from './picker' export * from './picker'
export * from './departures' export * from './departures'
export * from './stop' export * from './stop'
export * from './messages'

View File

@ -0,0 +1,45 @@
import Vue from 'vue';
import { Component, Prop, Watch } from "vue-property-decorator";
import messages = require("../../components/messages.html");
import { Message } from "../model/message";
import urls from "../urls";
import { faInfoCircle, faExclamationTriangle, faQuestionCircle } from "@fortawesome/pro-light-svg-icons";
@Component({ template: messages })
export class MessagesComponent extends Vue {
public messages: Message[] = [];
async mounted() {
this.update();
}
async update() {
const response = await fetch(urls.prepare(urls.messages));
if (response.ok) {
this.messages = await response.json();
}
this.$emit('updated', this.messages);
}
public icon(message: Message) {
switch (message.type) {
case "breakdown": return faExclamationTriangle;
case "info": return faInfoCircle;
case "unknown": return faQuestionCircle;
}
}
public type(message: Message) {
switch (message.type) {
case "breakdown": return "danger";
case "info": return "info";
case "unknown": return "warning";
}
}
}
Vue.component('Messages', MessagesComponent);

View File

@ -0,0 +1,10 @@
import { Moment } from "moment";
export type MessageType = "info" | "breakdown" | "unknown";
export interface Message {
type: MessageType;
message: string;
validFrom: Moment;
validTo: Moment;
}

View File

@ -49,6 +49,7 @@ const base = '/{provider}/api/v1';
export default { export default {
departures: `${base}/departures`, departures: `${base}/departures`,
messages: `${base}/messages`,
stops: { stops: {
all: `${base}/stops`, all: `${base}/stops`,
search: `${base}/stops/search`, search: `${base}/stops/search`,

View File

@ -18,13 +18,15 @@ class ZtmGdanskMessageRepository implements MessageRepository
const MESSAGES_URL = "http://87.98.237.99:88/displayMessages"; const MESSAGES_URL = "http://87.98.237.99:88/displayMessages";
private $cache; private $cache;
private $classifier;
/** /**
* ZtmGdanskStopRepository constructor. * ZtmGdanskStopRepository constructor.
*/ */
public function __construct(AdapterInterface $cache) public function __construct(AdapterInterface $cache, ZtmGdanskMessageTypeClassifier $classifier)
{ {
$this->cache = $cache; $this->cache = $cache;
$this->classifier = $classifier;
} }
public function getAll(): Collection public function getAll(): Collection
@ -32,12 +34,15 @@ class ZtmGdanskMessageRepository implements MessageRepository
return collect($this->queryZtmApi())->unique(function ($message) { return collect($this->queryZtmApi())->unique(function ($message) {
return $message['messagePart1'] . $message['messagePart2']; return $message['messagePart1'] . $message['messagePart2'];
})->map(function ($message) { })->map(function ($message) {
return Message::createFromArray([ $message = Message::createFromArray([
'message' => trim($message['messagePart1'] . $message['messagePart2']), 'message' => trim($message['messagePart1'] . $message['messagePart2']),
'type' => Message::TYPE_UNKNOWN,
'validFrom' => new Carbon($message['startDate']), 'validFrom' => new Carbon($message['startDate']),
'validTo' => new Carbon($message['endDate']), 'validTo' => new Carbon($message['endDate']),
]); ]);
$message->setType($this->classifier->classify($message));
return $message;
}); });
} }

View File

@ -0,0 +1,22 @@
<?php
namespace App\Provider\ZtmGdansk;
use App\Model\Message;
class ZtmGdanskMessageTypeClassifier
{
public function classify(Message $message): string
{
switch (true) {
case preg_match('/(awari|opóźnie)/i', $message->getMessage()):
return Message::TYPE_BREAKDOWN;
case preg_match('#gdansk.pl/powietrze#i', $message->getMessage()):
return Message::TYPE_INFO;
default:
return Message::TYPE_UNKNOWN;
}
}
}

View File

@ -20,7 +20,7 @@ class ZtmGdanskProvider implements Provider
public function getName() public function getName()
{ {
return 'MZKZG Trójmiasto'; return 'MZKZG - Trójmiasto';
} }
public function getIdentifier() public function getIdentifier()

View File

@ -2,6 +2,18 @@
{% block title "#{parent()} - #{provider.name}" %} {% block title "#{parent()} - #{provider.name}" %}
{% block body %} {% block body %}
<section class="messages" v-if="messages.count > 0">
<h2 class="section__title flex">
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
<button class="btn btn-action btn-sm flex-space-left" @click="messages.visible = !messages.visible">
<fa :icon="['fal', messages.visible ? 'chevron-up' : 'chevron-down']" fixed-width />
</button>
</h2>
<fold :visible="messages.visible">
<messages @update="handleMessagesUpdate"></messages>
</fold>
</section>
<stop-picker></stop-picker> <stop-picker></stop-picker>
{% endblock %} {% endblock %}

View File

@ -12,7 +12,7 @@
{% block body %}{% endblock %} {% block body %}{% endblock %}
</main> </main>
<script src="bundle.js"></script>
{% block javascripts %}{% endblock %} {% block javascripts %}{% endblock %}
<script src="bundle.js"></script>
</body> </body>
</html> </html>