Josh Kamau преди 5 години
родител
ревизия
11dca1fbdb

+ 0 - 24
app/Http/Controllers/AppSessionController.php

@@ -48,30 +48,6 @@ class AppSessionController extends Controller
         return redirect(route('pro-request-sms-login-token'))->withCookie($cookie);
     }
 
-    public function clientLogIn(){
-        return view('public.client-log-in');
-    }
-
-    public function processClientLogIn(Request $request){
-        $loginUrl = env('BACKEND_URL', 'http://localhost:8080') . '/api/session/proLogIn';
-
-        $response = Http::asForm()->post($loginUrl, [
-            'cellNumber' => $request->get('cellNumber'),
-            'token' => $request->get('token'),
-        ])->json();
-
-        if(!$response['success']){
-            return back()->with("message", $response['message']);
-        }
-
-        $sessionKey = $response['data']["sessionKey"];
-        $request->session()->put("authID", $response['data']["proId"]);
-
-        $cookie = cookie()->forever('sessionKey', $sessionKey, '/');
-
-        return redirect("/mc/dashboard")->withCookie($cookie);
-    }
-
     public function postToAPI(Request $request) {
 
         session()->remove('message');

+ 4 - 34
app/Http/Controllers/ClientController.php

@@ -16,41 +16,9 @@ class ClientController extends Controller
 {
 
     // GET /care_months
-    public function entranceNormal(Request $request) {
-        /* $sessionKey = Cookie::get('sessionKey');
-
-        if(!$sessionKey){
-            $loginUrl = env('BACKEND_URL', 'http://localhost:8080') . '/api/session/createStrangerSession';
-
-            $httpResponse = Http::asForm()->post($loginUrl)->json();
-
-            if(!$httpResponse['success']){
-                return back()->with("message", $httpResponse['message']);
-            }
-
-            $sessionKey = $httpResponse['data'];
-
-            // $cookie = cookie()->forever('sessionKey', $sessionKey, '/');
-
-            cookie()->queue('sessionKey', $sessionKey, 1440, '/');
-
-            // $response = new \Illuminate\Http\Response(view('client/index'));
-            // $response->withCookie($cookie);
-            // return $response;
-        }
-
-        $session = AppSession::where("session_key",$sessionKey)->first();
-
-        $meeting = null;
-        if ($session->meetingParticipant && $session->meetingParticipant->meeting->lobby_id === $lobby->id) {
-            $meeting = new MeetingModel($session->meetingParticipant->meeting);
-        }
-        return view('client/index',compact('lobbyModel','meeting','sessionKey')); */
-        return view('client/index');
-	}
 
 	public function entranceLobby(Request $request, Lobby $lobby) {
-        if (!$lobby->id) {
+        if (!$lobby->id || !$lobby->is_stranger_accessible) {
             \abort(404);
             return;
         }
@@ -84,7 +52,9 @@ class ClientController extends Controller
         // }
         $session = AppSession::where("session_key",$sessionKey)->first();
         $meeting = null;
-        if ($session->meetingParticipant && $session->meetingParticipant->meeting->lobby_id === $lobby->id) {
+        if ($session->meetingParticipant 
+                && $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'));

+ 2 - 1
app/Http/Controllers/MeetingCenterController.php

@@ -23,8 +23,9 @@ class MeetingCenterController extends Controller
 
         $appSession = AppSession::where("session_key",$sessionKey)->first();
         $user = new ProModel($appSession->pro);
+        $user->sessionKey = $sessionKey;
         $meeting = null;
-        if ($appSession->is_currently_meeting_participant) {
+        if ($appSession->is_currently_meeting_participant && $appSession->meetingParticipant->meeting->is_active) {
             $meeting = new MeetingWithLobbyModel($appSession->meetingParticipant->meeting);
         }
 

+ 5 - 1
app/Http/Kernel.php

@@ -66,5 +66,9 @@ class Kernel extends HttpKernel
 
         'ensureValidSession' => \App\Http\Middleware\EnsureValidSession::class,
         'ensureNoValidSession' => \App\Http\Middleware\EnsureNoValidSession::class,
+
+        'ensureValidProSession' => \App\Http\Middleware\EnsureValidProSession::class,
+        'ensureNoValidProSession' => \App\Http\Middleware\EnsureNoValidProSession::class,
+        'ensureOnlyStrangerSession' => \App\Http\Middleware\EnsureOnlyStrangerSession::class,
     ];
-}
+}

+ 43 - 0
app/Http/Middleware/EnsureNoValidProSession.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use App\Models\AppSession;
+
+class EnsureNoValidProSession
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+        //if not valid session, redirect to /pro/request-sms-login-token
+        $sessionKey = $request->cookie("sessionKey");
+
+        if(!$sessionKey){
+            return $next($request);
+        }
+
+        $appSession = AppSession::where("session_key",$sessionKey)->first();
+
+        if(!$appSession){
+            return $next($request);
+        }
+
+        if(!$appSession->is_active){
+            return $next($request);
+        }
+
+        if ($appSession->session_type !== 'PRO') {
+            return $next($request);
+        }
+
+        return redirect("/mc/dashboard");
+
+    }
+}

+ 46 - 0
app/Http/Middleware/EnsureOnlyStrangerSession.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use App\Models\AppSession;
+
+class EnsureOnlyStrangerSession
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+        //if not valid session, redirect to /pro/request-sms-login-token
+        $sessionKey = $request->cookie("sessionKey");
+
+        if(!$sessionKey){
+            return $next($request);
+        }
+
+        $appSession = AppSession::where("session_key",$sessionKey)->first();
+
+        if(!$appSession){
+            return $next($request);
+        }
+
+        if(!$appSession->is_active){
+            return $next($request);
+        }
+
+        if ($appSession->session_type === 'STRANGER') {
+            return $next($request);
+        }
+
+        if ($appSession->session_type === 'PRO')
+            return redirect("/mc/dashboard");
+        else
+            return redirect("/");
+
+    }
+}

+ 44 - 0
app/Http/Middleware/EnsureValidProSession.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+
+use App\Models\AppSession;
+
+class EnsureValidProSession
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+
+        //if not valid session, redirect to /pro/request-sms-login-token
+        $sessionKey = $request->cookie("sessionKey");
+
+        $appSession = AppSession::where("session_key",$sessionKey)->first();
+
+        if(!$appSession){
+            return $this->redirectToLogIn();
+        }
+
+        if(!$appSession->is_active){
+            return $this->redirectToLogIn();
+        }
+
+        if ($appSession->session_type !== 'PRO') {
+            return $this->redirectToLogIn();
+        }
+
+        return $next($request);
+    }
+
+    private function redirectToLogIn(){
+        return redirect("/");
+    }
+}

+ 4 - 0
app/HttpModels/ClientLobbyModel.php

@@ -6,10 +6,14 @@ use App\Models\Lobby;
 class ClientLobbyModel {
     public $uid;
     public $name;
+    public $pros = [];
 
     public function __construct(Lobby $lobby)
     {
         $this->uid = $lobby->uid;
         $this->name = $lobby->name;
+        foreach ($lobby->pros as $pro) {
+            $this->pros[] = new LobbyProModel($pro);
+        }
     }
 }

+ 4 - 1
app/HttpModels/LobbyModel.php

@@ -2,11 +2,13 @@
 namespace App\HttpModels;
 
 use App\Models\Lobby;
+use Carbon\Carbon;
 
 class LobbyModel extends ClientLobbyModel {
     public $isStrangerAccessible;
     public $isClientAccessible;
     public $isActive;
+    public $lobbyProAccessLevel;
     public $meetings = [];
 
     public function __construct(Lobby $lobby)
@@ -15,7 +17,8 @@ class LobbyModel extends ClientLobbyModel {
         $this->isStrangerAccessible = $lobby->is_stranger_accessible;
         $this->isClientAccessible = $lobby->is_client_accessible;
         $this->isActive = $lobby->is_active;
-        foreach ($lobby->meetings()->where('meeting.is_active',true)->get() as $meeting) {
+        $this->lobbyProAccessLevel = $lobby->lobby_pro_access_level;
+        foreach ($lobby->meetings()->where('meeting.is_active',true)->where('created_at','>=',Carbon::today())->get() as $meeting) {
             $this->meetings[] = new MeetingModel($meeting);
         }
     }

+ 15 - 0
app/HttpModels/LobbyProModel.php

@@ -0,0 +1,15 @@
+<?php
+namespace App\HttpModels;
+
+use App\Models\Pro;
+
+class LobbyProModel {
+    public $uid;
+    public $name;
+
+    public function __construct(Pro $pro)
+    {
+        $this->uid = $pro->uid;
+        $this->name = $pro->name_display;
+    }
+}

+ 3 - 0
app/HttpModels/MeetingWithLobbyModel.php

@@ -6,11 +6,14 @@ use App\Models\Meeting;
 class MeetingWithLobbyModel extends MeetingModel {
 
     public $lobby;
+    public $targetPro;
 
     public function __construct(Meeting $meeting)
     {
         parent::__construct($meeting);
 
         $this->lobby = new ClientLobbyModel($meeting->lobby);
+        if ($meeting->target_lobby_pro_id)
+            $this->targetPro = new LobbyProModel($meeting->targetLobbyPro->pro);
     }
 }

+ 1 - 0
app/HttpModels/ProModel.php

@@ -10,6 +10,7 @@ class ProModel {
     public $avatarFile;
     public $is_active_and_visible;
     public $lobbies = [];
+    public $sessionKey;
 
     public function __construct(Pro $pro)
     {

+ 5 - 0
app/Models/Lobby.php

@@ -13,4 +13,9 @@ class Lobby extends Model
     {
         return $this->hasMany(Meeting::class);
     }
+
+    public function pros()
+    {
+        return $this->belongsToMany(Pro::class, 'lobby_pro');
+    }
 }

+ 17 - 0
app/Models/LobbyPro.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class LobbyPro extends Model
+{
+    
+    protected $table = "lobby_pro";
+
+
+    public function pro()
+    {
+        return $this->belongsTo(Pro::class);
+    }
+}

+ 5 - 0
app/Models/Meeting.php

@@ -19,4 +19,9 @@ class Meeting extends Model
     {
         return $this->belongsTo(Lobby::class);
     }
+
+    public function targetLobbyPro()
+    {
+        return $this->belongsTo(LobbyPro::class, 'target_lobby_pro_id');
+    }
 }

+ 69 - 21
resources/js/components/pages/ClientEntrance.vue

@@ -40,8 +40,8 @@
 
                                 <div class="form-group mt-5 mb-3">
                                     <select class="form-control custom-select" v-model="user.targetLobbyProUid" name="targetLobbyProUid">
-                                        <option value="">Do you wish to speak with particular Doctor?</option>
-                                        <option v-for="pro in prosList" :value="pro.uid" :key="pro.uid">{{pro.name}} - {{pro.type}}</option>
+                                        <option value>Do you wish to speak with particular Doctor?</option>
+                                        <option v-for="pro in prosList" :value="pro.uid" :key="pro.uid">{{pro.name}}</option>
                                     </select>
                                 </div>
                             </form>
@@ -76,7 +76,7 @@
 
                     <v-btn color="primary" @click="gotoStep3" :disabled="!cameraWorkingConfirmed">Continue</v-btn>
 
-                    <v-btn text @click="stepper = 1">Cancel</v-btn>
+                    <!-- <v-btn text @click="stepper = 1">Cancel</v-btn> -->
                 </v-stepper-content>
 
                 <v-stepper-content step="3">
@@ -128,7 +128,11 @@ export default {
     props: {
         lobbyProp: {
             type: Object,
-            required: true
+            default: {
+                uid: null,
+                name: "Base",
+                pros: []
+            }
         },
         meetingProp: {
             type: Object
@@ -139,13 +143,13 @@ export default {
         }
     },
     computed: {
-        prosList(){
-            return [{
-                name: 'Test',
-                type: 'Cardiologist',
-                uid: 'someuid'
-            }]
-        }
+        // prosList(){
+        //     return [{
+        //         name: 'Test',
+        //         type: 'Cardiologist',
+        //         uid: 'someuid'
+        //     }]
+        // }
     },
     data() {
         return {
@@ -178,10 +182,39 @@ export default {
             maxRows: 4,
             rowHeight: 240,
             gridPadding: 8,
-            loadingInProgress: false
+            loadingInProgress: false,
+            prosList: []
         };
     },
-    sockets: {},
+    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();
@@ -334,6 +367,21 @@ export default {
                         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 */
@@ -664,7 +712,6 @@ export default {
         }
     },
     mounted() {
-        console.log(this.lobbyProp)
         if (this.meetingProp) {
             this.meetingUid = this.meetingProp.uid;
             this.$nextTick(this.initializePublisher);
@@ -672,8 +719,8 @@ export default {
         }
 
         this.sockets.subscribe("meeting-closed", data => {
-            this.$eventBus.$emit("leaveMeeting")
-        })
+            this.$eventBus.$emit("leaveMeeting");
+        });
 
         let self = this;
 
@@ -703,14 +750,15 @@ export default {
                     "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
                 },
                 error: jXhr => {
-                    console.error(getSingleError(jXhr))
+                    console.error(getSingleError(jXhr));
                 }
             });
-            this.$store.dispatch("leaveMeeting")
-            this.$socket.emit('meetingLeft')
-            this.disconnect()
-            alert('Meeting was Closed.')
+            this.$store.dispatch("leaveMeeting");
+            this.$socket.emit("meetingLeft");
+            this.disconnect();
+            alert("Meeting was Closed.");
         });
+        this.prosList.push(...this.lobbyProp.pros);
     }
 };
 </script>

+ 84 - 94
resources/js/components/pages/MeetingsAppRoot.vue

@@ -12,7 +12,7 @@
                 <v-expansion-panel-header>
                     <span>Meeting Room</span>
                     <v-spacer></v-spacer>
-                    <v-btn v-if="meeting.uid" color="purple" small ripple outlined class="mr-3" @click.stop="leaveMeeting">Leave</v-btn>
+                    <v-btn :disabled="meetingLoading" v-if="meeting.uid" color="purple" small ripple outlined class="mr-3" @click.stop="leaveMeeting">Leave</v-btn>
                 </v-expansion-panel-header>
                 <v-expansion-panel-content>
                     <meeting-room></meeting-room>
@@ -33,21 +33,21 @@
                 </v-expansion-panel-content>
             </v-expansion-panel>
         </v-expansion-panels>
-        <call-bubble :call="incomingCallDetails"></call-bubble>
+        <call-bubble></call-bubble>
     </v-app>
 </template>
 
 <script>
-import { mapState } from "vuex";
-import VueSocketIO from "vue-socket.io";
-import SocketIO from "socket.io-client";
+import { mapState } from "vuex"
+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 {
     props: {
@@ -62,23 +62,21 @@ export default {
     data() {
         return {
             active_panel: [0, 1, 2],
-            incomingCallDetails: null,
-            lobbies: []
-        };
+            lobbies_: []
+        }
     },
     computed: {
-        ...mapState(["user", "meeting"])
+        ...mapState(["user", "meeting", "lobbies", "meetingLoading"])
     },
     watch: {
         meeting: {
             handler(newVal, oldVal) {
                 if (oldVal && oldVal.uid) {
-                    this.$socket.emit("meetingLeft", { lobby_uid: oldVal.lobby_uid, meeting_name: oldVal.name, meeting_uid: oldVal.uid, user: this.user });
+                    this.$socket.emit("meetingLeft", { lobby_uid: oldVal.lobby_uid, meeting_name: oldVal.name, meeting_uid: oldVal.uid, user: this.user })
                 }
 
-
                 if (newVal && newVal.uid) {
-                    this.$socket.emit("meetingJoined", { lobby_uid: newVal.lobby_uid, meeting_name: newVal.name, meeting_uid: newVal.uid, user: this.user });
+                    this.$socket.emit("meetingJoined", { lobby_uid: newVal.lobby_uid, meeting_name: newVal.name, meeting_uid: newVal.uid, user: this.user })
 
                     this.$eventBus.$emit("updateMeetingMessages")
                     /* axios
@@ -86,54 +84,90 @@ export default {
                         .then(response => {
                             this.messages = response.data.map(cur => {
                                 // cur.id = cur.message_id
-                                cur.timestamp_formatted = timeago.format(cur.timestamp);
+                                cur.timestamp_formatted = timeago.format(cur.timestamp)
 
                                 // cur.user = {
                                 //     name: cur.name,
                                 //     UID: cur.user_uid,
                                 //     avatarFile: cur.avatarSrc || null
                                 // }
-                                cur.sent = this.user.UID == cur.user.UID ? true : false;
+                                cur.sent = this.user.UID == cur.user.UID ? true : false
 
                                 // delete cur.message_id
                                 // delete cur.name
                                 // delete cur.user_uid
 
-                                return cur;
-                            });
+                                return cur
+                            })
                         })
                         .catch(e => {
-                            console.log(e);
-                        }); */
+                            console.log(e)
+                        }) */
                 }
             }
         }
     },
     sockets: {
-        incomingCall: function(data) {
-            let self = this;
+        incomingCall: function(data){
+            let self = this
 
-            if (!data.time_limit) {
-                data.time_limit = 10;
+            this.$store.commit('setCall', data)
+        },
+        disconnect: function(){
+            this.$store.commit("nullifyMeetingsOnline")
+        },
+        reconnect: function(){
+            this.$socket.emit("userData", {
+                user: this.user,
+                meeting: this.meeting,
+                lobbies_uid_list: this.lobbies.reduce((acc, cur) => { return [...acc, cur.uid] }, [])
+            })
+
+            if (this.meeting.uid) {
+                this.$socket.emit("meetingJoined", { lobby_uid: this.meeting.lobby_uid, meeting_uid: this.meeting.uid, user: this.user })
+            }
+        },
+        'call-data': function(data){
+            if(data.callData && data.state == null){
+                this.$store.commit("setCall", data.callData)
             }
 
-            self.incomingCallDetails = data;
+            this.$socket.emit("lobbyDataRequest")
+        },
+        'lobby-data': function(data){
+            for (let meeting of data.meetings) {
+                this.$store.commit("setLobbyActivity", meeting)
+            }
+        },
 
-            let timer = setInterval(() => {
-                if (self.incomingCallDetails.time_limit > 0) {
-                    self.incomingCallDetails.time_limit--;
+        /* Meeting Handlers */
 
-                    if (self.incomingCallDetails.time_limit == 0) {
-                        clearInterval(timer);
-                        console.log("TIME IS OUT!");
-                    }
-                }
-            }, 1000);
+        'meeting-activity': function(data){
+            this.$store.commit("setLobbyActivity", data)
         },
-        reconnect: function() {
-            if (this.meeting.uid) {
-                this.$socket.emit("meetingJoined", { lobby_uid: this.meeting.lobby_uid, meeting_uid: this.meeting.uid, user: this.user });
-            }
+        'meeting-created': function(data){
+            this.$store.commit("addNewMeetingInLobby", data)
+        },
+        'meeting-updated': function(data){
+            this.$store.commit("setUpdatedMeetingInLobby", data)
+        },
+        'meeting-closed': function(data){
+            this.$store.dispatch("leaveMeeting");
+        },
+
+        /* Lobby Handlers */
+
+        'lobby-updated': function(data){
+            this.$store.commit("updateLobby", data)
+        },
+        'lobby-activated': function(data){
+            this.$store.commit("activateLobby", data)
+        },
+        'lobby-deactivated': function(data){
+            this.$store.commit("deactivateLobby", data)
+        },
+        'lobby-created-for-pro': function(data){
+            this.$store.commit("addNewLobby", data)
         }
     },
     methods: {
@@ -142,16 +176,16 @@ export default {
         }
     },
     mounted() {
-        let lobbies = this.userProp.lobbies;
-        delete this.userProp.lobbies;
+        let lobbies = this.userProp.lobbies
+        delete this.userProp.lobbies
 
         lobbies.map(lobby => {
-            lobby.selected_meeting = null;
+            lobby.selected_meeting = null
             lobby.meetings.map(meeting => {
-                meeting.active_members = [];
-                meeting.pros_online = [];
-            });
-        });
+                meeting.active_members = []
+                meeting.pros_online = []
+            })
+        })
 
         if (this.meetingProp) {
             let meeting = {
@@ -161,67 +195,23 @@ export default {
                 active_members: [],
                 pros_online: []
             }
-            this.$store.commit("setCurrentMeeting", meeting);
+            this.$store.commit("setCurrentMeeting", meeting)
         }
 
         this.$socket.emit("userData", {
             user: this.userProp,
             meeting: this.meeting,
-            lobbies_uid_list: lobbies.reduce((acc, cur) => { console.log(cur); return [...acc, cur.uid] }, [])
+            lobbies_uid_list: lobbies.reduce((acc, cur) => { return [...acc, cur.uid] }, [])
         })
 
-        this.$store.commit("setInitialUser", this.userProp);
-        this.$store.commit("setLobbies", lobbies);
-
-        this.$socket.emit("lobbyDataRequest", lobbies);
-
-        this.sockets.subscribe("lobby-data", data => {
-            for (let meeting of Object.values(data.meetings)) {
-                this.$store.commit("setLobbyActivity", meeting);
-            }
-        })
-
-        /* Meeting Handlers */
-
-        this.sockets.subscribe("meeting-activity", data => {
-            this.$store.commit("setLobbyActivity", data)
-        })
-
-        this.sockets.subscribe("meeting-created", data => {
-            this.$store.commit("addNewMeetingInLobby", data);
-        })
-
-        this.sockets.subscribe("meeting-updated", data => {
-            this.$store.commit("setUpdatedMeetingInLobby", data);
-        })
-
-        this.sockets.subscribe("meeting-closed", data => {
-            this.$eventBus.$emit("leaveMeeting")
-        })
-
-        /* Lobby Handlers */
-
-        this.sockets.subscribe("lobby-updated", data => {
-            this.$store.commit("updateLobby", data)
-        })
-
-        this.sockets.subscribe("lobby-activated", data => {
-            this.$store.commit("activateLobby", data);
-        })
-
-        this.sockets.subscribe("lobby-deactivated", data => {
-            this.$store.commit("deactivateLobby", data);
-        })
-
-        this.sockets.subscribe("lobby-created-for-pro", data => {
-            this.$store.commit("addNewLobby", data);
-        })
+        this.$store.commit("setInitialUser", this.userProp)
+        this.$store.commit("setLobbies", lobbies)
     }
-};
+}
 </script>
 
 <style>
 .v-expansion-panel-content__wrap {
-    padding: 24px 16px;
+    padding: 24px 16px
 }
 </style>

+ 32 - 11
resources/js/components/partials/LobbyList.vue

@@ -14,16 +14,16 @@
 
                 <v-divider class="mx-4"></v-divider>
 
-                <v-list dense v-if="meetingListFiltered(lobby.meetings).length">
+                <v-list dense v-if="meetingListFiltered(lobby).length">
                     <v-container class="overflow-y-auto px-0 pt-0">
                         <v-subheader class="d-flex flex-row justify-content-between">
-                            <span>Meetings ({{meetingListFiltered(lobby.meetings).length}})</span>
+                            <span>Meetings ({{meetingListFiltered(lobby).length}})</span>
                         </v-subheader>
                     </v-container>
                     <v-container style="height: 210px" class="overflow-y-auto">
                         <v-row>
                             <v-list-item-group class="w-100" v-model="lobby.selected_meeting" color="primary">
-                                <v-list-item v-for="(item, i) in meetingListFiltered(lobby.meetings)" :key="i" :value="item">
+                                <v-list-item v-for="(item, i) in meetingListFiltered(lobby)" :key="i" :value="item">
                                     <v-list-item-icon>
                                         <v-icon v-text="'mdi-clock'"></v-icon>
                                     </v-list-item-icon>
@@ -51,7 +51,7 @@
 
                 <v-list v-else>
                     <v-subheader class="d-flex flex-row justify-content-between">
-                        <span>Meetings ({{meetingListFiltered(lobby.meetings).length}})</span>
+                        <span>Meetings ({{meetingListFiltered(lobby).length}})</span>
                     </v-subheader>
                     <v-container style="height: 210px" class="overflow-y-auto">
                         <v-row>
@@ -67,14 +67,14 @@
                 </v-list>
 
                 <transition-expand>
-                    <div v-if="meetingListFiltered(lobby.meetings).length">
+                    <div v-if="meetingListFiltered(lobby).length">
                         <v-divider class="mx-4"></v-divider>
 
                         <v-card-actions>
-                            <v-btn :disabled="lobby.selected_meeting !== 0 && !lobby.selected_meeting" color="deep-purple accent-4" text @click="joinMeeting(lobby)">Join</v-btn>
+                            <v-btn :disabled="loading || (lobby.selected_meeting !== 0 && !lobby.selected_meeting)" color="deep-purple accent-4" text @click="joinMeeting(lobby)">Join</v-btn>
                             <v-btn :disabled="lobby.selected_meeting !== 0 && !lobby.selected_meeting" color="deep-purple accent-4" text @click="inviteToMeeting(lobby)">Invite</v-btn>
                             <v-spacer></v-spacer>
-                            <v-btn :disabled="lobby.selected_meeting !== 0 && !lobby.selected_meeting" color="deep-purple accent-4" text @click="closeMeeting(lobby)">Close</v-btn>
+                            <v-btn :disabled="loading || (lobby.selected_meeting !== 0 && !lobby.selected_meeting)" color="deep-purple accent-4" text @click="closeMeeting(lobby)">Close</v-btn>
                         </v-card-actions>
                     </div>
                 </transition-expand>
@@ -96,8 +96,22 @@ export default {
         ...mapState(["lobbies", "user", "meeting"])
     },
     methods: {
-        meetingListFiltered(meetings) {
-            return meetings.filter(x => x.active_members.length > 0 && (x.pros_online.length == 0 || x.pros_online.findIndex(y => y.uid == this.user.uid) !== -1));
+        meetingListFiltered(lobby) {
+            let visibilityLevel = lobby.lobbyProAccessLevel
+            let meetings = lobby.meetings
+
+            if(!visibilityLevel){
+                return []
+            }
+
+            switch(visibilityLevel){
+                case 'FREE_FOR_ALL':
+                    return meetings.filter(x => x.active_members.length > 0)
+                case 'VISIBLE_IF_UNATTENDED':
+                    return meetings.filter(x => x.active_members.length > 0 && (x.pros_online.length == 0 || x.pros_online.findIndex(y => y.uid == this.user.uid) !== -1))
+                case 'SYSTEM_CONTROLLED_BY_LOBBY_CALL':
+                    return []
+            }
         },
         joinMeeting(lobby) {
             this.loading = true;
@@ -120,8 +134,8 @@ export default {
                     if (this.meeting.uid === lobby.selected_meeting.uid) {
                         this.$eventBus.$emit("meetingRejoin")
                     } else {
-                        lobby.selected_meeting.lobby = lobby;
-                        this.$store.commit("setCurrentMeeting", { lobby_uid: lobby.uid, ...lobby.selected_meeting });
+                        lobby.selected_meeting.lobby = lobby.name;
+                        this.$store.commit("setCurrentMeeting", { lobby_uid: lobby.uid, lobby_name: lobby.name, ...lobby.selected_meeting });
                     }
                 },
                 error: jXhr => {},
@@ -155,6 +169,13 @@ export default {
                 }
             });
         }
+    },
+    mounted(){
+        let self = this
+
+        this.$eventBus.$on('joinMeeting', function(data){
+            self.joinMeeting(data)
+        })
     }
 };
 </script>

+ 8 - 9
resources/js/components/partials/MeetingRoom.vue

@@ -46,7 +46,7 @@ export default {
         GridItem: VueGridLayout.GridItem
     },
     computed: {
-        ...mapState(["meeting", "user", "session"])
+        ...mapState(["meeting", "user", "session", "meetingLoading"])
     },
     data() {
         return {
@@ -65,8 +65,7 @@ export default {
             maxCols: 1,
             maxRows: 12,
             rowHeight: 120,
-            gridPadding: 0,
-            loadingInProgress: false
+            gridPadding: 0
         };
     },
     methods: {
@@ -75,6 +74,7 @@ export default {
             this.openTokSession.disconnect();
             this.openTokSession.off();
             this.videos = [];
+            this.videoGrid = [];
             this.publisher.destroy();
             this.publisher = null;
             this.subscribers = [];
@@ -316,7 +316,7 @@ export default {
                     this.$store.commit("setSessionConnectivityState", true);
                 }
             });
-            this.loadingInProgress = false;
+            this.$store.commit('setMeetingLoadingState', false)
         },
         publishToSession() {
             this.openTokSession.publish(this.publisher, error => {
@@ -428,14 +428,13 @@ export default {
             this.publisher.publishAudio(val);
         },
         "meeting.uid"(val) {
-            if (this.loadingInProgress) return;
-            this.loadingInProgress = true;
-
+            if (this.meetingLoading) return;
+            this.$store.commit('setMeetingLoadingState', true)
             if (val) {
                 this.getToken();
             } else {
                 this.disconnect()
-                this.loadingInProgress = false;
+                this.$store.commit('setMeetingLoadingState', false)
             }
         }
     },
@@ -444,7 +443,7 @@ export default {
 
         this.$eventBus.$on("screenShare", this.shareScreen);
         this.$eventBus.$on("meetingRejoin", () => {
-            this.loadingInProgress = true;
+            this.$store.commit('setMeetingLoadingState', true)
             this.disconnect();
             this.getToken({}, true);
         });

+ 7 - 3
resources/js/components/partials/Settings.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="d-flex flex-column">
-        <v-switch v-model="newSettings.newMeetingNotificationExpanded" @change="updateSettings('newMeetingNotificationExpanded')" :label="'Always expand new meeting notification'"></v-switch>
+        <v-switch class="mt-0" v-model="newSettings.newMeetingNotificationExpanded" @change="updateSettings(newSettings.newMeetingNotificationExpanded)" label="Always expand new meeting notification"></v-switch>
     </div>
 </template>
 
@@ -10,7 +10,12 @@ import { mapState } from "vuex";
 export default {
     data() {
         return {
-            newSettings: null
+            newSettings: {
+                newMeetingNotificationExpanded: null,
+                admin: {
+                    showAllLobbiesMettings: null
+                }
+            }
         }
     },
     computed: {
@@ -20,7 +25,6 @@ export default {
         updateSettings(setting){
             localStorage.setItem(setting, this.newSettings[setting])
             this.$store.commit('updateSettings', this.newSettings)
-            console.log('here')
         }
     },
     created(){

+ 51 - 1
resources/js/components/vuex/index.js

@@ -29,7 +29,15 @@ export default () => new Vuex.Store({
         },
         lobbies: [],
         settings: {
-            newMeetingNotificationExpanded: localStorage.getItem('newMeetingNotificationExpanded') == 'true' ? true : false
+            newMeetingNotificationExpanded: localStorage.getItem('newMeetingNotificationExpanded') == 'true' ? true : false,
+            admin: {
+                showAllLobbiesMettings: localStorage.getItem('showAllLobbiesMettings') == 'true' ? true : false
+            }
+        },
+        meetingLoading: false,
+        callWidget: {
+            active: false,
+            callInfo: {}
         }
     },
     mutations: {
@@ -90,6 +98,14 @@ export default () => new Vuex.Store({
                     if (state.meeting.uid && state.meeting.uid == meeting[0].uid) {
                         state.meeting.active_members = data.active_members
                     }
+
+                    if(state.callWidget.callInfo.meeting_uid == meeting[0].uid){
+                        if(!meeting[0].active_members.length || meeting[0].pros_online.findIndex((x) => x.uid == state.user.uid) !== -1){
+                            state.callWidget.active = false
+                        } else {
+                            state.callWidget.active = true
+                        }
+                    }
                 }
             }
         },
@@ -97,6 +113,7 @@ export default () => new Vuex.Store({
         /* Meetings */
 
         addNewMeetingInLobby(state, data) {
+            console.log(data)
             let lobby = state.lobbies.filter((cur) => cur.uid == data.lobby.uid)
 
             if (lobby.length) {
@@ -125,9 +142,42 @@ export default () => new Vuex.Store({
         setCurrentMeeting(state, data) {
             state.meeting = data
         },
+        nullifyMeetingsOnline(state) {
+            for (let lobby of state.lobbies) {
+                for (let meeting of lobby.meetings) {
+                    meeting.active_members = []
+                    meeting.pros_online = []
+                }
+            }
+
+            state.callWidget.active = false
+        },
+        setMeetingLoadingState(state, data){
+            state.meetingLoading = data
+        },
 
         /* Other */
 
+        setCall(state, data) {
+            state.callWidget.callInfo = data
+
+            if(state.callWidget.callInfo.time_limit){
+                let timer = setInterval(() => {
+                    if (state.callWidget.callInfo.time_limit > 0) {
+                        state.callWidget.callInfo.time_limit--
+
+                        if (state.callWidget.callInfo.time_limit == 0) {
+                            clearInterval(timer)
+                            console.log('TIME IS OUT!')
+                        }
+                    }
+                }, 1000)
+            }
+        },
+        rejectCall(state) {
+            state.callWidget.active = false
+            state.callWidget.callInfo = {}
+        },
         setSessionConnectivityState(state, data) {
             state.session.sessionConnected = data
         },

+ 40 - 19
resources/js/components/widgets/CallBubble.vue

@@ -2,7 +2,7 @@
   <v-btn
         color="pink"
         class="callBtn"
-        :class="{'showingAll': showCalleeDetails, 'active': call && call.time_limit > 0}"
+        :class="{'showingAll': showCalleeDetails, 'active': (callWidget.active && callWidget.callInfo && (callWidget.callInfo.time_limit > 0 || callWidget.callInfo.time_limit == null))}"
         dark
         absolute
         bottom
@@ -10,28 +10,28 @@
         ripple
         @click="shiftForm"
         >
-        <div v-if="call">
+        <div v-if="callWidget.active">
             <div class="d-flex flex-row align-items-center btnHeader">
                 <v-icon>mdi-video</v-icon>
-                <div class="ml-2 incomingCallMsg">Incoming Call {{!showCalleeDetails ? `(${call.time_limit})` : ''}}</div>
+                <div class="ml-2 incomingCallMsg">Incoming Call {{!showCalleeDetails && callWidget.callInfo.time_limit !== null ? `(${callWidget.callInfo.time_limit})` : ''}}</div>
             </div>
             <div class="fullDetails mt-3">
                 <div class="d-flex flex-row justify-content-between">
                     <span>Callee:</span>
-                    <span>{{call.user_type}}</span>
+                    <span>{{callWidget.callInfo.user_type}}</span>
                 </div>
 
                 <div class="d-flex flex-row justify-content-between">
                     <span>Lobby:</span>
-                    <span>{{call.lobby || 'None'}}</span>
+                    <span>{{callWidget.callInfo.lobby || 'None'}}</span>
                 </div>
 
-                <div class="d-flex flex-row justify-content-between mt-2">
-                    <span>{{call.name || 'Unknown'}}</span>
+                <div class="d-flex flex-row justify-content-center mt-2">
+                    <span>{{callWidget.callInfo.name || 'Unknown'}}</span>
                 </div>
 
                 <div class="d-flex flex-row justify-content-center mt-5">
-                    <h2>{{call.time_limit}}</h2>
+                    <h2 v-if="callWidget.callInfo.time_limit">{{callWidget.callInfo.time_limit}}</h2>
                 </div>
 
                 <div class="d-flex flex-row justify-content-between mt-5 ctrlBtns">
@@ -52,24 +52,18 @@
 import { mapState } from "vuex"
 
 export default {
-    props: {
-        call: {
-            type: Object
-        }
-    },
     data(){
         return {
             showCalleeDetails: false
         }
     },
     computed: {
-        ...mapState(["settings"]),
+        ...mapState(["lobbies","settings", "callWidget"]),
     },
     watch: {
-        call: {
-            deep: true,
+        'callWidget.active': {
             handler(newVal){
-                if(newVal.time_limit == 0){
+                if(!newVal){
                     let self = this
 
                     setTimeout(() => {
@@ -82,9 +76,36 @@ export default {
     methods: {
         handleCall(acceptCall) {
             if(acceptCall){
-                console.log('Call accepted!')
+                this.$socket.emit('callDecision', true)
+                let lobby_data = {}
+                let meeting = []
+
+                for(let lobby of this.lobbies){
+                    meeting = lobby.meetings.filter((x) => x.uid == this.callWidget.callInfo.meeting_uid)
+
+                    if(meeting.length){
+                        lobby_data = {
+                            name: lobby.name,
+                            uid: lobby.uid
+                        }
+                        break
+                    }
+                }
+
+                if(!meeting.length){
+                    return
+                } else {
+                    let data = {
+                        uid: lobby_data.uid,
+                        name: lobby_data.name,
+                        selected_meeting: meeting[0]
+                    }
+
+                    this.$eventBus.$emit('joinMeeting', data)
+                }
             } else {
-                console.log('Call Rejected!')
+                this.$socket.emit('callDecision', false)
+                this.$store.commit('rejectCall')
             }
         },
         shiftForm(){

+ 9 - 6
routes/web.php

@@ -31,15 +31,13 @@ Route::get('/join/{meetingID}', function () {
 Route::get('/meeting/{meetingID}/{participantID}', 'GuestController@meeting');
 */
 
-Route::middleware('ensureNoValidSession')->group(function(){
+Route::middleware('ensureNoValidProSession')->group(function(){
     Route::get('/', 'AppSessionController@proRequestSmsLogInToken')->name('pro-request-sms-login-token');
     Route::get('/pro/login', 'AppSessionController@proLogIn')->name('pro-login');
     Route::post('/pro/login', 'AppSessionController@processProLogIn')->name('process-pro-login');
-    Route::get('/client/login', 'AppSessionController@clientLogIn')->name('client-login');
-    Route::get('/client/login', 'AppSessionController@clientLogIn')->name('process-client-login');
 });
 
-Route::middleware('ensureValidSession')->group(function(){
+Route::middleware('ensureValidProSession')->group(function(){
     Route::get('/dashboard', 'ProController@dashboard')->name('pro-dashboard');
 
     // old routes
@@ -62,8 +60,10 @@ Route::middleware('ensureValidSession')->group(function(){
 Route::post('/post-to-api', 'AppSessionController@postToAPI')->name('post-to-api');
 Route::post('/post-to-api-ajax', 'AppSessionController@postToAPIAjax')->name('post-to-api-ajax');
 
-Route::get('/client', 'ClientController@entranceNormal')->name('client-entrance');
-Route::get('/client/{url_slug}', 'ClientController@entranceLobby')->name('client-lobby');
+
+Route::middleware('ensureOnlyStrangerSession')->group(function(){
+	Route::get('/client/{url_slug}', 'ClientController@entranceLobby')->name('client-lobby');
+});
 Route::get('/client/meeting/{meeting_uid}', 'ClientController@entranceLobby')->name('join-meeting');
 
 Route::bind('url_slug', function($value, $route)
@@ -76,3 +76,6 @@ Route::get('/select_section_template_form/{note_uid}', 'NoteController@selectSec
 Route::get('/section_create_form/{note_uid}/{section_template_uid}', 'NoteController@sectionCreateForm')->name('section_create_form');
 Route::get('/section_update_form/{section_uid}', 'NoteController@sectionUpdateForm')->name('section_update_form');
 Route::post("/process_form_submit", 'NoteController@processFormSubmit')->name('process_form_submit');
+if (env('APP_ENV') === 'production') {
+    URL::forceScheme('https');
+}