meet.blade.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. @extends('layouts.meeting')
  2. @section('content')
  3. <div id="meetComponent">
  4. {{--<h5 class="bg-dark font-weight-bold text-white m-0 py-3 px-4 d-flex">
  5. <span>Meeting</span>
  6. <span class="ml-auto" v-if="!started">
  7. Connecting...
  8. </span>
  9. <span class="ml-auto" v-if="started">
  10. <i class="fa fa-clock mr-1 text-light"></i>
  11. @{{ timeDisplay() }}
  12. </span>
  13. </h5>--}}
  14. @if(!$guest)
  15. <div v-if="!started" class="d-flex align-items-center justify-content-center py-2">
  16. <button class="btn btn-sm btn-primary px-4 font-weight-bold"
  17. v-on:click.prevent="nextPatient()"
  18. :disabled="client || checkingForNextPatient">Next Patient</button>
  19. </div>
  20. <div v-if="!started && noNextPatient" class="bg-light rounded text-center py-1 font-weight-bold text-sm">@{{ noNextPatient }}</div>
  21. @endif
  22. <div class="">
  23. <div class="py-3 text-center" v-if="started">
  24. <h6 class="text-black font-weight-bold m-0">Call in progress: @{{ timeDisplay() }}</h6>
  25. </div>
  26. @if($guest)
  27. <div class="py-3 text-center" v-if="!pro || !started">
  28. <h6 class="text-black font-weight-bold m-0">Please wait. Your doctor will be with you shortly...</h6>
  29. </div>
  30. @endif
  31. <div class="main-view mx-auto">
  32. <div id="self-view" class="<?= $guest ? 'full-view' : 'd-none' ?>"></div>
  33. <div <?= !$guest ? 'v-show="!!client"' : '' ?> id="remote-view" class="<?= $guest ? 'thumb-view' : 'full-view' ?>"></div>
  34. <button class="btn btn-danger rounded-circle hang-up"
  35. v-if="started"
  36. v-on:click.prevent="hangUp()">
  37. <i class="fa fa-phone"></i>
  38. </button>
  39. </div>
  40. </div>
  41. </div>
  42. <script>
  43. new Vue({
  44. el: '#meetComponent',
  45. delimiters: ['@{{', '}}'],
  46. data: {
  47. time: 0,
  48. startTime: 0,
  49. started: false,
  50. client: false,
  51. pro: false,
  52. selfName: '',
  53. selfToken: '',
  54. @if($guest)
  55. clientUid: '',
  56. checkInToken: '',
  57. @endif
  58. otSessionId: '',
  59. @if(!$guest)
  60. checkingForNextPatient: false,
  61. noNextPatient: false,
  62. @endif
  63. otSession: false,
  64. },
  65. methods: {
  66. nextPatient: function() {
  67. var self = this;
  68. this.checkingForNextPatient = true;
  69. $.post('/api/client/getNextClientForVideoVisit', {}, function(_data) {
  70. self.checkingForNextPatient = false;
  71. if(!_data.success) {
  72. self.noNextPatient = _data.message;
  73. window.setTimeout(function() {
  74. self.noNextPatient = false;
  75. }, 2000);
  76. }
  77. else {
  78. // get ot session key from client record
  79. self.client = true;
  80. self.clientUid = _data.data;
  81. self.getOpenTokSessionId(function() {
  82. self.selfName = 'Pro'; // TODO: replace with name of authed pro
  83. $.post('/api/openTok/getClientToken', {
  84. opentokSessionId: self.otSessionId,
  85. name: self.selfName
  86. }, function (_data) {
  87. self.selfToken = _data.data;
  88. self.initOpenTok();
  89. });
  90. });
  91. }
  92. }, 'json');
  93. },
  94. getInitials: function(_name) {
  95. var parts = _name.split(/\s+/g);
  96. parts = parts.map(_part => _part[0]);
  97. return parts.join('');
  98. },
  99. timeDisplay: function() {
  100. var seconds = this.time / 1000,
  101. minutes = parseInt(seconds / 60, 10);
  102. seconds = parseInt(seconds % 60, 10);
  103. return minutes + " min, " + seconds + " sec";
  104. },
  105. hangUp: function() {
  106. if(this.otSession) {
  107. this.otSession.disconnect();
  108. this.otSession = false;
  109. this.otSessionId = '';
  110. this.started = false;
  111. this.startTime = false;
  112. @if(!$guest)
  113. this.client = false;
  114. @else
  115. window.location = '/join';
  116. @endif
  117. }
  118. },
  119. // OT methods
  120. initOpenTok: function() {
  121. /* fake video feed (temp) */
  122. const randomColour = () => {
  123. return Math.round(Math.random() * 255);
  124. };
  125. const canvas = document.createElement('canvas');
  126. canvas.width = 640;
  127. canvas.height = 480;
  128. const ctx = canvas.getContext('2d');
  129. var pos = 100;
  130. window.setInterval(function() {
  131. ctx.clearRect(0, 0, canvas.width, canvas.height);
  132. ctx.font = "20px Georgia";
  133. ctx.fillStyle = `rgb(220, 220, 220)`;
  134. var userType = '<?= $guest? "Client" : "Pro" ?>';
  135. ctx.fillText("Video feed from the " + userType, 20, pos);
  136. pos += 5;
  137. if(pos > canvas.height) pos = 100;
  138. }, 1000);
  139. var self = this;
  140. var apiKey = '<?= env('TOKBOX_API_KEY', '46678902') ?>';
  141. var sessionId = this.otSessionId;
  142. var token = this.selfToken;
  143. // destroy if existing
  144. self.hangUp();
  145. self.otSession = OT.initSession(apiKey, sessionId);
  146. self.otSession.on('streamCreated', function streamCreated(event) {
  147. var subscriberOptions = {
  148. insertMode: 'append',
  149. width: '100%',
  150. height: '100%'
  151. };
  152. self.otSession.subscribe(event.stream, 'remote-view', subscriberOptions, self.handleOpenTokError);
  153. @if($guest)
  154. $('#self-view').removeClass('full-view').addClass('thumb-view');
  155. $('#remote-view').removeClass('thumb-view').addClass('full-view');
  156. self.pro = true;
  157. @else
  158. self.joinMeetingAsPro();
  159. self.client = true;
  160. @endif
  161. if(!self.startTime) {
  162. self.startTime = new Date().getTime();
  163. window.setInterval(function() {
  164. self.time = new Date().getTime() - self.startTime;
  165. }, 1000);
  166. self.started = true;
  167. }
  168. });
  169. self.otSession.on("streamDestroyed", function(event) {
  170. @if($guest)
  171. $('#remote-view').removeClass('full-view').addClass('thumb-view');
  172. $('#self-view').removeClass('thumb-view').addClass('full-view');
  173. self.pro = false;
  174. @else
  175. self.client = false;
  176. @endif
  177. self.started = false;
  178. self.startTime = false;
  179. self.hangUp();
  180. });
  181. self.otSession.on('sessionDisconnected', function sessionDisconnected(event) {
  182. console.log('You were disconnected from the session.', event.reason);
  183. });
  184. // initialize the publisher
  185. var publisherOptions = {
  186. videoSource: canvas.captureStream(1).getVideoTracks()[0],
  187. insertMode: 'append',
  188. width: '100%',
  189. height: '100%',
  190. };
  191. var publisher = OT.initPublisher('self-view', publisherOptions, self.handleOpenTokError);
  192. // Connect to the session
  193. self.otSession.connect(token, function callback(error) {
  194. if (error) {
  195. self.handleOpenTokError(error);
  196. } else {
  197. // If the connection is successful, publish the publisher to the session
  198. self.otSession.publish(publisher, self.handleOpenTokError);
  199. }
  200. });
  201. },
  202. handleOpenTokError: function(e) {
  203. },
  204. getClientCheckinToken: function(_done) {
  205. var self = this;
  206. $.get('/get-client-checkin-token/' + this.clientUid, function(_data) {
  207. console.log(_data);
  208. self.checkInToken = _data.data;
  209. _done();
  210. }, 'json');
  211. },
  212. getOpenTokSessionId: function(_done) {
  213. var self = this;
  214. @if($guest)
  215. $.ajax({
  216. type: 'post',
  217. url: '/api/clientVideoVisit/startVideoVisitAsStranger',
  218. headers: {
  219. 'sessionKey': localStorage.sessionKey
  220. },
  221. data: {checkInToken: this.checkInToken},
  222. dataType: 'json'
  223. })
  224. .done(function (_data) {
  225. console.log(_data);
  226. if(_data.success) {
  227. self.otSessionId = _data.data;
  228. _done();
  229. }
  230. else {
  231. alert(_data.message);
  232. }
  233. })
  234. .fail(function (_data) {
  235. console.log(_data);
  236. alert(_data.message);
  237. });
  238. @else
  239. $.get('/pro/get-opentok-session-key/' + self.clientUid, function(_data) {
  240. self.otSessionId = _data.data;
  241. _done();
  242. }, 'json');
  243. @endif
  244. },
  245. joinMeetingAsPro: function() {
  246. var self = this;
  247. $.ajax({
  248. type: 'post',
  249. url: '/api/clientVideoVisit/joinVideoVisitAsMcpPro',
  250. headers: {
  251. 'sessionKey': localStorage.sessionKey
  252. },
  253. data: {uid: self.clientUid},
  254. dataType: 'json'
  255. })
  256. .done(function (_data) {
  257. console.log(_data);
  258. })
  259. .fail(function (_data) {
  260. console.warn(_data);
  261. alert(_data.message);
  262. });
  263. }
  264. },
  265. mounted: function() {
  266. var self = this;
  267. @if($guest)
  268. this.clientUid = localStorage.clientUid;
  269. this.getClientCheckinToken(function() { // get client check-in token
  270. self.getOpenTokSessionId(function() { // get opentok session id
  271. var name = [];
  272. if (localStorage.clientFirstName) name.push(localStorage.clientFirstName);
  273. if (localStorage.clientLastName) name.push(localStorage.clientLastName);
  274. this.selfName = name.join(' ');
  275. $.post('/api/openTok/getClientToken', {
  276. opentokSessionId: self.otSessionId,
  277. name: name.join(' ')
  278. }, function (_data) {
  279. self.selfToken = _data.data;
  280. self.initOpenTok();
  281. });
  282. });
  283. });
  284. @endif
  285. }
  286. });
  287. </script>
  288. @endsection