|
@@ -1,4 +1,4 @@
|
|
|
-@extends('layouts.guest-meeting')
|
|
|
+@extends('layouts.meeting')
|
|
|
@section('content')
|
|
|
|
|
|
<div id="meetingComponent">
|
|
@@ -20,18 +20,19 @@
|
|
|
class="tp-item mb-4"
|
|
|
:class="activeParticipant && activeType === 'guest' && activeParticipant.id === guest.id ? 'active' : ''"
|
|
|
v-on:click="setActiveView('guest', guest)">
|
|
|
- <img :src="guest.image" alt="" class="w-100">
|
|
|
- <p class="font-weight-bold text-center mt-1 mb-0">@{{ guest.name }}</p>
|
|
|
+ <div class="avatar text-white" :style="'background: ' + guest.color">@{{ getInitials(guest.name) }}</div>
|
|
|
+ <p class="font-weight-bold text-center mt-1 mb-0 text-single mx-1">@{{ guest.name }}</p>
|
|
|
</div>
|
|
|
- <div v-if="!guest" class="tp-item mb-4">
|
|
|
- <img src="/images/person/guest.png" alt="" class="w-100">
|
|
|
+ <div v-if="guest" class="tp-item mb-4">
|
|
|
+ <img src="/images/person/guest.png" alt="" class="invite-image">
|
|
|
<p class="font-weight-bold text-center mt-1">Invite Guest</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="main-view" style="width: 800px; min-height: 600px;">
|
|
|
- <div class="p-4 w-100 h-100 d-flex align-items-stretch justify-content-stretch flex-column">
|
|
|
- <img :src="activeParticipant.image" class="d-block mw-100 mh-100 mx-auto">
|
|
|
+ <div class="p-4 w-100 h-100 d-flex align-items-stretch justify-content-end flex-column">
|
|
|
<p class="font-weight-bold text-center text-white mt-2">Feed from @{{ activeParticipant.name }}</p>
|
|
|
+ <button class="btn btn-sm btn-danger px-4 align-self-end mx-auto font-weight-bold"
|
|
|
+ v-on:click="leaveCall()">Leave</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="tp-bar">
|
|
@@ -40,9 +41,9 @@
|
|
|
:class="activeParticipant && activeType === 'pro' && activeParticipant.id === pro.id ? 'active' : ''"
|
|
|
v-on:click="setActiveView('pro', pro)">
|
|
|
<div v-if="pro.status === 'active'">
|
|
|
- <img :src="pro.image" alt="" class="w-100">
|
|
|
- <p class="font-weight-bold text-center mt-1 mb-0">@{{ pro.name }}</p>
|
|
|
- <p class="font-weight-normal text-center">@{{ pro.type }}</p>
|
|
|
+ <div class="avatar text-white" :style="'background: ' + pro.color">@{{ getInitials(pro.name) }}</div>
|
|
|
+ <p class="font-weight-bold text-center mt-1 mb-0 text-single mx-1">@{{ pro.name }}</p>
|
|
|
+ <p v-if="pro.type" class="font-weight-normal text-center text-single mx-1">@{{ pro.type }}</p>
|
|
|
</div>
|
|
|
<div v-if="pro.status === 'connecting'">
|
|
|
<img src="/images/person/connecting.jpg" alt="" class="w-100">
|
|
@@ -52,44 +53,126 @@
|
|
|
</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div v-if="!guest" class="tp-item mb-4">
|
|
|
+ <img src="/images/person/guest.png" alt="" class="invite-image">
|
|
|
+ <p class="font-weight-bold text-center mt-1">Invite Pro</p>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
+
|
|
|
+ const allParticipants = {!! json_encode($participants) !!},
|
|
|
+ allPros = [],
|
|
|
+ allGuests = [];
|
|
|
+ for (let i = 0; i < allParticipants.length; i++) {
|
|
|
+ if(allParticipants[i].guest_or_pro === 'PRO') {
|
|
|
+ allPros.push({
|
|
|
+ id: allParticipants[i].uid,
|
|
|
+ name: allParticipants[i].proName,
|
|
|
+ type: 'Pro',
|
|
|
+ image: '',
|
|
|
+ color: '', // fill in mounted()
|
|
|
+ status: 'active',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ allGuests.push({
|
|
|
+ id: allParticipants[i].uid,
|
|
|
+ name: allParticipants[i].guest_name,
|
|
|
+ image: '',
|
|
|
+ color: '', // fill in mounted()
|
|
|
+ status: 'active',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
new Vue({
|
|
|
el: '#meetingComponent',
|
|
|
delimiters: ['@{{', '}}'],
|
|
|
data: {
|
|
|
meetingID: '<?= $meetingID ?>',
|
|
|
- participantID: '<?= $participantID ?>',
|
|
|
+ participantID: '<?= $guest ? $participantID : '' ?>',
|
|
|
+ socket: null,
|
|
|
+ stompClient: null,
|
|
|
time: 0,
|
|
|
startTime: 0,
|
|
|
started: false,
|
|
|
- guest: false,
|
|
|
+ guest: <?= $guest ? 'true' : 'false' ?>,
|
|
|
activeType: false,
|
|
|
activeParticipant: false,
|
|
|
+ exitURL: '<?= $guest ? '/' : '/pro/dashboard' ?>',
|
|
|
+ allPastels: [
|
|
|
+ '#89cff0',
|
|
|
+ '#99c5c4',
|
|
|
+ '#9adedb',
|
|
|
+ '#aa9499',
|
|
|
+ '#aaf0d1',
|
|
|
+ '#b2fba5',
|
|
|
+ '#b39eb5',
|
|
|
+ '#bdb0d0',
|
|
|
+ '#bee7a5',
|
|
|
+ '#befd73',
|
|
|
+ '#c1c6fc',
|
|
|
+ '#c6a4a4',
|
|
|
+ '#c8ffb0',
|
|
|
+ '#cb99c9',
|
|
|
+ '#cef0cc',
|
|
|
+ '#cfcfc4',
|
|
|
+ '#d6fffe',
|
|
|
+ '#d8a1c4',
|
|
|
+ '#dea5a4',
|
|
|
+ '#deece1',
|
|
|
+ '#dfd8e1',
|
|
|
+ '#e5d9d3',
|
|
|
+ '#e9d1bf',
|
|
|
+ '#f49ac2',
|
|
|
+ '#f4bfff',
|
|
|
+ '#fdfd96',
|
|
|
+ '#ff6961',
|
|
|
+ '#ff964f',
|
|
|
+ '#ff9899',
|
|
|
+ '#ffb7ce',
|
|
|
+ '#ca9bf7'
|
|
|
+ ],
|
|
|
+ usedPastels: [],
|
|
|
guests: [
|
|
|
{
|
|
|
- id: 1,
|
|
|
- name: 'You',
|
|
|
- image: '/images/person/you.jpg',
|
|
|
- status: 'active',
|
|
|
+ id: '',
|
|
|
+ name: '',
|
|
|
+ image: '',
|
|
|
+ color: '',
|
|
|
+ status: 'connecting',
|
|
|
},
|
|
|
],
|
|
|
pros: [
|
|
|
{
|
|
|
- id: 1,
|
|
|
- name: 'Nancy Drew',
|
|
|
- type: 'Receptionist',
|
|
|
- image: '/images/person/nancy.jpg',
|
|
|
- status: 'connecting',
|
|
|
+ id: '',
|
|
|
+ name: '',
|
|
|
+ type: '',
|
|
|
+ image: '',
|
|
|
+ color: '',
|
|
|
+ status: '',
|
|
|
}
|
|
|
]
|
|
|
- // pros: []
|
|
|
},
|
|
|
methods: {
|
|
|
+ getUnusedPastel: function() {
|
|
|
+ for (let i = 0; i < this.allPastels.length; i++) {
|
|
|
+ if(this.usedPastels.indexOf(this.allPastels[i]) === -1) {
|
|
|
+ this.usedPastels.push(this.allPastels[i]);
|
|
|
+ return this.allPastels[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '#fff';
|
|
|
+ },
|
|
|
+ getInitials: function(_name) {
|
|
|
+ var parts = _name.split(/\s+/g);
|
|
|
+ parts = parts.map(_part => _part[0]);
|
|
|
+ return parts.join('');
|
|
|
+ },
|
|
|
setActiveView: function(_type, _participant) {
|
|
|
if(_participant.status === 'active') {
|
|
|
this.activeType = _type;
|
|
@@ -97,60 +180,208 @@
|
|
|
}
|
|
|
},
|
|
|
timeDisplay: function() {
|
|
|
- // this.time = new Date().getTime() - this.startTime;
|
|
|
var seconds = this.time / 1000,
|
|
|
minutes = parseInt(seconds / 60, 10);
|
|
|
seconds = parseInt(seconds % 60, 10);
|
|
|
return minutes + " min, " + seconds + " sec";
|
|
|
+ },
|
|
|
+ connectToFirstPro: function() {
|
|
|
+ console.log('Connecting to first pro ...');
|
|
|
+ this.pros = [];
|
|
|
+ this.addPro();
|
|
|
+ $.post('/api/meeting/request-dial-pro', {
|
|
|
+ meetingUid: this.meetingID,
|
|
|
+ }, function(_data) {
|
|
|
+ console.log('Response to /api/meeting/request-dial-pro');
|
|
|
+ console.log(_data);
|
|
|
+ }, 'json');
|
|
|
+ },
|
|
|
+ ifGuestExisting: function(_id) {
|
|
|
+ var matching = this.guests.filter(function(_item) {
|
|
|
+ return _item.id === _id;
|
|
|
+ });
|
|
|
+ return !!matching.length;
|
|
|
+ },
|
|
|
+ addGuest: function() {
|
|
|
+ this.guests.push({
|
|
|
+ id: '',
|
|
|
+ name: '',
|
|
|
+ image: '',
|
|
|
+ color: this.getUnusedPastel(),
|
|
|
+ status: 'active',
|
|
|
+ });
|
|
|
+ return this.guests[this.guests.length - 1];
|
|
|
+ },
|
|
|
+ addPro: function() {
|
|
|
+ this.pros.push({
|
|
|
+ id: '0',
|
|
|
+ name: 'Pro',
|
|
|
+ type: 'Receptionist',
|
|
|
+ image: '/images/person/nancy.jpg',
|
|
|
+ color: this.getUnusedPastel(),
|
|
|
+ status: 'connecting',
|
|
|
+ });
|
|
|
+ return this.pros[this.pros.length - 1];
|
|
|
+ },
|
|
|
+ onProJoined: function(_data) {
|
|
|
+
|
|
|
+ var found = false;
|
|
|
+
|
|
|
+ // find pro with participant id
|
|
|
+ var pro = this.pros.filter(function(_pro) {
|
|
|
+ return _pro.id === _data.meetingParticipantUid;
|
|
|
+ });
|
|
|
+
|
|
|
+ // no pro with id, find first one with id = 0
|
|
|
+ if(!pro.length) {
|
|
|
+ pro = this.pros.filter(function(_pro) {
|
|
|
+ return _pro.id === "0";
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // no pro with id = 0, create one
|
|
|
+ if(!pro.length) {
|
|
|
+ pro = this.addPro();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ pro = pro[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ pro.id = _data.meetingParticipantUid;
|
|
|
+ pro.name = _data.proDisplayName;
|
|
|
+ pro.type = _data.hcpCategory;
|
|
|
+ pro.status = 'active';
|
|
|
+
|
|
|
+ @if($guest)
|
|
|
+ var self = this;
|
|
|
+ if(!this.startTime) {
|
|
|
+ this.startTime = new Date().getTime();
|
|
|
+ window.setInterval(function() {
|
|
|
+ self.time = new Date().getTime() - self.startTime;
|
|
|
+ }, 1000);
|
|
|
+ this.started = true;
|
|
|
+ }
|
|
|
+ @endif
|
|
|
+
|
|
|
+ // TODO: init pro stream
|
|
|
+ },
|
|
|
+ onParticipantLeft: function(_id) {
|
|
|
+ this.pros = this.pros.filter(function(_row) {
|
|
|
+ return _row.id !== _id;
|
|
|
+ });
|
|
|
+ this.guests = this.guests.filter(function(_row) {
|
|
|
+ return _row.id !== _id;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ leaveCall: function() {
|
|
|
+ this.stompClient.send("/app/meeting-participant-leave-meeting", {},
|
|
|
+ JSON.stringify({
|
|
|
+ meetingParticipantUid: this.participantID
|
|
|
+ })
|
|
|
+ );
|
|
|
+ window.location.href = this.exitURL;
|
|
|
}
|
|
|
},
|
|
|
mounted: function() {
|
|
|
- this.activeType = 'guest';
|
|
|
- this.activeParticipant = this.guests[0];
|
|
|
+
|
|
|
+ this.guests = allGuests;
|
|
|
+ this.pros = allPros;
|
|
|
+
|
|
|
+ for (let i = 0; i < this.guests.length; i++) {
|
|
|
+ this.guests[i].color = this.getUnusedPastel();
|
|
|
+ }
|
|
|
+ for (let i = 0; i < this.pros.length; i++) {
|
|
|
+ this.pros[i].color = this.getUnusedPastel();
|
|
|
+ }
|
|
|
|
|
|
var self = this;
|
|
|
|
|
|
- // after 2 seconds, connect recep
|
|
|
- window.setTimeout(function() {
|
|
|
- self.pros[0].status = 'active';
|
|
|
- self.started = true;
|
|
|
- self.startTime = new Date().getTime();
|
|
|
- self.activeType = 'pro';
|
|
|
- self.activeParticipant = self.pros[0];
|
|
|
- window.setInterval(function() {
|
|
|
- self.time = new Date().getTime() - self.startTime;
|
|
|
- }, 1000);
|
|
|
-
|
|
|
- // after 1 second, add 2 docs in connecting state
|
|
|
- window.setTimeout(function() {
|
|
|
- self.pros.push({
|
|
|
- id: 2,
|
|
|
- name: 'Dr. Strange',
|
|
|
- type: 'Dietitian',
|
|
|
- image: '/images/person/strange.0.jpg',
|
|
|
- status: 'connecting',
|
|
|
+ // connect to WS
|
|
|
+ self.socket = new SockJS('http://localhost:8080/ws');
|
|
|
+ self.stompClient = Stomp.over(self.socket);
|
|
|
+ self.stompClient.connect({}, function (frame) {
|
|
|
+ console.log('Connected: ' + frame);
|
|
|
+
|
|
|
+ @if($guest)
|
|
|
+
|
|
|
+ // add self and set as active
|
|
|
+ if(!self.ifGuestExisting('<?= $participantID ?>')) {
|
|
|
+ var guest = self.addGuest();
|
|
|
+ guest.id = '<?= $participantID ?>';
|
|
|
+ guest.status = 'active';
|
|
|
+ guest.name = 'Guest';
|
|
|
+ }
|
|
|
+
|
|
|
+ // WS Subscriptions
|
|
|
+ self.stompClient.subscribe("/topic/on-pro-join-meeting", function (message) {
|
|
|
+ console.log("on-pro-join-meeting:", message);
|
|
|
+ self.onProJoined(JSON.parse(message.body));
|
|
|
+ });
|
|
|
+ self.stompClient.subscribe("/topic/on-meeting-participant-left-meeting", function (message) {
|
|
|
+ console.log("/topic/on-meeting-participant-left-meeting", message);
|
|
|
+ var parsed = JSON.parse(message.body);
|
|
|
+ self.onParticipantLeft(parsed.meetingParticipantUid);
|
|
|
+ });
|
|
|
+
|
|
|
+ // join self
|
|
|
+ self.stompClient.send("/app/meeting-participant-join-meeting", {},
|
|
|
+ JSON.stringify({
|
|
|
+ meetingParticipantUid: self.participantID
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ // attempt to connect to first pro if "start"
|
|
|
+ @if(request('start'))
|
|
|
+ self.connectToFirstPro();
|
|
|
+ @endif
|
|
|
+
|
|
|
+ @else
|
|
|
+
|
|
|
+ // WS subscriptions
|
|
|
+
|
|
|
+ // self joined confirmation
|
|
|
+ self.stompClient.subscribe("/user/topic/on-pro-self-join-meeting", function (message) {
|
|
|
+ console.log("/user/topic/on-pro-self-join-meeting:", message);
|
|
|
+ var parsed = JSON.parse(message.body);
|
|
|
+ self.onProJoined(parsed);
|
|
|
+ self.participantID = parsed.meetingParticipantUid;
|
|
|
});
|
|
|
- self.pros.push({
|
|
|
- id: 3,
|
|
|
- name: 'Dr. Do Little',
|
|
|
- type: 'Cardiologist',
|
|
|
- image: '/images/person/dl.jpg',
|
|
|
- status: 'connecting',
|
|
|
+ self.stompClient.subscribe("/topic/on-meeting-participant-left-meeting", function (message) {
|
|
|
+ console.log("/topic/on-meeting-participant-left-meeting", message);
|
|
|
+ var parsed = JSON.parse(message.body);
|
|
|
+ self.onParticipantLeft(parsed.meetingParticipantUid);
|
|
|
});
|
|
|
|
|
|
- // after a second, connect strange
|
|
|
- window.setTimeout(function() {
|
|
|
- self.pros[1].status = 'active';
|
|
|
+ // join self
|
|
|
+ self.stompClient.send("/app/pro-join-meeting", {},
|
|
|
+ JSON.stringify({
|
|
|
+ sessionKey: "<?= request()->cookie('sessionKey') ?>",
|
|
|
+ meetingUid: "<?= $meetingID ?>",
|
|
|
+ })
|
|
|
+ );
|
|
|
|
|
|
- window.setTimeout(function() {
|
|
|
- self.pros[2].status = 'active';
|
|
|
+ @if(!$guest)
|
|
|
+ if(!self.startTime) {
|
|
|
+ self.startTime = new Date().getTime();
|
|
|
+ window.setInterval(function() {
|
|
|
+ self.time = new Date().getTime() - self.startTime;
|
|
|
}, 1000);
|
|
|
+ self.started = true;
|
|
|
+ }
|
|
|
+ @endif
|
|
|
+ @endif
|
|
|
|
|
|
- }, 1000);
|
|
|
+ // TODO: init own stream
|
|
|
|
|
|
- }, 1000);
|
|
|
+ self.stompClient.subscribe("/topic/on-meeting-participant-connection-status-change", function(message){
|
|
|
+ /*
|
|
|
+ String messagePartipantUid;
|
|
|
+ boolean isConnected;
|
|
|
+ */
|
|
|
+ console.log(message);
|
|
|
+ });
|
|
|
|
|
|
- }, 2000);
|
|
|
+ });
|
|
|
}
|
|
|
});
|
|
|
</script>
|