Compare commits

...

10 Commits

Author SHA1 Message Date
abdul-wahab12345 e2285db816 latest code 2024-10-29 06:42:23 +00:00
abdul-wahab12345 98b34a2959 latest code 2024-10-08 12:30:49 +00:00
abdul-wahab12345 203d845825 attachments work 2024-09-12 11:56:53 +00:00
abdul-wahab12345 412ffc0e87 chat functions 2024-08-01 17:26:06 +00:00
abdul-wahab12345 6b51f6a402 chat function 2024-07-12 15:23:36 +00:00
abdul-wahab12345 f13e2a1945 chat function 2024-07-09 10:58:20 +00:00
abdul-wahab12345 f0e7e09ef8 added domain verify middleware 2024-07-01 18:52:27 +00:00
abdul-wahab12345 521e3b084c fixed user access for company 2024-07-01 11:17:16 +00:00
abdul-wahab12345 fe3a69e9f7 Added internal emails and canned response 2024-06-29 19:15:55 +00:00
abdul-wahab12345 1760c7e0aa added cpanel api 2024-06-28 06:58:04 +00:00
80 changed files with 190290 additions and 1406 deletions

4
.gitignore vendored
View File

@ -6,6 +6,9 @@
/storage/*.key
/vendor
.env
.zip
/chat.kundesone.no
/mailgun.kundesone.no
.env.backup
.env.production
.phpunit.result.cache
@ -17,3 +20,4 @@ yarn-error.log
/.fleet
/.idea
/.vscode
/chat.kundesone.no

View File

@ -43,6 +43,11 @@ RewriteRule ^(/)?$ public/index.php [L]
php_flag zlib.output_compression Off
</IfModule>
# END cPanel-generated php ini directives, do not edit
# Deny access to .env files
<Files .env>
Order allow,deny
Deny from all
</Files>
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php81” package as the default “PHP” programming language.

View File

@ -0,0 +1,86 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\ChatGroup;
use App\Models\Ticket;
use App\Models\Response;
use App\Models\Message; // Assuming Message is the model for your messages table
use Illuminate\Support\Facades\DB;
class CheckChatGroupStatus extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'chatgroup:check-status';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Check ChatGroup status and create tickets if status is closed';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
// Fetch all closed chat groups
$closedChatGroups = ChatGroup::where('status', 'closed')->get();
foreach ($closedChatGroups as $chatGroup) {
DB::transaction(function () use ($chatGroup) {
$company = get_company('id',$chatGroup->company_id);
$ticket = insertTicket($chatGroup->email, $company->email, $chatGroup->subject, '','chat',$chatGroup->name,$chatGroup->user_id,'done',true );
// Fetch all messages from the chat group
$messages = $chatGroup->messages;
// Insert each message as a response to the ticket
foreach ($messages as $message) {
// Create a new Response instance
$response = new Response;
$html = $message->message;
if($message->type == 'image'){
$html = "<img src='{$message->message}' />";
}
if($message->type == 'file'){
$html = "<a target='_blank' href='{$message->message}'>View File</a>";
}
// Set the properties of the Response
$response->message = $html;
$response->ticket_id = $ticket->id;
$response->user_id = $message->from == 'user'?0:1; // You may want to dynamically set the user_id based on the authenticated user
$response->created_at = $message->created_at;
$response->updated_at = $message->updated_at;
// Save the response to the database
$response->save();
}
// Optionally update the chat group status to indicate a ticket has been created
$chatGroup->update(['status' => 'ticket_created']);
});
}
$this->info('Chat groups checked and tickets created for closed statuses.');
return 0;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use \Carbon\Carbon;
use App\Models\User;
class UpdateLastOnline extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'users:update-last-online';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update last online user if he/she is not active with the period of three minutes';
/**
* Execute the console command.
*/
public function handle()
{
$now = Carbon::now()->format('Y-m-d H:i:s');
$users = User::whereNotNull('last_online')->where('last_online', '!=', '')->get();
foreach($users as $user)
{
$lastOnline = Carbon::parse($user->last_online);
if ($lastOnline->diffInMinutes($now) > 3) {
//update user
$user->is_available = 0;
$user->save();
}
}
$this->info('Users last online updated successfully.');
return 0;
}
}

View File

@ -12,6 +12,8 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
$schedule->command('chatgroup:check-status')->everyMinute();
$schedule->command('users:update-last-online')->everyMinute();
// $schedule->command('inspire')->hourly();
}

View File

@ -3,9 +3,73 @@
use App\Models\CompanyMeta;
use App\Models\Settings;
use App\Models\Ticket;
use App\Models\TicketMeta;
use App\Models\Response;
use App\Models\TicketNote;
use Illuminate\Support\Facades\Session;
use Mailgun\Mailgun;
use App\Models\Company;
use App\Models\ChatGroup;
use App\Models\Message;
use App\Models\Tag;
use App\Models\Rule;
use App\Models\CompanyUser;
use App\Models\Notification;
function get_company_users($company_id){
return CompanyUser::where('company_id', $company_id)->with('user')->get();
}
function getCompanyTags($companyId) {
$tags = Tag::where('company_id', $companyId)->get();
return $tags;
}
function get_company($key,$value){
return Company::where($key,$value)->first();
}
function get_current_company_tickets($args = []){
$companyId = getSelectedCompany();
if(!$companyId){
return false;
}
$company = get_company('id',$companyId);
if(!$company){
return false;
}
$tickets = Ticket::where('to_email', $company->email);
$tickets->orderBy('created_at','desc');
if(isset($args['type'])){
$tickets->where('type',$args['type']);
}
if(isset($args['status'])){
$tickets->where('status',$args['status']);
}
if(isset($args['orderby'])){
$tickets->orderBy($args['orderby'],$args['order']??'asc');
}
if(isset($args['with'])){
$tickets->with($args['with']);
}
$tickets = $tickets->get();
return $tickets;
}
function getResponse($company_id, $key, $type) {
$meta = CompanyMeta::where('company_id', $company_id)->where('key', $key)->where('type', $type)->first();
@ -37,13 +101,24 @@ function verifyMailgunSignature($token, $timestamp, $signature)
}
//Insert Ticket
if (!function_exists('insertTicket')) {
function insertTicket($from_email, $to_email, $subject, $content, $type, $sender_name) {
function insertTicket($from_email, $to_email, $subject, $content, $type, $sender_name,$user_assigned = 0,$status = 'waiting',$force = false) {
$check = Ticket::where('subject', $subject)
->where('from_email',$from_email)
->where('to_email',$to_email)->first();
$check = Ticket::where(function ($query) use ($from_email, $to_email) {
$query->where('from_email', $from_email)
->where('to_email', $to_email);
})
->where(function ($query) use ($subject) {
$cleanSubject = trim(str_ireplace('Re:', '', $subject)); // Remove 'Re:' prefix and trim whitespace
$query->where('subject', $cleanSubject)
->orWhere('subject', 'Re: ' . $cleanSubject)
->orWhere('subject2', 'Re: ' . $cleanSubject)
->orWhere('subject2', $cleanSubject); // Consider both with and without 'Re:'
})
->first();
if(!$check){
if(!$check || $force){
$ticket = new Ticket;
$ticket->from_email = $from_email;
@ -53,9 +128,9 @@ function insertTicket($from_email, $to_email, $subject, $content, $type, $sender
$ticket->subject = $subject;
$ticket->content = $content;
$ticket->priority = 'low';
$ticket->status = 'waiting';
$ticket->status = $status;
$ticket->parent_id = 0;
$ticket->user_assigned = 0;
$ticket->user_assigned = $user_assigned;
$ticket->save();
}else{
@ -70,7 +145,7 @@ function insertTicket($from_email, $to_email, $subject, $content, $type, $sender
function getSelectedCompany() {
$company = Session::get('selected_company');
if (!$company) {
return response()->json(['message' => 'Company not found'], 404);
return false;
}
return $company;
}
@ -110,3 +185,194 @@ function containsHtml($string) {
return $string != strip_tags($string);
}
}
if (!function_exists('sendEmailViaMailgun')) {
function sendEmailViaMailgun( $domain, $from, $to, $subject, $html) {
$apiKey = env('MAILGUN_SECRET');
// Create a new Mailgun instance with API credentials
$mg = Mailgun::create($apiKey);
// Prepare the message parameters
$params = [
'from' => $from,
'to' => $to,
'subject' => $subject,
'html' => $html
];
// Send the email
$response = $mg->messages()->send($domain, $params);
// Return the response from Mailgun
return $response;
}
function createResponse($ticket_id, $message, $user_id = 0)
{
// Create a new Response instance
$response = new Response;
// Set the properties of the Response
$response->message = $message;
$response->ticket_id = $ticket_id;
$response->user_id = $user_id; // You may want to dynamically set the user_id based on the authenticated user
// Save the response to the database
$response->save();
// Return the created response
return $response;
}
}
/**
* Create a new chat group.
*
* @param int $companyId The ID of the company associated with the chat.
* @param int $userId The ID of the user creating the chat group.
* @param string $customerId Identifier for the customer involved in the chat.
* @param string $name Name or title of the chat group.
* @param string $email Email address associated with the chat group.
* @param string $subject Subject or initial topic of the chat group.
* @param string $status Current status of the chat group (e.g., 'active', 'closed').
* @return ChatGroup The newly created chat group object.
*/
function createChatGroup($companyId, $userId, $customerId, $name, $email, $subject, $status)
{
return ChatGroup::create([
'company_id' => $companyId,
'user_id' => $userId,
'customer_id' => $customerId,
'name' => $name,
'email' => $email,
'subject' => $subject,
'status' => $status
]);
}
/**
* Store a new message in a specified chat group.
*
* @param int $chatId The ID of the chat group.
* @param string $from Sender identifier.
* @param string $to Receiver identifier.
* @param string $message Content of the message.
* @param string $type Type of the message.
* @return Message The newly created message object.
*/
function storeMessage($chatId, $from, $to, $message, $type)
{
return Message::create([
'chat_id' => $chatId,
'from' => $from,
'to' => $to,
'message' => $message,
'type' => $type
]);
}
/**
* Retrieve all messages from a specified chat group.
*
* @param int $chatId The ID of the chat group.
* @return \Illuminate\Database\Eloquent\Collection A collection of messages.
*/
function getMessagesByChatId($chatId)
{
return Message::where('chat_id', $chatId)->orderBy('created_at', 'asc')->get();
}
function setTicketMeta(int $ticketId, string $key, $value, string $type = 'string')
{
$ticket_metas = [];
return TicketMeta::updateOrCreate(
['ticket_id' => $ticketId, 'key' => $key],
['value' => json_encode($value), 'type' => $type]
);
// foreach($value as $tag)
// {
// $ticket_meta = TicketMeta::updateOrCreate([
// 'ticket_id' => $ticketId,
// 'key' => $key
// ],[
// 'value' => $tag,
// 'type' => $type
// ]);
// $ticket_metas[] = $ticket_meta;
// }
// return $ticket_metas;
}
/**
* Get a meta value for a ticket.
*
* @param int $ticketId
* @param string $key
* @return string|null
*/
function getTicketMeta(int $ticketId, string $key)
{
$meta = TicketMeta::where('ticket_id', $ticketId)->where('key', $key)->first();
return $meta ? json_decode($meta->value) : null;
}
function getCompanyMeta(int $companyId, string $key)
{
$meta = CompanyMeta::where('company_id', $companyId)->where('key', $key)->first();
return $meta ? $meta->value : null;
}
function getChatSetting($key, $company_id = null)
{
$companyId = $company_id??getSelectedCompany();
$get_chat_setting = CompanyMeta::where('company_id', $companyId)->where('key', $key)->where('type', 'Chat Setting')->first();
return $get_chat_setting;
}
function getChatSettings($key, $company_id = null)
{
$companyId = $company_id??getSelectedCompany();
$get_chat_setting = CompanyMeta::where('company_id', $companyId)->where('key', $key)->where('type', 'Chat Setting')->get();
return $get_chat_setting;
}
function getCompanyRules()
{
$companyId = getSelectedCompany();
$rules = Rule::where('company_id', $companyId)->get();
return $rules;
}
function extractEmail($fromField) {
// Regular expression to extract email address within angle brackets or standalone
if (preg_match('/<?([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})>?/', $fromField, $matches)) {
return $matches[1]; // Return the email address
}
return null; // Return null if no email is found
}
function send_notification($user_id,$text,$type,$status='default')
{
$notify = new Notification;
$notify->user_id = $user_id;
$notify->text = $text;
$notify->status = $status;
$notify->type = $type;
$notify->save();
return $notify;
}

View File

@ -9,6 +9,9 @@
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\Services\MailgunService;
use App\Http\Controllers\Mailgun\MailgunController;
use App\Models\CompanyUser;
class LoginController extends Controller
{
@ -37,9 +40,13 @@ class LoginController extends Controller
*
* @return void
*/
protected $mailgunService;
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->mailgunService = app(MailgunService::class);
}
public function login()
@ -55,13 +62,52 @@ public function storeLogin(Request $request)
]);
if (Auth::attempt($credentials)) {
// dd(Auth::user());
if(Auth::user()->role_id == 3){
$company = CompanyUser::where('user_id',Auth::id())->first();
if($company){
Session::put('selected_company', $company->company_id);
return redirect('/dashboard');
}
}else{
if(!Auth::user()->Company) {
return redirect('/company-info');
} else {
$company = Company::where('user_id', Auth::id())->first();
Session::put('selected_company', $company->id);
return redirect('/dashboard');
$domain = $company->domain;
$mailgunDomain = $this->mailgunService->getDomain($domain);
if($mailgunDomain){
$state = $mailgunDomain->getDomain()->getState();
if($state == 'unverified'){
return redirect()->route('showDomain',$domain);
}elseif($state == 'active'){
if(empty($company->internal_email)){
$mailgun = new MailgunController();
$mailgun->createEmail($domain);
}
Session::put('selected_company', $company->id);
return redirect('/dashboard');
}
}
}
}
}
return redirect()->back()->with('error', 'Invalid Credentials');

View File

@ -0,0 +1,262 @@
<?php
namespace App\Http\Controllers\Chat;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Models\Company;
use App\Models\CompanyMeta;
use App\Models\ChatGroup;
use App\Models\Message;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Storage;
class ChatController extends Controller
{
public function chatDemo(Request $request){
return view('chat.demo');
}
public function CloseChat(Request $request){
$chat_id = $request->chat_id;
$chat = ChatGroup::find($chat_id);
if($chat){
$chat->status = 'closed';
$chat->save();
return true;
}else{
return false;
}
}
public function getChat(Request $request){
$chat_id = $request->chat_id;
return ChatGroup::find($chat_id);
}
public function getMessages(Request $request){
$chat_id = $request->chat_id;
return Message::where('chat_id',$chat_id)->get();
}
/**
* Start a new chat by creating a chat group.
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function startChat(Request $request)
{
$validator = Validator::make($request->all(), [
'company_id' => 'required|integer|exists:companies,id',
//'user_id' => 'required|integer|exists:users,id',
'customer_id' => 'required|string|max:255',
'name' => 'required|string|max:255',
'email' => 'required|email|max:255',
'subject' => 'required|string|max:1000',
//'status' => 'required|string|max:255'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$company_id = $request->company_id;
$user = $this->select_user($company_id);
if($user){
$data = [
'company_id' => $company_id,
'user_id' => $user->user_id,
'customer_id' => $request->customer_id,
'name' => $request->name,
'email' => $request->email,
'subject' => $request->subject,
'status' => 'open',
];
$chatGroup = ChatGroup::create($data);
return response()->json(['chat' => $chatGroup], 200);
}else{
return response()->json(['message' => 'user not found'], 400);
}
}
public function sendMessage(Request $request)
{
$validator = Validator::make($request->all(), [
'chat_id' => 'required|integer|exists:chat_group,id',
'from' => 'required|string|max:255',
//'to' => 'required|string|max:255',
//'message' => 'required|string',
'type' => 'required|string|max:255'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$fileUrl = '';
if ($request->hasFile('file')) {
$file = $request->file('file');
$filePath = $file->store('chat', 'public'); // Store in the 'public/uploads' directory
$fileUrl = url(Storage::url($filePath)); // Generate the file URL
}
$data = [
'chat_id' => $request->chat_id,
'from' => $request->from,
'to' => $request->from == 'user'?'company':'user',
'message' => $request->hasFile('file')? $fileUrl: $request->message,
'type' => $request->type,
];
$message = Message::create($data);
return response()->json(['message' => 'Message sent successfully', 'data' => $message], 200);
}
public function select_user($company_id){
$companyUsers = get_company_users($company_id);
//Get Max Number f Chats
$get_max_number_of_chats = CompanyMeta::where('company_id', $company_id)->where('key', 'max_number_of_chats_per_editor')->first();
if(!is_null($get_max_number_of_chats)){
$get_max_number_of_chats = $get_max_number_of_chats->value;
}else{
$get_max_number_of_chats = 5;
}
$selected = false;
foreach($companyUsers as $user){
$access = json_decode($user->access);
//Get Chat Groups
$chat_groups = ChatGroup::where('user_id', $user->user_id)->where('status', 'open')->count();
if(in_array('chat',$access) && $user->user->is_available == 1 && $chat_groups <= $get_max_number_of_chats){
$selected = $user;
break;
}
}
return $selected;
}
public function getChatGroupsByCompany(Request $request)
{
$companyId = getSelectedCompany();
$chatGroups = ChatGroup::where('company_id', $companyId)
->where(function($query) {
$query->where('status', '!=', 'ticket_created')
->where('status', '!=', 'closed');
})
->get();
return response()->json($chatGroups);
}
public function getIpAdresses($companyId)
{
return CompanyMeta::where('company_id', $companyId)
->where('type', 'Chat Setting')
->where('key', 'ip_addresses')
->pluck('value')
->toArray();
}
public function checkChat(Request $request){
$company_id = $request->company_id;
$domain = $request->domain;
$company = get_company('id',$company_id);
$ip_addresses = $this->getIpAdresses($company_id);
$ip = $_SERVER['REMOTE_ADDR'];
if(in_array($ip, $ip_addresses)) {
return response()->json(['status' => 'error', 'message' => 'this IP Address ' . $ip . ' has been blocked.']);
}
if($company){
// Str::contains('This is my name', 'my')
if( $company->domain == $domain ){
$start_message = getChatSetting('start_message',$company_id)?getChatSetting('start_message',$company_id)->value:"What can we help you with?"; //welcome message
$message_when_chat_is_closed = getChatSetting('message_when_chat_is_closed',$company_id)?getChatSetting('message_when_chat_is_closed',$company_id)->value:"No user is availble right now! Try later.";
$wellcome_text = getChatSetting('wellcome_text',$company_id)?getChatSetting('wellcome_text',$company_id)->value:"Hi, welcome how i can help you today?";
//Get Style
$styles = [
'text_theme_color' => getChatSetting('text_theme_color', $company_id) ? getChatSetting('text_theme_color', $company_id)->value : null,
'background_theme_color' => getChatSetting('background_theme_color', $company_id) ? getChatSetting('background_theme_color', $company_id)->value : null,
'text_color_for_sent_message' => getChatSetting('text_color_for_sent_message', $company_id) ? getChatSetting('text_color_for_sent_message', $company_id)->value : null,
'background_color_of_sent_message' => getChatSetting('background_color_of_sent_message', $company_id) ? getChatSetting('background_color_of_sent_message', $company_id)->value : null,
'background_color_of_received_message' => getChatSetting('background_color_of_received_message', $company_id) ? getChatSetting('background_color_of_received_message', $company_id)->value : null,
'text_color_of_received_message' => getChatSetting('text_color_of_received_message', $company_id) ? getChatSetting('text_color_of_received_message', $company_id)->value : null,
'text_color_of_notification' => getChatSetting('text_color_of_notification', $company_id) ? getChatSetting('text_color_of_notification', $company_id)->value : null,
'text_color_of_error_message' => getChatSetting('text_color_of_error_message', $company_id) ? getChatSetting('text_color_of_error_message', $company_id)->value : null,
'background_color_of_error_message' => getChatSetting('background_color_of_error_message', $company_id) ? getChatSetting('background_color_of_error_message', $company_id)->value : null,
'link_color' => getChatSetting('link_color', $company_id) ? getChatSetting('link_color', $company_id)->value : null,
];
//Get Display
$settings = getChatSettings('Display Chat', $company_id);
$display_chats = $settings ? $settings->pluck('value')->map(function($value) {
return json_decode($value);
}) : null;
$hide_chats = getChatSetting('Hide Chat', $company_id) ? getChatSetting('Hide Chat', $company_id)->value : null;
$displays = [
'display_chats' => $display_chats,
'hide_chat' => $hide_chats,
];
//Get Canned Responses
$canned_responses = getChatSettings('Chat Canned Responses', $company_id);
$canned_responses = $canned_responses ? $canned_responses->pluck('value')->map(function($value) {
return json_decode($value);
}) : null;
//Terms And Conditions
$link_text = "https://kundesone.no/terms-and-conditions/$company_id";//getChatSetting('link_text', $company_id) ? getChatSetting('link_text', $company_id)->value : null;
$user = $this->select_user($company_id);
if($user){
return response()->json(['status' => 'success','data' => ['welcome' => $wellcome_text, 'start_message' => $start_message, 'user' => $user->user->name, 'styles' => $styles,
'displays' => $displays, 'canned_responses' => $canned_responses, 'link_text' => $link_text] ]);
}else{
return response()->json(['status' => 'error', 'message' => $message_when_chat_is_closed]);
}
}else{
return response()->json(['status' => 'error', 'message' => "You are not authorized!"]);
}
}
return response()->json(['status' => 'error', 'message' => "You are not authorized!"]);
}
}

View File

@ -0,0 +1,326 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\CompanyMeta;
class ChatSettingController extends Controller
{
public function chatSetting()
{
$display_chats = CompanyMeta::where('key', 'Display Chat')->where('type', 'Chat Setting')->get();
$hide_chats = CompanyMeta::where('key', 'Hide Chat')->where('type', 'Chat Setting')->first();
$canned_responses = CompanyMeta::where('key', 'Chat Canned Responses')->where('type', 'Chat Setting')->get();
$abuses = CompanyMeta::where('key', 'ip_addresses')->where('type', 'Chat Setting')->get();
return view('chat-setting', ['display_chats' => $display_chats, 'hide_chats' => $hide_chats, 'canned_responses' => $canned_responses, 'abuses' => $abuses]);
}
public function storeFlowSetting(Request $request)
{
$companyId = getSelectedCompany();
//Update Company Meta
$flow_setting = [
'show_profile_image_of_editors' => $request->show_profile_image_of_editors,
'allow_visitor_to_send_messages' => $request->allow_visitor_to_send_messages,
'max_number_of_chats_per_editor' => $request->max_number_of_chats_per_editor,
'save_email_address_for_anonymous_chat' => $request->save_email_address_for_anonymous_chat,
'delete_chat_data_automatically' => $request->delete_chat_data_automatically,
'delay_for_automatic_deletion' => $request->delay_for_automatic_deletion,
'allow_users_to_join_queue' => $request->allow_users_to_join_queue,
'show_chat_button' => $request->show_chat_button,
'visitor_can_send_images' => $request->visitor_can_send_images,
'guest_must_write_name_and_email_to_chat' => $request->guest_must_write_name_and_email_to_chat,
'logout_editor_who_missed_chat' => $request->logout_editor_who_missed_chat,
'logout_everyone_automatically' => $request->logout_everyone_automatically,
'chat_assistant_show_suggestion_form' => $request->chat_assistant_show_suggestion_form,
'message_sent_to' => $request->message_sent_to,
];
foreach($flow_setting as $key => $value) {
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => $key,
'value' => $value,
'type' => 'Chat Setting'
]);
} else {
CompanyMeta::where('key', $key)->where('company_id', $companyId)->where('type', 'Chat Setting')->delete();
}
}
return redirect()->back()->with('success', 'Flow Setting Updated Successfully');
}
public function storeDisplayChat(Request $request)
{
$this->validate($request, [
'path' => 'required',
'start_chat_after' => 'required'
]);
$companyId = getSelectedCompany();
// Collect data into an array
$display_data = [
'path' => $request->path,
'start_chat_after' => $request->start_chat_after,
];
CompanyMeta::create([
'company_id' => $companyId,
'key' => 'Display Chat',
'value' =>json_encode($display_data),
'type' => 'Chat Setting'
]);
return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
}
public function deleteDisplayChat($id)
{
$display_chat = CompanyMeta::find($id);
$display_chat->delete();
return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
}
public function storeHideChat(Request $request)
{
$this->validate($request, [
'hide_chat_path' => 'required',
]);
$companyId = getSelectedCompany();
CompanyMeta::updateOrCreate([
'company_id' => $companyId,
'key' => 'Hide Chat',
],[
'company_id' => $companyId,
'key' => 'Hide Chat',
'value' => $request->hide_chat_path,
'type' => 'Chat Setting'
]);
return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
}
public function storeText(Request $request)
{
$companyId = getSelectedCompany();
//Update Company Meta
$text_data = [
'public_name' => $request->public_name,
'internal_name' => $request->internal_name,
'wellcome_text' => $request->wellcome_text,
'wellcome_text_at_queue' => $request->wellcome_text_at_queue,
'start_message' => $request->start_message,
'text_in_message_box' => $request->text_in_message_box,
'message_when_chat_is_closed' => $request->message_when_chat_is_closed
];
foreach($text_data as $key => $value) {
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => $key,
'value' => $value,
'type' => 'Chat Setting'
]);
} else {
CompanyMeta::where('key', $key)->where('company_id', $companyId)->where('type', 'Chat Setting')->delete();
}
}
return response()->json(['success' => 'Text Setting Updated Successfully']);
}
public function storeStyle(Request $request)
{
$companyId = getSelectedCompany();
//Update Company Meta
$style_data = [
'text_theme_color' => $request->text_theme_color,
'background_theme_color' => $request->background_theme_color,
'text_color_for_sent_message' => $request->text_color_for_sent_message,
'background_color_of_sent_message' => $request->background_color_of_sent_message,
'background_color_of_received_message' => $request->background_color_of_received_message,
'text_color_of_received_message' => $request->text_color_of_received_message,
'text_color_of_notification' => $request->text_color_of_notification,
'text_color_of_error_message' => $request->text_color_of_error_message,
'background_color_of_error_message' => $request->background_color_of_error_message,
'link_color' => $request->link_color
];
foreach($style_data as $key => $value) {
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => $key,
'value' => $value,
'type' => 'Chat Setting'
]);
} else {
CompanyMeta::where('key', $key)->where('company_id', $companyId)->where('type', 'Chat Setting')->delete();
}
}
return redirect()->back()->with('success', 'Style Setting Updated Successfully');
}
public function storeChatCannedResponses(Request $request)
{
$this->validate($request, [
'name' => 'required',
'text' => 'required'
]);
$companyId = getSelectedCompany();
// Collect data into an array
$canned_data = [
'name' => $request->name,
'text' => $request->text,
];
// Encode the data array as JSON
$jsonData = json_encode($canned_data);
CompanyMeta::create([
'company_id' => $companyId,
'key' => 'Chat Canned Responses',
'value' => $jsonData,
'type' => 'Chat Setting'
]);
return redirect()->back()->with('success', 'Canned Response Setting Updated Successfully');
}
public function deleteChatCannedResponses($id)
{
$get_chat_canned_response = CompanyMeta::find($id);
$get_chat_canned_response->delete();
return redirect()->back()->with('success', 'Canned Response Deleted Successfully.');
}
public function storePersonalData(Request $request)
{
$companyId = getSelectedCompany();
//Update Company Meta
$personal_data = [
'name' => $request->name,
'link_text' => $request->link_text,
'active_approval' => $request->active_approval,
];
foreach($personal_data as $key => $value) {
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => $key,
'value' => $value,
'type' => 'Chat Setting'
]);
} else {
CompanyMeta::where('key', $key)->where('company_id', $companyId)->where('type', 'Chat Setting')->delete();
}
}
return redirect()->back()->with('success', 'Personal Data Updated Successfully');
}
public function storeTags(Request $request)
{
$companyId = getSelectedCompany();
//Update Company Meta
$tags_data = [
'new_tags_to_be_created_when_tagging' => $request->new_tags_to_be_created_when_tagging,
];
foreach($tags_data as $key => $value) {
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => $key,
'value' => $value,
'type' => 'Chat Setting'
]);
} else {
CompanyMeta::where('key', $key)->where('company_id', $companyId)->where('type', 'Chat Setting')->delete();
}
}
return redirect()->back()->with('success', 'Tags Updated Successfully');
}
public function settingAllChat(Request $request)
{
$this->validate($request, [
'heading_for_chat_flow' => 'required'
]);
$companyId = getSelectedCompany();
CompanyMeta::updateOrCreate([
'key' => 'heading_for_chat_flow',
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => 'heading_for_chat_flow',
'value' => $request->heading_for_chat_flow,
'type' => 'Chat Setting'
]);
return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
}
public function blockIpAdresses(Request $request)
{
$this->validate($request, [
'ip_addresses' => 'required'
]);
$companyId = getSelectedCompany();
CompanyMeta::create([
'company_id' => $companyId,
'key' => 'ip_addresses',
'value' => $request->ip_addresses,
'type' => 'Chat Setting'
]);
return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
}
public function deleteBlockIpAdresses($id)
{
$get_ip_address = CompanyMeta::find($id);
$get_ip_address->delete();
return redirect()->back()->with('success', 'IP Address Deleted Successfully.');
}
public function companyTermsAndConditions($companyId)
{
$link_text = getChatSetting('link_text', $companyId)->value;
return view('terms-conditions', ['link_text' => $link_text]);
}
}

View File

@ -22,9 +22,9 @@ public function storeCompany(Request $request)
if(Session::has('user_id') || Auth::id()) {
$messages = [
$messages = [
'company_domain.unique' => 'The domain has already been registered.',
'company_domain.regex' => 'Please enter a valid domain format. e.g (example.com) wihtout https and /'
'company_domain.regex' => 'Please enter a valid domain format, e.g., example.com (without https and /)'
];
$this->validate($request, [
@ -32,11 +32,12 @@ public function storeCompany(Request $request)
'company_email' => 'required|email',
'company_domain' => [
'required',
'regex:/^([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+.*)$/',
'regex:/^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+)$/', // Updated regex
'unique:companies,domain'
],
], $messages);
$company = Company::updateOrCreate([
'user_id' => Session::has('user_id') ? Session::get('user_id') : Auth::id(),
],[

View File

@ -8,30 +8,70 @@
use App\Models\User;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use App\Models\CompanyMeta;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class DashboardController extends Controller
{
public function dashboard()
{
$companyId = Session::get('selected_company');
$company = Company::find($companyId);
$tickets = Ticket::where('type', 'inbox')
->where('to_email', 'LIKE', '%' . $company->domain)
->get();
return view('index', ['tickets' => $tickets]);
$tickets = get_current_company_tickets(['type' => 'inbox']);
$companyId = getSelectedCompany();
$tags = getCompanyTags($companyId);
$canned_response = $this->get_canned_responses();
return view('index', ['tickets' => $tickets, 'tags' => $tags, 'canned_response' => $canned_response]);
}
public function waiting()
{
$companyId = Session::get('selected_company');
$company = Company::find($companyId);
$tickets = Ticket::where('status', 'waiting')->where('type', 'chat')->where('to_email', 'LIKE', '%' . $company->domain)->get();
return view('waiting', ['tickets' => $tickets]);
public function get_canned_responses(){
$companyId = getSelectedCompany();
return CompanyMeta::where('company_id', $companyId)->where('key', 'canned_responses')->get();
}
public function profile()
{
$users = User::where('role_id', '!=', 1)->where('id', '!=', Auth::id())->get();
return view('profile', ['users' => $users]);
$company = getSelectedCompany();
$user = Auth::user();
$users = $users = User::where('role_id', '!=', 1)
//->where('id', '!=', Auth::id())
->join('company_users', 'users.id', '=', 'company_users.user_id')
->where('company_users.company_id', $company)
->select('users.*')
->get();
return view('profile', ['users' => $users, 'user' => $user]);
}
public function updateProfile(Request $request)
{
$request->validate([
'name' => 'required|string',
'profile_image' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
]);
$user = Auth::user();
if($request->hasFile('profile_image')) {
//Remove Old Image
if ($user->profile_image) {
$oldImagePath = str_replace('/storage/', '', $user->profile_image);
Storage::disk('public')->delete($oldImagePath);
}
//Store New Image
$file = $request->file('profile_image');
$extension = $file->getClientOriginalExtension();
$filename = time() . '_' . Str::slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME)) . '.' . $extension;
$path = $file->storeAs('profile_images', $filename, 'public');
$user->profile_image = Storage::url($path);
}
//update user
$user->name = $request->name;
$user->save();
return back()->with('success', 'Profile Updated Successfully');
}
}

View File

@ -6,23 +6,43 @@
use App\Models\Timezone;
use App\Models\User;
use App\Models\Ticket;
use App\Models\Comment;
use App\Models\Response;
use App\Models\Language;
use App\Models\Tag;
use App\Models\Rule;
use App\Models\CompanyMeta;
use App\Models\CompanyUser;
use Carbon\Carbon;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Auth;
class InboxController extends Controller
{
public function get_canned_responses(){
$companyId = getSelectedCompany();
return CompanyMeta::where('company_id', $companyId)->where('key', 'canned_responses')->get();
}
public function inboxSetting()
{
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
$timezones = Timezone::all();
$languages = Language::all();
$languages = Language::where('title', 'English (US)')->get();
$basic_setting = CompanyMeta::where('company_id', $companyId)->where('type', 'Basic Setting')->get();
$canned_response = CompanyMeta::where('company_id', $companyId)->where('type', 'Canned Response')->first();
$canned_response = $this->get_canned_responses();
$spam_handling = CompanyMeta::where('company_id', $companyId)->where('type', 'Spam Handling')->first();
$email_signature = CompanyMeta::where('company_id', $companyId)->where('type', 'Email Signature')->first();
$company_users = get_company_users($companyId);
$tags = Tag::where('company_id', $companyId)->get();
$rule = Rule::where('company_id', $companyId)->first();
return view('inbox-setting', ['timezones' => $timezones, 'basic_setting' => $basic_setting, 'spam_handling' => $spam_handling,
'email_signature' => $email_signature, 'canned_response' => $canned_response, 'languages' => $languages]);
'email_signature' => $email_signature, 'canned_response' => $canned_response, 'languages' => $languages, 'company' => get_company('id',$companyId),
'company_users' => $company_users, 'tags' => $tags, 'rule' => $rule]);
}
public function basicSetting(Request $request)
@ -36,7 +56,7 @@ public function basicSetting(Request $request)
'timezone' => ['required'],
]);
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
//Update Company Meta
$basic_data = [
@ -50,9 +70,9 @@ public function basicSetting(Request $request)
foreach($basic_data as $key => $value) {
CompanyMeta::updateOrCreate([
'key' => $key,
'value' => $value
],[
'company_id' => $companyId,
],[
'key' => $key,
'value' => $value,
'type' => 'Basic Setting'
@ -68,13 +88,11 @@ public function emailSignature(Request $request)
'email_signature' => 'required'
]);
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
CompanyMeta::updateOrCreate([
'key' => 'email_signature',
'value' => $request->email_signature
'company_id' => $companyId,
],[
'company_id' => $companyId,
'key' => 'email_signature',
'value' => $request->email_signature,
'type' => 'Email Signature'
]);
@ -84,7 +102,7 @@ public function emailSignature(Request $request)
public function responseTime(Request $request)
{
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
//Update Company Meta
$response_data = [
'monday_start_time' => $request->monday_start_time,
@ -115,9 +133,9 @@ public function responseTime(Request $request)
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'value' => $value
],[
'company_id' => $companyId,
],[
'key' => $key,
'value' => $value,
'type' => 'Response Time'
@ -137,36 +155,34 @@ public function cannedResponse(Request $request)
'text' => 'required'
]);
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
// Collect data into an array
$canned_data = [
$canned_data =
[
'name' => $request->name,
'text' => $request->text,
]
];
];
// Retrieve existing canned responses
$existingMeta = CompanyMeta::where('company_id', $companyId)
->where('key', 'canned_responses')
->where('type', 'Canned Response')
->first();
// $existingMeta = CompanyMeta::where('company_id', $companyId)
// ->where('key', 'canned_responses')
// ->where('type', 'Canned Response')
// ->first();
// Decode existing JSON data if it exists
if ($existingMeta) {
$existingData = json_decode($existingMeta->value, true);
$canned_data = array_merge($existingData, $canned_data);
}
// // Decode existing JSON data if it exists
// if ($existingMeta) {
// $existingData = json_decode($existingMeta->value, true);
// $canned_data = array_merge($existingData, $canned_data);
// }
// Encode the data array as JSON
// // Encode the data array as JSON
$jsonData = json_encode($canned_data);
// Update or create the CompanyMeta entry
CompanyMeta::updateOrCreate([
'company_id' => $companyId,
'key' => 'canned_responses',
], [
CompanyMeta::create([
'company_id' => $companyId,
'key' => 'canned_responses',
'value' => $jsonData,
@ -178,27 +194,26 @@ public function cannedResponse(Request $request)
public function deleteCannedResponse($index)
{
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
// Retrieve the existing canned responses
$cannedMeta = CompanyMeta::where('company_id', $companyId)
CompanyMeta::where('company_id', $companyId)
->where('key', 'canned_responses')
->where('type', 'Canned Response')
->first();
->where('id', $index)
->delete();
if ($cannedMeta) {
$canned_data = json_decode($cannedMeta->value, true);
// if ($cannedMeta) {
// $canned_data = json_decode($cannedMeta->value, true);
if (isset($canned_data[$index])) {
unset($canned_data[$index]);
// if (isset($canned_data[$index])) {
// unset($canned_data[$index]);
$canned_data = array_values($canned_data);
$jsonData = json_encode($canned_data);
// $canned_data = array_values($canned_data);
// $jsonData = json_encode($canned_data);
$cannedMeta->value = $jsonData;
$cannedMeta->save();
}
}
// $cannedMeta->value = $jsonData;
// $cannedMeta->save();
// }
// }
return redirect()->back()->with('success', 'Canned response deleted successfully.');
@ -206,7 +221,7 @@ public function deleteCannedResponse($index)
public function acknowledgementReceipt(Request $request)
{
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
//Update Company Meta
$acknowledgement_data = [
'automatic_reply_subject' => $request->automatic_reply_subject,
@ -220,10 +235,10 @@ public function acknowledgementReceipt(Request $request)
if(!is_null($value)) {
CompanyMeta::updateOrCreate([
'key' => $key,
'value' => $value
],[
'company_id' => $companyId,
'key' => $key,
],[
'value' => $value,
'type' => 'Acknowledgement of Receipt'
]);
@ -241,7 +256,7 @@ public function spamHandling(Request $request)
'spam_email' => 'required|email'
]);
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
// Collect data into an array
$canned_data = [
@ -282,7 +297,7 @@ public function spamHandling(Request $request)
public function deleteSpamHandling($index)
{
$companyId = Auth::user()->company->id;
$companyId = getSelectedCompany();
// Retrieve the existing canned responses
$spamMeta = CompanyMeta::where('company_id', $companyId)
@ -309,9 +324,20 @@ public function deleteSpamHandling($index)
public function inbox()
{
$tickets = Ticket::orderBy('id', 'desc')->with('lastResponse')->get();
$tickets = get_current_company_tickets([
'type' => 'inbox',
'orderby' => 'id',
'order' => 'desc',
'with' => 'lastResponse'
]);
$messages = [];
return view('inbox', ['tickets' => $tickets, 'messages' => $messages]);
$canned_response = $this->get_canned_responses();
return view('inbox', ['tickets' => $tickets, 'messages' => $messages, 'canned_response' => $canned_response]);
}
public function fetchChatMessages($ticketId)
@ -324,8 +350,104 @@ public function fetchChatMessages($ticketId)
public function fetchActionBox($ticketId)
{
$selectedCompany = getSelectedCompany();
$ticket = Ticket::where('id', $ticketId)->with('comments')->first();
$companyUsers = get_company_users($selectedCompany);//CompanyUser::where('company_id', $selectedCompany)->with('user')->get();
return view('partials.action-box', compact('ticket'))->render();
return view('partials.action-box', compact('ticket','companyUsers'))->render();
}
public function storeResponse(Request $request)
{
$this->validate($request, [
'message' => 'required',
'ticket_id' => 'required',
]);
// Handle both single and multiple ticket IDs
$ticket_ids = explode(',', $request->ticket_id);
$messageWithClasses = $request->message;
foreach ($ticket_ids as $ticket_id) {
$response = createResponse($ticket_id, $messageWithClasses, 1);
$ticket = Ticket::find($ticket_id);
if (!$ticket) continue;
$companyId = Session::get('selected_company');
$company = get_company('id', $companyId);
// Send mail to mailgun
$domain = $company->domain;
$company_name = $company->getMeta('sender_name') ?? $company->name;
$from = "$company_name <$company->email>";
$to = $ticket->from_email;
$subject = $ticket->subject;
$html = $request->message;
// Call the function to send the email
sendEmailViaMailgun($domain, $from, $to, $subject, $html);
}
return response()->json([
'message' => strip_tags($response->message),
'created_at' => $response->created_at->format('h:i A')
]);
}
public function storeComment(Request $request)
{
$request->validate([
'ticket_id' => 'required|exists:tickets,id',
'comment' => 'required|string',
]);
// Assuming authenticated user
$user_id = auth()->id();
$comment = new Comment();
$comment->author = $user_id;
$comment->ticket_id = $request->ticket_id;
$comment->comment = $request->comment;
$comment->save();
return $comment;
}
public function deleteComment($commentId)
{
$comment = Comment::findOrFail($commentId);
$comment->delete();
return response()->json(['message' => 'Comment Deleted Successfully']);
}
public function updateRule(Request $request)
{
$companyId = getSelectedCompany();
//Update Rule
Rule::updateOrCreate([
'company_id' => $companyId,
],[
'company_id' => $companyId,
'from' => $request->from,
'to' => $request->to,
'subject_contains' => $request->subject_contains,
'text_contains' => $request->text_contains,
'subject1_contains' => $request->subject1_contains,
'tag_id' => $request->tag_id,
'name' => $request->name,
'assign_to' => $request->assign_to,
'status' => isset($request->status) ? $request->status : 'set as done',
'priority' => isset($request->priority) ? $request->priority : 'Set highest priority',
'message_to_assigned_editor' => $request->message_to_assigned_editor,
'all_emails_automatically_mark_as_spam' => $request->all_emails_automatically_mark_as_spam,
]);
return redirect()->back()->with('success', 'Setting Updated successfully.');
}
}

View File

@ -4,39 +4,139 @@
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use App\Models\Ticket;
use App\Models\Response;
class EmailController extends Controller
{
public function saveEmail(Request $request){
$token = $request->input('token');
$timestamp = $request->input('timestamp');
$signature = $request->input('signature');
// DB::beginTransaction();
// if (!verifyMailgunSignature($token, $timestamp, $signature)) {
// abort(403, 'Invalid signature.');
// }
// try {
$file_urls = [];
$token = $request->input('token');
$timestamp = $request->input('timestamp');
$signature = $request->input('signature');
$data = $this->extractMailgunData($request->all());
insertTicket($data['from_email'], $data['to_email'], $data['subject'], $data['message'] );
update_setting('aw_test',json_encode($request->all()));
if (!verifyMailgunSignature($token, $timestamp, $signature)) {
update_setting('aw_test','Invalid signature.');
abort(403, 'Invalid signature.');
}
update_setting('aw_test',json_encode($request->all()));
$data = $this->extractMailgunData($request->all());
$to_email = $data['to_email'];
$message = $data['message'];
//update_setting('aw_test',$to_email);
$company = get_company('email',$to_email);
if($company){
$ticket = insertTicket($data['from_email'], $company->email, $data['subject'], $message,'inbox',$data['from_name'] );
if($ticket){
//Check Email if it is spam
$get_spam_handlings = getResponse($company->id,'spam_handling', 'Spam Handling');
if(!is_null($get_spam_handlings)) {
//pluck spam emails
$values = json_decode($get_spam_handlings->value, true);
$spam_emails = array_map(function ($item) {
return $item['spam_email'];
}, $values);
if(in_array($data['from_email'], $spam_emails)) {
//update status
$ticket->status = 'spam';
$ticket->save();
}
}
$this->sendEmail($company,$ticket->id);
$response = createResponse($ticket->id,$message);
$attachmentCount = $request->input('attachment-count', 0);
for ($i = 1; $i <= $attachmentCount; $i++) {
$attachment = $request->file("attachment-$i");
// update_setting('aw_test',$attachment->getClientOriginalName());
if ($attachment && $attachment->isValid()) {
// Define a unique filename, possibly using the original filename and appending a timestamp or a unique id
$filename = time() . '_' . $attachment->getClientOriginalName();
// Save the attachment to the local or specific disk
$filePath = $attachment->storeAs('tickets/' . $ticket->id, $filename, 'public');
$fileUrl = Storage::url($filePath);
$file_urls[] = $fileUrl;
}
}
//Update Responses Table with Attachments
if(count($file_urls) > 0) {
$response->attachments = json_encode($file_urls);
$response->save();
}
}
}else{}
//update_setting('aw_test',json_encode($request->all()));
// DB::commit();
// } catch (\Exception $e) {
// DB::rollBack();
// update_setting('aw_test',json_encode($e->getMessage()));
// sendEmailViaMailgun( 'ai.rapidev.tech', 'support@ai.rapidev.tech', '16bsse18212@gmail.com', 'error', json_encode($e->getMessage()));
// // Handle the exception
// }
}
private function sendEmail($company,$ticketId)
{
$ticket = Ticket::find($ticketId);
$responses = Response::where('ticket_id', $ticket->id)->get();
$activate_delivery_confirmation = getCompanyMeta($company->id,'activate_delivery_confirmation');
$subject = getCompanyMeta($company->id,'automatic_reply_subject');
$subject = str_replace(['{title}', '{ticket}'], [$ticket->subject, $ticket->id], $subject);
$message = getCompanyMeta($company->id,'automatic_reply_text');
$message = str_replace(['{title}', '{text}', '{ticket}', '{name}'], [$ticket->subject, $ticket->content, $ticket->id, $ticket->sender_name], $message);
if ($ticket && count($responses) == 0 && !is_null($subject) && !is_null($message) && $activate_delivery_confirmation == 'on') {
$company_name = $company->getMeta('sender_name')??$company->name;
$from = "$company_name <$company->email>";
sendEmailViaMailgun($company->domain, $from, $ticket->from_email, $subject, $message);
}
//Update Ticket With Subject2
$ticket->subject2 = $subject;
$ticket->save();
}
public function extractMailgunData($data) {
// Decode the JSON payload into an associative array
// $data = json_decode($jsonPayload, true);
// Prepare an array to hold the extracted data
$from = extractEmail($data['from']);
$to = extractEmail($data['To']);
$extractedData = [
'from_email' => $data['from'],
'to_email' => $data['To'],
'from_email' => $from,
'to_email' => $to,
'from_name' => '', // This will be extracted from the 'from' field
'subject' => $data['subject'],
'message' => $data['body-plain'],
'message' => isset($data['body-html'])?$data['body-html']:$data['body-plain'],
'mime_version' => $data['Mime-Version'],
'dkim_signature' => $data['Dkim-Signature']
];
@ -46,7 +146,7 @@ public function extractMailgunData($data) {
$extractedData['from_name'] = $matches[1];
$extractedData['from_email'] = $matches[2];
}
return $extractedData;
}
}

View File

@ -5,14 +5,35 @@
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Services\MailgunService;
use Illuminate\Support\Str;
use App\Services\CPanelApiService;
use Illuminate\Support\Facades\Storage;
class MailgunController extends Controller
{
protected $mailgunService;
protected $cpanelApiService;
public function __construct()
{
$this->mailgunService = app(MailgunService::class); // Resolving through the service container
$this->cpanelApiService = app(CPanelApiService::class);
}
public function test(){
$domain = 'test.com';
$email = "kundesone.$domain@mailgun.kundesone.no";
$company = get_company('id',14);
// $folderPath = 'tickets/51'; // Adjust the path according to your structure
// if (Storage::disk('public')->exists($folderPath)) {
// Storage::disk('public')->deleteDirectory($folderPath);
// }
dd($company->getMeta('sender_name'));
}
public function addDomain($domain)
@ -33,7 +54,7 @@ public function addDomain($domain)
$response = $this->mailgunService->addDomain($domain);
return route('showDomain',$domain)->redirect();
return redirect()->route('showDomain',$domain);
}else{
return redirect()->route('showDomain',$domain);
@ -60,16 +81,33 @@ public function showDomain($domain){
public function verifyDomain(Request $request)
{
$domain = $request->input('domain');
$response = $this->mailgunService->verifyDomain($domain);
$result = $this->is_domain_verified($domain);
if($result){
$email = "kundesone.$domain@mailgun.kundesone.no";
$this->createEmail($domain);
return redirect('/dashboard');
}else{
return redirect()->route('showDomain',$domain);
}
}
public function is_domain_verified($domain){
$response = $this->mailgunService->verifyDomain($domain);
$state = $response->getDomain()->getState();
if($state == 'unverified'){
return redirect()->route('showDomain',$domain);
return false;
}elseif($state == 'active'){
$this->createRoute($request);
return redirect('/dashboard');
//$this->createRoute($request);
return true;
}
}
@ -81,6 +119,30 @@ public function createRoute(Request $request)
$response = $this->mailgunService->createRoute($domain, $forwardUrl);
return $response;
}
public function createEmail($domain){
$email = "kundesone.$domain@mailgun.kundesone.no";
$password = Str::random(12);
$quota = 0;
$response = $this->cpanelApiService->createEmailAccount($domain, $email, $password, $quota);
if (isset($response['error'])) {
return false;
}
$company = get_company('domain',$domain);
if($company){
$company->internal_email = $email;
$company->save();
}
return $email;
}
}

View File

@ -4,52 +4,65 @@
use Illuminate\Http\Request;
use App\Models\Ticket;
use App\Models\TicketMeta;
use App\Models\TicketNote;
use App\Models\Comment;
use App\Models\Response;
use App\Models\Company;
use App\Models\CompanyMeta;
use App\Models\Tag;
use Carbon\Carbon;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class TicketController extends Controller
{
public function allTickets()
{
$tickets = Ticket::all();
return view('all-tickets', ['tickets' => $tickets]);
public function get_canned_responses(){
$companyId = getSelectedCompany();
return CompanyMeta::where('company_id', $companyId)->where('key', 'canned_responses')->get();
}
public function storeResponse(Request $request)
public function allTickets()
{
$this->validate($request, [
'message' => 'required'
]);
// Load the HTML content into DOMDocument
$dom = new \DOMDocument();
libxml_use_internal_errors(true); // Prevents HTML errors from being thrown as exceptions
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $request->message);
libxml_clear_errors();
$companyId = getSelectedCompany();
$tickets = get_current_company_tickets(['type' => 'chat']);
$tags = Tag::where('company_id', $companyId)->get();
return view('all-tickets', ['tickets' => $tickets, 'tags' => $tags]);
}
// Get all <p> tags
$paragraphs = $dom->getElementsByTagName('p');
public function waiting()
{
$tickets = get_current_company_tickets(['status' => 'waiting']);
return view('waiting', ['tickets' => $tickets]);
}
// Add classes to each <p> tag
foreach ($paragraphs as $paragraph) {
$existingClasses = $paragraph->getAttribute('class');
$paragraph->setAttribute('class', trim($existingClasses . ' user-message bg-light-green-color color-light'));
}
// Save the modified HTML
$messageWithClasses = $dom->saveHTML($dom->documentElement);
public function showTicket($id)
{
$companyId = getSelectedCompany();
$tickets = get_current_company_tickets([
'type' => 'inbox',
'orderby' => 'id',
'order' => 'desc',
'with' => 'lastResponse'
]);
$single_ticket = Ticket::find($id);
$messages = [];
$canned_response = $this->get_canned_responses();
$email_signature = CompanyMeta::where('company_id', $companyId)->where('type', 'Email Signature')->first();
$response = new Response;
$response->message = $messageWithClasses;
$response->ticket_id = $request->ticket_id;
$response->user_id = 1;
$response->save();
// Return the updated response and time
return response()->json([
'message' => strip_tags($response->message), // Stripping HTML tags
'created_at' => $response->created_at->format('h:i A') // Formatting time
return view('show-ticket', [
'tickets' => $tickets,
'single_ticket' => $single_ticket,
'messages' => $messages,
'canned_response' => $canned_response,
'email_signature' => $email_signature?$email_signature->value:''
]);
}
@ -67,22 +80,257 @@ public function updateStatus(Request $request, $ticketId)
return response()->json(['message' => 'Ticket status updated successfully']);
}
public function storeComment(Request $request)
public function updateTicket(Request $request, $ticketId)
{
$request->validate([
'ticket_id' => 'required|exists:tickets,id',
'comment' => 'required|string',
]);
// Assuming authenticated user
$user_id = auth()->id();
$comment = new Comment();
$comment->author = $user_id;
$comment->ticket_id = $request->ticket_id;
$comment->comment = $request->comment;
$comment->save();
$ticket = Ticket::find($ticketId);
//Update Ticket
if(isset($request->priority)) {
$ticket->priority = $request->priority;
}
if(isset($request->user_assigned)) {
$ticket->user_assigned = $request->user_assigned;
}
$ticket->save();
return $comment;
return response()->json(['success' => true, 'message' => 'Ticket Updated successfully!']);
}
public function storeTags(Request $request)
{
$company = getSelectedCompany();
$ticket_id = $request->ticket_id;
$tags = json_decode($request->tags);
TicketMeta::where('key','tags')->where('ticket_id',$ticket_id)->delete();
foreach($tags as $tag)
{
TicketMeta::create(
['ticket_id' => $ticket_id, 'key' => 'tags',
'value' => $tag->value, 'type' => 'string']
);
//Update Tags Table
Tag::updateOrCreate([
'company_id' => $company,
'name' => $tag->value
],[
'company_id' => $company,
'name' => $tag->value,
'type' => 'inbox'
]);
//Update Company Meta Table
// CompanyMeta::updateOrCreate([
// 'company_id' => $company,
// 'value' => $tag->value
// ],[
// 'company_id' => $company,
// 'value' => $tag->value,
// 'key' => 'tag',
// 'type' => 'tags'
// ]);
}
return response()->json(['success' => true, 'message' => 'Tags Added Successfully']);
}
public function AssignTicket(Request $request)
{
$this->validate($request, [
'user_assigned' => 'required|integer',
'message' => 'required|string',
'ticket_ids' => 'required|string',
]);
$companyId = getSelectedCompany();
$ticketIds = explode(',', $request->ticket_ids);
foreach ($ticketIds as $ticket_id) {
$ticket = Ticket::find($ticket_id);
if ($ticket) {
// Update Ticket
$ticket->user_assigned = $request->user_assigned;
$ticket->save();
//Send Mail
$company = Company::find($companyId);
sendEmailViaMailgun($company->domain, $company->email, $ticket->from_email, $ticket->subject, $request->message);
//Create Response
$formattedMessage = '<p>' . $request->message . '</p>';
createResponse($ticket_id,$formattedMessage,auth()->id());
}
}
return response()->json(['success' => true, 'message' => 'Post Assigned Successfully']);
}
public function deleteTickets(Request $request)
{
$this->validate($request, [
'ticket_ids' => 'required|string',
]);
$ticketIds = explode(',', $request->ticket_ids);
foreach ($ticketIds as $ticket_id) {
$ticket = Ticket::find($ticket_id);
if ($ticket) {
// Delete Ticket
Comment::where('ticket_id', $ticket_id)->delete();
TicketMeta::where('ticket_id', $ticket_id)->delete();
Response::where('ticket_id', $ticket_id)->delete();
TicketNote::where('ticket_id', $ticket_id)->delete();
//Delete Attachments
$folderPath = "tickets/$ticket_id"; // Adjust the path according to your structure
if (Storage::disk('public')->exists($folderPath)) {
Storage::disk('public')->deleteDirectory($folderPath);
}
$ticket->delete();
}
}
return response()->json(['success' => true, 'message' => 'Tickets Deleted Successfully']);
}
public function updateTicketStatus(Request $request)
{
$this->validate($request, [
'ticket_ids' => 'required|string',
'status' => 'required|string'
]);
$ticketIds = explode(',', $request->ticket_ids);
foreach ($ticketIds as $ticket_id) {
$ticket = Ticket::find($ticket_id);
if ($ticket) {
// Delete Ticket
$ticket->status = $request->status;
$ticket->save();
}
}
return response()->json(['success' => true, 'message' => 'Tickets Status Updated Successfully']);
}
public function filter(Request $request)
{
$this->validate($request, [
'filter' => 'required|string',
'status' => 'required|string',
]);
$companyId = getSelectedCompany();
$company = get_company('id',$companyId);
$now = \Carbon\Carbon::now();
if(isset($request->type)) {
$tickets = Ticket::where('to_email', $company->email)->where('type', $request->type)->where('status', '!=', 'done')->orderBy('created_at','desc');
} else {
$tickets = Ticket::where('to_email', $company->email)->where('status', '!=', 'done')->orderBy('created_at','desc');
}
if($request->filter == 'Assigned to') {
$all_tickets = $tickets->where('user_assigned', $request->status)->get();
return response()->json(['tickets' => $all_tickets]);
} elseif($request->filter == 'With activity') {
if ($request->status === 'last 24 hours') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subDay());
} elseif ($request->status === 'last 3 days') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subDays(3));
} elseif ($request->status === 'last week') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subWeek());
} elseif ($request->status === 'last month') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subMonth());
} elseif ($request->status === 'last 3 months') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subMonths(3));
} elseif ($request->status === 'last 6 months') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subMonths(6));
} elseif ($request->status === 'last year') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subYear());
} elseif ($request->status === 'the past 2 years') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subYears(2));
} elseif ($request->status === 'the past 3 years') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subYears(3));
} elseif ($request->status === 'the past 4 years') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subYears(4));
} elseif ($request->status === 'the past 5 years') {
$all_tickets = $tickets->where('updated_at', '>=', $now->subYears(5));
}
$activity_tickets = $all_tickets->get();
return response()->json(['tickets' => $activity_tickets]);
} elseif($request->filter == 'No activity') {
if ($request->status === 'last 24 hours') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subDay());
} elseif ($request->status === 'last 3 days') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subDays(3));
} elseif ($request->status === 'last week') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subWeek());
} elseif ($request->status === 'last month') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subMonth());
} elseif ($request->status === 'last 3 months') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subMonths(3));
} elseif ($request->status === 'last 6 months') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subMonths(6));
} elseif ($request->status === 'last year') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subYear());
} elseif ($request->status === 'the past 2 years') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subYears(2));
} elseif ($request->status === 'the past 3 years') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subYears(3));
} elseif ($request->status === 'the past 4 years') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subYears(4));
} elseif ($request->status === 'the past 5 years') {
$all_tickets = $tickets->where('updated_at', '<=', $now->subYears(5));
}
$no_activity_tickets = $all_tickets->get();
return response()->json(['tickets' => $no_activity_tickets]);
} elseif($request->filter == 'Spam') {
if($request->status == 'marked as spam') {
$all_tickets = $tickets->where('status', 'spam')->get();
return response()->json(['tickets' => $all_tickets]);
} else {
$all_tickets = $tickets->where('status', '!=', 'spam')->get();
return response()->json(['tickets' => $all_tickets]);
}
} elseif($request->filter == 'Status') {
$all_tickets = $tickets->where('status', $request->status)->get();
return response()->json(['tickets' => $all_tickets]);
} elseif($request->filter == 'Tags') {
$ticket_meta = TicketMeta::where('value', $request->status)->pluck('ticket_id')->toArray();
if(isset($request->type)) {
$all_tickets = Ticket::where('to_email', $company->email)->where('type', $request->type)->where('status', '!=', 'done')->orderBy('created_at','desc')->whereIn('id', $ticket_meta)->get();
} else {
$all_tickets = Ticket::where('to_email', $company->email)->orderBy('created_at','desc')->where('status', '!=', 'done')->whereIn('id', $ticket_meta)->get();
}
return response()->json(['tickets' => $all_tickets]);
}
}
public function defaultAllTickets(Request $request)
{
$companyId = getSelectedCompany();
$company = get_company('id',$companyId);
if(isset($request->type)) {
$tickets = get_current_company_tickets(['type' => $request->type]);
} else {
$tickets = get_current_company_tickets();
}
return response()->json(['tickets' => $tickets]);
}
}

View File

@ -4,7 +4,10 @@
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\CompanyUser;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
class UserController extends Controller
{
@ -15,6 +18,8 @@ public function addUser(Request $request)
'email' => ['required', 'email', 'unique:users'],
'password' => ['required', 'string', 'min:8'],
]);
$company = getSelectedCompany();
$user = new User;
$user->role_id = 3;
@ -22,6 +27,15 @@ public function addUser(Request $request)
$user->email = $request->email;
$user->password = Hash::make($request->password);
$user->save();
//Update Company User
CompanyUser::updateOrCreate([
'user_id' => $user->id
],[
'user_id' => $user->id,
'company_id' => $company,
'access' => json_encode($request->access)
]);
return redirect()->back()->with('success', 'User Added Successfully');
}
@ -32,4 +46,31 @@ public function deleteUser($id)
$user->delete();
return redirect()->back()->with('success', 'User Deleted Successfully');
}
public function updateChatAvailability(Request $request)
{
$user = Auth::user();
//update user
if($request->status == "on") {
$user->is_available = 1;
$user->save();
} else {
$user->is_available = 0;
$user->save();
}
return response()->json(['success' => 'Updated Successfully']);
}
public function updateLastOnline()
{
$user = Auth::user();
//update last online
$user->last_online = Carbon::now();
$user->save();
return response()->json(['success' => true]);
}
}

View File

@ -21,6 +21,7 @@ class Kernel extends HttpKernel
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// \App\Http\Middleware\VerifyDomain::class
];
/**
@ -36,6 +37,7 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
//\App\Http\Middleware\VerifyDomain::class,
],
'api' => [
@ -64,5 +66,6 @@ class Kernel extends HttpKernel
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'verifyDomain' => \App\Http\Middleware\VerifyDomain::class,
];
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Http\Controllers\Mailgun\MailgunController;
class VerifyDomain
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$companyId = getSelectedCompany();
if(!$companyId){
return false;
}
$company = get_company('id',$companyId);
if(!$company){
return false;
}
$domain = $company->domain;
$controller = new MailgunController();
$result = $controller->is_domain_verified($domain);
if($result){
return $next($request);
}else{
return redirect()->route('showDomain',$domain);
}
}
}

19
app/Models/ChatGroup.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ChatGroup extends Model
{
use HasFactory;
protected $table = 'chat_group';
protected $fillable = ['company_id', 'user_id', 'customer_id', 'name', 'email', 'subject', 'status'];
public function messages()
{
return $this->hasMany(Message::class, 'chat_id');
}
}

View File

@ -10,4 +10,9 @@ class Company extends Model
use HasFactory;
protected $guarded = [];
public function getMeta($key){
return getCompanyMeta($this->id,$key);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CompanyUser extends Model
{
use HasFactory;
protected $guarded = [];
public function user()
{
return $this->belongsTo(User::class);
}
public function company()
{
return $this->belongsTo(Company::class);
}
}

20
app/Models/Message.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
use HasFactory;
protected $table = 'message';
protected $fillable = ['chat_id', 'from', 'to', 'message', 'type'];
public function chat()
{
return $this->belongsTo(ChatGroup::class, 'chat_id');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Notification extends Model
{
use HasFactory;
protected $guarded = [];
}

13
app/Models/Rule.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Rule extends Model
{
use HasFactory;
protected $guarded = [];
}

13
app/Models/Tag.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
use HasFactory;
protected $guarded = [];
}

View File

@ -22,6 +22,7 @@ class User extends Authenticatable
'email',
'password',
'role_id',
'profile_image'
];
/**

View File

@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
*
* @var string
*/
public const HOME = '/home';
public const HOME = '/dashboard';
/**
* Define your route model bindings, pattern filters, and other route configuration.

View File

@ -0,0 +1,50 @@
<?php
// app/Services/CPanelApiService.php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class CPanelApiService
{
protected $client;
protected $cpanelUrl;
protected $cpanelUsername;
protected $cpanelToken;
public function __construct()
{
$this->cpanelUrl = env('CPANEL_URL');
$this->cpanelUsername = env('CPANEL_USERNAME');
$this->cpanelToken = env('CPANEL_TOKEN');
$this->client = new Client([
'base_uri' => $this->cpanelUrl,
'headers' => [
'Authorization' => 'cpanel ' . $this->cpanelUsername . ':' . $this->cpanelToken
]
]);
}
public function createEmailAccount($domain, $email, $password, $quota)
{
$query = [
'cpanel_jsonapi_user' => $this->cpanelUsername,
'cpanel_jsonapi_apiversion' => '2',
'cpanel_jsonapi_module' => 'Email',
'cpanel_jsonapi_func' => 'addpop',
'domain' => $domain,
'email' => $email,
'password' => $password,
'quota' => $quota
];
try {
$response = $this->client->request('GET', '/json-api/cpanel', ['query' => $query]);
return json_decode($response->getBody(), true);
} catch (GuzzleException $e) {
return ['error' => $e->getMessage()];
}
}
}

View File

@ -6,7 +6,7 @@
"license": "MIT",
"require": {
"php": "^8.1",
"guzzlehttp/guzzle": "^7.2",
"guzzlehttp/guzzle": "^7.8",
"laravel/framework": "^10.10",
"laravel/sanctum": "^3.3",
"laravel/tinker": "^2.8",

2
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e3f9f69a248021a08a4b420d64573db7",
"content-hash": "3427d1f055fffcf2c0867d5d8137c3f3",
"packages": [
{
"name": "brick/math",

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->string('internal_email')->default('');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('companies', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('company_users', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->foreignId('company_id')->constrained('companies')->onDelete('cascade');
$table->text('access')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('company_users');
}
};

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->foreignId('company_id')->constrained('companies')->onDelete('cascade');
$table->string('name');
$table->string('type');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('tags');
}
};

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_group', function (Blueprint $table) {
$table->id();
$table->foreignId('company_id')->constrained('companies')->onDelete('cascade');
$table->foreignId('user_id')->constrained('users');
$table->string('customer_id');
$table->string('name');
$table->string('email');
$table->text('subject');
$table->string('status');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chat_group');
}
};

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('message', function (Blueprint $table) {
$table->id();
$table->foreignId('chat_id')->constrained('chat_group')->onDelete('cascade');
$table->string('from');
$table->string('to');
$table->text('message');
$table->string('type');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('message');
}
};

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('last_online')->nullable();
$table->boolean('is_available')->default(true);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('rules', function (Blueprint $table) {
$table->id();
$table->foreignId('company_id')->constrained('companies')->onDelete('cascade');
$table->integer('tag_id')->nullable();
$table->string('name')->nullable();
$table->string('from')->nullable();
$table->string('to')->nullable();
$table->string('subject_contains')->nullable();
$table->string('text_contains')->nullable();
$table->string('subject1_contains')->nullable();
$table->string('assign_to')->nullable();
$table->string('message_to_assigned_editor')->nullable();
$table->string('all_emails_automatically_mark_as_spam')->nullable();
$table->string('status');
$table->string('priority');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('rules');
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('tickets', function (Blueprint $table) {
$table->string('subject2')->nullable()->after('subject');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('tickets', function (Blueprint $table) {
$table->dropColumn('subject2');
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('responses', function (Blueprint $table) {
$table->longText('attachments')->nullable()->after('message');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('responses', function (Blueprint $table) {
$table->dropColumn('attachments');
});
}
};

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('notifications', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->text('text')->nullable();
$table->string('status')->nullable();
$table->string('type')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('notifications');
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('profile_image')->nullable()->after('remember_token');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('profile_image');
});
}
};

182695
error_log

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,8 @@
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php81” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php81 .php .php8 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit

BIN
public/assets/noti.wav Normal file

Binary file not shown.

View File

@ -9,11 +9,13 @@ $(document).ready(function () {
});
initFomanticDropdown(".user-select-dropdown", { action: "activate" });
//Handle opening / closing of inbox
$(".open-inbox").on("click", function () {
slideTransition("#chat-feature-widget", "left", true);
slideTransition("#inbox", "right", false);
});
// $(".open-inbox").on("click", function () {
// slideTransition("#chat-feature-widget", "left", true);
// slideTransition("#inbox", "right", false);
// });
$("#back-to-users").on("click", function () {
slideTransition("#inbox", "left", true);
@ -38,7 +40,7 @@ function initFomanticDropdown(selector, config, callback = null) {
}
function slideTransition(selector, direction, shouldHide) {
$(selector).transition(`slide ${direction}`);
//$(selector).transition(`slide ${direction}`);
if (shouldHide) {
$(selector).addClass("hidden");
} else {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
public/dummy-image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
public/dummy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
public/images/canned.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
public/images/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
public/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -4,6 +4,422 @@
@section('content')
<script>
$(document).ready(function(){
$('.side-bar-links a').removeClass('bg-light-color');
$('.aw-a-inbox').addClass('bg-light-color');
});
</script>
<!-- Toastr CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet">
<!-- Toastr JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<!-- SweetAlert2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
<!-- SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>
@php
$companyId = getSelectedCompany();
$company_users = get_company_users($companyId);
@endphp
<script>
$(document).ready(function() {
// Toggle filter dropdown on button click
$('.list-filter-btn').click(function() {
$('.filter-options').toggle();
});
// Initial hide for handle_multiple__options
$('.filter-options').hide();
$('.handle_multiple__options').hide();
// Toggle visibility of handle_multiple__options on button click
$('.handle-multiple-btn').click(function() {
$('.handle_multiple__options').toggle();
});
// Initially disable all the buttons
$('.handle_multiple__options .tags button').prop('disabled', true);
// Enable/disable buttons based on the select all checkbox
// $('#select-all').change(function() {
// if ($(this).is(':checked')) {
// $('.handle_multiple__options .tags button').prop('disabled', false);
// } else {
// $('.handle_multiple__options .tags button').prop('disabled', true);
// }
// });
// Show the modal when "Assign post" button is clicked
$('.handle_multiple__options .tags button:contains("Assign post")').click(function(e) {
e.preventDefault();
$('#customModal').show();
});
// Show the modal when "Move" button is clicked
$('.handle_multiple__options .tags button:contains("Move")').click(function(e) {
e.preventDefault();
$('#customModal2').show();
});
// Show the modal when "Reply to multiple" button is clicked
$('.handle_multiple__options .tags button:contains("Reply to multiple")').click(function(e) {
e.preventDefault();
$('#customModal3').show();
});
// Close the modal when the close button or outside the modal is clicked
$('.modal-close, .modal').click(function() {
$('.modal').hide();
});
// Prevent modal content from closing the modal when clicked
$('.modal-content').click(function(e) {
e.stopPropagation();
});
// Update Select status options based on Select filter selection
$('#filter-select').change(function() {
var selectedFilter = $(this).val();
console.log("Selected filter:", selectedFilter); // Debugging log
updateStatusOptions(selectedFilter);
});
// Initially hide filter based data section
$('.filter_based__data').hide();
// Function to update status options based on selectedFilter
function updateStatusOptions(selectedFilter) {
console.log("Updating status options for:", selectedFilter); // Debugging log
switch (selectedFilter) {
case 'Assigned to':
// $('#status-select').html(`
// <option disabled value="">Select assigned to</option>
// <option value="Assigned">Assigned</option>
// <option value="Unassigned">Unassigned</option>
// <option value="Margin">Margin</option>
// `);
var options = '<option value="">Select assigned to</option>';
// Loop through the company_users array
@foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach
$('#status-select').html(options);
$('.filter_based__data').show();
break;
case 'With activity':
$('#status-select').html(`
<option value="">Select No activity</option>
<option value="last 24 hours">Last 24 hours</option>
<option value="last 3 days">Last 3 days</option>
<option value="last week">Last week</option>
<option value="last month">Last month</option>
<option value="last 3 months">Last 3 months</option>
<option value="last 6 months">Last 6 months</option>
<option value="last year">Last year</option>
<option value="the past 2 years">The past 2 years</option>
<option value="the past 3 years">The past 3 years</option>
<option value="the past 4 years">The past 4 years</option>
<option value="the past 5 years">The past 5 years</option>
`);
$('.filter_based__data').show();
break;
case 'No activity':
$('#status-select').html(`
<option value="">Select No activity</option>
<option value="last 24 hours">Last 24 hours</option>
<option value="last 3 days">Last 3 days</option>
<option value="last week">Last week</option>
<option value="last month">Last month</option>
<option value="last 3 months">Last 3 months</option>
<option value="last 6 months">Last 6 months</option>
<option value="last year">Last year</option>
<option value="the past 2 years">The past 2 years</option>
<option value="the past 3 years">The past 3 years</option>
<option value="the past 4 years">The past 4 years</option>
<option value="the past 5 years">The past 5 years</option>
`);
$('.filter_based__data').show();
break;
case 'Editor':
$('#status-select').html(`
<option value="">Select Editor</option>
<option value="Computer tool">Computer tool</option>
<option value="Direct editor">Direct editor</option>
`);
$('.filter_based__data').show();
break;
case 'Spam':
$('#status-select').html(`
<option value="">Select Spam</option>
<option value="marked as spam">Marked as spam</option>
<option value="marked as not spam">Marked as not spam</option>
`);
$('.filter_based__data').show();
break;
case 'Status':
$('#status-select').html(`
<option value="">Select status</option>
<option value="open">Open</option>
<option value="waiting">Waiting</option>
<option value="done">Done</option>
`);
$('.filter_based__data').show();
break;
case 'Tags':
var options = '<option value="">Select Tags</option>';
@foreach($tags as $tag)
options += '<option value="{{$tag->name}}">{{$tag->name}}</option>';
@endforeach
$('#status-select').html(options);
$('.filter_based__data').show();
break;
case 'Users':
var options = '<option value="">Select Users</option>';
// Loop through the company_users array
@foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach
// Update the select element with the generated options
$('#status-select').html(options);
$('.filter_based__data').show();
break;
default:
$('#status-select').html(`
<option disabled value="">Select status</option>
`);
$('.filter_based__data').show();
break;
}
}
});
</script>
<style>
.handle_multiple__options {
display: none;
background-color: #f8f9fa;
padding: 10px;
border: 1px solid #ddd;
margin-top: 10px;
}
.handle_multiple__options label {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.handle_multiple__options .tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.handle_multiple__options .tags button {
background-color: #748C62;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
.handle_multiple__options .tags button:hover {
background-color: #383F33;
}
.handle_multiple__options .tags button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.handle_multiple__options input{
width: 32px;
height: 19px;
}
.handle_multiple__options .common_shre{
display: flex;
justify-content: space-between;
}
/* Custom Modal CSS */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 13%;
border-radius: 10px;
position: relative;
}
#customModal3 .modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 40%;
border-radius: 10px;
position: relative;
}
.modal-content .btn-primary{
background-color: #748C62 !important;
}
.modal-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
position: absolute;
right: 20px;
top: 10px;
cursor: pointer;
}
.modal-close:hover,
.modal-close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.filter-options {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #f3f3f3;
}
.filter {
display: flex;
align-items: center;
}
.filter select {
margin-right: 10px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ccc;
}
/* Hide checkboxes initially */
.checkbox-wrapper {
display: none;
}
/* Show checkboxes when 'Handle Multiple' is active */
.handle-multiple-active .checkbox-wrapper {
display: block;
}
/* Show checkboxes when 'Handle Multiple' is active */
.handle-multiple-active .checkbox-wrapper {
display: block;
}
.chat-content {
padding: 12px 11px !important;
}
.chat-user-img{
margin-left:12px !important;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
}
/* When checkbox is checked, set background to green */
input[type="checkbox"]:checked {
background-color: #748C62;
border-color: #748C62;
}
/* Optional: Add checkmark icon or any visual effect */
input[type="checkbox"]:checked::before {
transform: translate(0px, -1px);
content: '✔';
display: block;
text-align: center;
color: white;
font-weight: bold;
font-size: 13px;
margin-bottom: -1px;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
margin-right: 7px;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
/* margin-top: 12px; */
transform: translate(2px, 6px);
}
#cannedResponseModal ul {
list-style: none;
padding: 0;
display: flex !important;
gap: 8px !important;
flex-wrap: wrap !important;
}
.canned-response {
background-color: #748C62 !important;
color: white;
}
</style>
<div class="content-wrapper">
<div class="ui card chat-card">
<div class="content chat-card-header d-flex align-items-center justify-content-between">
@ -20,15 +436,56 @@
</button>
</div>
</div>
<div class="filter-options">
<div class="filter">
<span> <b>Filter on:</b> &nbsp;</span>
<select id="filter-select" name="">
<option value="select_filter_default">Select filter</option>
<option value="Assigned to">Assigned to</option>
<option value="With activity">With activity</option>
<option value="No activity">No activity</option>
<!--<option value="Editor">Editor</option>-->
<option value="Spam">Spam</option>
<option value="Status">Status</option>
<option value="Tags">Tags</option>
<!--<option value="Users">Users</option>-->
</select>
<div class="filter_based__data">
<select id="status-select" name="">
<option disabled>Select status</option>
<!-- Options will be dynamically updated based on selected filter -->
</select>
</div>
</div>
</div>
<div class="handle_multiple__options">
<div class="common_shre">
<label for="select-all"> <input type="checkbox" name="" id="select-all"> Select all</label>
<div class="tags">
<button>Assign post</button>
<button id="delete-posts">Delete</button>
<!--<button>Move</button>-->
<button data-status="open" class="update-posts-status">Open</button>
<button data-status="waiting" class="update-posts-status">Waiting</button>
<button data-status="done" class="update-posts-status">Done</button>
<!--<button>Tag</button>-->
<!--<button>Not spam</button>-->
<button>Reply to multiple</button>
</div>
</div>
</div>
<div class="content chat-content">
<ul class="chat-details">
@foreach($tickets as $ticket)
<li>
<a href="{{ route('inbox') }}" class="chat-detail-item d-flex align-items-center">
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-{{$ticket->id}}">
</div>
<div class="chat-user-img all-tickets position-relative">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
<img style="height: 42px; width: 42px; border-radius: 50%;" src="{{ asset('dummy-image.jpg') }}" alt="User">
<div
class="chat-status-icon rounded-circle text-center align-content-center position-absolute">
<img src="{{ asset('images/icons/chat-round.svg') }}" alt="Chat Round">
@ -46,8 +503,8 @@ class="chat-status-icon rounded-circle text-center align-content-center position
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">{{ $ticket->subject }}</p>
<p class="receiver-message"> - {{ $ticket->content }}</p>
<p class="color-dark-green receiver-name">{{ $ticket->sender_name }}</p>
<p class="receiver-message"> - {{\Illuminate\Support\Str::limit($ticket->subject, 90)}}</p>
</div>
<p class="color-dark-green bold message-time">{{\Carbon\Carbon::parse($ticket->created_at)->format('h:i A')}}</p>
</div>
@ -62,4 +519,132 @@ class="chat-status-icon rounded-circle text-center align-content-center position
</div>
</div>
@endsection
<!--Filter Status Code-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
const filterSelect = $('#filter-select');
const statusSelect = $('#status-select');
const statusOptions = $('#status-options');
const chatDetails = $('.chat-details');
// Handle status change
$('#status-select').change(function() {
fetchTickets();
});
// Fetch tickets based on filter
function fetchTickets() {
const filter = filterSelect.val();
const status = $('#status-select').val();
$.ajax({
url: '/filter',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
filter: filter,
status: status,
},
success: function(data) {
chatDetails.empty();
$.each(data.tickets, function(index, ticket) {
chatDetails.append(`
<li>
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-${ticket.id}">
</div>
<div class="chat-user-img">
<img src="/images/Avatar.png" alt="User">
</div>
<div class="chat-message-info d-flex align-self-baseline">
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-light-green">#${ticket.id}</p>
<div class="ui tiny label bg-dark-green-color color-light">
${ticket.status}
</div>
</div>
<p class="color-dark-green">${new Date(ticket.created_at).toLocaleDateString()}</p>
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">${ticket.sender_name}</p>
<p class="receiver-message"> - ${ticket.subject}</p>
</div>
<p class="color-dark-green bold message-time">${new Date(ticket.created_at).toLocaleTimeString()}</p>
</div>
</div>
</a>
</li>
`);
});
}
});
}
});
</script>
<script>
$(document).ready(function(){
const chatDetails = $('.chat-details');
const filterSelect = $('#filter-select');
filterSelect.change(function() {
const selectedFilter = $(this).val();
if (selectedFilter === 'select_filter_default') {
$.ajax({
url: 'default/all-tickets',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
success: function(data) {
chatDetails.empty();
$.each(data.tickets, function(index, ticket) {
chatDetails.append(`
<li>
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-${ticket.id}">
</div>
<div class="chat-user-img">
<img src="/images/Avatar.png" alt="User">
</div>
<div class="chat-message-info d-flex align-self-baseline">
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-light-green">#${ticket.id}</p>
<div class="ui tiny label bg-dark-green-color color-light">
${ticket.status}
</div>
</div>
<p class="color-dark-green">${new Date(ticket.created_at).toLocaleDateString()}</p>
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">${ticket.sender_name}</p>
<p class="receiver-message"> - ${ticket.subject}</p>
</div>
<p class="color-dark-green bold message-time">${new Date(ticket.created_at).toLocaleTimeString()}</p>
</div>
</div>
</a>
</li>
`);
});
}
});
}
});
});
</script>
<x-custom-modals />
@endsection

View File

@ -11,8 +11,8 @@
<meta content="" name="keywords">
<!-- Favicons -->
<link href="" rel="icon">
<link href="assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/png">
<!--<link href="assets/img/apple-touch-icon.png" rel="apple-touch-icon">-->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
<link rel="stylesheet" href="https://chat.rapidev.tech/chat/chat.css">
<div id="aw-root-chat" data-company="{{getSelectedCompany()}}"></div>
<script src="https://chat.rapidev.tech/chat/chat.js"></script>

View File

@ -0,0 +1,629 @@
<style>
.aw-chat-head img{
cursor:pointer;
}
.scrollhint .item .single-user-content img,.scrollhint .item .sender-message-box img{
width:100%;
}
@media screen and (max-width: 767px) {
.chat-message-box {
left: 20px !important;
}
}
@media only screen and (max-width: 525px) {
div.chat-inbox>.chat-content-wrapper>.chat-message>.single-message-chat>.user-message {
max-width: 100% !important;
width: 100% !important;;
}
}
</style>
<!-- Support and Chat Fixed Buttons -->
<div class="chat-message-box position-fixed">
<!-- Chat Drop Down -->
<div class="ui floating bg-dark-green-color chat-widget-wrapper icon dropdown button">
<img src="{{ asset('images/icons/Vector 386.png') }}" alt="Chat Icon">
<div class="menu chat-menu">
<div id="chat-feature-widget" class="ui transition chat-feature-widget">
<div class="header d-flex justify-content-between align-items-center text-white">
<p class="chat-popup-label text-light">Chats</p>
<img class="remove-chat" src="{{ asset('images/icons/Vector (3).svg') }}" alt="Cross Chat Icon">
</div>
<div class="aw-chats">
</div>
</div>
<!-- User Inbox menu -->
<div id="inbox" class="ui transition hidden chat-feature-widget inbox-wrapper">
<div class="header aw-chat-head d-flex align-items-center" style="justify-content: space-between;">
<img id="back-to-users" src="{{ asset('images/icons/Vector 387.png') }}" alt="Back To Chat">
<p class="chat-popup-label text-light">James</p>
<img id="close-chat" src="{{ asset('images/icons/Vector (3).svg') }}" alt="Close Chat">
</div>
<div class="scrollhint">
<!--<div class="item">-->
<!-- <div class="single-user-content d-flex">-->
<!-- <div class="chat-user-img-box receiver-message-box d-flex">-->
<!-- <img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">-->
<!-- <p>Typing...</p>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
</div>
<div class="outer-message-input-box">
<div class="inner-message-input d-flex align-items-center justify-content-between">
<input id="aw-sms" type="text" class="border-0" placeholder="Type a reply">
<p class="input-action d-flex align-items-center">
<!--<img src="{{ asset('images/icons/gif.png') }}" alt="Gif">-->
<!--<img src="{{ asset('images/icons/emoji.png') }}" alt="Emoji">-->
<img src="{{ asset('images/icons/attachment.png') }}" alt="Attachment">
<input type="file" id="file-picker" class="file-picker">
<i class="fa fa-paper-plane-o send-icon" aria-hidden="true"></i>
</p>
</div>
</div>
</div>
</div>
</div>
<!-- End -->
<!-- Support Drop down -->
<div class="ui floating bg-dark-green-color support-widget-wrapper icon dropdown button ">
<img src="{{asset('images/icons/support.svg')}}" alt="Support Icon">
<div class="menu support-widget">
<div class="header support-header mt-0 text-center">
<h2 class="color-dark-green">Help & Support</h2>
</div>
<div class="support-facilities-box d-flex justify-content-between flex-wrap">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/faq-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green">FAQ</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/laptop-minimalistic-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green">Using Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/launch-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green text-wrap">Launching Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/setting-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Settings</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/data-mapping-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green ">Integration</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/open-door-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green text-wrap">Privacy & Policy</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/news-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green text-wrap">News & Updates</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/graduate-cap-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green ">Training</p>
</div>
</div>
<div class="header contact-us-header text-center">
<h2 class="color-dark-green">Contact Us</h2>
</div>
<div class="contact-us-box d-flex justify-content-center">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/email-14-svgrepo-com (1) 1.svg')}}" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Questions</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{asset('images/icons/about-filled-svgrepo-com 1.svg')}}" alt="">
</div>
<p class="color-dark-green">About Kundo</p>
</div>
</div>
</div>
</div>
<!-- End -->
</div>
<!-- End -->
<audio style="display:none;" id="messageSound" src="{{asset('assets/noti.wav')}}" preload="auto"></audio>
<script src="https://chat.rapidev.tech/socket.io/socket.io.js"></script>
<script>
var customer_id = false;
var startData = false;
var localId = false;
var customers = [];
const socket = io('https://chat.rapidev.tech/', {
withCredentials: false,
});
// Event listener for successful connection
socket.on('connect', () => {
console.log('Connected to the server with socket ID:', socket.id);
customer_id = socket.id;
localId = "{{auth()->user()->id}}";
socket.emit('register', localId);
console.log(localId);
});
// Optionally, handle the disconnect event
socket.on('disconnect', (reason) => {
console.log('Disconnected from the server:', reason);
customer_id = false;
if (reason === 'io server disconnect') {
// The server disconnected the client, try to reconnect
socket.connect();
}
});
function loadChats(){
$.ajax({
url: "{{route('chatgroups.get')}}",
method: 'GET',
success: function(response) {
console.log(response);
var html = '';
for(var i=0;i<response.length;i++){
var chat = response[i];
chat['isFirst'] = true;
customers[chat.id] = chat;
html += ` <div class="item open-inbox" data-chat="${chat.id}" data-customer="${chat.customer_id}" data-subject="${chat.subject}" data-user="${chat.user_id}">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" class="aw-avatar" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">${chat.name} <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">${chat.subject}</p>
</div>
</div>
</div>`;
}
$('.aw-chats').html(html);
// Update action box with fetched content
// $('.action-box').html(response);
},
error: function(error) {
console.log('Error fetching action box content:', error);
}
});
}
console.log(socket);
document.addEventListener('DOMContentLoaded', (event) => {
loadChats()
var activeChat = false;
var inbox = $('#inbox .scrollhint');
$('#close-chat').click(function(){
Swal.fire({
title: 'Are you sure?',
text: "Do you want to close this chat?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes'
}).then((result) => {
if (result.isConfirmed && activeChat) {
$.ajax({
url: '{{ route("CloseChat") }}',
type: 'POST',
data: {
_token: '{{csrf_token()}}',
chat_id: activeChat.id
},
success: function(response) {
console.log(response);
socket.emit('chat_closed',
{ customer_id:activeChat.customer_id, chat_id: activeChat.id }
);
Swal.fire({
title: 'Success',
text: "Chat is closed.",
icon: 'success',
showCancelButton: false,
confirmButtonColor: '#3085d6',
//cancelButtonColor: '#d33',
confirmButtonText: 'OK'
}).then((result) => {
if (result.isConfirmed) {
loadChats();
$('#back-to-users').click();
}
});
},
error: function(xhr, status, error) {
console.log(xhr.responseText);
}
});
console.log('chat closed');
}
});
});
$(document).on('click', '.open-inbox', async function() {
inbox.html(null);
var chat = customers[$(this).data('chat')];
var messages = await getMessage(chat.id);
console.log(messages);
if(messages){
for(var i=0;i<messages.length;i++){
var sms = messages[i];
var content = sms.message;
if(sms.type == 'image'){
content = '<img src="'+sms.message+'"/>';
}
if(sms.type == 'file'){
content = '<a target="_blank" href="'+sms.message+'"> View File </a>';
}
if(sms.from == "user"){
//<img src="{{ asset('images/Avatar.png') }}" class="aw-avatar" alt="Dummy User">
inbox.append(` <div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<p>${content}</p>
</div>
</div>
</div>`);
}else{
inbox.append(` <div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>${content}</p>
</div>
</div>`);
}
}
}
$('.chat-popup-label').text(chat.name);
activeChat = chat;
if(chat.isFirst){
}
console.log(activeChat);
slideTransition('#chat-feature-widget', 'left', true);
slideTransition('#inbox', 'right', false);
});
$('.send-icon').click(async function(){
var sms = $('#aw-sms').val();
const fileInput = document.getElementById("file-picker");
const file = fileInput.files[0];
var type = "text";
if(sms != "" || file){
console.log(activeChat.id);
const formData = new FormData();
if (file) {
formData.append("file", file); // Append the selected file
// Check the file type
const fileType = file.type;
if (fileType.startsWith("image/")) {
console.log("This is an image file.");
type = "image";
} else {
type = "file";
}
}
formData.append('chat_id', activeChat.id); // Static value as per your example
formData.append('from', 'company'); // Assuming a static value for simplicity
formData.append('message', sms);
formData.append('type', type);
// API endpoint
const apiUrl = 'https://kundesone.no/api/chat/send-message';
// Fetch API to send the FormData
fetch(apiUrl, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
var sms = data.data;
var content = sms.message;
console.log('Success:', data,'chat message',{
sms:content,
id:activeChat.id,
type:sms.type
},
activeChat.customer_id);
socket.emit('chat message',
{
sms:content,
id:activeChat.id,
type:sms.type
},
activeChat.customer_id
);
if(sms.type == 'image'){
content = '<img src="'+content+'"/>';
}
if(sms.type == 'file'){
content = '<a target="_blank" href="'+content+'"> View File </a>';
}
inbox.append(` <div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>${content}</p>
</div>
</div>`);
$('#aw-sms').val("");
scrollToBottom();
})
}
});
async function getMessage(chat_id) {
const apiUrl = 'https://kundesone.no/api/chat/getMessages';
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json' // Assuming the server expects JSON
},
body: JSON.stringify({ chat_id: chat_id })
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const messages = await response.json();
return messages;
} catch (error) {
console.error('Error:', error);
return false;
}
}
socket.on('chat_created',function(data){
loadChats();
console.log(data);
playMessageSound();
});
socket.on('chat message', function(msg) {
playMessageSound();
if(msg.id == activeChat.id){
var sms = msg;
var content = sms.sms;
if(sms.type == 'image'){
content = '<img src="'+content+'"/>';
}
if(sms.type == 'file'){
content = '<a target="_blank" href="'+content+'"> View File </a>';
}
//<img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
inbox.append(` <div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<p>${content}</p>
</div>
</div>
</div>`);
}
console.log(msg);
// var item = document.createElement('li');
// item.textContent = msg;
// document.getElementById('messages').appendChild(item);
// window.scrollTo(0, document.body.scrollHeight);
scrollToBottom();
});
socket.on('start_chat', function(msg) {
console.log(msg);
});
});
function scrollToBottom() {
var $div = $('.scrollhint');
$div.scrollTop($div.prop("scrollHeight"));
}
function playMessageSound() {
var sound = document.getElementById('messageSound');
sound.play();
}
</script>
<script>document.querySelector('.input-action img[alt="Attachment"]').addEventListener('click', function() {
document.getElementById('file-picker').click();
});
</script>
<style>
.outer-message-input-box {
width: 100%;
padding: 10px;
background-color: #f8f9fa;
}
.inner-message-input {
width: 100%;
background-color: #ffffff;
border-radius: 5px;
padding: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.inner-message-input input {
flex-grow: 1;
margin-right: 10px;
}
.input-action img {
margin-left: 10px;
cursor: pointer;
}
.input-action .file-picker {
display: none;
}
.fa-paper-plane-o {
font-size: 17px !important;
background: #748C62 !important;
padding: 3px 7px !important;
color: white !important;
border-radius: 3px !important;
cursor: pointer !important;
}
</style>

View File

@ -0,0 +1,570 @@
<style>
#cke_editor1{
width:100%!important;
}
div.chat-inbox.chat-box{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 100%;
max-width: 600px;
}
.close-button {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
background:;#748c62 !important
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#cannedResponseModal ul {
list-style: none;
padding: 0;
}
#cannedResponseModal li {
padding: 8px 0; /* Spacing between buttons */
}
.canned-response {
width: 100%;
padding: 10px;
font-size: 16px;
border: none;
background-color: #4CAF50;
color: white;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
}
.canned-response:hover {
background-color: #45a049;
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.24);
}
.close-button {
color: #aaa;
/* float: right; */
font-size: 28px;
font-weight: bold;
background: ;
display: flex !important;
justify-content: flex-end !important;
margin-top: -14px;
font-size: 32px;
}
</style>
<!-- Custom Modal post -->
<div id="customModal" class="modal">
<div class="modal-content">
<span class="modal-close">&times;</span>
<h5>Assign Post</h5>
<form id="assignForm">
<input type="hidden" id="ticket-ids" name="ticket_ids">
<div class="mb-3">
<label for="recipient-name" class="col-form-label">Recipient:</label>
@php
$companyId = getSelectedCompany();
$company_users = get_company_users($companyId);
@endphp
<select name="user_assigned" class="form-control" required>
<option>Select User</option>
@foreach($company_users as $company_user)
<option value="{{$company_user->user->id}}">{{$company_user->user->name}}</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label for="message-text" class="col-form-label">Message:</label>
<textarea class="form-control" id="message-text" name="message" required></textarea>
</div>
</form>
<button type="button" class="btn btn-primary assign-post">Send</button>
</div>
</div>
<!-- Custom Modal move-->
<div id="customModal2" class="modal">
<div class="modal-content">
<span class="modal-close">&times;</span>
<h5>Move</h5>
<form>
<div class="mb-3">
<label for="recipient-name" class="col-form-label">Conversation moved:</label>
<input type="text" class="form-control" id="recipient-name" placeholder="Inbox">
</div>
</form>
<button type="button" class="btn btn-primary">Confirm</button>
</div>
</div>
<!-- Custom Modal Replay to multiple-->
<div id="customModal3" class="modal">
<div class="modal-content">
<span class="modal-close">&times;</span>
<h5>Reply to multiple</h5>
<form>
<div class="content d-flex align-items-end flex-column message-writing-content-area">
<textarea name="email_signature" id="editor1" rows="10" placeholder="Your Message"
class="form-control input-reply-textarea" required></textarea>
</div>
<div style="display: flex;flex-direction: row-reverse;">
<button type="button" class="btn btn-primary reply-to-multiple">Reply</button>
</div>
</form>
</div>
</div>
<!-- Canned Response Modal -->
<div id="cannedResponseModal" class="modal">
<div class="modal-content">
<span class="close-button">&times;</span>
<h2>Canned Responses</h2>
<ul>
@php
$companyId = getSelectedCompany();
$canned_response = \App\Models\CompanyMeta::where('company_id', $companyId)->where('key', 'canned_responses')->get();
$email_signature = \App\Models\CompanyMeta::where('company_id', $companyId)->where('type', 'Email Signature')->first()?->value;
@endphp
@if(count($canned_response) > 0)
@foreach($canned_response as $index => $value)
@php
$result = json_decode($value->value);
@endphp
<li><button class="canned-response" data-response="{{$result->text}}">{{$result->name}}</button></li>
@endforeach
@endif
</ul>
</div>
</div>
<script>
//CKEDITOR.replace('editor1');
CKEDITOR.plugins.add('addcannedresponse', {
init: function(editor) {
// Command for inserting canned response
editor.addCommand('addCannedResponseCmd', {
exec: function(editor) {
// Show your modal or handle canned response insertion
document.getElementById('cannedResponseModal').style.display = 'block';
}
});
// Command for inserting signature
editor.addCommand('addSignatureCmd', {
exec: function(editor) {
var signatureHtml = `<br>{!! $email_signature !!}`; // Signature content
CKEDITOR.instances.editor1.insertHtml(signatureHtml);
}
});
// Add "Insert Canned Response" button
editor.ui.addButton('AddCannedResponse', {
label: 'Insert Canned Response',
command: 'addCannedResponseCmd',
icon: 'https://kundesone.no/images/canned.png', // Use an accessible icon URL or local path
toolbar: 'insert,0'
});
// Add "Insert Signature" button
editor.ui.addButton('AddSignature', {
label: 'Insert Signature',
command: 'addSignatureCmd',
icon: 'https://kundesone.no/images/signature-icon.png', // Placeholder icon URL, replace with a valid one
toolbar: 'insert,1'
});
}
});
CKEDITOR.replace('editor1', {
extraPlugins: 'addcannedresponse', // Ensure your plugin is added to extraPlugins
// Optionally customize your toolbar further, or use the default configuration
toolbarGroups: [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
]
});
// Get the modal
var modal = document.getElementById("cannedResponseModal");
// Get the button that opens the modal
var btn = document.getElementsByClassName("canned-response");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close-button")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// Add event listeners to canned response buttons
Array.from(btn).forEach(function(element) {
element.addEventListener('click', function() {
var response = this.getAttribute('data-response');
CKEDITOR.instances.editor1.insertHtml(response);
modal.style.display = "none";
});
});
</script>
<script>
$(document).ready(function() {
var $handleMultipleButton = $('.handle-multiple-btn');
var $selectAllCheckbox = $('#select-all');
var $ticketCheckboxes = $('.ticket-checkbox');
var $actionButtons = $('.handle_multiple__options .tags button');
// Function to toggle button states
function updateButtonStates() {
var selectedCount = $ticketCheckboxes.filter(':checked').length;
$actionButtons.prop('disabled', selectedCount === 0);
}
// Toggle checkboxes visibility
$handleMultipleButton.on('click', function() {
$('.content').toggleClass('handle-multiple-active');
});
// Toggle all checkboxes based on 'Select all'
$selectAllCheckbox.on('change', function() {
$ticketCheckboxes.prop('checked', $selectAllCheckbox.prop('checked'));
updateButtonStates();
});
// Toggle button states when individual checkboxes change
$ticketCheckboxes.on('change', function() {
updateButtonStates();
});
// Initialize button states
updateButtonStates();
});
</script>
<!--Assigned Post Start-->
<script>
$(document).ready(function() {
$('.assign-post').on('click', function() {
var selectedTickets = [];
$('.ticket-checkbox:checked').each(function() {
selectedTickets.push($(this).attr('id').replace('ticket-', ''));
});
$('#ticket-ids').val(selectedTickets.join(','));
// SweetAlert2 confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: 'You are about to send this message.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, send it!',
cancelButtonText: 'Cancel'
}).then((result) => {
if (result.isConfirmed) {
// Get form data
var formData = $('#assignForm').serialize();
// AJAX request to submit the form
$.ajax({
url: 'assign/ticket',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: formData,
success: function(response) {
// Show success notification
Swal.fire(
'Assigned!',
'Post Assigned Successfully!',
'success'
);
location.reload();
// Hide the modal
$('#customModal').modal('hide');
},
error: function(xhr) {
// Show error notification
Swal.fire(
'Error!',
'An error occurred. Please try again.',
'error'
);
}
});
}
});
});
});
</script>
<!--Assigned Post End-->
<!--Delete Post Start-->
<script>
$(document).ready(function() {
$('#delete-posts').on('click', function() {
var selectedTickets = [];
$('.ticket-checkbox:checked').each(function() {
selectedTickets.push($(this).attr('id').replace('ticket-', ''));
});
var ticket_ids = selectedTickets.join(',');
// SweetAlert2 confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: 'You are about to delete selected tickets.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete them!',
cancelButtonText: 'Cancel'
}).then((result) => {
if (result.isConfirmed) {
// AJAX request to delete the tickets
$.ajax({
url: 'delete/tickets',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
ticket_ids: ticket_ids
},
success: function(response) {
// Show success notification
Swal.fire(
'Deleted!',
'Tickets have been deleted successfully.',
'success'
);
// Reload the page or update the UI as needed
location.reload();
},
error: function(xhr) {
// Show error notification
Swal.fire(
'Error!',
'An error occurred. Please try again.',
'error'
);
}
});
}
});
});
});
</script>
<!--Delete Post End-->
<!--Update Status Start-->
<script>
$(document).ready(function() {
$('.update-posts-status').on('click', function() {
var status = $(this).data('status');
var selectedTickets = [];
$('.ticket-checkbox:checked').each(function() {
selectedTickets.push($(this).attr('id').replace('ticket-', ''));
});
var ticket_ids = selectedTickets.join(',');
// SweetAlert2 confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: 'You are about to update the status of selected tickets.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, update it!',
cancelButtonText: 'Cancel'
}).then((result) => {
if (result.isConfirmed) {
// AJAX request to submit the form
$.ajax({
url: 'update/ticket/status',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
ticket_ids: ticket_ids,
status: status
},
success: function(response) {
// Show success notification
Swal.fire(
'Updated!',
'Tickets status has been updated successfully.',
'success'
);
// Optionally reload or update the page
location.reload();
},
error: function(xhr) {
// Show error notification
Swal.fire(
'Error!',
'An error occurred. Please try again.',
'error'
);
}
});
}
});
});
});
</script>
<!--Update Status End-->
<!-- Reply to Multiple Start -->
<script>
$(document).ready(function() {
$('.reply-to-multiple').on('click', function(){
var message = CKEDITOR.instances.editor1.getData();
if(message.trim() === '') {
toastr.error('Message cannot be empty');
return;
}
var selectedTickets = [];
$('.ticket-checkbox:checked').each(function() {
selectedTickets.push($(this).attr('id').replace('ticket-', ''));
});
var ticket_ids = selectedTickets.join(',');
console.log(ticket_ids);
// SweetAlert2 confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: 'are you sure to send reply?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, send it!',
cancelButtonText: 'Cancel'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: '/store/response',
method: 'POST',
data: {
ticket_id: ticket_ids,
message: message,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Show success notification
Swal.fire(
'Updated!',
'Reply has been sent successfully.',
'success'
);
// Optionally reload or update the page
location.reload();
},
error: function(xhr) {
// Show error notification
Swal.fire(
'Error!',
'An error occurred. Please try again.',
'error'
);
}
});
}
});
});
});
</script>
<!-- Reply to Multiple End -->

View File

@ -0,0 +1,88 @@
<script>
$(document).ready(function() {
// Toggle filter dropdown on button click
$('.list-filter-btn').click(function() {
$('.filter-options').toggle();
});
// Initial hide for handle_multiple__options
$('.filter-options').hide();
$('.handle_multiple__options').hide();
// Toggle visibility of handle_multiple__options on button click
$('.handle-multiple-btn').click(function() {
$('.handle_multiple__options').toggle();
});
// Initially disable all the buttons
$('.handle_multiple__options .tags button').prop('disabled', true);
// Enable/disable buttons based on the select all checkbox
// $('#select-all').change(function() {
// if ($(this).is(':checked')) {
// $('.handle_multiple__options .tags button').prop('disabled', false);
// } else {
// $('.handle_multiple__options .tags button').prop('disabled', true);
// }
// });
// Show the modal when "Assign post" button is clicked
$('.handle_multiple__options .tags button:contains("Assign post")').click(function(e) {
e.preventDefault();
$('#customModal').show();
});
// Show the modal when "Move" button is clicked
$('.handle_multiple__options .tags button:contains("Move")').click(function(e) {
e.preventDefault();
$('#customModal2').show();
});
// Show the modal when "Reply to multiple" button is clicked
$('.handle_multiple__options .tags button:contains("Reply to multiple")').click(function(e) {
e.preventDefault();
$('#customModal3').show();
});
// Close the modal when the close button or outside the modal is clicked
$('.modal-close, .modal').click(function() {
$('.modal').hide();
});
// Prevent modal content from closing the modal when clicked
$('.modal-content').click(function(e) {
e.stopPropagation();
});
});
</script>
<div class="content chat-card-header d-flex align-items-center justify-content-between">
<div class="header">Chats</div>
<div class="data-actions d-flex justify-content-end">
<button class="action-button bg-dark-green-color color-light handle-multiple-btn">
<img src="{{ asset('images/icons/Add_Plus.png') }}" alt="Plus Icon">
<span>Handle Multiple</span>
</button>
</div>
</div>
<div class="handle_multiple__options">
<div class="common_shre">
<label for="select-all"> <input type="checkbox" name="" id="select-all"> Select all</label>
<div class="tags">
<button>Assign post</button>
<button id="delete-posts">Delete</button>
<!--<button>Move</button>-->
<button data-status="open" class="update-posts-status">Open</button>
<button data-status="waiting" class="update-posts-status">Waiting</button>
<button data-status="done" class="update-posts-status">Done</button>
<!--<button>Tag</button>-->
<!--<button>Not spam</button>-->
<button>Reply to multiple</button>
</div>
</div>
</div>

View File

@ -1,10 +1,157 @@
<style>
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.chat{
transform: translate(15px, 1px);
font-size: 17px;
font-weight: 500;
}
.in_setting{
display: none !important;
}
@media screen and (max-width: 767px) {
div.inbox-content-wrapper>.inbox-inner-wrapper>.user-box {
width: 90px;
display: none !important;
}
}
@media only screen and (max-width: 420px) {
.logout {
display: none !important;
}
.in_setting{
display: block !important;
margin-left:12px;
}
@media only screen and (max-width: 348px) {
header .nav-links {
gap: 17px;
}
.chat {
transform: translate(7px, 1px) !important;
font-size: 17px;
font-weight: 500;
}
}
@media only screen and (max-width: 525px) {
div.chat-inbox>.chat-content-wrapper>.chat-message>.single-message-chat>.user-message {
max-width: 100% !important;
width: 100% !important;;
}
}
@media only screen and (max-width: 315px) {
header .nav-links {
gap: 15px;
}
.chat {
transform: translate(7px, 1px) !important;
font-size: 17px;
font-weight: 500;
}
}
.logout_form {
display: flex;
justify-content: center;
margin-top: 14px;
margin-bottom: 10px;
}
.logout_form .nav-btn {
border: none;
outline: none;
border-radius: 6.26px;
height: 38px;
width: 126.89px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
@media screen and (max-width: 767px) {
.content-area header .row .col-sm-8 {
flex-direction: column;
align-items: center !important;
gap: 10px;
}
}
.single-message-chat {
width: 100%;
height: -webkit-fill-available !important;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<header>
<div class="row">
<div class="col-sm-4 user-name-nav-area d-flex align-content-center">
<div class="dev-toggle-sidebar">
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
<img src="https://kundesone.no/images/logo_cropped.png">
</div>
<h2 class="d-flex align-items-center">Hello Maxwell <span>👋🏼</span>,</h2>
<h2 class="d-flex align-items-center">Hello {{auth()->user()->name}} <span>👋🏼</span>,</h2>
</div>
<div class="col-sm-8 d-flex justify-content-end align-items-center">
<div class="search-box d-flex align-items-center">
@ -12,7 +159,12 @@
<input type="text" class="color-dark-green" placeholder="Search...">
</div>
<div class="nav-links d-flex align-items-center">
<form method="POST" action="{{route('logout')}}">
<span class="chat">Chat </span>
<label class="switch">
<input type="checkbox" id="toggleSwitch" @if(auth()->user()->is_available == 1) checked @endif>
<span class="slider round">
</label>
<form class="logout" method="POST" action="{{route('logout')}}">
@csrf
<button class="nav-btn bg-dark-green-color">
<img height="25" width="50" src="{{ asset('images/logout.png') }}" alt="">
@ -77,6 +229,7 @@ class="chat-settings-btn-row text-center d-flex justify-content-center align-ite
<a
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div>
<div class="item">
<p class="action-heading-paragraph text-center align-content-center">
@ -89,7 +242,15 @@ class="chat-settings-btn-row text-center d-flex justify-content-center align-ite
<!--<a class="ui secondary basic button tag-btn shadow-none">Tags</a>-->
<a href="{{ route('profile') }}"
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div> <hr >
<div class="logout_form">
<form class="in_setting" method="POST" action="https://kundesone.no/logout">
<input type="hidden" name="_token" value="18hlNz76CXQJdP55j8LVsnhIf8KpaEi5MXKu9EFV" autocomplete="off"> <button class="nav-btn bg-dark-green-color">
<img height="25" width="50" src="https://kundesone.no/images/logout.png" alt="">
</button>
</form>
</div>
</div>
</div>
</div>
@ -97,4 +258,75 @@ class="ui secondary basic button shadow-none setting-btn text-white align-conten
</div>
</div>
</div>
</header>
</header>
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<!-- Toastr JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<style>
.cke_notification.cke_notification_warning{
display:none!important;
}
</style>
<script>
document.getElementById('toggleButton').addEventListener('click', function() {
this.classList.toggle('btn-success');
this.classList.toggle('btn-primary');
this.textContent = this.classList.contains('btn-success') ? 'On' : 'Off';
});
</script>
<!--chat avialability ajax-->
<script>
$(document).ready(function() {
$('#toggleSwitch').off('change').on('change', function(e) {
// Prevent default form submission if the toggle is inside a form
e.preventDefault();
const isChecked = $(this).is(':checked');
let status = isChecked ? 'on' : 'off';
// Disable the checkbox to avoid multiple clicks during the AJAX call
$(this).prop('disabled', true);
$.ajax({
url: 'update/chat-availability',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
status: status
},
success: function(response) {
if(response.success) {
toastr.success('Chat Availability Updated Successfully');
}
// Enable the checkbox again after the AJAX call completes
$('#toggleSwitch').prop('disabled', false);
},
error: function(xhr, status, error) {
console.error('Error:', error);
$('#toggleSwitch').prop('disabled', false);
}
});
});
});
</script>
<style>
@media screen and (max-width: 767px) {
.content-area header .row .col-sm-8 {
flex-direction: column;
align-items: center !important;
gap: 10px;
}
}
</style>

View File

@ -1,17 +1,37 @@
<div class="sidebar-area">
<aside class="bg-dark-green-color">
<div class="image-box d-flex justify-content-between">
<div class="image-box d-flex justify-content-between frame">
<img src="{{ asset('images/logo-white.png') }}" alt="Site Logo">
<div class="dev-toggle-sidebar dev-close"><img src="{{ asset('images/icons/close-icon.svg') }}" alt=""></div>
<div class="dev-toggle-sidebar dev-close"><img src="https://kundesone.no/images/icons/Frame.png" alt=""></div>
</div>
<style>
.side-bar-links ul li .bg-light-color .color-light{
color: #383f33 !important;
}
.sidebar_icon{
font-size: 20px !important;
color: white !important;
}
.bg-light-color .sidebar_icon{
color: #383F33 !important;
}
.frame .dev-toggle-sidebar img {
width: 26px;
height: 26px;
vertical-align: top !important;
border-radius: 50%;
}
</style>
<div class="side-bar-links">
<ul>
<li>
<a href="{{ route('index') }}"
class="side-bar-link bg-light-color d-flex align-items-center justify-content-between">
class="side-bar-link bg-light-color d-flex align-items-center justify-content-between aw-a-inbox">
<div class="link-left-content align-items-center d-flex">
<img src="{{ asset('images/icons/Message.png') }}" alt="Message">
<h6 class="color-dark-green">Inbox</h6>
<i class="fa fa-envelope-o sidebar_icon" aria-hidden="true"></i>
<h6 class="color-light">Inbox</h6>
</div>
<div class="link-right-content">
<img src="{{ asset('images/icons/chevron-right-dark.png') }}" alt="chevron right">
@ -20,9 +40,9 @@ class="side-bar-link bg-light-color d-flex align-items-center justify-content-be
</li>
<li>
<a href="{{ route('waiting') }}"
class="side-bar-link d-flex align-items-center justify-content-between">
class="side-bar-link d-flex align-items-center justify-content-between aw-a-waiting">
<div class="link-left-content align-items-center d-flex">
<img src="{{ asset('images/icons/Time_light.png') }}" alt="Message">
<i class="fa fa-clock-o sidebar_icon" aria-hidden="true"></i>
<h6 class="color-light">Waiting</h6>
</div>
<div class="link-right-content">
@ -32,10 +52,10 @@ class="side-bar-link d-flex align-items-center justify-content-between">
</li>
<li>
<a href="{{ route('all.tickets') }}"
class="side-bar-link d-flex align-items-center justify-content-between">
class="side-bar-link d-flex align-items-center justify-content-between aw-a-all">
<div class="link-left-content align-items-center d-flex">
<img src="{{ asset('images/Ticket_use.svg') }}" alt="Message">
<h6 class="color-light">All Tickets</h6>
<i class="fa fa-ticket sidebar_icon" aria-hidden="true"></i>
<h6 class="color-light">Chats</h6>
</div>
<div class="link-right-content">
<img src="{{ asset('images/icons/chevron-right-light.png') }}" alt="chevron right">
@ -43,9 +63,9 @@ class="side-bar-link d-flex align-items-center justify-content-between">
</a>
</li>
<li>
<a href="#" class="side-bar-link d-flex align-items-center justify-content-between">
<a href="#" class="side-bar-link d-flex align-items-center justify-content-between aw-a-stats">
<div class="link-left-content align-items-center d-flex">
<img src="{{ asset('images/chart-square.svg') }}" alt="Message">
<i class="fa fa-bar-chart sidebar_icon" aria-hidden="true"></i>
<h6 class="color-light">Statistics</h6>
</div>
<div class="link-right-content">
@ -62,7 +82,7 @@ class="side-bar-link d-flex align-items-center justify-content-between">
<li class="channels-widgets-wrapper side-bar-link bg-light-color d-flex align-items-center justify-content-between">
<div class="link-left-content align-items-center d-flex">
<img src="{{ asset('images/icons/Message.png') }}" alt="Message">
<i class="fa fa-envelope-o sidebar_icon" aria-hidden="true"></i>
<h6 class="color-dark-green">Channels</h6>
</div>
<div class="link-right-content">
@ -100,12 +120,15 @@ class="dropdown-item-label color-light">FORUM</span></p>
<div class="profile-nav-row d-flex side-bar-link">
<div class="profile-nav-box">
<div class="img-box"><img src="{{ asset('images/user.png') }}" alt="User Image"></div>
@if(!is_null(Auth::user()->profile_image))
<div class="img-box"><a href="{{route('profile')}}"><img style="height: 42px; width: 42px; border-radius: 50%" src="{{ url('' . Auth::user()->profile_image) }}" alt="User Image"></a></div>
@else
<div class="img-box"><img style="height: 42px; width: 42px; border-radius: 50%" src="{{ asset('dummy-image.jpg') }}" alt="User Image"></div>
@endif
</div>
<div class="user-info-box d-flex justify-content-between">
<div class="info">
<p class="color-light side-bar-user-name">Maxwell</p>
<p class="color-offset-white">Project Manager</p>
<a style="text-decoration: none; color: white;" href="{{route('profile')}}"><p class="color-light side-bar-user-name">{{Auth::user()->name}}</p></a>
</div>
<div class="icon align-self-center">
<img src="{{ asset('images/icons/chevron-down 3.png') }}" alt="Chevron Down Icon">

View File

@ -10,56 +10,134 @@
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="" rel="icon">
<link href="assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>
<!-- Bootstrap Styles -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,301,400,401,500,501,700,701,900,901&display=swap"
rel="stylesheet">
<!-- font-awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<link rel="stylesheet" href="{{ asset('assets/auth.css') }}">
<!-- Toastr CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css">
<style>
body {
font-family: 'Satoshi', sans-serif;
background-color: #f4f7f9;
color: #333;
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 90%;
margin: 40px auto;
padding: 30px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
h1, h2 {
margin-bottom: 15px;
color: #4A4A4A;
}
.alert {
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
font-weight: bold;
}
.domain-details, .dns-records {
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.record {
background-color: #ffffff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 12px;
margin-bottom: 10px;
transition: background-color 0.3s, transform 0.2s;
}
.record:hover {
background-color: #f1f1f1;
transform: translateY(-1px);
}
.btn.signup {
background: #748C62;
color: white;
border: none;
padding: 12px 25px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s, transform 0.2s;
}
.btn.signup:hover {
background: #45a049;
transform: translateY(-1px);
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
.btn.signup {
width: 100%;
font-size: 18px;
}
}
p:last-child {
margin-bottom: 0;
overflow-wrap: break-word;
}
.verify{
display: flex;
justify-content: flex-end;
}
</style>
</head>
<body>
<div class="container">
<h1>Domain Verification Response</h1>
<h1>Instructions to Verify Domain</h1>
<div class="domain-details">
<div class="alert alert-danger">
<ul>
<li>Domain is {{$domain->getDomain()->getState()}}</li>
</ul>
<div class="alert alert-{{$domain->getDomain()->getState() == 'active'?'success':'danger'}}">
<ul>
<li>Domain is {{$domain->getDomain()->getState()}}</li>
</ul>
</div>
<h2>Domain Information</h2>
<p><strong>Name:</strong> {{ $domain->getDomain()->getName() }}</p>
<p><strong>State:</strong> {{ $domain->getDomain()->getState() }}</p>
</div>
<div class="dns-records">
<h2>Inbound DNS Records</h2>
@foreach($domain->getInboundDnsRecords() as $record)
<div class="record">
<p><strong>Type:</strong> {{ $record->getType() }}</p>
<p><strong>Value:</strong> {{ $record->getValue() }}</p>
</div>
@endforeach
<h2>Outbound DNS Records</h2>
<h2>Step 1: Add Forwarder</h2>
<div class="record">
<p>Forward your email to internal email: <span class="alert-success"><b>kundesone.{{ $domain->getDomain()->getName() }}@mailgun.kundesone.no</b></span>. Make sure to forward only your company email that you registered.</p>
</div>
<h2>Step 2: Add Outbound DNS Records</h2>
@foreach($domain->getOutboundDnsRecords() as $record)
<div class="record">
<p><strong>Type:</strong> {{ $record->getType() }}</p>
@ -67,69 +145,31 @@
<p><strong>Value:</strong> {{ $record->getValue() }}</p>
</div>
@endforeach
<h2>Step 3: Add Inbound DNS Records</h2>
@foreach($domain->getInboundDnsRecords() as $record)
<div class="record">
<p><strong>Type:</strong> {{ $record->getType() }}</p>
<p><strong>Name:</strong> {{ $domain->getDomain()->getName() }}</p>
<p><strong>Value:</strong> {{ $record->getValue() }}</p>
<p><strong>Priority:</strong> 10</p>
</div>
@endforeach
<h2>Note: DNS Propagation Time</h2>
<div class="record">
<p>DNS propagation can take up to 48 hours. During this time, your domain may not be active.</p>
</div>
</div>
<form id="verify-form" action="{{route('verifyDomain')}}" method="post">
@csrf
<input type="hidden" name="domain" value="{{$domain->getDomain()->getName()}}"/>
<button type="submit" class="btn signup">Verify Domain
</button>
<form id="verify-form" action="{{route('verifyDomain')}}" method="post">
@csrf
<input type="hidden" name="domain" value="{{$domain->getDomain()->getName()}}"/>
<div class="verify">
<button type="submit" class="btn signup">Verify Domain</button>
</div>
</form>
</div>
<style>
#verify-form{
display:flex;
justify-content: flex-end;
}
.btn.signup{
background:#748c62;
color:white;
}
.container {
width: 80%;
margin: 0 auto;
padding: 20px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1, h2 {
color: #333;
}
.message {
background-color: #f0f0f0;
padding: 10px;
border-left: 5px solid green;
margin-bottom: 20px;
}
.domain-details, .dns-records {
background-color: #fff;
border: 1px solid #ddd;
padding: 10px;
margin-bottom: 20px;
}
.record {
background-color: #f9f9f9;
border: 1px solid #eee;
padding: 8px;
margin-bottom: 10px;
word-break: break-all;
}
</style>
</body>
</html>
</html>

View File

@ -14,7 +14,7 @@
<button type="button">Response</button>
<button type="button">Canned Responses</button>
<button type="button">Acknowledge</button>
<button type="button">Rules</button>
<!--<button type="button">Rules</button>-->
<button type="button">Spam handling</button>
<!--<button type="button">Tags</button>-->
<!--<button type="button">Others</button>-->
@ -30,7 +30,7 @@
<div class="col col-left">
<div class="dev-input-group dev-input-group-input-info">
<label>Receiving email address </label>
<input name="company_email" type="email" value="{{ Auth::user()->company->email }}" placeholder="kundo@limonmedia.no" readonly required>
<input name="company_email" type="email" value="{{ $company->email }}" placeholder="support@kundesone.no" readonly required>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. support@yourcompany.com</span>
@ -38,23 +38,23 @@
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>Email address on Kundo</label>
<input name="kundo_email" type="email" value="{{ $basic_setting[0]['value'] ?? '' }}" placeholder="kundo.limonmedia.no@mail.kundo.se" required>
<input name="kundo_email" readonly type="email" value="{{ $company->internal_email }}" placeholder="kundo.limonmedia.no@mailgun.kundesone.no" required>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>Updates when you change the email address above</span>
<span>Your kundesone internal email address.</span>
</div>
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>Inbox name</label>
<input name="inbox_name" type="text" placeholder="Type here.." value="{{ $basic_setting[1]['value'] ?? '' }}" required>
<input name="inbox_name" type="text" placeholder="Type here.." value="{{ $company->getMeta('inbox_name') ?? '' }}" required>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>Your internal name. I.e. the email address</span>
<span>Your internal name. I.e. the Inbox</span>
</div>
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>Sender name</label>
<input name="sender_name" type="text" placeholder="Type here.." value="{{ $basic_setting[2]['value'] ?? '' }}" required>
<input name="sender_name" type="text" placeholder="Type here.." value="{{ $company->getMeta('sender_name') ?? '' }}" required>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. company name or department</span>
@ -69,7 +69,7 @@
<select name="language" required>
<option value="">Select Language</option>
@foreach($languages as $language)
<option value="{{$language->value}}" @if(count($basic_setting) > 0 && $basic_setting[3]['value'] == $language->value) selected @endif>{{$language->title}}</option>
<option value="{{$language->value}}" @if(count($basic_setting) > 0 && $company->getMeta('language') == $language->value) selected @endif>{{$language->title}}</option>
@endforeach
</select>
</div>
@ -80,7 +80,7 @@
<select name="timezone" required>
<option value="">Select your Timezone</option>
@foreach($timezones as $timezone)
<option value="{{$timezone->label}}" @if(count($basic_setting) > 0 && $basic_setting[4]['value'] == $timezone->label) selected @endif>{{$timezone->label}}</option>
<option value="{{$timezone->label}}" @if(count($basic_setting) > 0 && $company->getMeta('timezone') == $timezone->label) selected @endif>{{$timezone->label}}</option>
@endforeach
</select>
</div>
@ -165,7 +165,7 @@
<h2>Common email signature</h2>
</div>
<div class="dev-content-inner">
<form method="POST" action="{{ route('inbox.email.signature') }}">
<form method="POST" action="{{ route('inbox.email.signature') }}" onsubmit="return validateSignatureForm()">
@csrf
<div class="dev-input-group dev-input-group-input-info">
<div class="input-box-row">
@ -186,13 +186,21 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
title.</span>
</div>
</div>
@if(Auth::user()->role_id == 2)
<button type="submit" class="dev-form-submit-btn">Save</button>
@endif
</form>
</div>
</div>
</div>
<script>
function validateSignatureForm() {
var textarea = document.getElementById('editor1');
if (textarea.value === '') {
toastr.error('Please enter a message in the textarea.');
return false;
}
return true;
}
</script>
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<script>
CKEDITOR.replace('editor1');
@ -218,7 +226,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<h3>Monday</h3>
<div class="schedule-box">
@php
$monday_start_time = getResponse(Auth::user()->company->id, 'monday_start_time', 'Response Time');
$monday_start_time = getResponse($company->id, 'monday_start_time', 'Response Time');
@endphp
<input id="monday_start_time" name="monday_start_time" type="time" @if(isset($monday_start_time) && !is_null($monday_start_time)) value="{{$monday_start_time->value}}" @endif placeholder="08:00">
<!-- <img src="{{ asset('images/downn.svg') }}" alt=""> -->
@ -226,14 +234,14 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<span class="line"></span>
<div class="schedule-box">
@php
$monday_end_time = getResponse(Auth::user()->company->id, 'monday_end_time', 'Response Time');
$monday_end_time = getResponse($company->id, 'monday_end_time', 'Response Time');
@endphp
<input id="monday_end_time" name="monday_end_time" type="time" @if(isset($monday_end_time) && !is_null($monday_end_time)) value="{{$monday_end_time->value}}" @endif placeholder="16:00">
<!-- <img src="{{ asset('images/downn.svg') }}" alt=""> -->
</div>
<div class="dev-input-group">
@php
$monday_closed = getResponse(Auth::user()->company->id, 'monday_closed', 'Response Time');
$monday_closed = getResponse($company->id, 'monday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="monday_closed" name="monday_closed" @if(isset($monday_closed) && !is_null($monday_closed)) checked @endif type="checkbox" onclick="toggleClosed('monday')">
@ -244,7 +252,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Tuesday</h3>
@php
$tuesday_start_time = getResponse(Auth::user()->company->id, 'tuesday_start_time', 'Response Time');
$tuesday_start_time = getResponse($company->id, 'tuesday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="tuesday_start_time" name="tuesday_start_time" type="time" @if(isset($tuesday_start_time) && !is_null($tuesday_start_time)) value="{{$tuesday_start_time->value}}" @endif placeholder="08:00">
@ -252,7 +260,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$tuesday_end_time = getResponse(Auth::user()->company->id, 'tuesday_end_time', 'Response Time');
$tuesday_end_time = getResponse($company->id, 'tuesday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="tuesday_end_time" name="tuesday_end_time" type="time" @if(isset($tuesday_end_time) && !is_null($tuesday_end_time)) value="{{$tuesday_end_time->value}}" @endif placeholder="16:00">
@ -260,7 +268,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$tuesday_closed = getResponse(Auth::user()->company->id, 'tuesday_closed', 'Response Time');
$tuesday_closed = getResponse($company->id, 'tuesday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="tuesday_closed" name="tuesday_closed" @if(isset($tuesday_closed) && !is_null($tuesday_closed)) checked @endif type="checkbox" onclick="toggleClosed('tuesday')">
@ -271,7 +279,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Wednesday</h3>
@php
$wednesday_start_time = getResponse(Auth::user()->company->id, 'wednesday_start_time', 'Response Time');
$wednesday_start_time = getResponse($company->id, 'wednesday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="wednesday_start_time" name="wednesday_start_time" @if(isset($wednesday_start_time) && !is_null($wednesday_start_time)) value="{{$wednesday_start_time->value}}" @endif type="time" placeholder="08:00">
@ -279,7 +287,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$wednesday_end_time = getResponse(Auth::user()->company->id, 'wednesday_end_time', 'Response Time');
$wednesday_end_time = getResponse($company->id, 'wednesday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="wednesday_end_time" name="wednesday_end_time" @if(isset($wednesday_end_time) && !is_null($wednesday_end_time)) value="{{$wednesday_end_time->value}}" @endif type="time" placeholder="16:00">
@ -287,7 +295,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$wednesday_closed = getResponse(Auth::user()->company->id, 'wednesday_closed', 'Response Time');
$wednesday_closed = getResponse($company->id, 'wednesday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="wednesday_closed" name="wednesday_closed" @if(isset($wednesday_closed) && !is_null($wednesday_closed)) checked @endif type="checkbox" onclick="toggleClosed('wednesday')">
@ -298,7 +306,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Thursday</h3>
@php
$thursday_start_time = getResponse(Auth::user()->company->id, 'thursday_start_time', 'Response Time');
$thursday_start_time = getResponse($company->id, 'thursday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="thursday_start_time" name="thursday_start_time" @if(isset($thursday_start_time) && !is_null($thursday_start_time)) value="{{$thursday_start_time->value}}" @endif type="time" placeholder="08:00">
@ -306,7 +314,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$thursday_end_time = getResponse(Auth::user()->company->id, 'thursday_end_time', 'Response Time');
$thursday_end_time = getResponse($company->id, 'thursday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="thursday_end_time" name="thursday_end_time" @if(isset($thursday_end_time) && !is_null($thursday_end_time)) value="{{$thursday_end_time->value}}" @endif type="time" placeholder="16:00">
@ -314,7 +322,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$thursday_closed = getResponse(Auth::user()->company->id, 'thursday_closed', 'Response Time');
$thursday_closed = getResponse($company->id, 'thursday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="thursday_closed" name="thursday_closed" @if(isset($thursday_closed) && !is_null($thursday_closed)) checked @endif type="checkbox" onclick="toggleClosed('thursday')">
@ -325,7 +333,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Friday</h3>
@php
$friday_start_time = getResponse(Auth::user()->company->id, 'friday_start_time', 'Response Time');
$friday_start_time = getResponse($company->id, 'friday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="friday_start_time" name="friday_start_time" @if(isset($friday_start_time) && !is_null($friday_start_time)) value="{{$friday_start_time->value}}" @endif type="time" placeholder="08:00">
@ -333,7 +341,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$friday_end_time = getResponse(Auth::user()->company->id, 'friday_end_time', 'Response Time');
$friday_end_time = getResponse($company->id, 'friday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="friday_end_time" name="friday_end_time" @if(isset($friday_end_time) && !is_null($friday_end_time)) value="{{$friday_end_time->value}}" @endif type="time" placeholder="16:00">
@ -341,7 +349,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$friday_closed = getResponse(Auth::user()->company->id, 'friday_closed', 'Response Time');
$friday_closed = getResponse($company->id, 'friday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="friday_closed" name="friday_closed" @if(isset($friday_closed) && !is_null($friday_closed)) checked @endif type="checkbox" onclick="toggleClosed('friday')">
@ -352,7 +360,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Saturday</h3>
@php
$saturday_start_time = getResponse(Auth::user()->company->id, 'saturday_start_time', 'Response Time');
$saturday_start_time = getResponse($company->id, 'saturday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="saturday_start_time" name="saturday_start_time" @if(isset($saturday_start_time) && !is_null($saturday_start_time)) value="{{$saturday_start_time->value}}" @endif type="time" placeholder="08:00">
@ -360,7 +368,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$saturday_end_time = getResponse(Auth::user()->company->id, 'saturday_end_time', 'Response Time');
$saturday_end_time = getResponse($company->id, 'saturday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="saturday_end_time" name="saturday_end_time" @if(isset($saturday_end_time) && !is_null($saturday_end_time)) value="{{$saturday_end_time->value}}" @endif type="time" placeholder="16:00">
@ -368,7 +376,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$satureday_closed = getResponse(Auth::user()->company->id, 'satureday_closed', 'Response Time');
$satureday_closed = getResponse($company->id, 'satureday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="saturday_closed" name="saturday_closed" @if(isset($saturday_closed) && !is_null($saturday_closed)) checked @endif type="checkbox" onclick="toggleClosed('saturday')">
@ -379,7 +387,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-content-schedule">
<h3>Sunday</h3>
@php
$sunday_start_time = getResponse(Auth::user()->company->id, 'sunday_start_time', 'Response Time');
$sunday_start_time = getResponse($company->id, 'sunday_start_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="sunday_start_time" name="sunday_start_time" @if(isset($sunday_start_time) && !is_null($sunday_start_time)) value="{{$sunday_start_time->value}}" @endif type="time" placeholder="08:00">
@ -387,7 +395,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<span class="line"></span>
@php
$sunday_end_time = getResponse(Auth::user()->company->id, 'sunday_end_time', 'Response Time');
$sunday_end_time = getResponse($company->id, 'sunday_end_time', 'Response Time');
@endphp
<div class="schedule-box">
<input id="sunday_end_time" name="sunday_end_time" @if(isset($sunday_end_time) && !is_null($sunday_end_time)) value="{{$sunday_end_time->value}}" @endif type="time" placeholder="16:00">
@ -395,7 +403,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
<div class="dev-input-group">
@php
$sunday_closed = getResponse(Auth::user()->company->id, 'sunday_closed', 'Response Time');
$sunday_closed = getResponse($company->id, 'sunday_closed', 'Response Time');
@endphp
<label class="dev-checkbox-wrapper">Closed
<input id="sunday_closed" name="sunday_closed" @if(isset($sunday_closed) && !is_null($sunday_closed)) checked @endif type="checkbox" onclick="toggleClosed('sunday')">
@ -409,7 +417,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
<div class="dev-input-group dev-input-group-input-info">
<label>Expected response time, in hours</label>
@php
$expected_response = getResponse(Auth::user()->company->id, 'expected_response', 'Response Time');
$expected_response = getResponse($company->id, 'expected_response', 'Response Time');
@endphp
<input name="expected_response" type="text" @if(isset($expected_response) && !is_null($expected_response)) value="{{ $expected_response->value }}" @endif placeholder="8">
<div class="dev-input-info">
@ -420,9 +428,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
</div>
</div>
</form>
@if(Auth::user()->role_id == 2)
<button type="submit" class="dev-form-submit-btn">Save</button>
@endif
</div>
</form>
</div>
@ -471,15 +477,13 @@ function toggleClosed(day) {
@csrf
<div class="dev-input-group dev-input-group-input-info">
<label>Name</label>
<input name="name" type="text" placeholder="Type here" value="{{ $canned_response[0]['value'] ?? '' }}" required>
<input name="name" type="text" placeholder="Type here" required>
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>Text</label>
<textarea name="text" required rows="6">{{ $canned_response[1]['value'] ?? '' }}</textarea>
<textarea name="text" required rows="6"></textarea>
</div>
@if(Auth::user()->role_id == 2)
<button type="submit" class="dev-form-submit-btn">Save</button>
@endif
</form>
</div>
</div>
@ -487,20 +491,29 @@ function toggleClosed(day) {
<div class="dev-title-row">
<h2>Canned responses</h2>
<div class="dev-users-boxs">
@foreach(json_decode($canned_response->value) as $index => $values)
@if(count($canned_response) > 0)
@foreach($canned_response as $index => $value)
@php
$result = json_decode($value->value);
@endphp
<div class="dev-users-box">
<div class="dev-box">
<h3>{{ $values->name }}</h3>
<span>{{ $values->text }}</span>
<h3>{{ $result->name }}</h3>
<span>{{ $result->text }}</span>
</div>
<!--<div class="dev-icon">-->
<!-- <img src="{{ asset('images/settingss.svg') }}" alt="">-->
<!--</div>-->
<div class="dev-icon">
<img src="{{ asset('images/settingss.svg') }}" alt="">
</div>
<div class="dev-icon">
<a href="{{ route('delete.canned.response', $index) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
<a style="cursor:pointer;" href="{{ route('delete.canned.response', $value->id) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
</div>
</div>
@endforeach
@endif
</div>
</div>
</div>
@ -520,7 +533,7 @@ function toggleClosed(day) {
@csrf
<div class="dev-input-group">
@php
$activate_delivery_confirmation = getResponse(Auth::user()->company->id, 'activate_delivery_confirmation', 'Acknowledgement of Receipt')
$activate_delivery_confirmation = getResponse($company->id, 'activate_delivery_confirmation', 'Acknowledgement of Receipt')
@endphp
<label class="dev-checkbox-wrapper">Activate delivery confirmation
<input name="activate_delivery_confirmation" @if(isset($activate_delivery_confirmation) && !is_null($activate_delivery_confirmation)) checked @endif type="checkbox">
@ -530,7 +543,7 @@ function toggleClosed(day) {
<div class="dev-form-inner">
<div class="dev-input-group dev-input-group-input-info">
@php
$automatic_reply_subject = getResponse(Auth::user()->company->id, 'automatic_reply_subject', 'Acknowledgement of Receipt')
$automatic_reply_subject = getResponse($company->id, 'automatic_reply_subject', 'Acknowledgement of Receipt')
@endphp
<label>Subject of the automatic reply</label>
<input name="automatic_reply_subject" type="text" @if(isset($automatic_reply_subject) && !is_null($automatic_reply_subject)) value="{{ $automatic_reply_subject->value }}" @endif placeholder="Type here">
@ -558,7 +571,7 @@ function toggleClosed(day) {
<h3>Text in the automatic reply</h3>
<div class="input-box-row">
@php
$automatic_reply_text = getResponse(Auth::user()->company->id, 'automatic_reply_text', 'Acknowledgement of Receipt')
$automatic_reply_text = getResponse($company->id, 'automatic_reply_text', 'Acknowledgement of Receipt')
@endphp
<div class="ui card inbox-send-message-card w-100">
<div class="content input-options bg-dark-green-color">
@ -596,7 +609,7 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
</div>
<div class="dev-input-group">
@php
$confirmation_receipt = getResponse(Auth::user()->company->id, 'confirmation_receipt', 'Acknowledgement of Receipt')
$confirmation_receipt = getResponse($company->id, 'confirmation_receipt', 'Acknowledgement of Receipt')
@endphp
<label class="dev-checkbox-wrapper">Only send confirmation of receipt outside
of business hours
@ -612,7 +625,7 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
</p>
<div class="dev-input-group">
@php
$activate_ticket_number = getResponse(Auth::user()->company->id, 'activate_ticket_number', 'Acknowledgement of Receipt')
$activate_ticket_number = getResponse($company->id, 'activate_ticket_number', 'Acknowledgement of Receipt')
@endphp
<label class="dev-checkbox-wrapper">Activate ticket numbers
<input name="activate_ticket_number" @if(isset($activate_ticket_number) && !is_null($activate_ticket_number)) checked @endif type="checkbox">
@ -645,185 +658,178 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
</div>
<!-- -->
<div class="dev-tabcontent dev-tabcontent-rules">
<div class="dev-tabcontent-outers">
<div class="dev-title-row">
<h2>Automatic rules</h2>
<p>
With automatic rules you can perform common tasks automatically, e.g. assign an
e-mail to a specific person if the subject contains a certain word. Automatic
rules consist of a filter and an effect.
</p>
</div>
<h2>Create a new rule</h2>
<form>
<div class="dev-input-group dev-input-group-input-info">
<label>Name</label>
<input type="text" placeholder="Type here..">
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>Tag everything from the sales department</span>
</div>
</div>
</form>
<h3>Filter</h3>
<p>If you complete the From, To, and Subject fields, they must all match an email for
the rule to be activated. Leave any field empty to avoid having to match that part.
If you specify multiple email addresses in the same field, it's enough for one of
them to match.
If, for example, you fill in <a href="#">support@kundo.se</a> and <a
href="#">info@kundo.se</a> in the From field,
and "hello" in the subject field, all e-mails from <a href="#">support@kundo.se</a>
OR <a href="#">info@kundo.se</a>
that ALSO contains "hello" in the subject field will match.
If you want to activate a rule for all emails that come from a group of email
addresses, you can write *@kundo.se in the "from" field.
</p>
<form>
<div class="dev-form-inner">
<div class="col-left">
<div class="dev-input-group dev-input-group-input-info">
<label>From</label>
<input type="text" placeholder="Type here..">
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. example@example.com or *@example.com</span>
</div>
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>To</label>
<input type="text" placeholder="Type here..">
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. test@example.com</span>
</div>
</div>
</div>
<div class="col-right">
<div class="dev-input-group dev-input-group-input-info">
<label>Subject Contains</label>
<input type="text" placeholder="Type here..">
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. Great deals!</span>
</div>
</div>
<div class="dev-input-group dev-input-group-input-info">
<label>Text Contains</label>
<input type="text" placeholder="Type here..">
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. Great deals!</span>
</div>
</div>
</div>
</div>
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">All e-mails automatically marked as spam
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
</form>
<h3>Exceptions</h3>
<p>Email that matches the filter above but for which the rule should not be activated.
</p>
<form>
<div class="dev-form-inner">
<div class="col-left">
<div class="dev-input-group dev-input-group-input-info">
<label>Subject Contains</label>
<textarea rows="6">Type here..</textarea>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>Order Confirmation</span>
</div>
</div>
</div>
<div class="col-right">
<div class="dev-input-group dev-input-group-input-info">
<label>Text Contains</label>
<textarea rows="6">Type here..</textarea>
<div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info">
<span>Your Order</span>
</div>
</div>
</div>
</div>
</form>
<h3>Effect</h3>
<p>The effect describes what should happen when the filter above matches. It happens
automatically, before the e-mail shows up in
the dashboard.</p>
<form>
<div class="dev-content-schedule">
<label>Monday</label>
<div class="schedule-box">
<input type="text" placeholder="08:00">
<img src="{{ asset('images/downn.svg') }}" alt="">
</div>
</div>
<div class="dev-form-inner">
<div class="col-left">
<div class="dev-input-group dev-input-group-input-info">
<label>Message to assigned editor</label>
<textarea rows="6">Hi! Feel free to contact us via chat if you are wondering about anything.
</textarea>
</div>
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">Remove and hide from the statistics 
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
</div>
<div class="col-right">
<div class="dev-content-schedule">
<label>Add tags</label>
<div class="schedule-box">
<input type="text" placeholder="Add tags">
<img src="{{ asset('images/downn.svg') }}" alt="">
</div>
</div>
<div class="checkbox-box">
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">Set as done
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">Set highest priority
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">Mark as spam
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
<div class="dev-input-group">
<label class="dev-checkbox-wrapper">Set lowest priority
<input type="checkbox">
<span class="checkmark"></span>
</label>
</div>
</div>
</div>
</div>
</form>
<!--<div class="dev-tabcontent dev-tabcontent-rules">-->
<!-- <div class="dev-tabcontent-outers">-->
<!-- <div class="dev-title-row">-->
<!-- <h2>Automatic rules</h2>-->
<!-- <p>-->
<!-- With automatic rules you can perform common tasks automatically, e.g. assign an-->
<!-- e-mail to a specific person if the subject contains a certain word. Automatic-->
<!-- rules consist of a filter and an effect.-->
<!-- </p>-->
<!-- </div>-->
<!-- <h2>Create a new rule</h2>-->
<!-- <form method="POST" action="{{ route('update.rule') }}">-->
<!-- @csrf-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Name</label>-->
<!-- <input name="name" type="text" placeholder="Type here.." value="{{$rule->name ?? ''}}">-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>Tag everything from the sales department</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- <h3>Filter</h3>-->
<!-- <p>If you complete the From, To, and Subject fields, they must all match an email for-->
<!-- the rule to be activated. Leave any field empty to avoid having to match that part.-->
<!-- If you specify multiple email addresses in the same field, it's enough for one of-->
<!-- them to match.-->
<!-- If, for example, you fill in <a href="#">support@kundo.se</a> and <a-->
<!-- href="#">info@kundo.se</a> in the From field,-->
<!-- and "hello" in the subject field, all e-mails from <a href="#">support@kundo.se</a>-->
<!-- OR <a href="#">info@kundo.se</a>-->
<!-- that ALSO contains "hello" in the subject field will match.-->
<!-- If you want to activate a rule for all emails that come from a group of email-->
<!-- addresses, you can write *@kundo.se in the "from" field.-->
<!-- </p>-->
<!-- <div class="dev-form-inner">-->
<!-- <div class="col-left">-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>From</label>-->
<!-- <input type="email" name="from" placeholder="Type here.." value="{{$rule->from ?? ''}}">-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>E.g. example@example.com or *@example.com</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>To</label>-->
<!-- <input type="email" name="to" placeholder="Type here.." value="{{$rule->to ?? ''}}">-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>E.g. test@example.com</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-right">-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Subject Contains</label>-->
<!-- <input type="text" name="subject_contains" placeholder="Type here.." value="{{$rule->subject_contains ?? ''}}">-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>E.g. Great deals!</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Text Contains</label>-->
<!-- <input type="text" name="text_contains" placeholder="Type here.." value="{{$rule->text_contains ?? ''}}">-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>E.g. Great deals!</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">All e-mails automatically marked as spam-->
<!-- <input name="all_emails_automatically_mark_as_spam" type="checkbox" @if($rule && !is_null($rule->all_emails_automatically_mark_as_spam)) checked @endif>-->
<!-- <span class="checkmark"></span>-->
<!-- </label>-->
<!-- </div>-->
<!-- <h3>Exceptions</h3>-->
<!-- <p>Email that matches the filter above but for which the rule should not be activated.-->
<!-- </p>-->
<!-- <div class="dev-form-inner">-->
<!-- <div class="col-left">-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Subject Contains</label>-->
<!-- <textarea rows="6" name="subject1_contains">{{$rule->subject1_contains ?? ''}}</textarea>-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>Order Confirmation</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--<div class="col-right">-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Text Contains</label>-->
<!-- <textarea rows="6">Type here..</textarea>-->
<!-- <div class="dev-input-info">-->
<!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<!-- <span>Your Order</span>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
<!-- </div>-->
<!-- <h3>Effect</h3>-->
<!-- <p>The effect describes what should happen when the filter above matches. It happens-->
<!-- automatically, before the e-mail shows up in-->
<!-- the dashboard.</p>-->
<!-- <div class="dev-content-schedule">-->
<!-- <label>Assign To</label>-->
<!-- <div class="schedule-box">-->
<!-- <select name="assign_to">-->
<!-- @foreach($company_users as $company_user)-->
<!-- <option value="{{$company_user->user->id}}" @if($rule && !is_null($rule->assign_to) && $rule->assign_to == $company_user->user->id) selected @endif>{{$company_user->user->name}}</option>-->
<!-- @endforeach-->
<!-- </select>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="dev-form-inner">-->
<!-- <div class="col-left">-->
<!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Message to assigned editor</label>-->
<!-- <textarea rows="6" name="message_to_assigned_editor">{{$rule->message_to_assigned_editor ?? ''}}</textarea>-->
<!-- </div>-->
<!--<div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">Remove and hide from the statistics -->
<!-- <input type="checkbox">-->
<!-- <span class="checkmark"></span>-->
<!-- </label>-->
<!--</div>-->
<!-- </div>-->
<!-- <div class="col-right">-->
<!-- <div class="dev-content-schedule">-->
<!-- <label>Add tags</label>-->
<!-- <div class="schedule-box">-->
<!-- <select name="tag_id">-->
<!-- @foreach($tags as $tag)-->
<!-- <option value="{{$tag->id}}" @if($rule && !is_null($rule->tag_id) && $rule->tag_id == $tag->id) selected @endif>{{$tag->name}}</option>-->
<!-- @endforeach-->
<!-- </select>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="checkbox-box">-->
<!-- <div class="dev-input-group">-->
<!-- <input type="radio" value="set as done" name="status" @if($rule && !is_null($rule->status) && $rule->status == 'set as done') checked @endif>-->
<!-- <label class="dev-checkbox-wrapper">Set as done</label>-->
<!-- </div>-->
<!-- <div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">Set highest priority</label>-->
<!-- <input type="radio" value="Set highest priority" name="priority" @if($rule && !is_null($rule->priority) && $rule->priority == 'Set highest priority') checked @endif>-->
<!-- </div>-->
<!-- <div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">Mark as spam</label>-->
<!-- <input type="radio" value="mask as spam" name="status" @if($rule && !is_null($rule->status) && $rule->status == 'mask as spam') checked @endif>-->
<!-- </div>-->
<!-- <div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">Set lowest priority</label>-->
<!-- <input type="radio" value="Set lowest priority" name="priority" @if($rule && !is_null($rule->priority) && $rule->priority == 'Set lowest priority') checked @endif>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<button type="button" class="dev-form-submit-btn">Save</button>
</div>
<!-- <button type="submit" class="dev-form-submit-btn">Save</button>-->
<!-- </form>-->
<!-- </div>-->
</div>
<!--</div>-->
<!-- -->
<div class="dev-tabcontent dev-tabcontent-canned">
<div class="dev-tabcontent-outers">
@ -865,24 +871,57 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
<h2>Email addresses that never should be marked as spam<br>
Blocked email addresses</h2>
<div class="dev-users-boxs">
@if(!is_null($spam_handling))
@foreach(json_decode($spam_handling->value) as $index => $values)
<div class="dev-users-box">
<div class="dev-box">
<h3>{{ $values->spam_email }}</h3>
<span>{{ $values->marking_radio }}</span>
</div>
<!--<div class="dev-icon">-->
<!-- <img src="{{ asset('images/settingss.svg') }}" alt="">-->
<!--</div>-->
<div class="dev-icon">
<img src="{{ asset('images/settingss.svg') }}" alt="">
</div>
<div class="dev-icon">
<a href="{{ route('delete.spam.handling', $index) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
<a href="{{ route('delete.spam.handling', $index) }}" style="cursor:pointer;" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
</div>
</div>
@endforeach
@endif
</div>
</div>
</div>
</div>
<script defer>
document.addEventListener('DOMContentLoaded', function () {
const deleteLinks = document.querySelectorAll('.delete-user');
deleteLinks.forEach(function (link) {
link.addEventListener('click', function (event) {
event.preventDefault(); // Prevent the default link click behavior
const url = this.href;
Swal.fire({
title: 'Are you sure?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
// If the user confirms, redirect to the delete URL
window.location.href = url;
}
});
});
});
});
</script>
<!-- -->
<div class="dev-tabcontent dev-tabcontent-tags">
<div class="dev-tabcontent-outers">

View File

@ -74,9 +74,112 @@ class="form-control input-reply-textarea" id="editor1" required></textarea>
</div>
</div>
<!--wysywyg editor-->
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<!--<script src="https://cdn.ckeditor.com/4.24.0/standard/ckeditor.js"></script>-->
<!-- Canned Response Modal -->
<!-- Canned Response Modal -->
<div id="cannedResponseModal" class="modal">
<div class="modal-content">
<span class="close-button">&times;</span>
<h2>Canned Responses</h2>
<ul>
@if(count($canned_response) > 0)
@foreach($canned_response as $index => $value)
@php
$result = json_decode($value->value);
@endphp
<li><button class="canned-response" data-response="{{$result->text}}">{{$result->name}}</button></li>
@endforeach
@endif
</ul>
</div>
</div>
<script>
CKEDITOR.replace('editor1');
//CKEDITOR.replace('editor1');
CKEDITOR.plugins.add('addcannedresponse', {
init: function(editor) {
editor.addCommand('addCannedResponseCmd', {
exec: function(editor) {
document.getElementById('cannedResponseModal').style.display = 'block';
}
});
editor.ui.addButton('AddCannedResponse', {
label: 'Insert Canned Response',
command: 'addCannedResponseCmd',
icon: 'https://kundesone.no/images/canned.png', // Use an accessible icon URL or local path
toolbar: 'insert,0'
});
}
});
CKEDITOR.replace('editor1', {
extraPlugins: 'addcannedresponse', // Ensure your plugin is added to extraPlugins
// Optionally customize your toolbar further, or use the default configuration
toolbarGroups: [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
]
});
// Get the modal
var modal = document.getElementById("cannedResponseModal");
// Get the button that opens the modal
var btn = document.getElementsByClassName("canned-response");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close-button")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// Add event listeners to canned response buttons
Array.from(btn).forEach(function(element) {
element.addEventListener('click', function() {
var response = this.getAttribute('data-response');
CKEDITOR.instances.editor1.insertHtml(response);
modal.style.display = "none";
});
});
</script>
<!-- Action Box -->
@ -86,9 +189,105 @@ class="form-control input-reply-textarea" id="editor1" required></textarea>
</div>
</div>
<!-- Tagify CSS -->
<link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet">
<!-- Tagify JS -->
<script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.min.js"></script>
<style>
#cke_editor1{
width:100%!important;
}
div.chat-inbox.chat-box{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 100%;
max-width: 600px;
}
.close-button {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
background:;#748c62 !important
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#cannedResponseModal ul {
list-style: none;
padding: 0;
}
#cannedResponseModal li {
padding: 8px 0; /* Spacing between buttons */
}
.canned-response {
width: 100%;
padding: 10px;
font-size: 16px;
border: none;
background-color: #4CAF50;
color: white;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
}
.canned-response:hover {
background-color: #45a049;
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.24);
}
</style>
<!--Script Tag-->
<script>
$(document).ready(function(){
var activeTicketId = $('.chat-detail-item.active').data('ticket-id');
// Load chat messages for the active ticket on page load
@ -137,7 +336,7 @@ function loadActionBox(ticketId) {
$('.saveReply').on('click', function(){
var message = CKEDITOR.instances.editor1.getData();
if(message.trim() === '') {
alert('Message cannot be empty');
toastr.error('Message cannot be empty');
return;
}
$.ajax({

View File

@ -4,18 +4,475 @@
@section('content')
<script>
$(document).ready(function(){
$('.side-bar-links a').removeClass('bg-light-color');
$('.aw-a-inbox').addClass('bg-light-color');
});
</script>
<!-- Toastr CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet">
<!-- Toastr JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<!-- SweetAlert2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
<!-- SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>
@php
$companyId = getSelectedCompany();
$company_users = get_company_users($companyId);
@endphp
<script>
$(document).ready(function() {
// Toggle filter dropdown on button click
$('.list-filter-btn').click(function() {
$('.filter-options').toggle();
});
// Initial hide for handle_multiple__options
$('.filter-options').hide();
$('.handle_multiple__options').hide();
// Toggle visibility of handle_multiple__options on button click
$('.handle-multiple-btn').click(function() {
$('.handle_multiple__options').toggle();
});
// Initially disable all the buttons
$('.handle_multiple__options .tags button').prop('disabled', true);
// Enable/disable buttons based on the select all checkbox
// $('#select-all').change(function() {
// if ($(this).is(':checked')) {
// $('.handle_multiple__options .tags button').prop('disabled', false);
// } else {
// $('.handle_multiple__options .tags button').prop('disabled', true);
// }
// });
// Show the modal when "Assign post" button is clicked
$('.handle_multiple__options .tags button:contains("Assign post")').click(function(e) {
e.preventDefault();
$('#customModal').show();
});
// Show the modal when "Move" button is clicked
$('.handle_multiple__options .tags button:contains("Move")').click(function(e) {
e.preventDefault();
$('#customModal2').show();
});
// Show the modal when "Reply to multiple" button is clicked
$('.handle_multiple__options .tags button:contains("Reply to multiple")').click(function(e) {
e.preventDefault();
$('#customModal3').show();
});
// Close the modal when the close button or outside the modal is clicked
$('.modal-close, .modal').click(function() {
$('.modal').hide();
});
// Prevent modal content from closing the modal when clicked
$('.modal-content').click(function(e) {
e.stopPropagation();
});
// Update Select status options based on Select filter selection
$('#filter-select').change(function() {
var selectedFilter = $(this).val();
console.log("Selected filter:", selectedFilter); // Debugging log
updateStatusOptions(selectedFilter);
});
// Initially hide filter based data section
$('.filter_based__data').hide();
// Function to update status options based on selectedFilter
function updateStatusOptions(selectedFilter) {
console.log("Updating status options for:", selectedFilter); // Debugging log
switch (selectedFilter) {
case 'Assigned to':
// $('#status-select').html(`
// <option disabled value="">Select assigned to</option>
// <option value="Assigned">Assigned</option>
// <option value="Unassigned">Unassigned</option>
// <option value="Margin">Margin</option>
// `);
var options = '<option value="">Select assigned to</option>';
// Loop through the company_users array
@foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach
$('#status-select').html(options);
$('.filter_based__data').show();
break;
case 'With activity':
$('#status-select').html(`
<option value="">Select No activity</option>
<option value="last 24 hours">Last 24 hours</option>
<option value="last 3 days">Last 3 days</option>
<option value="last week">Last week</option>
<option value="last month">Last month</option>
<option value="last 3 months">Last 3 months</option>
<option value="last 6 months">Last 6 months</option>
<option value="last year">Last year</option>
<option value="the past 2 years">The past 2 years</option>
<option value="the past 3 years">The past 3 years</option>
<option value="the past 4 years">The past 4 years</option>
<option value="the past 5 years">The past 5 years</option>
`);
$('.filter_based__data').show();
break;
case 'No activity':
$('#status-select').html(`
<option value="">Select No activity</option>
<option value="last 24 hours">Last 24 hours</option>
<option value="last 3 days">Last 3 days</option>
<option value="last week">Last week</option>
<option value="last month">Last month</option>
<option value="last 3 months">Last 3 months</option>
<option value="last 6 months">Last 6 months</option>
<option value="last year">Last year</option>
<option value="the past 2 years">The past 2 years</option>
<option value="the past 3 years">The past 3 years</option>
<option value="the past 4 years">The past 4 years</option>
<option value="the past 5 years">The past 5 years</option>
`);
$('.filter_based__data').show();
break;
case 'Editor':
$('#status-select').html(`
<option value="">Select Editor</option>
<option value="Computer tool">Computer tool</option>
<option value="Direct editor">Direct editor</option>
`);
$('.filter_based__data').show();
break;
case 'Spam':
$('#status-select').html(`
<option value="">Select Spam</option>
<option value="marked as spam">Marked as spam</option>
<option value="marked as not spam">Marked as not spam</option>
`);
$('.filter_based__data').show();
break;
case 'Status':
$('#status-select').html(`
<option value="">Select status</option>
<option value="open">Open</option>
<option value="waiting">Waiting</option>
<option value="done">Done</option>
`);
$('.filter_based__data').show();
break;
case 'Tags':
var options = '<option value="">Select Tags</option>';
@foreach($tags as $tag)
options += '<option value="{{$tag->name}}">{{$tag->name}}</option>';
@endforeach
$('#status-select').html(options);
$('.filter_based__data').show();
break;
case 'Users':
var options = '<option value="">Select Users</option>';
// Loop through the company_users array
@foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach
$('#status-select').html(options);
$('.filter_based__data').show();
break;
default:
$('#status-select').html(`
<option disabled value="">Select status</option>
`);
$('.filter_based__data').show();
break;
}
}
});
</script>
<!--chat avialability ajax-->
<script>
$(document).ready(function() {
// $('#toggleSwitch').on('change', function() {
// const isChecked = $(this).is(':checked');
// if (isChecked) {
// // Call route when toggle is ON
// $.ajax({
// url: 'update/chat-availability',
// method: 'POST',
// headers: {
// 'X-CSRF-TOKEN': "{{ csrf_token() }}"
// },
// data: {
// status: 'on'
// },
// success: function(response) {
// console.log('Success:', response);
// if(response.success) {
// toastr.success('Chat Availability Updated Successfully');
// }
// },
// error: function(xhr, status, error) {
// console.error('Error:', error);
// }
// });
// } else {
// // Call route when toggle is OFF
// $.ajax({
// url: 'update/chat-availability',
// method: 'POST',
// headers: {
// 'X-CSRF-TOKEN': "{{ csrf_token() }}"
// },
// data: {
// status: 'off'
// },
// success: function(response) {
// console.log('Success:', response);
// if(response.success) {
// toastr.success('Chat Availability Updated Successfully');
// }
// },
// error: function(xhr, status, error) {
// console.error('Error:', error);
// }
// });
// }
// });
});
</script>
<style>
.handle_multiple__options {
display: none;
background-color: #f8f9fa;
padding: 10px;
border: 1px solid #ddd;
margin-top: 10px;
}
.handle_multiple__options label {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.handle_multiple__options .tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.handle_multiple__options .tags button {
background-color: #748C62;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
.handle_multiple__options .tags button:hover {
background-color: #383F33;
}
.handle_multiple__options .tags button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.handle_multiple__options input{
width: 32px;
height: 19px;
}
.handle_multiple__options .common_shre{
display: flex;
justify-content: space-between;
}
/* Custom Modal CSS */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 13%;
border-radius: 10px;
position: relative;
}
#customModal3 .modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 40%;
border-radius: 10px;
position: relative;
}
.modal-content .btn-primary{
background-color: #748C62 !important;
}
.modal-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
position: absolute;
right: 20px;
top: 10px;
cursor: pointer;
}
.modal-close:hover,
.modal-close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.filter-options {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #f3f3f3;
}
.filter {
display: flex;
align-items: center;
}
.filter select {
margin-right: 10px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ccc;
}
/* Hide checkboxes initially */
.checkbox-wrapper {
display: none;
}
/* Show checkboxes when 'Handle Multiple' is active */
.handle-multiple-active .checkbox-wrapper {
display: block;
}
/* Show checkboxes when 'Handle Multiple' is active */
.handle-multiple-active .checkbox-wrapper {
display: block;
}
.chat-content {
padding: 12px 11px !important;
}
.chat-user-img{
margin-left:12px !important;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
}
/* When checkbox is checked, set background to green */
input[type="checkbox"]:checked {
background-color: #748C62;
border-color: #748C62;
}
/* Optional: Add checkmark icon or any visual effect */
input[type="checkbox"]:checked::before {
transform: translate(0px, -1px);
content: '✔';
display: block;
text-align: center;
color: white;
font-weight: bold;
font-size: 13px;
margin-bottom: -1px;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
margin-right: 7px;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
/* margin-top: 12px; */
transform: translate(2px, 6px);
}
</style>
<div class="content-wrapper">
<div class="ui card chat-card">
<div class="content chat-card-header d-flex align-items-center justify-content-between">
<div class="header">Chats</div>
<div class="data-actions d-flex justify-content-end">
<div class="date-filter d-flex align-items-center">
<img src="{{ asset('images/icons/calendar.png') }}" alt="Calendar">
<!--<div class="date-filter d-flex align-items-center">-->
<!-- <img src="{{ asset('images/icons/calendar.png') }}" alt="Calendar">-->
<select class="date-filter-selectbox" name="">
<option value="">Last 7 Days</option>
</select>
</div>
<!-- <select class="date-filter-selectbox" name="">-->
<!-- <option value="">Last 7 Days</option>-->
<!-- </select>-->
<!--</div>-->
<button class="action-button d-flex align-items-center list-filter-btn">
<img src="{{ asset('images/icons/list-filter.png') }}" alt="">
</button>
@ -27,12 +484,53 @@
</div>
</div>
<div class="filter-options">
<div class="filter">
<span> <b>Filter on:</b> &nbsp;</span>
<select id="filter-select" name="">
<option value="select_filter_default">Select filter</option>
<option value="Assigned to">Assigned to</option>
<option value="With activity">With activity</option>
<option value="No activity">No activity</option>
<!--<option value="Editor">Editor</option>-->
<option value="Spam">Spam</option>
<option value="Status">Status</option>
<option value="Tags">Tags</option>
<!--<option value="Users">Users</option>-->
</select>
<div class="filter_based__data">
<select id="status-select" name="">
<option disabled>Select status</option>
<!-- Options will be dynamically updated based on selected filter -->
</select>
</div>
</div>
</div>
<div class="handle_multiple__options">
<div class="common_shre">
<label for="select-all"> <input type="checkbox" name="" id="select-all"> Select all</label>
<div class="tags">
<button>Assign post</button>
<button id="delete-posts">Delete</button>
<!--<button>Move</button>-->
<button data-status="open" class="update-posts-status">Open</button>
<button data-status="waiting" class="update-posts-status">Waiting</button>
<button data-status="done" class="update-posts-status">Done</button>
<!--<button>Tag</button>-->
<!--<button>Not spam</button>-->
<button>Reply to multiple</button>
</div>
</div>
</div>
<div class="content chat-content">
<ul class="chat-details">
@foreach($tickets as $ticket)
<li>
<a href="{{ route('inbox') }}" class="chat-detail-item d-flex align-items-center">
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-{{$ticket->id}}">
</div>
<div class="chat-user-img">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
</div>
@ -48,8 +546,8 @@
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">{{$ticket->subject}}</p>
<p class="receiver-message"> - {{$ticket->content}}.</p>
<p class="color-dark-green receiver-name">{{$ticket->sender_name}}</p>
<p class="receiver-message"> - {{\Illuminate\Support\Str::limit($ticket->subject, 90)}}.</p>
</div>
<p class="color-dark-green bold message-time">{{ \Carbon\Carbon::parse($ticket->created_at)->format('h:i A')}}</p>
</div>
@ -63,4 +561,136 @@
</div>
</div>
<!--Filter Status Code-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
const filterSelect = $('#filter-select');
const statusSelect = $('#status-select');
const statusOptions = $('#status-options');
const chatDetails = $('.chat-details');
// Handle status change
$('#status-select').change(function() {
fetchTickets();
});
// Fetch tickets based on filter
function fetchTickets() {
const filter = filterSelect.val();
const status = $('#status-select').val();
$.ajax({
url: '/filter',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
filter: filter,
status: status,
type: 'inbox',
},
success: function(data) {
chatDetails.empty();
$.each(data.tickets, function(index, ticket) {
chatDetails.append(`
<li>
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-${ticket.id}">
</div>
<div class="chat-user-img">
<img src="/images/Avatar.png" alt="User">
</div>
<div class="chat-message-info d-flex align-self-baseline">
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-light-green">#${ticket.id}</p>
<div class="ui tiny label bg-dark-green-color color-light">
${ticket.status}
</div>
</div>
<p class="color-dark-green">${new Date(ticket.created_at).toLocaleDateString()}</p>
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">${ticket.sender_name}</p>
<p class="receiver-message"> - ${ticket.subject}</p>
</div>
<p class="color-dark-green bold message-time">${new Date(ticket.created_at).toLocaleTimeString()}</p>
</div>
</div>
</a>
</li>
`);
});
}
});
}
});
</script>
<script>
$(document).ready(function(){
const chatDetails = $('.chat-details');
const filterSelect = $('#filter-select');
filterSelect.change(function() {
const selectedFilter = $(this).val();
if (selectedFilter === 'select_filter_default') {
$.ajax({
url: 'default/all-tickets',
method: 'POST',
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
data: {
type: 'inbox'
},
success: function(data) {
chatDetails.empty();
$.each(data.tickets, function(index, ticket) {
chatDetails.append(`
<li>
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-${ticket.id}">
</div>
<div class="chat-user-img">
<img src="/images/Avatar.png" alt="User">
</div>
<div class="chat-message-info d-flex align-self-baseline">
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-light-green">#${ticket.id}</p>
<div class="ui tiny label bg-dark-green-color color-light">
${ticket.status}
</div>
</div>
<p class="color-dark-green">${new Date(ticket.created_at).toLocaleDateString()}</p>
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">${ticket.sender_name}</p>
<p class="receiver-message"> - ${ticket.subject}</p>
</div>
<p class="color-dark-green bold message-time">${new Date(ticket.created_at).toLocaleTimeString()}</p>
</div>
</div>
</a>
</li>
`);
});
}
});
}
});
});
</script>
<x-custom-modals />
@endsection

View File

@ -6,7 +6,7 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="icon" href="./assets/images/favicon.ico" type="image/png">
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/png">
<!-- Google fonts -->
@ -30,4 +30,29 @@
crossorigin="anonymous"></script>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
function updateLastOnline() {
$.ajax({
url: '/update-last-online',
method: 'GET',
success: function(response) {
if (response.success) {
console.log('Last online updated successfully.');
}
},
error: function(xhr) {
console.error('An error occurred:', xhr.responseText);
}
});
}
// Update last online every minute (60000 milliseconds)
setInterval(updateLastOnline, 60000);
});
</script>
</html>

View File

@ -4,17 +4,20 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSRF Token Meta Tag -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Inbox</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>-->
<!-- Bootstrap Styles -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Main Styles -->
<link rel="stylesheet" href="{{ asset('assets/style.css') }}">
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
</head>
</head>
@ -38,231 +41,53 @@
@yield('content')
<!-- End -->
<!-- Support and Chat Fixed Buttons -->
<div class="chat-message-box position-fixed">
<!-- Chat Drop Down -->
<div class="ui floating bg-dark-green-color chat-widget-wrapper icon dropdown button">
<img src="{{ asset('images/icons/Vector 386.png') }}" alt="Chat Icon">
<div class="menu chat-menu">
<div id="chat-feature-widget" class="ui transition chat-feature-widget">
<div class="header d-flex justify-content-between align-items-center text-white">
<p class="chat-popup-label text-light">Chats</p>
<img class="remove-chat" src="{{ asset('images/icons/Vector (3).svg') }}" alt="Cross Chat Icon">
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
</div>
<!-- User Inbox menu -->
<div id="inbox" class="ui transition hidden chat-feature-widget inbox-wrapper">
<div class="header d-flex align-items-center">
<img id="back-to-users" src="{{ asset('images/icons/Vector 387.png') }}" alt="Back To Chat">
<p class="chat-popup-label text-light">James</p>
</div>
<div class="scrollhint">
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>👋 Hi there! How can I help?</p>
</div>
</div>
</div>
<div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing</p>
</div>
</div>
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In lorem
est,
tincidunt at placerat ultricies, vehicula in erat. Donec vitae ante
mollis, pretium augue vel, feugiat risus.</p>
</div>
</div>
</div>
<div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing</p>
</div>
</div>
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>Typing...</p>
</div>
</div>
</div>
</div>
<div class="outer-message-input-box">
<div class="inner-message-input d-flex align-items-center justify-content-between ">
<input type="text" class="border-0" placeholder="Type a reply">
<p class="input-action d-flex align-items-center ">
<img src="{{ asset('images/icons/gif.png') }}" alt="Gif">
<img src="{{ asset('images/icons/emoji.png') }}" alt="Gif">
<img src="{{ asset('images/icons/attachment.png') }}" alt="Gif">
</p>
</div>
</div>
</div>
</div>
</div>
<!-- End -->
<!-- Support Drop down -->
<div class="ui floating bg-dark-green-color support-widget-wrapper icon dropdown button ">
<img src="images/icons/support.svg" alt="Support Icon">
<div class="menu support-widget">
<div class="header support-header mt-0 text-center">
<h2 class="color-dark-green">Help & Support</h2>
</div>
<div class="support-facilities-box d-flex justify-content-between flex-wrap">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/faq-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green">FAQ</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/laptop-minimalistic-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green">Using Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/launch-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green text-wrap">Launching Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/setting-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Settings</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/data-mapping-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green ">Integration</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/open-door-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green text-wrap">Privacy & Policy</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/news-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green text-wrap">News & Updates</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/graduate-cap-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green ">Training</p>
</div>
</div>
<div class="header contact-us-header text-center">
<h2 class="color-dark-green">Contact Us</h2>
</div>
<div class="contact-us-box d-flex justify-content-center">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/email-14-svgrepo-com (1) 1.svg" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Questions</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/about-filled-svgrepo-com 1.svg" alt="">
</div>
<p class="color-dark-green">About Kundo</p>
</div>
</div>
</div>
</div>
<!-- End -->
</div>
<!-- End -->
<x-chat-box />
</div>
</div>
</div>
<!-- Jquery -->
<!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<!-- Bootstrap scripts -->
<!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script> -->
crossorigin="anonymous"></script>
<!-- Fomantic Ui Scripts -->
<!-- <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>
<!-- Main Custom Js -->
<script src="{{ asset('assets/script.js') }}"></script>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
function updateLastOnline() {
$.ajax({
url: '/update-last-online',
method: 'GET',
success: function(response) {
if (response.success) {
console.log('Last online updated successfully.');
}
},
error: function(xhr) {
console.error('An error occurred:', xhr.responseText);
}
});
}
// Update last online every minute (60000 milliseconds)
setInterval(updateLastOnline, 60000);
});
</script>
</html>

View File

@ -4,6 +4,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSRF Token Meta Tag -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Inbox</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
@ -21,7 +23,16 @@
<!-- Main Styles -->
<link rel="stylesheet" href="{{ asset('assets/style.css') }}">
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<style>
.logo_be .img{
transform: translate(7px, -5px) !important;
}
</style>
</head>
</head>
@ -32,9 +43,9 @@
<!-- Sidebar -->
<div class=" sidebar-area short-sidebar">
<aside class="bg-dark-green-color align-items-center">
<div class="image-box d-flex justify-content-between">
<img src="{{ asset('images/logo-white.png') }}" alt="Site Logo">
<aside class="bg-dark-green-color align-items-center ">
<div class="image-box d-flex justify-content-between logo_be">
<img src="{{ asset('images/logo_cropped.png') }}" class="img" alt="Site Logo">
<div class="dev-toggle-sidebar dev-close"><img src="{{ asset('images/icons/close-icon.svg') }}" alt=""></div>
</div>
<div class="side-bar-links d-flex justify-content-center">
@ -84,7 +95,11 @@ class="side-bar-link bg-light-color d-flex align-items-center justify-content-be
<div class="profile-nav-row d-flex side-bar-link">
<div class="profile-nav-box">
<div class="img-box"><img src="{{ asset('images/user.png') }}" alt="User Image"></div>
@if(!is_null(Auth::user()->profile_image))
<div class="img-box"><a href="{{route('profile')}}"><img style="height: 42px; width: 42px; border-radius: 50%" src="{{ url('' . Auth::user()->profile_image) }}" alt="User Image"></a></div>
@else
<div class="img-box"><img style="height: 42px; width: 42px; border-radius: 50%" src="{{ asset('dummy-image.jpg') }}" alt="User Image"></div>
@endif
</div>
</div>
@ -97,304 +112,15 @@ class="side-bar-link bg-light-color d-flex align-items-center justify-content-be
<div class="content-area position-relative bg-light-color">
<!-- Header -->
<header class="position-relative">
<div class="row">
<div class="col-sm-4 user-name-nav-area d-flex align-content-center">
<div class="dev-toggle-sidebar">
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
</div>
<h2 class="d-flex align-items-center">Hello Maxwell <span>👋🏼</span>,</h2>
</div>
<div class="col-sm-8 d-flex justify-content-end align-items-center">
<div class="search-box d-flex align-items-center">
<img src="{{ asset('images/icons/search 1.png') }}" alt="">
<input type="text" class="color-dark-green" placeholder="Search...">
</div>
<div class="nav-links d-flex align-items-center">
<form method="POST" action="{{route('logout')}}">
@csrf
<button class="nav-btn bg-dark-green-color">
<img height="25" width="50" src="{{ asset('images/logout.png') }}" alt="">
</button>
</form>
<a href="{{ route('chat.setting') }}" class="nav-btn bg-dark-green-color">
<img src="{{ asset('images/icons/Message_alt_fill.png') }}" alt="">
</a>
<a href="{{ route('inbox.setting') }}" class="nav-btn bell-btn bg-dark-green-color">
<img src="{{ asset('images/icons/notification.svg') }}" alt="">
</a>
<div class="ui dropdown custom-dropdown options-widget-wrapper">
<div class="text">
<button class="nav-btn bg-dark-green-color">
<img src="{{ asset('images/icons/Group 32.png') }}" alt="">
</button>
</div>
<div class="menu nav-bar-menu mt-2">
<div class="item">
<p class="action-heading-paragraph text-center align-content-center">
<img src="{{ asset('images/icons/Vector (3).png') }}" alt="">
<span class="action-label text-white">Inbox</span>
</p>
<div class="chat-settings-btn-row text-center">
<a class="ui secondary basic button tag-btn shadow-none">Tags</a>
<a
href="{{ route('inbox.setting') }}" class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div>
<div class="item">
<p class="action-heading-paragraph text-center align-content-center">
<img src="{{ asset('images/icons/chat-round-white.svg') }}" alt="">
<span class="action-label text-white">Chats</span>
</p>
<div class="chat-settings-btn-row text-center">
<a class="ui secondary basic button tag-btn shadow-none">Tags</a>
<a
href="{{ route('chat.setting') }}" class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div>
<div class="item">
<p class="action-heading-paragraph text-center align-content-center">
<img src="{{ asset('images/icons/Group 133630.svg') }}" alt="">
<span class="action-label text-white">Help Center</span>
</p>
<div class="chat-settings-btn-row text-center">
<i class="external link square alternate icon color-dark-green"></i>
<a class="ui secondary basic button tag-btn shadow-none">Tags</a>
<a
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div>
<div class="item">
<p class="action-heading-paragraph text-center align-content-center">
<img src="{{ asset('images/icons/question-square-svgrepo-com 2.svg') }}" alt="">
<span class="action-label text-white">Forum</span>
</p>
<div class="chat-settings-btn-row text-center d-flex justify-content-center align-items-center">
<i class="external link square alternate icon color-dark-green"></i>
<a class="ui secondary basic button tag-btn shadow-none">Tags</a>
<a
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
<!-- End -->
<x-header />
<!-- End -->
<!-- Main Content Area -->
@yield('content')
<!-- End -->
<!-- Support and Chat Fixed Buttons -->
<div class="chat-message-box position-fixed">
<!-- Chat Drop Down -->
<div class="chat-widget-wrapper ui floating bg-dark-green-color icon dropdown button">
<img src="{{ asset('images/icons/Vector 386.png') }}" alt="Chat Icon">
<div class="menu chat-menu">
<div id="chat-feature-widget" class="ui transition chat-feature-widget">
<div class="header d-flex justify-content-between align-items-center text-white">
<p class="chat-popup-label text-light">Chats</p>
<img class="remove-chat" src="{{ asset('images/icons/Vector (3).svg') }}" alt="Cross Chat Icon">
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
<div class="item open-inbox">
<div class="single-user-content d-flex">
<div class="chat-user-img-box">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
</div>
<div class="user-message-detail">
<p class="recepient-message-detail">James <span>Sep 27</span></p>
<p class="text-wrap descriptive-message">Lorem ipsum dolor sit amet,
adipiscing
elit. In lorem est... </p>
</div>
</div>
</div>
</div>
<!-- User Inbox menu -->
<div id="inbox" class="ui transition hidden chat-feature-widget inbox-wrapper">
<div class="header d-flex align-items-center">
<img id="back-to-users" src="{{ asset('images/icons/Vector 387.png') }}" alt="Back To Chat">
<p class="chat-popup-label text-light">James</p>
</div>
<div class="scrollhint">
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>👋 Hi there! How can I help?</p>
</div>
</div>
</div>
<div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing</p>
</div>
</div>
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In lorem
est,
tincidunt at placerat ultricies, vehicula in erat. Donec vitae ante
mollis, pretium augue vel, feugiat risus.</p>
</div>
</div>
</div>
<div class="item d-flex justify-content-end">
<div class="sender-message-box text-white">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing</p>
</div>
</div>
<div class="item">
<div class="single-user-content d-flex">
<div class="chat-user-img-box receiver-message-box d-flex">
<img class="align-self-end" src="{{ asset('images/Avatar.png') }}" alt="Dummy User">
<p>Typing...</p>
</div>
</div>
</div>
</div>
<div class="outer-message-input-box">
<div class="inner-message-input d-flex align-items-center justify-content-between ">
<input type="text" class="border-0" placeholder="Type a reply">
<p class="input-action d-flex align-items-center ">
<img src="{{ asset('images/icons/gif.png') }}" alt="Gif">
<img src="{{ asset('images/icons/emoji.png') }}" alt="Gif">
<img src="{{ asset('images/icons/attachment.png') }}" alt="Gif">
</p>
</div>
</div>
</div>
</div>
</div>
<!-- End -->
<!-- Support Drop down -->
<div class="ui floating bg-dark-green-color support-widget-wrapper icon dropdown button ">
<img src="{{ asset('images/icons/support.svg') }}" alt="Support Icon">
<div class="menu support-widget">
<div class="header support-header mt-0 text-center">
<h2 class="color-dark-green">Help &amp; Support</h2>
</div>
<div class="support-facilities-box d-flex justify-content-between flex-wrap">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/faq-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green">FAQ</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/laptop-minimalistic-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green">Using Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/launch-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green text-wrap">Launching Kundo</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/setting-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Settings</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/data-mapping-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green ">Integration</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/open-door-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green text-wrap">Privacy &amp; Policy</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/news-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green text-wrap">News &amp; Updates</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="{{ asset('images/icons/graduate-cap-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green ">Training</p>
</div>
</div>
<div class="header contact-us-header text-center">
<h2 class="color-dark-green">Contact Us</h2>
</div>
<div class="contact-us-box d-flex justify-content-center">
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/email-14-svgrepo-com (1) 1.svg') }}" alt="">
</div>
<p class="color-dark-green text-wrap">Technical Questions</p>
</div>
<div class="item text-center">
<div class="support-img-box align-content-center">
<img src="images/icons/about-filled-svgrepo-com 1.svg') }}" alt="">
</div>
<p class="color-dark-green">About Kundo</p>
</div>
</div>
</div>
</div>
<!-- End -->
</div>
<x-chat-box />
<!-- End -->
</div>
</div>
@ -416,6 +142,27 @@ class="ui secondary basic button shadow-none setting-btn text-white align-conten
@endif
});
</script>
<script>
$(document).ready(function() {
function updateLastOnline() {
$.ajax({
url: '/update-last-online',
method: 'GET',
success: function(response) {
if (response.success) {
console.log('Last online updated successfully.');
}
},
error: function(xhr) {
console.error('An error occurred:', xhr.responseText);
}
});
}
// Update last online every minute (60000 milliseconds)
setInterval(updateLastOnline, 60000);
});
</script>
<!-- Main Custom Js -->
<script src="{{ asset('assets/script.js') }}"></script>
</body>

View File

@ -1,3 +1,6 @@
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet">
<div class="box-top-area">
<div class="box-heading-row d-flex justify-content-between align-items-center">
<p class="heading color-dark-green">Administrate</p>
@ -10,20 +13,187 @@
<button class="action-btn status-btn @if($ticket->status == 'done') active @endif" data-status="done">Done</button>
</div>
</div>
<div class="box-body-area">
<ul class="inbox-chat-options">
<li class="single-option d-flex justify-content-between">
<p>Assign <span>(Assign to me)</span></p>
<p><img src="{{ asset('images/icons/Frame (1).png') }}" alt="Chevron Right"></p>
<p><b>Assign:</b></p>
<p class="dev-custom-select">
<select class="aw-select" name="user_assigned">
<option>(Assign)</option>
@foreach($companyUsers as $companyUser)
<option value="{{$companyUser->user_id}}" @if($ticket->user_assigned == $companyUser->user_id) selected @endif>{{$companyUser->user->name}}</option>
@endforeach
</select>
</p>
<p class="aw-done bg-light-green-color" id="save-ticket" data-ticket_id="{{$ticket->id}}"><i class="fas fa-check"></i></p>
</li>
<li class="single-option d-flex justify-content-between">
<p>Priority <span>(Choose Priority)</span></p>
<p><img src="{{ asset('images/icons/Frame (1).png') }}" alt="Chevron Right"></p>
<p><b>Priority:</b></span></p>
<p class="dev-custom-select">
<select class="aw-select" name="priority">
<option>(Choose Priority)</option>
<option value="low" @if($ticket->priority == 'low') selected @endif>Low</option>
<option value="medium" @if($ticket->priority == 'medium') selected @endif>Medium</option>
<option value="high" @if($ticket->priority == 'high') selected @endif>High</option>
</select>
</p>
<p class="aw-done bg-light-green-color" id="save-priority" data-ticket_id="{{$ticket->id}}"><i class="fas fa-check"></i></p>
<!--<p><img src="{{ asset('images/icons/Frame (1).png') }}" alt="Chevron Right"></p>-->
</li>
<li class="single-option d-flex justify-content-between">
<li class="single-option">
<p>Tags <span>(Choose Tags)</span></p>
<p><img src="{{ asset('images/icons/+.png') }}" alt="Chevron Right"></p>
<!--save user assigned-->
<script>
$(document).ready(function() {
$('#save-ticket').on('click', function() {
var userAssigned = $('select[name="user_assigned"]').val();
var ticketId = $(this).data('ticket_id');
// Check if a user is selected
if (userAssigned === '(Assign)') {
toastr.error("Please select a user to assign.");
return;
}
// AJAX request to save the ticket assignment
$.ajax({
url: '/update-ticket/' + ticketId,
type: 'POST',
data: {
user_assigned: userAssigned,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Handle the response from the server
if (response.success) {
toastr.success('Ticket Assigned Successfully');
} else {
alert('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
// Handle any errors that occurred during the request
console.error('AJAX Error:', status, error);
toastr.error("An error occurred while assigning the ticket.");
}
});
});
});
</script>
<!--save priority-->
<script>
$(document).ready(function() {
$('#save-priority').on('click', function() {
var priority = $('select[name="priority"]').val();
var ticketId = $(this).data('ticket_id');
// Check if a user is selected
if (priority === '(Choose Priority)') {
toastr.error("Please select a priority.");
return;
}
// AJAX request to save the ticket assignment
$.ajax({
url: '/update-ticket/' + ticketId,
type: 'POST',
data: {
priority: priority,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Handle the response from the server
if (response.success) {
toastr.success('Priority Updated Successfully');
} else {
toastr.error('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
// Handle any errors that occurred during the request
console.error('AJAX Error:', status, error);
toastr.error('An error occurred while updating the priority.');
}
});
});
});
</script>
<script>
// Assuming you have a DOM element with the ID 'tags'
var input = document.getElementById('tags');
new Tagify(input);
</script>
<?php
$tags = [];
$db_tags = getTicketMeta($ticket->id,'tags',false);
// if($db_tags){
// foreach($db_tags as $tag){
// $tags[] = $tag->value;
// }
// }
?>
<input type="text" name="tags" id="tags" value="{{implode(',',$tags)}}" placeholder="Type and press Enter"
class="form-control input-reply-textarea input-comment-textarea" required/>
<button data-ticket_id="{{$ticket->id}}" class="ui button bg-light-green-color mt-4 color-light" id="save-tags">
Save
</button>
<script>
$(document).ready(function() {
$('#save-tags').on('click', function(event) {
event.preventDefault();
var tags = $('#tags').val();
var ticketId = $(this).data('ticket_id');
// Check if the input field is not empty
if (tags === '') {
toastr.error('Please enter some tags.');
return;
}
// AJAX request to save the tags
$.ajax({
url: '/store-tags',
type: 'POST',
data: {
tags: tags,
ticket_id:ticketId,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Handle the response from the server
if (response.success) {
toastr.success('Tags Added successfully!');
} else {
toastr.error('Error: ' + response.message);
}
},
error: function(xhr, status, error) {
// Handle any errors that occurred during the request
console.error('AJAX Error:', status, error);
toastr.error('An error occurred while saving the tags.');
}
});
});
});
</script>
<!--<p><img src="{{ asset('images/icons/+.png') }}" alt="Chevron Right"></p>-->
</li>
</form>
<li class="single-option d-flex justify-content-between">
<div class="accordion w-100 border-0" id="accordionExample">
<div class="accordion-item custom-accordion">
@ -39,7 +209,7 @@
<div class="accordion-body accordion-body--custom">
<div class="body-content">
<textarea rows="7" placeholder="Your Message"
class="form-control input-reply-textarea input-comment-textarea"></textarea>
class="form-control input-reply-textarea input-comment-textarea" id="add-comment"></textarea>
<button class="ui button bg-light-green-color mt-4 add-comment-btn color-light">
Add Your Comment
</button>
@ -56,12 +226,12 @@ class="form-control input-reply-textarea input-comment-textarea"></textarea>
<p class="response-comment-user-name">{{ $comment->user->name }}</p>
</div>
<div class="right-area d-flex">
<!--<button-->
<!-- class="ui button comment--btn bg-dark-green-color color-light comment-edit-btn ">-->
<!-- <i class="edit outline icon"></i>-->
<!--</button>-->
<button
class="ui button comment--btn bg-dark-green-color color-light comment-edit-btn ">
<i class="edit outline icon"></i>
</button>
<button
class="ui button comment--btn bg-light-green-color color-light comment-delete-btn">
class="ui button comment--btn bg-light-green-color color-light comment-delete-btn" data-comment-id="{{ $comment->id }}">
<i class="trash alternate outline icon"></i>
</button>
</div>
@ -80,16 +250,85 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
</ul>
</div>
<style>
.aw-done{
padding:10px;
color:white;
font-size:20px!important;
cursor:pointer;
}
.aw-select{
color: #8d98aa;
font-family: Poppins;
font-size: 11px;
font-weight: 500;
padding: 13px;
background: linear-gradient(0deg, #edf2f6 0%, #edf2f6 100%), #fff;
border: none;
outline: none;
border-radius: 6px;
width: 100%;
resize: unset;
}
</style>
<!--delete Comment-->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
$(document).ready(function() {
$('.comment-delete-btn').on('click', function() {
var commentId = $(this).data('comment-id');
var commentElement = $(this).closest('.response-comment');
// SweetAlert confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: '/delete-comment/' + commentId,
method: 'GET',
data: {
_token: '{{ csrf_token() }}'
},
success: function(response) {
toastr.success("Comment Deleted Successfully");
commentElement.remove();
},
error: function(error) {
console.error('Error deleting comment:', error);
Swal.fire(
'Error!',
'An error occurred while deleting the comment.',
'error'
);
}
});
}
});
});
});
</script>
<!--store comment-->
<script>
$(document).ready(function() {
$('.add-comment-btn').on('click', function() {
var ticketId = $('.chat-detail-item.active').data('ticket-id');
var comment = $('.input-comment-textarea').val();
var comment = $('#add-comment').val();
if (comment === '') {
alert('Comment cannot be empty');
return;
toastr.error('Comment cannot be empty');
return;
}
$.ajax({
@ -101,9 +340,18 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
_token: '{{ csrf_token() }}'
},
success: function(response) {
$('.accordion-body--custom').prepend(response);
toastr.success("Comment Added Successfully");
$('.input-comment-textarea').val('');
$('#add-comment').val('');
$.ajax({
url: '/fetch-action-box/' + ticketId,
method: 'GET',
success: function(response) {
$('.action-box').html(response);
},
error: function(error) {
console.log('Error fetching action box content:', error);
}
});
},
error: function(error) {
console.error('Error adding comment:', error);
@ -116,35 +364,27 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
<!--change ticket status-->
<script>
$(document).ready(function() {
// Click event for status buttons
$('.status-btn').on('click', function() {
var newStatus = $(this).data('status');
// Update UI immediately
$('.status-btn').removeClass('active');
$(this).addClass('active');
// Optionally, update backend via AJAX
updateTicketStatus(newStatus);
});
// Function to update ticket status via AJAX
function updateTicketStatus(newStatus) {
// Example AJAX request
$.ajax({
url: 'update-ticket-status/{{ $ticket->id }}', // Replace with your route
url: '/update-ticket-status/{{ $ticket->id }}',
method: 'POST',
data: {
status: newStatus,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Handle success response if needed
toastr.success(response.message);
},
error: function(error) {
console.error('Error updating ticket status:', error);
// Optionally handle error response
}
});
}

View File

@ -1,3 +1,65 @@
<style>
.attachment {
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
}
.chat-sender .single-message-chat{
display: flex;
justify-content: flex-end;
}
.chat-sender .single-message-chat{
text-align:right;
}
.chat_style p{
text-align:left !important;
}
.single-message-chat img {
width: 83% !important;
height: auto !important;
max-height:200px;
}
.left_box img {
width: 62% !important;
height: auto !important;
}
.left_box p{
color: rgba(117, 138, 137, 1);
font-family: "Satoshi", sans-serif;
font-size: 10px;
transform: translate(8px, 2px);
}
#cannedResponseModal ul {
list-style: none;
padding: 0;
display: flex !important;
gap: 8px !important;
flex-wrap: wrap !important;
}
.canned-response {
width: 100%;
padding: 10px;
font-size: 16px;
border: none;
background-color: #748C62 !important;
color: white;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
}
.single-message-chat {
width: 100%;
height: -webkit-fill-available !important;
}
</style>
@foreach($messages as $message)
<!-- Recepient Message -->
@if($message->user_id == 0)
@ -6,7 +68,19 @@
<img src="{{ asset('images/Avatar.png') }}" alt="User">
</div>
<div class="single-message-chat">
<p class="user-message">{!!$message->message!!}</p>
<div class="user-message">
{!!$message->message!!}
@if(!is_null($message->attachments) && count(json_decode($message->attachments)) > 0)
@foreach(json_decode($message->attachments) as $attachment)
<div class="attachment">
@php
$fileName = basename($attachment);
@endphp
<a download href="{{ url('' . $attachment) }}">{{$fileName}}</a>
</div>
@endforeach
@endif
</div>
<p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p>
</div>
</div>
@ -14,16 +88,15 @@
@elseif($message->user_id == 1)
<div class="chat-message chat-sender d-flex justify-content-end">
<div class="single-message-chat">
@if(!containsHtml($message->message))
<p class="user-message bg-light-green-color color-light">{!!$message->message!!}</p>
@else
{!! $message->message !!}
@endif
<p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p>
</div>
<div class="chat-user-img-box align-self-end">
<div class="user-message bg-light-green-color color-light chat_style">{!!$message->message!!}</div>
<div class="chat-user-img-box align-self-end left_box">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
<p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p>
</div>
</div>
</div>
@endif
@endforeach

View File

@ -4,6 +4,38 @@
@section('content')
<!-- Update Profile --->
<div class="content-wrapper">
<div class="dev-chat-tabs">
<div class="dev-tabcontent dev-tabcontent-users">
<div class="dev-tabcontent-outers">
<div class="dev-title-row">
<h2>Update Profile</h2>
</div>
<form method="POST" action="{{ route('update.profile') }}" enctype="multipart/form-data">
@csrf
<div class="dev-input-group">
<label for="name">Name</label>
<input name="name" value="{{$user->name}}" type="text" placeholder="Enter your name" required>
</div>
<div class="dev-input-group">
<label for="email">Email</label>
<input name="email" type="email" readonly value="{{$user->email}}" placeholder="Enter your email" required>
</div>
<div class="dev-input-group">
<label for="email">Profile Image</label>
<input name="profile_image" type="file">
</div>
<button type="submit">Update</button>
</form>
</div>
</div>
</div>
</div>
<!-- End Update Profile -->
<div class="content-wrapper">
<div class="dev-chat-tabs">
<div class="dev-tabcontent dev-tabcontent-users">
@ -11,7 +43,7 @@
<div class="dev-title-row">
<h2>Add a new user</h2>
</div>
<form method="POST" action="{{ route('inbox.add.user') }}">
<form method="POST" action="{{ route('inbox.add.user') }}" id="accessForm" onsubmit="return validateCheckboxes()">
@csrf
<div class="dev-input-group">
<label for="name">Name</label>
@ -25,6 +57,17 @@
<label for="email">Email</label>
<input name="email" type="email" placeholder="Enter your email" required>
</div>
<div class="dev-input-group">
<label for="email">Access</label>
<label class="dev-checkbox-wrapper">Inbox Module
<input name="access[]" type="checkbox" value="inbox">
<span class="checkmark"></span>
</label>
<label class="dev-checkbox-wrapper">Chat Module
<input name="access[]" type="checkbox" value="chat">
<span class="checkmark"></span>
</label>
</div>
<button type="submit">Send Activation Email</button>
</form>
<div class="dev-title-row">
@ -50,7 +93,7 @@
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<script defer>
document.addEventListener('DOMContentLoaded', function () {
const deleteLinks = document.querySelectorAll('.delete-user');
@ -79,6 +122,23 @@
});
});
</script>
<script>
function validateCheckboxes() {
const checkboxes = document.querySelectorAll('input[name="access[]"]');
let checked = false;
checkboxes.forEach((checkbox) => {
if (checkbox.checked) {
checked = true;
}
});
if (!checked) {
alert('Please select at least one checkbox.');
return false;
}
return true;
}
</script>
</div>
</div>

View File

@ -0,0 +1,468 @@
@extends('layouts.setting')
<title>Inbox</title>
@section('content')
<style>
div.chat-inbox>.chat-content-wrapper>.chat-message>.single-message-chat>.user-message{
max-width:90%!important;
width: 70%;
}
.single-message-chat{
width:100%;
}
.receiver-message{
word-break: break-all;
}
.single-message-chat img{
width: 100% !important;
height: auto !important;
}
.close-button {
color: #aaa;
/* float: right; */
font-size: 28px;
font-weight: bold;
background: ;
display: flex !important;
justify-content: flex-end !important;
margin-top: -14px;
font-size: 32px;
}
</style>
<input type="hidden" value="{{$single_ticket->id}}" id="aw-ticket_id"/>
<div class="inbox-content-wrapper w-100 ">
<div class="inbox-inner-wrapper w-100 d-flex">
<!-- User Box -->
<div class="box user-box">
<ul>
@foreach($tickets as $key => $ticket)
<li style="cursor:pointer;" class="chat-detail-item @if($single_ticket->id == $ticket->id) active @endif inbox-user-box d-flex" data-ticket-id="{{ $ticket->id }}">
<div class="chat-user-img inbox position-relative">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
<div class="chat-status-icon rounded-circle text-center align-content-center position-absolute">
<img src="{{ asset('images/icons/chat-round.svg') }}" alt="Chat Round">
</div>
</div>
<div class="chat-message-info d-flex align-self-baseline">
<div class="chat-ticket-row align-items-center d-flex justify-content-between">
<div class="ticket-status d-flex flex-column">
<p class="color-dark-green receiver-name">{{$ticket->sender_name}}</p>
<p class="receiver-message">{!! \Illuminate\Support\Str::limit(strip_tags($ticket?->lastResponse?->message) ?? '', 90) !!}</p>
</div>
<p class=" bold message-time">{{\Carbon\Carbon::parse($ticket?->lastResponse?->created_at)->format('h:i A') ?? ''}}</p>
</div>
</div>
</li>
@endforeach
</ul>
</div>
<!-- Chat Box -->
<div class="chat-inbox chat-box">
<div class="chat-content-wrapper">
</div>
<!-- Send Message Input -->
<div class="message-input-box">
<!--<div class="select-user-row mt-2">-->
<!-- <p>To:</p>-->
<!-- <select name="skills" multiple="" class="ui fluid dropdown user-select-dropdown">-->
<!-- <option value="">Select User</option>-->
<!-- <option value="angular">Angular</option>-->
<!-- <option value="css">CSS</option>-->
<!-- </select>-->
<!--</div>-->
<div class="input-box-row">
<div class="ui card inbox-send-message-card w-100">
<!--<div class="content input-options bg-dark-green-color">-->
<!-- <div class="input-option-row ">-->
<!-- <img src="{{ asset('images/icons/B.png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/I.png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/Vector (5).png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/Vector (6).png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/Vector (8).png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/drive.png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/Vector (5).png') }}" alt="">-->
<!-- <img src="{{ asset('images/icons/Vector (6).png') }}" alt="">-->
<!-- </div>-->
<!--</div>-->
@if($single_ticket->type != 'chat')
<div class="content d-flex align-items-end flex-column message-writing-content-area">
<textarea rows="7" placeholder="Your Message"
class="form-control input-reply-textarea" id="editor1" required></textarea>
<button class="ui button bg-light-green-color mt-4 color-light saveReply">
Reply
</button>
</div>
@endif
</div>
</div>
</div>
</div>
<!--wysywyg editor-->
<!--<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>-->
<!-- Canned Response Modal -->
<!-- Canned Response Modal -->
<div id="cannedResponseModal" class="modal">
<div class="modal-content">
<span class="close-button">&times;</span>
<h2>Canned Responses</h2>
<ul>
@if(count($canned_response) > 0)
@foreach($canned_response as $index => $value)
@php
$result = json_decode($value->value);
@endphp
<li><button class="canned-response" data-response="{{$result->text}}">{{$result->name}}</button></li>
@endforeach
@endif
</ul>
</div>
</div>
<script>
//CKEDITOR.replace('editor1');
CKEDITOR.plugins.add('addcannedresponse', {
init: function(editor) {
// Command for inserting canned response
editor.addCommand('addCannedResponseCmd', {
exec: function(editor) {
// Show your modal or handle canned response insertion
document.getElementById('cannedResponseModal').style.display = 'block';
}
});
// Command for inserting signature
editor.addCommand('addSignatureCmd', {
exec: function(editor) {
var signatureHtml = `<br>{!! $email_signature !!}`; // Signature content
CKEDITOR.instances.editor1.insertHtml(signatureHtml);
}
});
// Add "Insert Canned Response" button
editor.ui.addButton('AddCannedResponse', {
label: 'Insert Canned Response',
command: 'addCannedResponseCmd',
icon: 'https://kundesone.no/images/canned.png', // Use an accessible icon URL or local path
toolbar: 'insert,0'
});
// Add "Insert Signature" button
editor.ui.addButton('AddSignature', {
label: 'Insert Signature',
command: 'addSignatureCmd',
icon: 'https://kundesone.no/images/signature-icon.png', // Placeholder icon URL, replace with a valid one
toolbar: 'insert,1'
});
}
});
CKEDITOR.replace('editor1', {
extraPlugins: 'addcannedresponse', // Ensure your plugin is added to extraPlugins
// Optionally customize your toolbar further, or use the default configuration
toolbarGroups: [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
]
});
// Get the modal
var modal = document.getElementById("cannedResponseModal");
// Get the button that opens the modal
var btn = document.getElementsByClassName("canned-response");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close-button")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// Add event listeners to canned response buttons
Array.from(btn).forEach(function(element) {
element.addEventListener('click', function() {
var response = this.getAttribute('data-response');
CKEDITOR.instances.editor1.insertHtml(response);
modal.style.display = "none";
});
});
</script>
<!-- Action Box -->
<div class="action-box">
</div>
</div>
</div>
<!-- Tagify CSS -->
<link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet">
<!-- Tagify JS -->
<script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.min.js"></script>
<style>
#cke_editor1{
width:100%!important;
}
div.chat-inbox.chat-box{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 100%;
max-width: 600px;
}
.close-button {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
background:;#748c62 !important
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#cannedResponseModal ul {
list-style: none;
padding: 0;
}
#cannedResponseModal li {
padding: 8px 0; /* Spacing between buttons */
}
.canned-response {
width: 100%;
padding: 10px;
font-size: 16px;
border: none;
background-color: #4CAF50;
color: white;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
}
.canned-response:hover {
background-color: #45a049;
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.24);
}
</style>
<!--Script Tag-->
<script>
$(document).ready(function(){
// var activeTicketId = $('.chat-detail-item.active').data('ticket-id');
var activeTicketId = $('#aw-ticket_id').val();
// Load chat messages for the active ticket on page load
loadChatMessages(activeTicketId);
loadActionBox(activeTicketId);
// Click event to switch between tickets
$('.chat-detail-item').on('click', function() {
$('.chat-detail-item').removeClass('active');
$(this).addClass('active');
activeTicketId = $(this).data('ticket-id');
loadChatMessages(activeTicketId);
loadActionBox(activeTicketId);
});
// Function to load chat messages for a specific ticket
function loadChatMessages(ticketId) {
$.ajax({
url: '/fetch-chat-messages/' + ticketId,
method: 'GET',
success: function(response) {
console.log(response);
// Update chat box with fetched messages
$('.chat-content-wrapper').html(response);
},
error: function(error) {
console.log('Error loading messages:', error);
}
});
}
// Function to load action box for a specific ticket
function loadActionBox(ticketId) {
$.ajax({
url: '/fetch-action-box/' + ticketId,
method: 'GET',
success: function(response) {
// Update action box with fetched content
$('.action-box').html(response);
},
error: function(error) {
console.log('Error fetching action box content:', error);
}
});
}
// Save reply
$('.saveReply').on('click', function(){
var message = CKEDITOR.instances.editor1.getData();
if(message.trim() === '') {
toastr.error('Message cannot be empty');
return;
}
$.ajax({
url: '/store/response',
method: 'POST',
data: {
ticket_id: activeTicketId,
message: message,
_token: '{{ csrf_token() }}'
},
success: function(response) {
// Reload chat messages for the active ticket
loadChatMessages(activeTicketId);
loadActionBox(activeTicketId);
// Update the last response in the ticket list
var ticketElement = $('.chat-detail-item[data-ticket-id="' + activeTicketId + '"]');
ticketElement.find('.receiver-message').text(response.message);
ticketElement.find('.message-time').text(response.created_at);
// Clear the editor
CKEDITOR.instances.editor1.setData('');
// window.location.reload();
},
error: function(error) {
console.log('Error creating a response:', error);
}
});
});
});
</script>
<script>
$(document).ready(function(){
$('.chat-detail-item').on('click', function(){
$('.chat-detail-item').removeClass('active');
$(this).addClass('active');
var ticketId = $(this).data('ticket-id');
fetchChatMessages(ticketId);
updateActionBox(ticketId);
});
// Function to fetch and display chat messages for a ticket
function fetchChatMessages(ticketId) {
$.ajax({
url: '/fetch-chat-messages/' + ticketId,
method: 'GET',
success: function(response) {
// Update chat box with fetched messages
$('.chat-content-wrapper').html(response);
},
error: function(error) {
console.log('Error fetching chat messages:', error);
}
});
}
// Function to update the action box for a ticket
function updateActionBox(ticketId) {
$.ajax({
url: '/fetch-action-box/' + ticketId,
method: 'GET',
success: function(response) {
// Update action box with fetched content
$('.action-box').html(response);
},
error: function(error) {
console.log('Error fetching action box content:', error);
}
});
}
});
</script>
@endsection

View File

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Terms And Conditions</title>
</head>
<body>
<div>
{!! $link_text !!}
</div>
</body>
</html>

View File

@ -4,29 +4,232 @@
@section('content')
<script>
$(document).ready(function(){
$('.side-bar-links a').removeClass('bg-light-color');
$('.aw-a-waiting').addClass('bg-light-color');
});
</script>
<!-- Toastr CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet">
<!-- Toastr JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<!-- SweetAlert2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
<!-- SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>
<style>
.handle_multiple__options {
display: none;
background-color: #f8f9fa;
padding: 10px;
border: 1px solid #ddd;
margin-top: 10px;
}
.handle_multiple__options label {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.handle_multiple__options .tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.handle_multiple__options .tags button {
background-color: #748C62;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
.handle_multiple__options .tags button:hover {
background-color: #383F33;
}
.handle_multiple__options .tags button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.handle_multiple__options input{
width: 32px;
height: 19px;
}
.handle_multiple__options .common_shre{
display: flex;
justify-content: space-between;
}
/* Custom Modal CSS */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 13%;
border-radius: 10px;
position: relative;
}
#customModal3 .modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 40%;
border-radius: 10px;
position: relative;
}
.modal-content .btn-primary{
background-color: #748C62 !important;
}
.modal-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
position: absolute;
right: 20px;
top: 10px;
cursor: pointer;
}
.modal-close:hover,
.modal-close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.filter-options {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #f3f3f3;
}
.filter {
display: flex;
align-items: center;
}
.filter select {
margin-right: 10px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ccc;
}
/* Hide checkboxes initially */
.checkbox-wrapper {
display: none;
}
/* Show checkboxes when 'Handle Multiple' is active */
.handle-multiple-active .checkbox-wrapper {
display: block;
}
.chat-content {
padding: 12px 11px !important;
}
.chat-user-img{
margin-left:12px !important;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
}
/* When checkbox is checked, set background to green */
input[type="checkbox"]:checked {
background-color: #748C62;
border-color: #748C62;
}
/* Optional: Add checkmark icon or any visual effect */
input[type="checkbox"]:checked::before {
transform: translate(0px, -1px);
content: '✔';
display: block;
text-align: center;
color: white;
font-weight: bold;
font-size: 13px;
margin-bottom: -1px;
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
margin-right: 7px;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
}
.handle_multiple__options label {
display: flex;
margin-bottom: 10px;
align-items: flex-start;
/* margin-top: 12px; */
transform: translate(2px, 6px);
}
</style>
<div class="content-wrapper">
<div class="ui card chat-card waiting-chat-card">
<div class="content chat-card-header d-flex align-items-center justify-content-between">
<div class="header">Waiting</div>
<div class="data-actions d-flex justify-content-end">
<button class="action-button d-flex align-items-center list-filter-btn">
<img src="{{ asset('images/icons/list-filter.png') }}" alt="">
</button>
<button class="action-button bg-dark-green-color color-light handle-multiple-btn">
<img src="{{ asset('images/icons/Add_Plus.png') }}" alt="Plus Icon">
<span>Handle Multiple</span>
</button>
</div>
</div>
<!--handle multiple-->
<x-handle-filter />
@if(count($tickets) > 0)
<div class="content chat-content">
<ul class="chat-details">
@foreach($tickets as $ticket)
<li>
<a href="{{ route('inbox') }}" class="chat-detail-item d-flex align-items-center">
<a href="{{ route('show.ticket', $ticket->id) }}" class="chat-detail-item d-flex align-items-center">
<div class="checkbox-wrapper">
<input type="checkbox" class="ticket-checkbox" id="ticket-{{$ticket->id}}">
</div>
<div class="chat-user-img">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
</div>
@ -42,8 +245,8 @@
</div>
<div class="chat-ticket-row d-flex justify-content-between">
<div class="ticket-status d-flex">
<p class="color-dark-green receiver-name">{{$ticket->subject}}</p>
<p class="receiver-message"> - {{$ticket->content}}.</p>
<p class="color-dark-green receiver-name">{{$ticket->sender_name}}</p>
<p class="receiver-message"> - {{\Illuminate\Support\Str::limit($ticket->subject, 90)}}.</p>
</div>
<p class="color-dark-green bold message-time">{{ \Carbon\Carbon::parse($ticket->created_at)->format('h:i A')}}</p>
</div>
@ -62,4 +265,5 @@
</div>
</div>
<x-custom-modals />
@endsection

View File

@ -3,6 +3,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Mailgun\EmailController;
use App\Http\Controllers\Chat\ChatController;
/*
|--------------------------------------------------------------------------
@ -18,6 +19,17 @@
Route::post('/save-email', [EmailController::class, 'saveEmail']);
Route::post('/chat/start', [ChatController::class, 'startChat']);
Route::post('/chat/send-message', [ChatController::class, 'sendMessage']);
Route::post('/chat/get', [ChatController::class, 'getChat']);
Route::post('/chat/getMessages', [ChatController::class, 'getMessages']);
Route::post('/chat/check', [ChatController::class, 'checkChat']);
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();

View File

@ -7,8 +7,12 @@
use App\Http\Controllers\UserController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\TicketController;
use App\Http\Controllers\ChatSettingController;
use App\Http\Controllers\Mailgun\MailgunController;
use App\Http\Controllers\Chat\ChatController;
/*
|--------------------------------------------------------------------------
@ -21,7 +25,6 @@
|
*/
Route::get('/', [LoginController::class, 'login'])->name('login.create');
Route::post('store/login', [LoginController::class, 'storeLogin'])->name('store.login');
Route::post('store/register', [RegisterController::class, 'storeRegister'])->name('store.register');
@ -31,24 +34,47 @@
Route::middleware(['auth'])->group(function(){
Route::get('/test', [MailgunController::class, 'addDomain'])->name('addDomain');
// In routes/web.php
Route::get('/chatgroups', [ChatController::class, 'getChatGroupsByCompany'])->name('chatgroups.get');
Route::get('/chat-demo', [ChatController::class, 'chatDemo'])->name('chat.demo');
Route::post('/close-chat', [ChatController::class, 'CloseChat'])->name('CloseChat');
Route::get('/test', [MailgunController::class, 'test'])->name('test');
Route::get('/show-domain/{domain}', [MailgunController::class, 'showDomain'])->name('showDomain');
Route::post('/verify-domain', [MailgunController::class, 'verifyDomain'])->name('verifyDomain');
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('index');
//Filter Route
Route::post('filter', [TicketController::class, 'filter']);
Route::post('default/all-tickets', [TicketController::class, 'defaultAllTickets']);
Route::get('update-last-online', [UserController::class, 'updateLastOnline']);
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('index')->middleware('verifyDomain');;
Route::get('/profile', [DashboardController::class, 'profile'])->name('profile');
Route::post('update/profile', [DashboardController::class, 'updateProfile'])->name('update.profile');
Route::get('company-info', [CompanyController::class, 'getCompanyInfo'])->name('get.company.info');
Route::get('/waiting', [DashboardController::class, 'waiting'])->name('waiting');
Route::get('/waiting', [TicketController::class, 'waiting'])->name('waiting');
Route::get('/all-tickets', [TicketController::class, 'allTickets'])->name('all.tickets');
Route::get('/show-ticket/{ticketId}', [TicketController::class, 'showTicket'])->name('show.ticket');
Route::post('update-ticket-status/{ticketId}', [TicketController::class, 'updateStatus']);
Route::post('update-ticket/{ticketId}', [TicketController::class, 'updateTicket'])->name('update.ticket');
Route::post('store-tags', [TicketController::class, 'storeTags'])->name('store.tags');
Route::get('inbox', [InboxController::class, 'inbox'])->name('inbox');
Route::get('fetch-chat-messages/{ticketId}', [InboxController::class, 'fetchChatMessages']);
Route::get('fetch-action-box/{ticketId}', [InboxController::class, 'fetchActionBox']);
Route::get('/inbox-setting', [InboxController::class, 'inboxSetting'])->name('inbox.setting');
Route::post('update-ticket-status/{ticketId}', [TicketController::class, 'updateStatus']);
Route::post('store-comment', [TicketController::class, 'storeComment']);
Route::post('store/response', [TicketController::class, 'storeResponse'])->name('store.response');
Route::post('store-comment', [InboxController::class, 'storeComment']);
Route::get('delete-comment/{commentId}', [InboxController::class, 'deleteComment']);
Route::post('store/response', [InboxController::class, 'storeResponse'])->name('store.response');
Route::post('update/chat-availability', [UserController::class, 'updateChatAvailability']);
Route::post('assign/ticket', [TicketController::class, 'AssignTicket']);
Route::post('delete/tickets', [TicketController::class, 'deleteTickets']);
Route::post('update/ticket/status', [TicketController::class, 'updateTicketStatus']);
Route::post('update/rule', [InboxController::class, 'updateRule'])->name('update.rule');
//Basic Setting Route
Route::post('inbox/basic-setting', [InboxController::class, 'basicSetting'])->name('inbox.basic.setting');
//User Routes
@ -66,9 +92,23 @@
//Spam Handling
Route::post('inbox/spam-handling', [InboxController::class, 'spamHandling'])->name('inbox.spam.handling');
Route::get('spam-handling/{index}', [InboxController::class, 'deleteSpamHandling'])->name('delete.spam.handling');
Route::get('/chat-setting', function(){
return view('chat-setting');
})->name('chat.setting');
//Chat Setting Routes
Route::get('/chat-setting', [ChatSettingController::class, 'chatSetting'])->name('chat.setting');
Route::post('store/flow-setting', [ChatSettingController::class, 'storeFlowSetting'])->name('store.flow.setting');
Route::post('store/display-chat', [ChatSettingController::class, 'storeDisplayChat'])->name('store.display.chat');
Route::get('delete/display-chat/{id}', [ChatSettingController::class, 'deleteDisplayChat'])->name('delete.display.chat');
Route::post('store/hide-chat', [ChatSettingController::class, 'storeHideChat'])->name('store.hide.chat');
Route::post('store/text', [ChatSettingController::class, 'storeText'])->name('store.text');
Route::post('store/style', [ChatSettingController::class, 'storeStyle'])->name('store.style');
Route::post('store/chat-canned-responses', [ChatSettingController::class, 'storeChatCannedResponses'])->name('store.chat.canned.responses');
Route::get('delete/chat-canned-responses/{id}', [ChatSettingController::class, 'deleteChatCannedResponses'])->name('delete.chat.canned.responses');
Route::post('store/personal-data', [ChatSettingController::class, 'storePersonalData'])->name('store.personal.data');
Route::get('terms-and-conditions/{companyId}', [ChatSettingController::class, 'companyTermsAndConditions'])->name('company.terms.conditions');
Route::post('store/tags', [ChatSettingController::class, 'storeTags'])->name('store.tags');
Route::post('setting/all-chat', [ChatSettingController::class, 'settingAllChat'])->name('setting.all.chat');
Route::post('block/ip-addresses', [ChatSettingController::class, 'blockIpAdresses'])->name('block.ip.addresses');
Route::get('delete/block/ip-addresses/{id}', [ChatSettingController::class, 'deleteBlockIpAdresses'])->name('delete.block.ip.addresses');
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::post('logout', [LoginController::class, 'logout'])->name('logout');
});