Просмотр исходного кода

ClientEntrance splited into 2 views.

Kain_Stropov 5 лет назад
Родитель
Сommit
a8f0551fcc

+ 25 - 3
app/Http/Controllers/ClientController.php

@@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Http;
 use App\HttpModels\ClientLobbyModel;
 use App\HttpModels\MeetingModel;
 use App\Models\AppSession;
+use App\Models\MeetingParticipant;
 
 use Cookie;
 
@@ -26,6 +27,9 @@ class ClientController extends Controller
         $sessionKey = Cookie::get('sessionKey');
 
         $lobbyModel = new ClientLobbyModel($lobby);
+        session([
+            'lobbyId' => $lobby->id
+        ]);
         // $response = response()->view('client/index',compact('lobbyModel'),200);
 
         if(!$sessionKey){
@@ -50,13 +54,31 @@ class ClientController extends Controller
         // else {
         //     return view('client/index');
         // }
+        return view('client/index',compact('lobbyModel','sessionKey'));
+    }
+    
+    public function meeting(MeetingParticipant $meetingParticipant)
+    {
+        $sessionKey = Cookie::get('sessionKey');
+        if (!$meetingParticipant || !$meetingParticipant->id || !session('lobbyId')) {
+            \abort(404);
+            return;
+        }
+
+        $lobby = Lobby::find(session('lobbyId'));
+        $lobbyModel = new ClientLobbyModel($lobby);
         $session = AppSession::where("session_key",$sessionKey)->first();
         $meeting = null;
-        if ($session->meetingParticipant 
+        if ($session->meetingParticipant
+                // && $session->meetingParticipant->is_active 
                 && $session->meetingParticipant->meeting->is_active
                 && ($session->meetingParticipant->meeting->lobby_id === $lobby->id || $session->meetingParticipant->meeting->lobby_id == null) ) {
             $meeting = new MeetingModel($session->meetingParticipant->meeting);
         }
-        return view('client/index',compact('lobbyModel','meeting','sessionKey'));
-	}
+        else {
+            \abort(404);
+            return; 
+        }
+        return view('client/meeting',compact('lobbyModel','meeting','sessionKey'));
+    }
 }

+ 22 - 557
resources/js/components/pages/ClientEntrance.vue

@@ -50,66 +50,14 @@
 
                     <v-btn color="primary" @click="checkIn" :loading="loading">Continue</v-btn>
                 </v-stepper-content>
-
-                <v-stepper-content step="2">
-                    <p>
-                        Please make sure your webcam is working. Accept the access request to your hardware on the top left to continue.
-                        <br />Then, someone should be with you shortly.
-                    </p>
-
-                    <v-card class="mb-12" color="grey lighten-1" height="50vh">
-                        <grid-layout
-                            :layout="videoGridPreview"
-                            :key="`preview_${uniqueId}`"
-                            :col-num="maxCols"
-                            :max-rows="maxRows"
-                            :row-height="rowHeight"
-                            :is-draggable="false"
-                            :is-resizable="false"
-                            :verticalCompact="true"
-                            :margin="[gridPadding, gridPadding]"
-                            :use-css-transforms="true"
-                        >
-                            <grid-item v-for="video in videoGridPreview" :key="video.id" :id="video.id" :x="video.x" :y="video.y" :w="video.w" :h="video.h" :i="video.i"></grid-item>
-                        </grid-layout>
-                    </v-card>
-
-                    <v-btn color="primary" @click="gotoStep3" :disabled="!cameraWorkingConfirmed">Continue</v-btn>
-
-                    <!-- <v-btn text @click="stepper = 1">Cancel</v-btn> -->
-                </v-stepper-content>
-
-                <v-stepper-content step="3">
-                    <p>Great! Please wait a little, doctor should join shortly.</p>
-
-                    <v-card class="mb-12" color="grey lighten-1" height="50vh">
-                        <grid-layout
-                            :layout="videoGrid"
-                            :key="uniqueId"
-                            :col-num="maxCols"
-                            :max-rows="maxRows"
-                            :row-height="rowHeight"
-                            :is-draggable="false"
-                            :is-resizable="false"
-                            :verticalCompact="true"
-                            :margin="[gridPadding, gridPadding]"
-                            :use-css-transforms="true"
-                        >
-                            <grid-item v-for="video in videoGrid" :key="video.id" :id="video.id" :x="video.x" :y="video.y" :w="video.w" :h="video.h" :i="video.i"></grid-item>
-                        </grid-layout>
-                    </v-card>
-                </v-stepper-content>
             </v-stepper-items>
         </v-stepper>
-        <div style="display: none" ref="otContainer"></div>
     </div>
 </template>
 
 <script>
 import { mapState } from "vuex";
 
-import VueGridLayout from "vue-grid-layout";
-
 import VueSocketIO from "vue-socket.io";
 import SocketIO from "socket.io-client";
 
@@ -121,10 +69,6 @@ Vue.use(
 );
 
 export default {
-    components: {
-        GridLayout: VueGridLayout.GridLayout,
-        GridItem: VueGridLayout.GridItem
-    },
     props: {
         lobbyProp: {
             type: Object,
@@ -134,9 +78,6 @@ export default {
                 pros: []
             }
         },
-        meetingProp: {
-            type: Object
-        },
         clientUid: {
             type: String,
             required: true
@@ -160,8 +101,8 @@ export default {
                 targetLobbyProUid: ""
             },
             meetingUid: "",
-            meetingName: sessionStorage.getItem("meeting_name") || "",
-            stepper: sessionStorage.getItem("step") || 1,
+            meetingName: this.meetingProp.name,
+            stepper: 1,
             cameraWorkingConfirmed: false,
             loading: false,
             /* Copied */
@@ -216,28 +157,6 @@ export default {
         }
     },
     watch: {
-        publisherReady(val) {
-            if (val && this.sessionConnected) this.publishToSession();
-        },
-        sessionConnected(val) {
-            if (val && this.publisherReady) this.publishToSession();
-        },
-        "user.is_active_and_visible"(val) {
-            if (!this.publisher || !this.publisher.publishVideo) return;
-            this.publisher.publishVideo(val);
-            this.publisher.publishAudio(val);
-        },
-        "meeting.id"(val) {
-            if (this.loadingInProgress) return;
-            this.loadingInProgress = true;
-            this.disconnect();
-
-            if (val) {
-                this.getToken({}, true);
-            } else {
-                this.loadingInProgress = false;
-            }
-        },
         stepper: {
             handler(newVal) {
                 sessionStorage.setItem("step", newVal);
@@ -274,490 +193,36 @@ export default {
                         alert(data.message);
                         return;
                     }
-                    this.stepper = 2;
-                    this.meetingUid = data.data;
-
-                    this.$socket.emit("userData", {
-                        user: {
-                            uid: this.clientUid,
-                            name: `${this.firstName} ${this.lastName}`,
-                            type: "STRANGER"
-                        },
-                        meeting: {
-                            uid: this.meetingUid,
-                            lobby_uid: this.lobbyProp.uid
-                        },
-                        lobbies_uid_list: [`${this.lobbyProp.uid}`]
-                    });
 
-                    if (!this.publisher) {
-                        this.$nextTick(this.initializePublisher);
-                    }
+                    window.location = `/client/meeting-participant/${data.data}`;
+                    // this.stepper = 2;
+                    // this.meetingUid = data.data;
+
+                    // this.$socket.emit("userData", {
+                    //     user: {
+                    //         uid: this.clientUid,
+                    //         name: `${this.firstName} ${this.lastName}`,
+                    //         type: "STRANGER"
+                    //     },
+                    //     meeting: {
+                    //         uid: this.meetingUid,
+                    //         lobby_uid: this.lobbyProp.uid
+                    //     },
+                    //     lobbies_uid_list: [`${this.lobbyProp.uid}`]
+                    // });
+
+                    // if (!this.publisher) {
+                    //     this.$nextTick(this.initializePublisher);
+                    // }
                 },
                 error: jXhr => {},
                 complete: () => {
                     this.loading = false;
                 }
             });
-        },
-        initializePublisher() {
-            this.publisher = OT.initPublisher(
-                this.$refs.otContainer,
-                {
-                    insertMode: "append",
-                    width: "100%",
-                    height: "100%",
-                    resolution: "1280x720",
-                    frameRate: 30,
-                    name: `${this.user.firstName} ${this.user.lastName}`,
-                    style: {
-                        nameDisplayMode: "on",
-                        archiveStatusDisplayMode: "off"
-                    }
-                },
-                error => {
-                    if (error) {
-                        alert(error.message);
-                    } else {
-                        this.publisherReady = true;
-                        const cont = this.createVideoContainer(true);
-                        this.$nextTick(() => {
-                            cont.el = $(`#${cont.id}`)[0];
-                            cont.el.appendChild(this.publisher.element);
-                            cont.obj = this.publisher;
-                            this.$set(cont, "self", true);
-                            this.cameraWorkingConfirmed = true;
-
-                            if (this.stepper == 3) {
-                                this.gotoStep3();
-                            }
-                        });
-                    }
-                }
-            );
-            this.publisher.on({
-                accessDialogOpened: e => {
-                    this.accessDialogShown = true;
-                },
-                accessDialogClosed: e => {
-                    this.accessDialogShown = false;
-                }
-            });
-        },
-        gotoStep3() {
-            if (this.stepper != 3) {
-                this.stepper = 3;
-            }
-
-            this.videoGridPreview = [];
-            this.adjustVideoContainers();
-            this.$nextTick(() => {
-                const cont = this.videos[0];
-                cont.el = $(`#${cont.id}`)[0];
-                cont.el.appendChild(cont.obj.element);
-                this.getToken();
-
-                this.$socket.emit("meetingJoined", {
-                    lobby_uid: this.lobbyProp.uid,
-                    meeting_name: this.meetingName,
-                    meeting_uid: this.meetingUid,
-                    user: {
-                        name: `${this.firstName} ${this.lastName}`,
-                        type: "STRANGER",
-                        uid: this.clientUid
-                    }
-                });
-                $.ajax({
-                    url: "/post-to-api-ajax",
-                    method: "POST",
-                    headers: {
-                        "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
-                    },
-                    data: {
-                        _api: "/api/meeting/startLobbyCall",
-                        uid: this.meetingUid,
-                        lobbyUid: this.lobbyProp.uid
-                    },
-                    success: data => {
-                        if (!data.success) console.log(data.message);
-                    }
-                });
-            });
-        },
-        /* Copied */
-        disconnect() {
-            if (!this.openTokSession) return;
-            this.openTokSession.disconnect();
-            this.openTokSession.off();
-            this.videos = [];
-            this.publisher.destroy();
-            this.publisher = null;
-            this.subscribers = [];
-            this.publisherReady = false;
-            this.$store.commit("setSessionConnectivityState", false);
-            this.openTokSession = null;
-            if (this.screenPublisher) {
-                this.screenPublisher.destroy();
-                this.screenPublisher = null;
-            }
-        },
-        getToken() {
-            // if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date() && (this.user.type === "guest" || !confirm("Meeting not started. Start it now?")))
-            //     return;
-            $.ajax({
-                url: "/post-to-api-ajax",
-                method: "POST",
-                headers: {
-                    "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
-                },
-                data: {
-                    _api: "/api/meeting/getToken",
-                    uid: this.meetingUid
-                },
-                success: data => {
-                    if (!data.success) {
-                        alert(data.message);
-                        return;
-                    }
-                    // this.$refs.initialModal.hide();
-                    // if (!isAssociate) {
-                    //     const user = Object.assign({}, this.user);
-                    //     user.id = data.participantId;
-                    //     user.name = data.participantName;
-                    //     user.pin = data.participantPin;
-                    //     this.$store.commit("setUser", user);
-                    // }
-                    this.initializeOpenTok(data.data.apiKey, data.data.sessionId, data.data.token);
-                },
-                error: jXhr => {
-                    if (jXhr.responseJSON && jXhr.responseJSON.errorCode) {
-                        switch (jXhr.responseJSON.errorCode) {
-                            case "LM-1":
-                                alert("Meeting not started yet.");
-                                break;
-                            case "LM-2":
-                                alert("You was kicked from this meeting.");
-                                window.location = "/";
-                                break;
-                            case "LM-3":
-                                alert("Wrong password");
-                                this.$refs.initialModal.disableWaiting();
-                                break;
-                        }
-                    } else {
-                        // this.$refs.initialModal.disableWaiting();
-                        alert(jXhr.responseJSON.message);
-                    }
-                }
-            });
-        },
-        createVideoContainer(preview = false) {
-            let videoCont = {};
-            videoCont.id = `${this.uniqueId}_video_${this.counter++}`;
-
-            this.videos.push(videoCont);
-            this.adjustVideoContainers(preview);
-
-            return videoCont;
-        },
-        adjustVideoContainers(preview = false) {
-            let videoGrid;
-            if (preview) {
-                videoGrid = this.videoGridPreview = [];
-            } else {
-                videoGrid = this.videoGrid = [];
-            }
-
-            let windowHeight = window.innerHeight / 2;
-            this.rowHeight = (windowHeight - this.gridPadding * (this.maxRows + 1)) / this.maxRows;
-
-            let cols = Math.ceil(Math.sqrt(this.videos.length));
-            let rows = Math.ceil(this.videos.length / cols);
-
-            let elementsLastRow = this.videos.length % cols;
-            let lastNormalIndex = this.videos.length - elementsLastRow;
-
-            if (elementsLastRow) {
-                this.maxCols = cols * elementsLastRow;
-            } else {
-                this.maxCols = cols;
-            }
-
-            let colsPerElement = this.maxCols / cols;
-            let rowsPerElement = this.maxRows / rows;
-
-            let colsLastRow = Math.ceil(this.maxCols / elementsLastRow);
-
-            let cntX = 0;
-            let cntY = 0;
-
-            for (let [index, video] of this.videos.entries()) {
-                video.i = index;
-                video.x = cntX;
-                video.y = cntY;
-                video.h = rowsPerElement;
-                video.w = colsPerElement;
-                cntX += colsPerElement;
-
-                if (cntX >= this.maxCols) {
-                    cntX = 0;
-                    cntY += rowsPerElement;
-                }
-
-                let videoTemp = Object.assign({}, video);
-                videoTemp.video = video;
-                videoGrid.push(videoTemp);
-            }
-
-            /* OLD IMPLEMENTATION */
-
-            /* for (let [index, video] of this.videos.entries()) {
-                video.i = index
-                if (index < lastNormalIndex) {
-                    video.x = cntX
-                    video.y = cntY
-                    video.h = rowsPerElement
-                    video.w = colsPerElement
-                    cntX += colsPerElement
-
-                    if (cntX >= this.maxCols) {
-                        cntX = 0
-                        cntY += rowsPerElement
-                    }
-                } else {
-                    video.x = cntX
-                    video.y = cntY
-                    video.h = rowsPerElement
-                    video.w = colsLastRow
-                    cntX += colsLastRow
-                }
-
-                let videoTemp = Object.assign({}, video)
-                this.videoGrid.push(videoTemp)
-            } */
-
-            /* let gridColumn, gridRows = ''
-
-            if(rows && cols){
-                gridColumn = `grid-template-columns: repeat(${cols}, minmax(320px, 1fr))`
-                gridRows = `grid-template-rows: repeat(${rows}, minmax(240px, 1fr))`
-            } */
-        },
-        initializeOpenTok(apiKey, sessionId, token) {
-            this.openTokSession = OT.initSession(apiKey, sessionId);
-
-            this.openTokSession.on({
-                sessionDisconnected: event => {
-                    if (event.reason === "forceDisconnected") {
-                        alert("You were kicked out of meeting.");
-                        //window.location.reload();
-                        //TODO: Kicked
-                        // if (this.user.type === "associate") {
-                        //     this.disconnect();
-                        //     this.$store.dispatch("leaveMeeting");
-                        // } else {
-                        //     window.location = "/";
-                        // }
-                    }
-                }
-            });
-
-            // Create a publisher
-            // this.publisher = OT.initPublisher(
-            //     this.$refs.otContainer,
-            //     {
-            //         insertMode: "append",
-            //         width: "100%",
-            //         height: "100%",
-            //         resolution: "1280x720",
-            //         frameRate: 30,
-            //         name: this.user.name,
-            //         style: {
-            //             nameDisplayMode: "on",
-            //             archiveStatusDisplayMode: "off"
-            //         }
-            //     },
-            //     error => {
-            //         if (error) {
-            //             alert(error.message);
-            //         } else {
-            //             this.publisherReady = true;
-            //             const cont = this.createVideoContainer();
-            //             this.$nextTick(() => {
-            //                 cont.el = $(`#${cont.id}`)[0];
-            //                 cont.el.appendChild(this.publisher.element);
-            //                 cont.obj = this.publisher;
-            //                 this.$set(cont, "self", true);
-            //                 //cont.self = true
-            //             });
-            //         }
-            //     }
-            // );
-
-            // this.publisher.on({
-            //     accessDialogOpened: e => {
-            //         this.accessDialogShown = true;
-            //     },
-            //     accessDialogClosed: e => {
-            //         this.accessDialogShown = false;
-            //     }
-            // });
-
-            this.openTokSession.on("streamCreated", event => {
-                //console.log("stream Created event")
-                let container;
-                if (event.stream.videoType === "screen") {
-                    //TODO: This is screenshare
-                }
-                const subscriber = this.openTokSession.subscribe(
-                    event.stream,
-                    this.$refs.otContainer,
-                    {
-                        insertMode: "append",
-                        width: "100%",
-                        height: "100%",
-                        style: { nameDisplayMode: "on" }
-                    },
-                    error => {
-                        if (error) {
-                            alert(error.message);
-                        } else {
-                            const cont = this.createVideoContainer();
-                            this.$nextTick(() => {
-                                cont.el = $(`#${cont.id}`)[0];
-                                cont.el.appendChild(subscriber.element);
-                                cont.obj = subscriber;
-                                container = cont;
-                            });
-                        }
-                    }
-                );
-                subscriber.on({
-                    destroyed: e => {
-                        container.el.remove();
-                        const index = this.videos.findIndex(v => v.id == container.id);
-                        if (index >= 0) this.videos.splice(index, 1);
-                        this.adjustVideoContainers();
-                    }
-                });
-                this.subscribers.push(subscriber);
-            });
-
-            /* console.log(sessionId);
-            console.log(token);
-            console.log(apiKey); */
-            this.openTokSession.connect(token, error => {
-                // If the connection is successful, publish to the session
-                if (error) {
-                    alert(error.message);
-                } else {
-                    this.sessionConnected = true;
-                }
-            });
-            this.loadingInProgress = false;
-        },
-        publishToSession() {
-            this.openTokSession.publish(this.publisher, error => {
-                if (error) {
-                    alert(error.message);
-                }
-            });
-        },
-        ready() {
-            this.$nextTick(function() {
-                this.readyForUse = true;
-                if (this.user.type === "associate") {
-                    if (!this.meeting.id) return;
-                    this.getToken({}, true);
-                    return;
-                }
-
-                if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date()) {
-                    alert("Meeting not started.");
-                    return;
-                }
-                let participantId = this.user.id;
-                if (!participantId) {
-                    this.$refs.initialModal.show(this.meeting.passwordRequired);
-                    return;
-                }
-                this.getToken({
-                    participantId
-                });
-            });
-        }
-    },
-    created() {
-        if (this.meetingProp) {
-            this.user.firstName = this.meetingProp.strangerFirstName;
-            this.user.lastName = this.meetingProp.strangerLastName;
-            this.user.dateOfBirth = this.meetingProp.strangerDob;
-
-            if (this.stepper == 1) {
-                this.stepper = 2;
-            }
-
-            this.$socket.emit("userData", {
-                user: {
-                    uid: this.clientUid,
-                    name: `${this.firstName} ${this.lastName}`,
-                    type: "STRANGER"
-                },
-                meeting: {
-                    uid: this.meetingUid,
-                    lobby_uid: this.lobbyProp.uid
-                },
-                lobbies_uid_list: [`${this.lobbyProp.uid}`]
-            });
         }
     },
     mounted() {
-        if (this.meetingProp) {
-            this.meetingUid = this.meetingProp.uid;
-            this.$nextTick(this.initializePublisher);
-            let self = this;
-        }
-
-        this.sockets.subscribe("meeting-closed", data => {
-            this.$eventBus.$emit("leaveMeeting");
-        });
-
-        let self = this;
-
-        this.$eventBus.$on("meetingRejoin", () => {
-            this.loadingInProgress = true;
-            this.disconnect();
-            this.getToken({}, true);
-        });
-
-        let width = $(window).width();
-        let height = $(window).height();
-
-        window.addEventListener("resize", function() {
-            let new_width = $(window).width();
-            let new_height = $(window).height();
-
-            if (width !== new_width || height !== new_height) {
-                self.adjustVideoContainers();
-            }
-        });
-
-        this.$eventBus.$on("leaveMeeting", () => {
-            $.ajax({
-                url: "/post-to-api-ajax",
-                method: "POST",
-                headers: {
-                    "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
-                },
-                error: jXhr => {
-                    console.error(getSingleError(jXhr));
-                }
-            });
-            this.$store.dispatch("leaveMeeting");
-            this.$socket.emit("meetingLeft");
-            this.disconnect();
-            alert("Meeting was Closed.");
-        });
         this.prosList.push(...this.lobbyProp.pros);
     }
 };

+ 696 - 0
resources/js/components/pages/ClientMeeting.vue

@@ -0,0 +1,696 @@
+<template>
+    <div class="login-box">
+        <div class="login-logo auth-branding text-center border-0">
+            <span class="brand-text font-weight-light text-white">
+                Welcome to
+                <!-- <b>Dr. Smith & Dr. Brown's Office</b>! -->
+                <b>{{ lobbyProp.name }}</b>
+            </span>
+        </div>
+        <v-stepper v-model="stepper">
+            <v-stepper-header>
+                <v-stepper-step :complete="stepper > 1" step="1">Check In</v-stepper-step>
+
+                <v-divider></v-divider>
+
+                <v-stepper-step :complete="stepper > 2" step="2">Test your webcam</v-stepper-step>
+
+                <v-divider></v-divider>
+
+                <v-stepper-step step="3">Meet your Doctor</v-stepper-step>
+            </v-stepper-header>
+
+            <v-stepper-items>
+                <v-stepper-content step="2">
+                    <p>
+                        Please make sure your webcam is working. Accept the access request to your hardware on the top left to continue.
+                        <br />Then, someone should be with you shortly.
+                    </p>
+
+                    <v-card class="mb-12" color="grey lighten-1" height="50vh">
+                        <grid-layout
+                            :layout="videoGridPreview"
+                            :key="`preview_${uniqueId}`"
+                            :col-num="maxCols"
+                            :max-rows="maxRows"
+                            :row-height="rowHeight"
+                            :is-draggable="false"
+                            :is-resizable="false"
+                            :verticalCompact="true"
+                            :margin="[gridPadding, gridPadding]"
+                            :use-css-transforms="true"
+                        >
+                            <grid-item v-for="video in videoGridPreview" :key="video.id" :id="video.id" :x="video.x" :y="video.y" :w="video.w" :h="video.h" :i="video.i"></grid-item>
+                        </grid-layout>
+                    </v-card>
+
+                    <v-btn color="primary" @click="gotoStep3" :disabled="!cameraWorkingConfirmed">Continue</v-btn>
+
+                    <!-- <v-btn text @click="stepper = 1">Cancel</v-btn> -->
+                </v-stepper-content>
+
+                <v-stepper-content step="3">
+                    <p>Great! Please wait a little, doctor should join shortly.</p>
+
+                    <v-card class="mb-12" color="grey lighten-1" height="50vh">
+                        <grid-layout
+                            :layout="videoGrid"
+                            :key="uniqueId"
+                            :col-num="maxCols"
+                            :max-rows="maxRows"
+                            :row-height="rowHeight"
+                            :is-draggable="false"
+                            :is-resizable="false"
+                            :verticalCompact="true"
+                            :margin="[gridPadding, gridPadding]"
+                            :use-css-transforms="true"
+                        >
+                            <grid-item v-for="video in videoGrid" :key="video.id" :id="video.id" :x="video.x" :y="video.y" :w="video.w" :h="video.h" :i="video.i"></grid-item>
+                        </grid-layout>
+                    </v-card>
+                </v-stepper-content>
+            </v-stepper-items>
+        </v-stepper>
+        <div style="display: none" ref="otContainer"></div>
+    </div>
+</template>
+
+<script>
+import { mapState } from "vuex";
+
+import VueGridLayout from "vue-grid-layout";
+
+import VueSocketIO from "vue-socket.io";
+import SocketIO from "socket.io-client";
+
+Vue.use(
+    new VueSocketIO({
+        debug: true,
+        connection: SocketIO(process.env.MIX_SOCKET_SERVICE_URL)
+    })
+);
+
+export default {
+    components: {
+        GridLayout: VueGridLayout.GridLayout,
+        GridItem: VueGridLayout.GridItem
+    },
+    props: {
+        lobbyProp: {
+            type: Object,
+            default: {
+                uid: null,
+                name: "Base",
+                pros: []
+            }
+        },
+        meetingProp: {
+            type: Object
+        },
+        clientUid: {
+            type: String,
+            required: true
+        }
+    },
+    computed: {
+        // prosList(){
+        //     return [{
+        //         name: 'Test',
+        //         type: 'Cardiologist',
+        //         uid: 'someuid'
+        //     }]
+        // }
+    },
+    data() {
+        return {
+            user: {
+                firstName: "",
+                lastName: "",
+                dateOfBirth: null,
+                targetLobbyProUid: ""
+            },
+            meetingUid: "",
+            meetingName: sessionStorage.getItem("meeting_name") || "",
+            stepper: 2,
+            cameraWorkingConfirmed: false,
+            loading: false,
+            /* Copied */
+            readyForUse: false,
+            uniqueId: Math.floor(Math.random() * Math.floor(10000)),
+            counter: 1,
+            openTokSession: null,
+            publisher: null,
+            screenPublisher: null,
+            subscribers: [],
+            publisherReady: false,
+            sessionConnected: false,
+            accessDialogShown: false,
+            videos: [],
+            videoGrid: [],
+            videoGridPreview: [],
+            maxCols: 12,
+            maxRows: 4,
+            rowHeight: 240,
+            gridPadding: 8,
+            loadingInProgress: false,
+            prosList: []
+        };
+    },
+    sockets: {
+        reconnect: function() {
+            this.$socket.emit("userData", {
+                user: {
+                    uid: this.clientUid,
+                    name: `${this.firstName} ${this.lastName}`,
+                    type: "STRANGER"
+                },
+                meeting: {
+                    uid: this.meetingUid,
+                    lobby_uid: this.lobbyProp.uid
+                },
+                lobbies_uid_list: [`${this.lobbyProp.uid}`]
+            });
+
+            if (this.meetingUid) {
+                this.$socket.emit("meetingJoined", {
+                    lobby_uid: this.lobbyProp.uid,
+                    meeting_name: this.meetingName,
+                    meeting_uid: this.meetingUid,
+                    user: {
+                        name: `${this.firstName} ${this.lastName}`,
+                        type: "STRANGER",
+                        uid: this.clientUid
+                    }
+                });
+            }
+        }
+    },
+    watch: {
+        publisherReady(val) {
+            if (val && this.sessionConnected) this.publishToSession();
+        },
+        sessionConnected(val) {
+            if (val && this.publisherReady) this.publishToSession();
+        },
+        "user.is_active_and_visible"(val) {
+            if (!this.publisher || !this.publisher.publishVideo) return;
+            this.publisher.publishVideo(val);
+            this.publisher.publishAudio(val);
+        },
+        "meeting.id"(val) {
+            if (this.loadingInProgress) return;
+            this.loadingInProgress = true;
+            this.disconnect();
+
+            if (val) {
+                this.getToken({}, true);
+            } else {
+                this.loadingInProgress = false;
+            }
+        },
+        stepper: {
+            handler(newVal) {
+                sessionStorage.setItem(`${this.meetingProp.uid}.step`, newVal);
+            }
+        }
+    },
+    methods: {
+        initializePublisher() {
+            this.publisher = OT.initPublisher(
+                this.$refs.otContainer,
+                {
+                    insertMode: "append",
+                    width: "100%",
+                    height: "100%",
+                    resolution: "1280x720",
+                    frameRate: 30,
+                    name: `${this.user.firstName} ${this.user.lastName}`,
+                    style: {
+                        nameDisplayMode: "on",
+                        archiveStatusDisplayMode: "off"
+                    }
+                },
+                error => {
+                    if (error) {
+                        alert(error.message);
+                    } else {
+                        this.publisherReady = true;
+                        const cont = this.createVideoContainer(true);
+                        this.$nextTick(() => {
+                            cont.el = $(`#${cont.id}`)[0];
+                            cont.el.appendChild(this.publisher.element);
+                            cont.obj = this.publisher;
+                            this.$set(cont, "self", true);
+                            this.cameraWorkingConfirmed = true;
+
+                            if (this.stepper == 3) {
+                                this.gotoStep3();
+                            }
+                        });
+                    }
+                }
+            );
+            this.publisher.on({
+                accessDialogOpened: e => {
+                    this.accessDialogShown = true;
+                },
+                accessDialogClosed: e => {
+                    this.accessDialogShown = false;
+                }
+            });
+        },
+        gotoStep3() {
+            if (this.stepper != 3) {
+                this.stepper = 3;
+            }
+
+            this.videoGridPreview = [];
+            this.adjustVideoContainers();
+            this.$nextTick(() => {
+                const cont = this.videos[0];
+                cont.el = $(`#${cont.id}`)[0];
+                cont.el.appendChild(cont.obj.element);
+                this.getToken();
+
+                this.$socket.emit("meetingJoined", {
+                    lobby_uid: this.lobbyProp.uid,
+                    meeting_name: this.meetingName,
+                    meeting_uid: this.meetingUid,
+                    user: {
+                        name: `${this.firstName} ${this.lastName}`,
+                        type: "STRANGER",
+                        uid: this.clientUid
+                    }
+                });
+                $.ajax({
+                    url: "/post-to-api-ajax",
+                    method: "POST",
+                    headers: {
+                        "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
+                    },
+                    data: {
+                        _api: "/api/meeting/startLobbyCall",
+                        uid: this.meetingUid,
+                        lobbyUid: this.lobbyProp.uid
+                    },
+                    success: data => {
+                        if (!data.success) console.log(data.message);
+                    }
+                });
+            });
+        },
+        /* Copied */
+        disconnect() {
+            if (!this.openTokSession) return;
+            this.openTokSession.disconnect();
+            this.openTokSession.off();
+            this.videos = [];
+            this.publisher.destroy();
+            this.publisher = null;
+            this.subscribers = [];
+            this.publisherReady = false;
+            this.$store.commit("setSessionConnectivityState", false);
+            this.openTokSession = null;
+            if (this.screenPublisher) {
+                this.screenPublisher.destroy();
+                this.screenPublisher = null;
+            }
+        },
+        getToken() {
+            // if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date() && (this.user.type === "guest" || !confirm("Meeting not started. Start it now?")))
+            //     return;
+            $.ajax({
+                url: "/post-to-api-ajax",
+                method: "POST",
+                headers: {
+                    "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
+                },
+                data: {
+                    _api: "/api/meeting/getToken",
+                    uid: this.meetingUid
+                },
+                success: data => {
+                    if (!data.success) {
+                        alert(data.message);
+                        return;
+                    }
+                    // this.$refs.initialModal.hide();
+                    // if (!isAssociate) {
+                    //     const user = Object.assign({}, this.user);
+                    //     user.id = data.participantId;
+                    //     user.name = data.participantName;
+                    //     user.pin = data.participantPin;
+                    //     this.$store.commit("setUser", user);
+                    // }
+                    this.initializeOpenTok(data.data.apiKey, data.data.sessionId, data.data.token);
+                },
+                error: jXhr => {
+                    if (jXhr.responseJSON && jXhr.responseJSON.errorCode) {
+                        switch (jXhr.responseJSON.errorCode) {
+                            case "LM-1":
+                                alert("Meeting not started yet.");
+                                break;
+                            case "LM-2":
+                                alert("You was kicked from this meeting.");
+                                window.location = "/";
+                                break;
+                            case "LM-3":
+                                alert("Wrong password");
+                                this.$refs.initialModal.disableWaiting();
+                                break;
+                        }
+                    } else {
+                        // this.$refs.initialModal.disableWaiting();
+                        alert(jXhr.responseJSON.message);
+                    }
+                }
+            });
+        },
+        createVideoContainer(preview = false) {
+            let videoCont = {};
+            videoCont.id = `${this.uniqueId}_video_${this.counter++}`;
+
+            this.videos.push(videoCont);
+            this.adjustVideoContainers(preview);
+
+            return videoCont;
+        },
+        adjustVideoContainers(preview = false) {
+            let videoGrid;
+            if (preview) {
+                videoGrid = this.videoGridPreview = [];
+            } else {
+                videoGrid = this.videoGrid = [];
+            }
+
+            let windowHeight = window.innerHeight / 2;
+            this.rowHeight = (windowHeight - this.gridPadding * (this.maxRows + 1)) / this.maxRows;
+
+            let cols = Math.ceil(Math.sqrt(this.videos.length));
+            let rows = Math.ceil(this.videos.length / cols);
+
+            let elementsLastRow = this.videos.length % cols;
+            let lastNormalIndex = this.videos.length - elementsLastRow;
+
+            if (elementsLastRow) {
+                this.maxCols = cols * elementsLastRow;
+            } else {
+                this.maxCols = cols;
+            }
+
+            let colsPerElement = this.maxCols / cols;
+            let rowsPerElement = this.maxRows / rows;
+
+            let colsLastRow = Math.ceil(this.maxCols / elementsLastRow);
+
+            let cntX = 0;
+            let cntY = 0;
+
+            for (let [index, video] of this.videos.entries()) {
+                video.i = index;
+                video.x = cntX;
+                video.y = cntY;
+                video.h = rowsPerElement;
+                video.w = colsPerElement;
+                cntX += colsPerElement;
+
+                if (cntX >= this.maxCols) {
+                    cntX = 0;
+                    cntY += rowsPerElement;
+                }
+
+                let videoTemp = Object.assign({}, video);
+                videoTemp.video = video;
+                videoGrid.push(videoTemp);
+            }
+
+            /* OLD IMPLEMENTATION */
+
+            /* for (let [index, video] of this.videos.entries()) {
+                video.i = index
+                if (index < lastNormalIndex) {
+                    video.x = cntX
+                    video.y = cntY
+                    video.h = rowsPerElement
+                    video.w = colsPerElement
+                    cntX += colsPerElement
+
+                    if (cntX >= this.maxCols) {
+                        cntX = 0
+                        cntY += rowsPerElement
+                    }
+                } else {
+                    video.x = cntX
+                    video.y = cntY
+                    video.h = rowsPerElement
+                    video.w = colsLastRow
+                    cntX += colsLastRow
+                }
+
+                let videoTemp = Object.assign({}, video)
+                this.videoGrid.push(videoTemp)
+            } */
+
+            /* let gridColumn, gridRows = ''
+
+            if(rows && cols){
+                gridColumn = `grid-template-columns: repeat(${cols}, minmax(320px, 1fr))`
+                gridRows = `grid-template-rows: repeat(${rows}, minmax(240px, 1fr))`
+            } */
+        },
+        initializeOpenTok(apiKey, sessionId, token) {
+            this.openTokSession = OT.initSession(apiKey, sessionId);
+
+            this.openTokSession.on({
+                sessionDisconnected: event => {
+                    if (event.reason === "forceDisconnected") {
+                        alert("You were kicked out of meeting.");
+                        //window.location.reload();
+                        //TODO: Kicked
+                        // if (this.user.type === "associate") {
+                        //     this.disconnect();
+                        //     this.$store.dispatch("leaveMeeting");
+                        // } else {
+                        //     window.location = "/";
+                        // }
+                    }
+                }
+            });
+
+            // Create a publisher
+            // this.publisher = OT.initPublisher(
+            //     this.$refs.otContainer,
+            //     {
+            //         insertMode: "append",
+            //         width: "100%",
+            //         height: "100%",
+            //         resolution: "1280x720",
+            //         frameRate: 30,
+            //         name: this.user.name,
+            //         style: {
+            //             nameDisplayMode: "on",
+            //             archiveStatusDisplayMode: "off"
+            //         }
+            //     },
+            //     error => {
+            //         if (error) {
+            //             alert(error.message);
+            //         } else {
+            //             this.publisherReady = true;
+            //             const cont = this.createVideoContainer();
+            //             this.$nextTick(() => {
+            //                 cont.el = $(`#${cont.id}`)[0];
+            //                 cont.el.appendChild(this.publisher.element);
+            //                 cont.obj = this.publisher;
+            //                 this.$set(cont, "self", true);
+            //                 //cont.self = true
+            //             });
+            //         }
+            //     }
+            // );
+
+            // this.publisher.on({
+            //     accessDialogOpened: e => {
+            //         this.accessDialogShown = true;
+            //     },
+            //     accessDialogClosed: e => {
+            //         this.accessDialogShown = false;
+            //     }
+            // });
+
+            this.openTokSession.on("streamCreated", event => {
+                //console.log("stream Created event")
+                let container;
+                if (event.stream.videoType === "screen") {
+                    //TODO: This is screenshare
+                }
+                const subscriber = this.openTokSession.subscribe(
+                    event.stream,
+                    this.$refs.otContainer,
+                    {
+                        insertMode: "append",
+                        width: "100%",
+                        height: "100%",
+                        style: { nameDisplayMode: "on" }
+                    },
+                    error => {
+                        if (error) {
+                            alert(error.message);
+                        } else {
+                            const cont = this.createVideoContainer();
+                            this.$nextTick(() => {
+                                cont.el = $(`#${cont.id}`)[0];
+                                cont.el.appendChild(subscriber.element);
+                                cont.obj = subscriber;
+                                container = cont;
+                            });
+                        }
+                    }
+                );
+                subscriber.on({
+                    destroyed: e => {
+                        container.el.remove();
+                        const index = this.videos.findIndex(v => v.id == container.id);
+                        if (index >= 0) this.videos.splice(index, 1);
+                        this.adjustVideoContainers();
+                    }
+                });
+                this.subscribers.push(subscriber);
+            });
+
+            /* console.log(sessionId);
+            console.log(token);
+            console.log(apiKey); */
+            this.openTokSession.connect(token, error => {
+                // If the connection is successful, publish to the session
+                if (error) {
+                    alert(error.message);
+                } else {
+                    this.sessionConnected = true;
+                }
+            });
+            this.loadingInProgress = false;
+        },
+        publishToSession() {
+            this.openTokSession.publish(this.publisher, error => {
+                if (error) {
+                    alert(error.message);
+                }
+            });
+        },
+        ready() {
+            this.$nextTick(function() {
+                this.readyForUse = true;
+                if (this.user.type === "associate") {
+                    if (!this.meeting.id) return;
+                    this.getToken({}, true);
+                    return;
+                }
+
+                if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date()) {
+                    alert("Meeting not started.");
+                    return;
+                }
+                let participantId = this.user.id;
+                if (!participantId) {
+                    this.$refs.initialModal.show(this.meeting.passwordRequired);
+                    return;
+                }
+                this.getToken({
+                    participantId
+                });
+            });
+        }
+    },
+    created() {
+        if (this.meetingProp) {
+            this.user.firstName = this.meetingProp.strangerFirstName;
+            this.user.lastName = this.meetingProp.strangerLastName;
+            this.user.dateOfBirth = this.meetingProp.strangerDob;
+
+            if (this.stepper == 1) {
+                this.stepper = 2;
+            }
+
+            this.$socket.emit("userData", {
+                user: {
+                    uid: this.clientUid,
+                    name: `${this.firstName} ${this.lastName}`,
+                    type: "STRANGER"
+                },
+                meeting: {
+                    uid: this.meetingUid,
+                    lobby_uid: this.lobbyProp.uid
+                },
+                lobbies_uid_list: [`${this.lobbyProp.uid}`]
+            });
+            this.stepper = sessionStorage.getItem(`${this.meetingProp.uid}.step`) || 2;
+        } else {
+            window.location = "/";
+        }
+    },
+    mounted() {
+        if (this.meetingProp) {
+            this.meetingUid = this.meetingProp.uid;
+            this.$nextTick(this.initializePublisher);
+            let self = this;
+        }
+
+        this.sockets.subscribe("meeting-closed", data => {
+            this.$eventBus.$emit("leaveMeeting");
+        });
+
+        let self = this;
+
+        this.$eventBus.$on("meetingRejoin", () => {
+            this.loadingInProgress = true;
+            this.disconnect();
+            this.getToken({}, true);
+        });
+
+        let width = $(window).width();
+        let height = $(window).height();
+
+        window.addEventListener("resize", function() {
+            let new_width = $(window).width();
+            let new_height = $(window).height();
+
+            if (width !== new_width || height !== new_height) {
+                self.adjustVideoContainers();
+            }
+        });
+
+        this.$eventBus.$on("leaveMeeting", () => {
+            $.ajax({
+                url: "/post-to-api-ajax",
+                method: "POST",
+                headers: {
+                    "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
+                },
+                error: jXhr => {
+                    console.error(getSingleError(jXhr));
+                }
+            });
+            this.$store.dispatch("leaveMeeting");
+            this.$socket.emit("meetingLeft");
+            this.disconnect();
+            alert("Meeting was Closed.");
+        });
+        this.prosList.push(...this.lobbyProp.pros);
+    }
+};
+</script>
+
+<style lang="scss" scoped>
+.login-box {
+    width: 100%;
+}
+
+.checkin-form {
+    height: 200px;
+
+    form {
+        width: 75%;
+    }
+}
+</style>

+ 3 - 0
resources/js/components/vuex/index.js

@@ -144,6 +144,9 @@ export default () => new Vuex.Store({
                     }
                 }
             }
+            if (state.meeting.uid === data.uid) {
+                state.meeting.name = data.name
+            }
         },
         setCurrentMeeting(state, data) {
             state.meeting = data

+ 0 - 1
resources/views/client/index.blade.php

@@ -3,7 +3,6 @@
 <v-app id="meetingsApp" class="client">
     <client-entrance 
         :lobby-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($lobbyModel))) !!}"
-        :meeting-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($meeting))) !!}"
         client-uid="{{ $sessionKey }}"
     ></client-entrance>
 </v-app>

+ 10 - 0
resources/views/client/meeting.blade.php

@@ -0,0 +1,10 @@
+@extends('layouts.client')
+@section('content')
+<v-app id="meetingsApp" class="client">
+    <client-meeting 
+        :lobby-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($lobbyModel))) !!}"
+        :meeting-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($meeting))) !!}"
+        client-uid="{{ $sessionKey }}"
+    ></client-meeting>
+</v-app>
+@endsection

+ 4 - 3
routes/web.php

@@ -62,9 +62,10 @@ Route::post('/post-to-api-ajax', 'AppSessionController@postToAPIAjax')->name('po
 
 
 Route::middleware('ensureOnlyStrangerSession')->group(function(){
-	Route::get('/client/{url_slug}', 'ClientController@entranceLobby')->name('client-lobby');
+    Route::get('/client/{url_slug}', 'ClientController@entranceLobby')->name('client-lobby');
+    Route::get('/client/meeting-participant/{meetingParticipant:uid}', 'ClientController@meeting');
 });
-Route::get('/client/meeting/{meeting_uid}', 'ClientController@entranceLobby')->name('join-meeting');
+// Route::get('/client/meeting/{meeting_uid}', 'ClientController@entranceLobby')->name('join-meeting');
 
 Route::bind('url_slug', function($value, $route)
 {
@@ -78,4 +79,4 @@ Route::get('/section_update_form/{section_uid}', 'NoteController@sectionUpdateFo
 Route::post("/process_form_submit", 'NoteController@processFormSubmit')->name('process_form_submit');
 if (env('APP_ENV') === 'production') {
     URL::forceScheme('https');
-}
+}