Vijayakrishnan 5 年 前
コミット
0ef81fbcbb

+ 8 - 0
app/Http/Controllers/HomeController.php

@@ -24,4 +24,12 @@ class HomeController extends Controller
         return view('app/new-patient');
     }
 
+    public function mc(Request $request, $fragment = "") {
+        $page = "/";
+        if($fragment) {
+            $page = '/' . $fragment;
+        }
+        return view('app/mc', compact('page'));
+    }
+
 }

+ 20 - 0
app/Http/Controllers/PracticeManagementController.php

@@ -2,6 +2,8 @@
 
 namespace App\Http\Controllers;
 
+use App\Models\AppSession;
+use App\Models\Client;
 use Illuminate\Http\Request;
 
 class PracticeManagementController extends Controller
@@ -50,4 +52,22 @@ class PracticeManagementController extends Controller
     {
         return view('app.practice-management.contract');
     }
+
+    // video call page (RHS)
+    // generic call handle (no uid)
+    // specific call handle (uid of client)
+    public function meet(Request $request, $uid = false) {
+        $session = AppSession::where('session_key', $request->cookie('sessionKey'))->first();
+        $pro = $session ? $session->pro() : null;
+        $client = !empty($uid) ? Client::where('uid', $uid)->first() : null;
+        return view('app.video.call', compact('session', 'pro', 'client'));
+    }
+
+    // ajax ep used by the video page
+    // this is needed bcoz meet() is used not
+    // just for the client passed to the view
+    public function getOpentokSessionKey(Request $request, $uid) {
+        $client = Client::where('uid', $uid)->first();
+        return json_encode(["data" => $client ? $client->opentok_session_id : '']);
+    }
 }

+ 2 - 1
composer.json

@@ -13,7 +13,8 @@
         "fruitcake/laravel-cors": "^1.0",
         "guzzlehttp/guzzle": "^6.5",
         "laravel/framework": "^7.0",
-        "laravel/tinker": "^2.0"
+        "laravel/tinker": "^2.0",
+        "ext-json": "*"
     },
     "require-dev": {
         "facade/ignition": "^2.0",

+ 21 - 0
public/v-splitter-px/v-splitter.css

@@ -0,0 +1,21 @@
+.v-split {
+    position: absolute;
+    /*height: 100%;*/
+    width: 6px;
+    background: gray;
+    opacity: 0.3;
+    box-sizing: border-box;
+    cursor: ew-resize;
+    z-index: 2;
+    margin-left: 3px;
+    border-radius: 3px;
+    margin-top: 2px;
+    height: calc(100% - 4px);
+}
+.v-moving .v-split-active, .v-split:hover {
+    opacity: 0.5;
+}
+
+.v-moving .v-split-panel {
+    pointer-events: none;
+}

+ 59 - 0
public/v-splitter-px/v-splitter.js

@@ -0,0 +1,59 @@
+function initVSplitter(_name, _left, _right, _alignTo = null) {
+
+    var minSplitWidth = 300;
+
+    if($('.v-split[data-name="' + _name + '"]').length) return;
+
+    if(localStorage['v-split-rounded-' + _name]) {
+        var tempFinalLeft = Math.round(parseFloat(localStorage['v-split-rounded-' + _name]));
+        _left.css({flex: '0 0 ' + tempFinalLeft + '%'});
+        _right.css({flex: '0 0 ' + (100 - tempFinalLeft) + '%'});
+    }
+
+    var origLeft = -1, finalLeft = -1, origX = -1, vMoving = false, totalWidth = _left.parent().width();
+    _left.parent().css({position: 'relative'});
+    _left.addClass('v-split-panel').css({maxWidth: 'unset', minWidth: 'unset'});
+    _right.addClass('v-split-panel').css({maxWidth: 'unset', minWidth: 'unset'});
+    const vSplit = $('<div/>').addClass('v-split').attr('data-name', _name).insertAfter(_left);
+
+    function _setSplitterHeight() {
+        if(!_alignTo) return;
+        vSplit.css({marginTop: (_alignTo.position().top + 'px'), height: (_alignTo.outerHeight())});
+    }
+    _setSplitterHeight();
+
+    vSplit.css({left: (_left.outerWidth() * 100 / totalWidth) + '%'})
+        .off('mousedown.' + _name).on('mousedown.' + _name, function(_e) {
+            totalWidth = _left.parent().width();
+            origLeft = vSplit.position().left;
+            origX = _e.screenX;
+            vMoving = true;
+            $('body').addClass('v-moving');
+            $(this).addClass('v-split-active');
+            return false;
+        });
+
+    $(document)
+        .off('mousemove.' + _name).on('mousemove.' + _name, function(_e) {
+            if(!vMoving) return;
+            var tempFinalLeft = origLeft + (_e.screenX - origX);
+            if(tempFinalLeft < minSplitWidth || tempFinalLeft > (totalWidth - minSplitWidth)) return;
+            finalLeft = tempFinalLeft;
+            vSplit.css({left: ((tempFinalLeft * 100) / totalWidth) + '%'});
+        })
+        .off('mouseup.' + _name).on('mouseup.' + _name, function(_e) {
+            if(!vMoving) return;
+            vMoving = false;
+            $('body').removeClass('v-moving');
+            var tempFinalLeft = ((_left.outerWidth() + (finalLeft - origLeft)) * 100 / totalWidth);
+            tempFinalLeft = Math.round(tempFinalLeft);
+            _left.css({flex: '0 0 ' + tempFinalLeft + '%'});
+            vSplit.css({left: (_left.outerWidth() * 100 / totalWidth) + '%'})
+            _right.css({flex: '0 0 ' + (100 - tempFinalLeft) + '%'});
+            $('.v-split-active').removeClass('v-split-active');
+            localStorage['v-split-rounded-' + _name] = tempFinalLeft;
+        });
+
+    $(window).off('resize.' + _name).on('resize.' + _name, function(_e) { _setSplitterHeight(); });
+    $(window).off('scroll.' + _name).on('scroll.' + _name, function(_e) { _setSplitterHeight(); });
+}

+ 31 - 0
resources/views/app/mc.blade.php

@@ -0,0 +1,31 @@
+{{-- lean wrapper for 2 pane page --}}
+<!doctype html>
+<html lang="en" class="h-100">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
+    <link href="/css/app.css" rel="stylesheet">
+    <link href="/v-splitter-px/v-splitter.css" rel="stylesheet" >
+    <script src="/v-splitter-px/v-splitter.js"></script>
+    <title>Stag | MCP</title>
+</head>
+<body class="h-100">
+    <div class="row mx-0 h-100">
+        <div class="col-9 px-0 app-left-panel">
+            <iframe id="stag_mcp_lhs" src="{{ $page }}" frameborder="0" class="h-100 w-100"></iframe>
+        </div>
+        <div class="col-3 border-left app-right-panel pr-1">
+            <iframe id="stag_mcp_rhs" src="/pro/meet" frameborder="0" class="h-100 w-100"></iframe>
+        </div>
+    </div>
+    <script>
+        initVSplitter('stag-mc-main', $('.app-left-panel'), $('.app-right-panel'));
+        window.openInRHS = function(_url) {
+            $('#stag_mcp_rhs').attr('src', _url);
+            return false;
+        };
+    </script>
+</body>
+</html>

+ 0 - 0
resources/views/app/video/call.blade.php


+ 7 - 0
routes/web.php

@@ -67,6 +67,13 @@ Route::middleware('pro.auth')->group(function () {
         Route::get('duplicate', 'PatientController@duplicate')->name('duplicate');
     });
 
+    // 2-pane outer page housing lhs (practice management) and rhs (video call)
+    Route::get('/mc/{fragment?}', 'HomeController@mc')
+        ->where('fragment', '.*')
+        ->name('mc');
 
+    // pro meeting
+    Route::get('/pro/meet/{uid?}', 'PracticeManagementController@meet');
+    Route::get('/pro/get-opentok-session-key/{uid}', 'PracticeManagementController@getOpentokSessionKey');
 
 });