Advertisement
kamil321

Untitled

Feb 25th, 2025
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 24.24 KB | Legal | 0 0
  1. controller :
  2.  
  3. <?php
  4.  
  5. namespace App\Http\Controllers\Admin;
  6.  
  7. use App\Models\Inbox;
  8. use App\Models\Device;
  9. use App\Models\Message;
  10. use Illuminate\Support\Str;
  11. use Illuminate\Http\Request;
  12. use Illuminate\Support\Facades\DB;
  13. use App\Http\Controllers\Controller;
  14. use Exception;
  15. use Illuminate\Support\Facades\Http;
  16. use Illuminate\Database\Eloquent\Collection;
  17.  
  18. class InboxMessageController extends Controller
  19. {
  20.  
  21.     protected $url;
  22.     public function __construct()
  23.     {
  24.         $this->url = config('url.wa_server');
  25.     }
  26.  
  27.     public function inboxIndexFunction()
  28.     {
  29.         $device = Device::join('inboxes', 'devices.id', '=', 'inboxes.device_id')
  30.             ->select(
  31.                 'devices.name',
  32.                 'devices.number',
  33.                 'devices.expired_date',
  34.                 DB::raw('COUNT(inboxes.id) as total_message'),
  35.                 'devices.status',
  36.                 'devices.id'
  37.             )
  38.             ->where('devices.user_id', auth()->user()->id)
  39.             ->where('devices.status', 'AUTHENTICATED')
  40.             ->where('devices.expired_date', '>=', date('Y-m-d'))
  41.             ->groupBy(
  42.                 'devices.id',
  43.                 'devices.name',
  44.                 'devices.number',
  45.                 'devices.expired_date',
  46.                 'devices.status'
  47.             )
  48.             ->get();
  49.  
  50.         return view('message.inbox.index', compact('device'));
  51.     }
  52.  
  53.  
  54.     public function inboxChatFunction($deviceId)
  55.     {
  56.         $inbox = DB::select("
  57.    SELECT i.*
  58.    FROM inboxes i
  59.    WHERE i.device_id = :deviceId
  60.    AND i.id IN (
  61.        SELECT MAX(sub_i.id)
  62.        FROM inboxes sub_i
  63.        WHERE sub_i.device_id = i.device_id
  64.        AND sub_i.remote_jid = i.remote_jid
  65.        GROUP BY sub_i.remote_jid
  66.    )
  67.    ORDER BY i.created_at DESC
  68. ", ['deviceId' => $deviceId]);
  69.  
  70.         $device = Device::find($deviceId);
  71.  
  72.         return view('message.inbox.chat', compact('inbox', 'deviceId', 'device'));
  73.     }
  74.     public function fetchChatMessages($deviceId, $sender)
  75.     {
  76.         // Ambil data perangkat berdasarkan deviceId untuk mendapatkan nomor perangkat (receiver)
  77.         $device = Device::find($deviceId);
  78.  
  79.         // Periksa apakah perangkat ditemukan
  80.         if (!$device) {
  81.             return response()->json([
  82.                 'error' => 'Device not found'
  83.             ], 404);
  84.         }
  85.  
  86.         $messages = Inbox::where('device_id', $device->id)
  87.             ->where('remote_jid', $sender)
  88.             ->select('*')
  89.             ->get();
  90.  
  91.  
  92.         // Kembalikan pesan dalam format JSON
  93.         return response()->json([
  94.             'messages' => $messages
  95.         ]);
  96.     }
  97.  
  98.     public function sendMessage($deviceId, $sender, Request $request)
  99.     {
  100.         $deviceId = $request->device_id;
  101.         $receiver = $request->receiver;
  102.         $message = $request->message;
  103.  
  104.         $sender = Device::where('id', $deviceId)->value('number');
  105.         $name = Device::where('id', $deviceId)->value('name');
  106.         // random string 10 character sementara
  107.         // $messageId = Str::random(10);
  108.  
  109.  
  110.         // kirim message ke whatsapp
  111.         if (!is_array($receiver)) {
  112.             $receiver = [$receiver];
  113.         }
  114.         $send_to_string = $receiver[0] . '@s.whatsapp.net';
  115.  
  116.         $response = Http::post($this->url . "/send-message", [
  117.             'sessionId' => $sender,
  118.             'to' => $send_to_string,
  119.             'message' => $message
  120.         ]);
  121.  
  122.         if ($response->failed()) {
  123.             Message::create([
  124.                 'device_id' => $deviceId,
  125.                 'send_to' => $receiver[0],
  126.                 'message' => $message,
  127.                 'status' => 'failed',
  128.                 'is_group' => false,
  129.                 'type' => 'Text Message'
  130.             ]);
  131.  
  132.  
  133.             throw new Exception('Request failed with status: ' . $response->status() . ' and message: ' . $response->body());
  134.         } else {
  135.             // save to database
  136.             Message::create([
  137.                 'device_id' => $deviceId,
  138.                 'send_to' => $receiver[0],
  139.                 'message' => $message,
  140.                 'status' => 'sent',
  141.                 'is_group' => false,
  142.                 'type' => 'Text Message'
  143.             ]);
  144.  
  145.             // Inbox::create([
  146.             //     'device_id' => $deviceId,
  147.             //     'sender' => $sender,
  148.             //     'receiver' => $receiver[0],
  149.             //     'message' => $message,
  150.             //     'subject' => 'sender',
  151.             //     'status' => 'sent',
  152.             //     'name' => $name,
  153.             //     'message_id' => $messageId
  154.             // ]);
  155.             return response()->json([
  156.                 'success' => true,
  157.                 'message' => 'Message sent successfully'
  158.             ]);
  159.         }
  160.     }
  161.  
  162.     public function checkDeviceFunction($deviceId)
  163.     {
  164.         $device = Device::where('number', $deviceId)->value('id');
  165.         return response()->json([
  166.             'device' => $device
  167.         ]);
  168.     }
  169. }
  170. blade :
  171. @extends('partials.master')
  172. @section('title', 'Message')
  173. @push('custom_styles')
  174. <style>
  175.     .chat-message {
  176.         height: 500px;
  177.         background-image: url("{{asset('admin/assets/images/message/background_whatsapp.jpeg')}}");
  178.         background-size: cover;
  179.         overflow-y: auto;
  180.     }
  181.  
  182.     .card-custom:hover .card-title {
  183.         color: #fff !important;
  184.    }
  185.  
  186.     .card-custom .card-title {
  187.         color: #2755CE !important;
  188.    }
  189.  
  190.    
  191.    
  192.  
  193.     .chat-item {
  194.         background-color: #F2F4F7;
  195.        border-color: #2755CE;
  196.        border-radius: 6px;
  197.         display: flex;
  198.         align-items: center;
  199.     }
  200.  
  201.     .chat-item img {
  202.         width: 50px;
  203.         height: 50px;
  204.         border-radius: 50%;
  205.     }
  206.  
  207.     .chat-item-selected {
  208.         background-color: #6581ca;
  209.        color: #fff;
  210.        border-color: #6581ca;
  211.        border-radius: 6px;
  212.         display: flex;
  213.         align-items: center;
  214.     }
  215.  
  216.     .chat-item-selected img {
  217.         width: 50px;
  218.         height: 50px;
  219.         border-radius: 50%;
  220.     }
  221.  
  222.     .app-content {
  223.         overflow: hidden;
  224.         height: 100vh;
  225.         /* Pastikan tinggi utama diatur ke layar penuh */
  226.     }
  227.  
  228.     /* Aktifkan scroll pada "Chat Room" */
  229.     .mailbox-list {
  230.         overflow-y: auto;
  231.         max-height: calc(100vh - 200px);
  232.         scrollbar-width: none;
  233.         -ms-overflow-style: none;
  234.     }
  235.  
  236.     /* Aktifkan scroll pada "Chat Messages" hanya saat mouse berada di atas */
  237.     .chat-message {
  238.         height: 400px;
  239.         /* Tinggi tetap untuk kontainer pesan */
  240.         overflow-y: hidden;
  241.         /* Default tidak ada scroll */
  242.     }
  243.  
  244.     /* Aktifkan scroll saat mouse berada di atas "Chat Messages" */
  245.     .chat-message:hover {
  246.         overflow-y: auto;
  247.         /* Scroll aktif saat hover */
  248.     }
  249.  
  250.     .message-text {
  251.         white-space: pre-wrap;
  252.     }
  253. </style>
  254. @endpush
  255. @section('content')
  256. <div class="app-content">
  257.     <div class="content-wrapper">
  258.         <div class="container-fluid">
  259.             <div class="row">
  260.                 <div class="col">
  261.                     {{-- Basic Card --}}
  262.                     <div class="card" id="chat-card">
  263.                         <div class="card-header">
  264.                             <h5 class="card-title">Inbox Message</h5>
  265.                         </div>
  266.                         <div class="card-body">
  267.                             <div class="col-md-12">
  268.                                 <div class="row">
  269.                                     {{-- Chat Room --}}
  270.                                     <div class="col-md-4 my-3">
  271.                                         <h5 class="mb-3">Chat Room</h5>
  272.                                         <input type="text" class="form-control" placeholder="Search chat" oninput="handleSearchContact(event)">
  273.                                         {{-- List Chat --}}
  274.                                         <div class="mailbox-list">
  275.                                             @foreach ($inbox as $item)
  276.                                             <div class="chat-item my-3 p-2" data-chat-id="{{ $item->device_id }}"
  277.                                                 data-remote_jid="{{ $item->remote_jid }}" data-receiver="{{ $item->receiver }}"
  278.                                                 data-name="{{ $item->name }}" data-message="{{ $item->message }}"
  279.                                                 id="list-chat" style="cursor: pointer;">
  280.                                                 <div class="mailbox-list-item-content my-auto me-auto">
  281.                                                     <span class="mailbox-list-item-title fw-bold">
  282.                                                         {{ $item->name }}
  283.                                                     </span>
  284.                                                     <p class="mailbox-list-item-text fw-lighter">
  285.                                                         {{ Str::limit($item->message, 10) }}
  286.                                                     </p>
  287.                                                 </div>
  288.                                                 <div class="ms-auto me-3">
  289.                                                     <span class="badge badge-secondary">
  290.                                                         @php
  291.                                                         $createdAt = \Carbon\Carbon::parse($item->created_at);
  292.                                                         $now = \Carbon\Carbon::now();
  293.                                                         $diffInSeconds = $createdAt->diffInSeconds($now);
  294.                                                         $diffInMinutes = $createdAt->diffInMinutes($now);
  295.                                                         $diffInHours = $createdAt->diffInHours($now);
  296.  
  297.                                                         if ($diffInHours < 24) {
  298.                                                             if ($diffInMinutes < 1) {
  299.                                                             echo $diffInSeconds . ' second' . ($diffInSeconds> 1 ? 's' : '') . ' ago';
  300.                                                             } elseif ($diffInHours < 1) {
  301.                                                                 echo $diffInMinutes . ' minute' . ($diffInMinutes> 1 ? 's' : '') . ' ago';
  302.                                                                 } else {
  303.                                                                 echo $diffInHours . ' hour' . ($diffInHours > 1 ? 's' : '') . ' ago';
  304.                                                                 }
  305.                                                                 } else {
  306.                                                                 echo $createdAt->format('d M Y H:i');
  307.                                                                 }
  308.                                                                 @endphp
  309.                                                     </span>
  310.                                                 </div>
  311.                                             </div>
  312.                                             @endforeach
  313.                                         </div>
  314.                                     </div>
  315.  
  316.                                     <div class="col-md-8" id="chat-area">
  317.                                         <div class="card">
  318.                                             <div class="card-header">
  319.                                                 <h5 class="card-title">Select a chat to view messages</h5>
  320.                                             </div>
  321.                                             <div class="card-body chat-message"
  322.                                                 style="
  323.                                                height: calc(100vh - 250px);
  324.                                                overflow-y: auto; display: flex; flex-direction: column;"
  325.                                                 >
  326.                                                 <p class="text-muted">No chat selected.</p>
  327.                                             </div>
  328.                                             <div class="card-footer">
  329.                                                 <div class="d-flex justify-content-between">
  330.                                                     <textarea class="form-control" placeholder="Type your message"
  331.                                                         disabled></textarea>
  332.                                                     <button class="btn btn-primary my-3 ms-3" disabled>Send</button>
  333.                                                 </div>
  334.                                             </div>
  335.                                         </div>
  336.                                     </div>
  337.                                 </div>
  338.                             </div>
  339.                         </div>
  340.                     </div>
  341.                 </div>
  342.             </div>
  343.         </div>
  344.     </div>
  345. </div>
  346. @endsection
  347.  
  348.  
  349. @push('custom_script')
  350. <script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script>
  351. <script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.7/plugin/relativeTime.min.js"></script>
  352.  
  353. <script>
  354.     const API_URL = "{{config('url.wa_server')}}"; // URL backend
  355.     const WS_URL = "{{config('url.websocket_server')}}"; // URL WebSocket backend
  356.     const connectedSessions = new Set();
  357.     let ws;
  358.     let remote_jid_selected;
  359.     let inboxData = @json($inbox);
  360.     let messages = [];
  361.     dayjs.extend(dayjs_plugin_relativeTime);
  362.  
  363.     console.log('');
  364.  
  365.     function handleSearchContact(e) {
  366.         const inputValue = e.target.value;
  367.         console.log(inputValue);
  368.         const result = findByNameLike(inboxData, inputValue);
  369.         renderMailbox(result)
  370.  
  371.     }
  372.  
  373.     function findByNameLike(inboxData, keyword) {
  374.         return inboxData.filter(item => item.name.toLowerCase().includes(keyword.toLowerCase()));
  375.     }
  376.  
  377.  
  378.  
  379.     if (ws) {
  380.         ws.close();
  381.     }
  382.  
  383.     // Buat koneksi WebSocket baru
  384.     ws = new WebSocket(WS_URL);
  385.  
  386.     ws.onopen = () => {
  387.         console.log(`WebSocket connected `);
  388.     };
  389.  
  390.     ws.onclose = () => {
  391.         console.log(`WebSocket disconnected `);
  392.     };
  393.  
  394.     function formatTimestamp(timestamp) {
  395.         const date = new Date(timestamp);
  396.         return date.toLocaleString(); // You can customize the format as needed
  397.     }
  398.  
  399.     ws.onmessage = (event) => {
  400.         const data = JSON.parse(event.data);
  401.  
  402.         if (data.sessionId == '{{$device->number}}') {
  403.             if (data.type == "notify") {
  404.  
  405.                 if (data.messageType == "REVOKE") {
  406.  
  407.  
  408.  
  409.                     const inboxIndex = inboxData.findIndex(
  410.                         (msg) => msg.remote_jid === data.remote_jid
  411.                     );
  412.                     if (inboxIndex !== -1) {
  413.                         if (data.latestMessage) {
  414.                             inboxData[inboxIndex] = {
  415.                                 ...inboxData[inboxIndex],
  416.                                 ...data.latestMessage
  417.                             };
  418.                         } else {
  419.                             inboxData.splice(inboxIndex, 1);
  420.                         }
  421.                     }
  422.  
  423.  
  424.                     const filteredInboxData = messages[data.remote_jid]?.filter(inbox => {
  425.                         if (inbox.message_id !== data.id) {
  426.                             return inbox.message_id
  427.                         }
  428.  
  429.                     });
  430.  
  431.                     messages[data.remote_jid] = filteredInboxData
  432.                     renderChat()
  433.                     renderMailbox(inboxData)
  434.                 } else {
  435.                     const chatMessageDiv = $('#chat-area .chat-message');
  436.  
  437.                     let replace = 0;
  438.                     inboxData.forEach((inbox, index) => {
  439.                         if (inbox.remote_jid === data.message.remote_jid) {
  440.                             inboxData[index] = data.message;
  441.                             replace += 1;
  442.                         }
  443.                     });
  444.  
  445.                     if (replace === 0) {
  446.                         inboxData.push(data.message);
  447.                     }
  448.  
  449.                     renderMailbox(inboxData)
  450.  
  451.                     if (remote_jid_selected == data.message.remote_jid) {
  452.                         messages[remote_jid_selected].push(data.message)
  453.                         messages[remote_jid_selected].sort(
  454.                             (a, b) => new Date(a.created_at) - new Date(b.created_at)
  455.                         );
  456.  
  457.  
  458.                         renderChat();
  459.  
  460.                     }
  461.  
  462.                 }
  463.  
  464.  
  465.                 console.log("contact", inboxData);
  466.  
  467.  
  468.             }
  469.         }
  470.  
  471.  
  472.  
  473.     };
  474.  
  475.     function renderMailbox(inboxData) {
  476.         inboxData.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
  477.         $('.mailbox-list').empty();
  478.  
  479.  
  480.         inboxData.forEach(element => {
  481.  
  482.             const newChatItem = `  
  483.                                 <div class="chat-item my-3 p-2" data-chat-id="${element.deviceId}"  
  484.                                 data-remote_jid="${element.remote_jid}" data-receiver="${element.receiver}"  
  485.                                 data-name="${element.name}" data-message="${element.message}"  
  486.                                 style="cursor: pointer;">  
  487.                                 <div class="mailbox-list-item-content my-auto me-auto">  
  488.                                 <span class="mailbox-list-item-title fw-bold">${element.name}</span>  
  489.                                  <p class="mailbox-list-item-text fw-lighter">
  490.                                     ${element.message.length > 10 ? element.message.substring(0, 10) + '...' : element.message}
  491.                                 </p>
  492.                                 </div>  
  493.                                 <div class="ms-auto me-3">  
  494.                                 <span class="badge badge-secondary">${dayjs(element.created_at).fromNow()}</span>  
  495.                                 </div>  
  496.                                 </div>  
  497.                                 `;
  498.             $('.mailbox-list').append(newChatItem); // Menambahkan item baru ke dalam .mailbox-list
  499.         });
  500.     }
  501.  
  502.  
  503.     function renderChat() {
  504.         const chatMessageDiv = $('#chat-area .chat-message');
  505.         chatMessageDiv.empty();
  506.         if (messages[remote_jid_selected]?.length > 0) {
  507.             // Iterate through each message and append to the chat area
  508.             messages[remote_jid_selected].forEach(function(message) {
  509.                 console.log(message);
  510.  
  511.  
  512.                 const isSender = message.from_me == 0 ? true : false;
  513.                 const message_text = message.message ? message.message : "<b>Maaf chat ini tidak dapat kami tampilkan</b>"
  514.  
  515.  
  516.                 const messageElement = `
  517.                                 <div class="message-item mb-3 d-flex ${isSender ? 'justify-content-start' : 'justify-content-end'}">
  518.                                     <div class="message-content p-2 rounded ${isSender ? 'bg-light text-dark' : 'bg-primary text-white'}" style="max-width: 70%;">
  519.                                         <p class="mb-1 message-text">${message_text}</p>
  520.                                         <small style="${isSender ? 'text-end' : 'text-start'}">${formatTimestamp(message.created_at)}</small>
  521.                                     </div>
  522.                                 </div>
  523.                             `;
  524.                 chatMessageDiv.append(messageElement);
  525.             });
  526.  
  527.             // Scroll to the bottom of the chat messages
  528.             chatMessageDiv.scrollTop(chatMessageDiv[0].scrollHeight);
  529.         } else {
  530.             // If no messages, display a placeholder
  531.             chatMessageDiv.append(
  532.                 '<p class="text-muted">No messages in this chat.</p>');
  533.         }
  534.  
  535.         // Enable the textarea and send button
  536.         $('#chat-area textarea').prop('disabled', false);
  537.         $('#chat-area button').prop('disabled', false);
  538.  
  539.     }
  540.  
  541.  
  542.  
  543.     $(document).ready(function() {
  544.         // Function to format the timestamp to a readable format
  545.         function formatTimestamp(timestamp) {
  546.             const date = new Date(timestamp);
  547.             return date.toLocaleString(); // You can customize the format as needed
  548.         }
  549.  
  550.         // Event listener for chat item clicks
  551.         $('.mailbox-list').on('click', '.chat-item', function() {
  552.             // Retrieve data attributes from the clicked chat item
  553.             const deviceId = $(this).data('chat-id');
  554.             const remote_jid = $(this).data('remote_jid');
  555.             const receiver = $(this).data('receiver');
  556.             const name = $(this).data('name');
  557.             remote_jid_selected = remote_jid;
  558.  
  559.  
  560.  
  561.             // Optional: Highlight the selected chat item
  562.             $('.chat-item').removeClass('active'); // Remove active class from all
  563.             $(this).addClass('active'); // Add active class to the clicked one
  564.  
  565.             // Update the chat area header with the selected chat's name
  566.             $('#chat-area .card-header .card-title').text(`Chat with ${name}`);
  567.  
  568.             // Make an AJAX GET request to fetch chat messages
  569.             $.ajax({
  570.                 url: `/admin/message/inbox/fetch-chat/{{$deviceId}}/${remote_jid_selected}`,
  571.                 method: 'GET',
  572.                 dataType: 'json',
  573.                 success: function(response) {
  574.                     // Clear the current chat messages
  575.                     messages = [];
  576.  
  577.                     messages[remote_jid] = response.messages;
  578.                     renderChat();
  579.  
  580.  
  581.                 },
  582.                 error: function(xhr, status, error) {
  583.                     console.error('Error fetching chat messages:', error);
  584.                     alert('Failed to load chat messages. Please try again.');
  585.                 }
  586.             });
  587.         });
  588.  
  589.         // Optional: Handle sending messages
  590.         $('#chat-area button').on('click', function() {
  591.             const message = $('#chat-area textarea').val().trim();
  592.             if (message === '') {
  593.                 alert('Please enter a message.');
  594.                 return;
  595.             }
  596.  
  597.             // Disable the send button to prevent multiple clicks
  598.             $(this).prop('disabled', true);
  599.             console.log("{{$deviceId}}", remote_jid_selected);
  600.  
  601.  
  602.             // Make an AJAX POST request to send the message
  603.             $.ajax({
  604.                 url: `/admin/message/inbox/send-message/{{$deviceId}}/${remote_jid_selected}`, // Ensure this route exists in your routes file
  605.                 method: 'POST',
  606.                 dataType: 'json',
  607.                 data: {
  608.                     device_id: "{{$deviceId}}",
  609.                     receiver: remote_jid_selected,
  610.                     message: message,
  611.                     _token: '{{ csrf_token() }}' // Include CSRF token
  612.                 },
  613.                 success: function(response) {
  614.                     // Clear the textarea
  615.                     $('#chat-area textarea').val('');
  616.  
  617.                     // Optionally, append the new message to the chat area
  618.                     const chatMessageDiv = $('#chat-area .chat-message');
  619.                     const messageElement = `
  620.                         <div class="message-item mb-3 d-flex justify-content-end">
  621.                             <div class="message-content p-2 rounded bg-primary text-white" style="max-width: 50%;">
  622.                                 <p class="mb-1">${message}</p>
  623.                                 <small style="text-end">${formatTimestamp(new Date())}</small>
  624.                             </div>
  625.                         </div>
  626.                     `;
  627.                     // chatMessageDiv.append(messageElement);
  628.                     chatMessageDiv.scrollTop(chatMessageDiv[0].scrollHeight);
  629.  
  630.                     // Re-enable the send button
  631.                     $('#chat-area button').prop('disabled', false);
  632.                 },
  633.                 error: function(xhr, status, error) {
  634.                     console.error('Error sending message:', error);
  635.                     alert('Failed to send message. Please try again.');
  636.                     $('#chat-area button').prop('disabled', false);
  637.                 }
  638.             });
  639.         });
  640.     });
  641. </script>
  642.  
  643. @endpush
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement