messages.blade.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. @extends('app.my-account.admin.users.single')
  2. @section('details')
  3. <div>
  4. <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
  5. <div class="pb-5">
  6. <div class="custom-card w-100 p-0 patients-content">
  7. <div class="mcp-theme-1 im-body" id="messages">
  8. <div class="card overflow-hidden border-0 h-100">
  9. <div class="msg-header p-3 d-flex align-items-center shadow-sm">
  10. <strong class="">
  11. <i class="fas fa-comments mr-2"></i>
  12. Messages
  13. </strong>
  14. </div>
  15. <div class="card-body p-0 h-100">
  16. <div class="im-container h-100">
  17. <div class="im-rhs p-2">
  18. @if (!$messages || !count($messages))
  19. <div class="py-4 text-center text-secondary">
  20. <h3 class="mb-0"><i class="far fa-comment-dots"></i></h3>
  21. No messages yet!
  22. </div>
  23. @endif
  24. <div class="im-messages">
  25. <div class="mh-100 overflow-auto opacity-0" id="im-scroller">
  26. <?php $messageDates = []; ?>
  27. @foreach ($messages as $k => $message)
  28. @if (!in_array(friendly_date($message->created_at), $messageDates))
  29. <?php array_push($messageDates, friendly_date($message->created_at)); ?>
  30. <div class="text-center my-4">
  31. <span style="background:#c2efff"
  32. class="py-1 px-3 text-secondary rounded text-sm">{{ friendly_date_est($message->created_at) }}</span>
  33. </div>
  34. @endif
  35. <div class="d-flex align-items-start">
  36. @if ($message->from_user_id !== $performer->user->id)
  37. <div class="">
  38. @if (!$message->is_removed)
  39. @if ($k == 0 || $messages[$k - 1]->from_user_id !== $messages[$k]->from_user_id)
  40. <!-- remove unecessary timestamps -->
  41. <div class="circle-icon">
  42. {{ mb_substr($message->fromUser->name_first, 0, 1) }}
  43. </div>
  44. @else
  45. <div class="circle-icon op">
  46. {{ mb_substr($message->fromUser->name_first, 0, 1) }}
  47. </div>
  48. @endif
  49. @endif
  50. </div>
  51. @endif
  52. <div class="w-100">
  53. <div class="im-message mt-0 pe-5 {{ $message->from_user_id === $performer->user->id ? 'sent' : 'received' }}"
  54. data-uid="{{ $message->uid }}"
  55. data-mark-as-read="{{ !$message->is_read ? 1 : 0 }}">
  56. <div class="im-message-sender align-items-center">
  57. @if (!$message->is_removed)
  58. @if ($k == 0 || $messages[$k - 1]->from_user_id !== $messages[$k]->from_user_id)
  59. <!-- remove unecessary timestamps -->
  60. @if ($message->from_user_id !== $performer->user->id)
  61. <small
  62. class="me-2 text-secondary">{{ $message->fromUser->displayName() }},</small>
  63. @endif
  64. <small
  65. class="header-item text-secondary text-sm">{{ friendly_time_by_time_zone($message->created_at) }}</small>
  66. @endif
  67. @if ($performer->user->id == $message->created_by_user_id && $message->content_text)
  68. <div class="header-item">
  69. <div moe large relative>
  70. @if ($k == 0 || $messages[$k - 1]->from_user_id !== $messages[$k]->from_user_id)
  71. <a href="#" start show><i
  72. class="fa fa-edit on-hover-opaque text-pry text-sm hidden edit"
  73. style="top:18px;"></i></a>
  74. @else
  75. <a href="#" start show><i
  76. class="fa fa-edit on-hover-opaque text-pry text-sm hidden edit"></i></a>
  77. @endif
  78. <form url="/api/message/editContent"
  79. class="text-left" right>
  80. <input type="hidden" name="uid"
  81. value="{{ $message->uid }}">
  82. <div class="mb-2">
  83. <label class="mb-1 text-sm">Edit
  84. Message</label>
  85. <textarea name="contentText" rows="3" class="form-control form-control-sm">{{ $message->content_text }}</textarea>
  86. </div>
  87. <div class="mt-3">
  88. <button submit
  89. class="btn btn-sm btn-primary mr-2">Submit</button>
  90. <button cancel
  91. class="btn btn-default btn-sm border">Cancel</button>
  92. </div>
  93. </form>
  94. </div>
  95. </div>
  96. @endif
  97. @if ($message->from_user_id === $performer->user->id)
  98. <span class="header-item hidden delete">
  99. <a href="#" native class="remove-message"
  100. data-message-uid="{{ $message->uid }}"><i
  101. class="fa fa-trash-alt text-danger text-sm"></i></a>
  102. </span>
  103. @endif
  104. @endif
  105. </div>
  106. @if ($message->is_removed)
  107. <div class="im-message-content text-secondary font-italic">
  108. This message was removed.</div>
  109. @else
  110. @if ($message->content_text)
  111. <?php
  112. $message->content_text = preg_replace_callback(
  113. '~(?:http|ftp)s?://(?:www\.)?([a-z0-9.-]+\.[a-z]{2,3}(?:/\S*)?)~i',
  114. function ($match) {
  115. return '<a native target="_blank" href="' . $match[0] . '">' . $match[0] . '</a>';
  116. },
  117. $message->content_text,
  118. );
  119. ?>
  120. <div class="im-message-content">{!! $message->content_text !!}
  121. </div>
  122. @endif
  123. @endif
  124. @if (count($message->attachments) && !$message->is_removed)
  125. <div class="attachments-container mt-1 d-flex align-items-center flex-wrap {{ $message->from_user_id === $performer->user->id ? 'justify-content-end' : 'justify-content-start' }}"
  126. data-message-uid="{{ $message->uid }}"
  127. data-attachments-loaded="0">
  128. <span class="my-1 text-primary c-pointer text-sm">
  129. <i class="fa fa-paperclip"></i>
  130. {{ count($message->attachments) }}
  131. attachment{{ count($message->attachments) === 1 ? '' : 's' }}
  132. </span>
  133. </div>
  134. @endif
  135. </div>
  136. </div>
  137. </div>
  138. @endforeach
  139. </div>
  140. </div>
  141. @if ($toUser)
  142. <div class="im-input">
  143. <div class="d-flex align-items-end">
  144. <div class="msg-input">
  145. <textarea placeholder="Enter your message here..."></textarea>
  146. <button class="btn btn-sm btn-input" id="im-btn-send"><i
  147. class="fa fa-paper-plane"></i></button>
  148. </div>
  149. <div class="fabs ms-2">
  150. <button class="btn btn-sm btn-primary ms-2" id="im-btn-select-file"><i
  151. class="fa fa-paperclip"></i></button>
  152. </div>
  153. </div>
  154. <div class="d-flex align-items-end flex-wrap" id="selected-files">
  155. </div>
  156. </div>
  157. @endif
  158. <!-- <div>
  159. {{ $messages->withQueryString()->links() }}
  160. </div> -->
  161. </div>
  162. </div>
  163. </div>
  164. </div>
  165. </div>
  166. </div>
  167. </div>
  168. <script>
  169. $(document).ready(function() {
  170. setTimeout(function() {
  171. jQuery('.mark-as-read').click();
  172. }, 1000);
  173. let inProgress = false;
  174. function showSelectedFiles() {
  175. $('#selected-files').empty();
  176. $('.im-file-upload').each(function() {
  177. if (this.files && this.files.length) {
  178. for (let i = 0; i < this.files.length; i++) {
  179. $('#selected-files').append($('<div class="selected-file" data-id="' + this.id +
  180. '" title="Click to remove">').text(this.files[i].name));
  181. }
  182. }
  183. });
  184. var hght = $('#selected-files')[0].scrollHeight;
  185. $('.im-messages').css('margin-bottom', (hght + 100) + 'px');
  186. $('.im-messages').scrollTop($('.im-messages')[0].scrollHeight);
  187. }
  188. function hasError(_data) {
  189. let msg = 'Unknown error!';
  190. if (_data) {
  191. if (_data.success) return false;
  192. else if (_data.message) msg = _data.message;
  193. }
  194. toastr.error(msg);
  195. return true;
  196. }
  197. function doSend(_elem) {
  198. if (inProgress) return false;
  199. inProgress = true;
  200. showMask();
  201. let text = $.trim(_elem.value);
  202. let formData = new FormData();
  203. formData.set('fromUserUid', '{{ $performer->user->uid }}');
  204. formData.set('toUserUid', '{{ isset($toUser) ? $toUser->uid : null }}');
  205. formData.set('contentText', text);
  206. let hasFiles = false;
  207. $('.im-file-upload').each(function() {
  208. if (this.files && this.files.length) {
  209. for (let i = 0; i < this.files.length; i++) {
  210. formData.append('attachments', this.files[i]);
  211. hasFiles = true;
  212. }
  213. }
  214. });
  215. if (!hasFiles && !text) { // either attachment or text or both should be there
  216. inProgress = false;
  217. hideMask();
  218. return false;
  219. }
  220. jQuery.ajax('/api/message/create', {
  221. dataType: 'json',
  222. data: formData,
  223. processData: false,
  224. contentType: false,
  225. type: 'POST',
  226. }).done(function(_data) {
  227. if (!hasError(_data)) {
  228. fastReload();
  229. } else {
  230. $('.im-input textarea').val('');
  231. inProgress = false;
  232. hideMask();
  233. }
  234. });
  235. return false;
  236. }
  237. function init() {
  238. @if (isset($user))
  239. $('.im-input textarea').on('keydown', function(_e) {
  240. if (_e.which === 13 && !_e.shiftKey) {
  241. return doSend(this);
  242. }
  243. });
  244. $('#im-btn-send').click(function() {
  245. return doSend($('.im-input textarea')[0]);
  246. });
  247. $('#plusBtn').click(function() {
  248. $('.hide').toggle();
  249. $('.show').toggle();
  250. });
  251. $('#im-btn-select-file').click(function() {
  252. let fiID = Math.floor(Math.random() * 10000);
  253. let fileInput = $('<input type="file" class="d-none im-file-upload" accept="image/*, .pdf, .doc, .docx, application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document" id="fu-' +
  254. fiID + '">');
  255. $('.im-input').append(fileInput)
  256. fileInput.click();
  257. });
  258. $(document).on('change', '.im-file-upload', function() {
  259. showSelectedFiles();
  260. });
  261. $(document)
  262. .off('click', '.selected-file')
  263. .on('click', '.selected-file', function() {
  264. $('#' + $(this).attr('data-id')).remove();
  265. showSelectedFiles();
  266. });
  267. $(document)
  268. .off('click.load-attachments', '.attachments-container[data-attachments-loaded="0"]>span')
  269. .on('click.load-attachments', '.attachments-container[data-attachments-loaded="0"]>span',
  270. function() {
  271. let container = $(this).closest('.attachments-container');
  272. if (inProgress) return false;
  273. inProgress = true;
  274. $.get('/admin/users/view/{{$user->uid}}/messages/' + container.attr(
  275. 'data-message-uid') + '/attachments', (_data) => {
  276. container.html(_data).attr('data-attachments-loaded', 1);
  277. }).then(function() {
  278. inProgress = false;
  279. });
  280. });
  281. $(document)
  282. .off('click', '.mark-as-read')
  283. .on('click', '.mark-as-read', function() {
  284. $.post('/api/message/markRead', {
  285. uid: $(this).attr('data-message-uid')
  286. }, () => {
  287. $(this).replaceWith(
  288. '<i class="fa fa-check text-secondary on-hover-opaque text-sm"></i>'
  289. );
  290. let unreadBadge = $('.unread-badge[data-user-id="' +
  291. {{ $user->id }} + '"]').first();
  292. if (unreadBadge.length) {
  293. let newCount = (+unreadBadge.text()) - 1;
  294. if (newCount) {
  295. unreadBadge.text(newCount);
  296. } else {
  297. unreadBadge.remove();
  298. }
  299. }
  300. }, 'json');
  301. return false;
  302. });
  303. $(document)
  304. .off('click', '.remove-message')
  305. .on('click', '.remove-message', function() {
  306. $.post('/api/message/markAsRemoved', {
  307. uid: $(this).attr('data-message-uid')
  308. }, () => {
  309. $(this).closest('.im-message').html(
  310. '<div class="im-message-content text-secondary font-italic">This message was removed.</div>'
  311. );
  312. }, 'json');
  313. return false;
  314. });
  315. var imScroller = document.getElementById("im-scroller");
  316. imScroller.scrollTop = imScroller.scrollHeight;
  317. $(imScroller).removeClass('opacity-0');
  318. @endif
  319. }
  320. init();
  321. });
  322. </script>
  323. </div>
  324. @endsection