latest code

This commit is contained in:
abdul-wahab12345 2024-10-08 12:30:49 +00:00
parent 203d845825
commit 98b34a2959
41 changed files with 39327 additions and 510 deletions

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

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

View File

@ -12,7 +12,9 @@
use App\Models\ChatGroup; use App\Models\ChatGroup;
use App\Models\Message; use App\Models\Message;
use App\Models\Tag; use App\Models\Tag;
use App\Models\Rule;
use App\Models\CompanyUser; use App\Models\CompanyUser;
use App\Models\Notification;
function get_company_users($company_id){ function get_company_users($company_id){
@ -108,7 +110,9 @@ function insertTicket($from_email, $to_email, $subject, $content, $type, $sender
->where(function ($query) use ($subject) { ->where(function ($query) use ($subject) {
$cleanSubject = trim(str_ireplace('Re:', '', $subject)); // Remove 'Re:' prefix and trim whitespace $cleanSubject = trim(str_ireplace('Re:', '', $subject)); // Remove 'Re:' prefix and trim whitespace
$query->where('subject', $cleanSubject) $query->where('subject', $cleanSubject)
->orWhere('subject', 'Re: ' . $cleanSubject); // Consider both with and without 'Re:' ->orWhere('subject', 'Re: ' . $cleanSubject)
->orWhere('subject2', 'Re: ' . $cleanSubject)
->orWhere('subject2', $cleanSubject); // Consider both with and without 'Re:'
}) })
->first(); ->first();
@ -287,25 +291,25 @@ function getMessagesByChatId($chatId)
function setTicketMeta(int $ticketId, string $key, $value, string $type = 'string') function setTicketMeta(int $ticketId, string $key, $value, string $type = 'string')
{ {
$ticket_metas = []; $ticket_metas = [];
// return TicketMeta::updateOrCreate( return TicketMeta::updateOrCreate(
// ['ticket_id' => $ticketId, 'key' => $key], ['ticket_id' => $ticketId, 'key' => $key],
// ['value' => json_encode($value), 'type' => $type] ['value' => json_encode($value), 'type' => $type]
// ); );
foreach($value as $tag) // foreach($value as $tag)
{ // {
$ticket_meta = TicketMeta::updateOrCreate([ // $ticket_meta = TicketMeta::updateOrCreate([
'ticket_id' => $ticketId, // 'ticket_id' => $ticketId,
'key' => $key // 'key' => $key
],[ // ],[
'value' => $tag, // 'value' => $tag,
'type' => $type // 'type' => $type
]); // ]);
$ticket_metas[] = $ticket_meta; // $ticket_metas[] = $ticket_meta;
} // }
return $ticket_metas; // return $ticket_metas;
} }
/** /**
@ -321,6 +325,12 @@ function getTicketMeta(int $ticketId, string $key)
return $meta ? json_decode($meta->value) : null; 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) function getChatSetting($key, $company_id = null)
{ {
$companyId = $company_id??getSelectedCompany(); $companyId = $company_id??getSelectedCompany();
@ -328,4 +338,41 @@ function getChatSetting($key, $company_id = null)
return $get_chat_setting; 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

@ -171,6 +171,9 @@ public function checkChat(Request $request){
$domain = $request->domain; $domain = $request->domain;
$company = get_company('id',$company_id); $company = get_company('id',$company_id);
$ip = $_SERVER['REMOTE_ADDR'];
// return response()->json(['status' => 'error', 'message' => $ip]);
if($company){ if($company){
// Str::contains('This is my name', 'my') // Str::contains('This is my name', 'my')
@ -180,10 +183,46 @@ public function checkChat(Request $request){
$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."; $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?"; $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 = getChatSetting('link_text', $company_id) ? getChatSetting('link_text', $company_id)->value : null;
$user = $this->select_user($company_id); $user = $this->select_user($company_id);
if($user){ if($user){
return response()->json(['status' => 'success','data' => ['welcome' => $wellcome_text, 'start_message' => $start_message, 'user' => $user->user->name] ]); 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{ }else{
return response()->json(['status' => 'error', 'message' => $message_when_chat_is_closed]); return response()->json(['status' => 'error', 'message' => $message_when_chat_is_closed]);
} }

View File

@ -153,6 +153,7 @@ public function storeStyle(Request $request)
'background_theme_color' => $request->background_theme_color, 'background_theme_color' => $request->background_theme_color,
'text_color_for_sent_message' => $request->text_color_for_sent_message, '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_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_received_message' => $request->text_color_of_received_message,
'text_color_of_notification' => $request->text_color_of_notification, 'text_color_of_notification' => $request->text_color_of_notification,
'text_color_of_error_message' => $request->text_color_of_error_message, 'text_color_of_error_message' => $request->text_color_of_error_message,
@ -223,7 +224,6 @@ public function storePersonalData(Request $request)
$personal_data = [ $personal_data = [
'name' => $request->name, 'name' => $request->name,
'link_text' => $request->link_text, 'link_text' => $request->link_text,
'preview' => $request->preview,
'active_approval' => $request->active_approval, 'active_approval' => $request->active_approval,
]; ];
@ -311,4 +311,10 @@ public function blockIpAdresses(Request $request)
return redirect()->back()->with('success', 'Chat Setting Updated Successfully'); return redirect()->back()->with('success', 'Chat Setting Updated Successfully');
} }
public function companyTermsAndConditions($companyId)
{
$link_text = getChatSetting('link_text', $companyId)->value;
return view('terms-conditions', ['link_text' => $link_text]);
}
} }

View File

@ -9,6 +9,9 @@
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Models\CompanyMeta;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class DashboardController extends Controller class DashboardController extends Controller
{ {
@ -17,18 +20,58 @@ public function dashboard()
$tickets = get_current_company_tickets(['type' => 'inbox']); $tickets = get_current_company_tickets(['type' => 'inbox']);
$companyId = getSelectedCompany(); $companyId = getSelectedCompany();
$tags = getCompanyTags($companyId); $tags = getCompanyTags($companyId);
return view('index', ['tickets' => $tickets, 'tags' => $tags]); $canned_response = $this->get_canned_responses();
return view('index', ['tickets' => $tickets, 'tags' => $tags, 'canned_response' => $canned_response]);
}
public function get_canned_responses(){
$companyId = getSelectedCompany();
return CompanyMeta::where('company_id', $companyId)->where('key', 'canned_responses')->get();
} }
public function profile() public function profile()
{ {
$company = getSelectedCompany(); $company = getSelectedCompany();
$user = Auth::user();
$users = $users = User::where('role_id', '!=', 1) $users = $users = User::where('role_id', '!=', 1)
//->where('id', '!=', Auth::id()) //->where('id', '!=', Auth::id())
->join('company_users', 'users.id', '=', 'company_users.user_id') ->join('company_users', 'users.id', '=', 'company_users.user_id')
->where('company_users.company_id', $company) ->where('company_users.company_id', $company)
->select('users.*') ->select('users.*')
->get(); ->get();
return view('profile', ['users' => $users]); 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

@ -30,7 +30,7 @@ public function inboxSetting()
{ {
$companyId = getSelectedCompany(); $companyId = getSelectedCompany();
$timezones = Timezone::all(); $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(); $basic_setting = CompanyMeta::where('company_id', $companyId)->where('type', 'Basic Setting')->get();
$canned_response = $this->get_canned_responses(); $canned_response = $this->get_canned_responses();
$spam_handling = CompanyMeta::where('company_id', $companyId)->where('type', 'Spam Handling')->first(); $spam_handling = CompanyMeta::where('company_id', $companyId)->where('type', 'Spam Handling')->first();
@ -70,9 +70,9 @@ public function basicSetting(Request $request)
foreach($basic_data as $key => $value) { foreach($basic_data as $key => $value) {
CompanyMeta::updateOrCreate([ CompanyMeta::updateOrCreate([
'key' => $key, 'key' => $key,
'value' => $value
],[
'company_id' => $companyId, 'company_id' => $companyId,
],[
'key' => $key, 'key' => $key,
'value' => $value, 'value' => $value,
'type' => 'Basic Setting' 'type' => 'Basic Setting'
@ -91,10 +91,8 @@ public function emailSignature(Request $request)
$companyId = getSelectedCompany(); $companyId = getSelectedCompany();
CompanyMeta::updateOrCreate([ CompanyMeta::updateOrCreate([
'key' => 'email_signature', 'key' => 'email_signature',
'value' => $request->email_signature
],[
'company_id' => $companyId, 'company_id' => $companyId,
'key' => 'email_signature', ],[
'value' => $request->email_signature, 'value' => $request->email_signature,
'type' => 'Email Signature' 'type' => 'Email Signature'
]); ]);
@ -135,9 +133,9 @@ public function responseTime(Request $request)
if(!is_null($value)) { if(!is_null($value)) {
CompanyMeta::updateOrCreate([ CompanyMeta::updateOrCreate([
'key' => $key, 'key' => $key,
'value' => $value
],[
'company_id' => $companyId, 'company_id' => $companyId,
],[
'key' => $key, 'key' => $key,
'value' => $value, 'value' => $value,
'type' => 'Response Time' 'type' => 'Response Time'
@ -237,10 +235,10 @@ public function acknowledgementReceipt(Request $request)
if(!is_null($value)) { if(!is_null($value)) {
CompanyMeta::updateOrCreate([ CompanyMeta::updateOrCreate([
'key' => $key, 'key' => $key,
'value' => $value
],[
'company_id' => $companyId, 'company_id' => $companyId,
'key' => $key, ],[
'value' => $value, 'value' => $value,
'type' => 'Acknowledgement of Receipt' 'type' => 'Acknowledgement of Receipt'
]); ]);
@ -366,47 +364,38 @@ public function storeResponse(Request $request)
'ticket_id' => 'required', 'ticket_id' => 'required',
]); ]);
$ticket_id = $request->ticket_id; // Handle both single and multiple ticket IDs
$ticket_ids = explode(',', $request->ticket_id);
// Load the HTML content into DOMDocument $messageWithClasses = $request->message;
$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();
// Get all <p> tags foreach ($ticket_ids as $ticket_id) {
$paragraphs = $dom->getElementsByTagName('p');
// 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);
// create response
$response = createResponse($ticket_id, $messageWithClasses, 1); $response = createResponse($ticket_id, $messageWithClasses, 1);
$ticket = Ticket::find($ticket_id); $ticket = Ticket::find($ticket_id);
if (!$ticket) continue;
$companyId = Session::get('selected_company'); $companyId = Session::get('selected_company');
$company = get_company('id', $companyId); $company = get_company('id', $companyId);
//Send mail to mailgun
// Send mail to mailgun
$domain = $company->domain; $domain = $company->domain;
$from = $company->email; $company_name = $company->getMeta('sender_name') ?? $company->name;
$from = "$company_name <$company->email>";
$to = $ticket->from_email; $to = $ticket->from_email;
$subject = $ticket->subject; $subject = $ticket->subject;
$html = $request->message; $html = $request->message;
// Call the function to send the email
sendEmailViaMailgun($domain, $from, $to, $subject, $html); sendEmailViaMailgun($domain, $from, $to, $subject, $html);
}
// Return the updated response and time
return response()->json([ return response()->json([
'message' => strip_tags($response->message), // Stripping HTML tags 'message' => strip_tags($response->message),
'created_at' => $response->created_at->format('h:i A') // Formatting time 'created_at' => $response->created_at->format('h:i A')
]); ]);
} }
public function storeComment(Request $request) public function storeComment(Request $request)
@ -453,8 +442,8 @@ public function updateRule(Request $request)
'tag_id' => $request->tag_id, 'tag_id' => $request->tag_id,
'name' => $request->name, 'name' => $request->name,
'assign_to' => $request->assign_to, 'assign_to' => $request->assign_to,
'status' => $request->status, 'status' => isset($request->status) ? $request->status : 'set as done',
'priority' => $request->priority, 'priority' => isset($request->priority) ? $request->priority : 'Set highest priority',
'message_to_assigned_editor' => $request->message_to_assigned_editor, 'message_to_assigned_editor' => $request->message_to_assigned_editor,
'all_emails_automatically_mark_as_spam' => $request->all_emails_automatically_mark_as_spam, 'all_emails_automatically_mark_as_spam' => $request->all_emails_automatically_mark_as_spam,
]); ]);

View File

@ -6,6 +6,9 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use App\Models\Ticket;
use App\Models\Response;
class EmailController extends Controller class EmailController extends Controller
{ {
public function saveEmail(Request $request){ public function saveEmail(Request $request){
@ -14,6 +17,7 @@ public function saveEmail(Request $request){
// try { // try {
$file_urls = [];
$token = $request->input('token'); $token = $request->input('token');
$timestamp = $request->input('timestamp'); $timestamp = $request->input('timestamp');
$signature = $request->input('signature'); $signature = $request->input('signature');
@ -22,6 +26,7 @@ public function saveEmail(Request $request){
update_setting('aw_test','Invalid signature.'); update_setting('aw_test','Invalid signature.');
abort(403, 'Invalid signature.'); abort(403, 'Invalid signature.');
} }
update_setting('aw_test',json_encode($request->all()));
$data = $this->extractMailgunData($request->all()); $data = $this->extractMailgunData($request->all());
@ -30,33 +35,57 @@ public function saveEmail(Request $request){
$to_email = $data['to_email']; $to_email = $data['to_email'];
$message = $data['message']; $message = $data['message'];
update_setting('aw_test',$to_email); //update_setting('aw_test',$to_email);
$company = get_company('email',$to_email); $company = get_company('email',$to_email);
if($company){ if($company){
$ticket = insertTicket($data['from_email'], $company->email, $data['subject'], $message,'inbox',$data['from_name'] ); $ticket = insertTicket($data['from_email'], $company->email, $data['subject'], $message,'inbox',$data['from_name'] );
if($ticket){ 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); $response = createResponse($ticket->id,$message);
$attachmentCount = $request->input('attachment-count', 0); $attachmentCount = $request->input('attachment-count', 0);
update_setting('aw_test',$attachmentCount);
for ($i = 1; $i <= $attachmentCount; $i++) { for ($i = 1; $i <= $attachmentCount; $i++) {
$attachment = $request->file("attachment-$i"); $attachment = $request->file("attachment-$i");
update_setting('aw_test',$attachment->getClientOriginalName()); // update_setting('aw_test',$attachment->getClientOriginalName());
if ($attachment && $attachment->isValid()) { if ($attachment && $attachment->isValid()) {
// Define a unique filename, possibly using the original filename and appending a timestamp or a unique id // Define a unique filename, possibly using the original filename and appending a timestamp or a unique id
$filename = time() . '_' . $attachment->getClientOriginalName(); $filename = time() . '_' . $attachment->getClientOriginalName();
// Save the attachment to the local or specific disk // Save the attachment to the local or specific disk
$filePath = $attachment->storeAs('tickets/' . $ticket->id, $filename, 'public'); $filePath = $attachment->storeAs('tickets/' . $ticket->id, $filename, 'public');
$fileUrl = url(Storage::url($filePath)); $fileUrl = Storage::url($filePath);
update_setting('aw_test',$fileUrl); $file_urls[] = $fileUrl;
} }
} }
//Update Responses Table with Attachments
if(count($file_urls) > 0) {
$response->attachments = json_encode($file_urls);
$response->save();
}
} }
}else{} }else{}
@ -73,16 +102,41 @@ public function saveEmail(Request $request){
} }
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) { public function extractMailgunData($data) {
// Prepare an array to hold the extracted data // Prepare an array to hold the extracted data
$from = extractEmail($data['from']);
$to = extractEmail($data['To']);
$extractedData = [ $extractedData = [
'from_email' => $data['from'], 'from_email' => $from,
'to_email' => $data['To'], 'to_email' => $to,
'from_name' => '', // This will be extracted from the 'from' field 'from_name' => '', // This will be extracted from the 'from' field
'subject' => $data['subject'], 'subject' => $data['subject'],
'message' => $data['body-html'], 'message' => isset($data['body-html'])?$data['body-html']:$data['body-plain'],
'mime_version' => $data['Mime-Version'], 'mime_version' => $data['Mime-Version'],
'dkim_signature' => $data['Dkim-Signature'] 'dkim_signature' => $data['Dkim-Signature']
]; ];

View File

@ -7,6 +7,8 @@
use App\Services\MailgunService; use App\Services\MailgunService;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use App\Services\CPanelApiService; use App\Services\CPanelApiService;
use Illuminate\Support\Facades\Storage;
class MailgunController extends Controller class MailgunController extends Controller
{ {
@ -22,7 +24,16 @@ public function __construct()
public function test(){ public function test(){
$domain = 'test.com'; $domain = 'test.com';
$email = "kundesone.$domain@mailgun.kundesone.no"; $email = "kundesone.$domain@mailgun.kundesone.no";
dd($this->createEmail($domain,$email));
$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) public function addDomain($domain)

View File

@ -14,6 +14,7 @@
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class TicketController extends Controller class TicketController extends Controller
{ {
@ -25,7 +26,7 @@ public function get_canned_responses(){
public function allTickets() public function allTickets()
{ {
$companyId = getSelectedCompany(); $companyId = getSelectedCompany();
$tickets = get_current_company_tickets(); $tickets = get_current_company_tickets(['type' => 'chat']);
$tags = Tag::where('company_id', $companyId)->get(); $tags = Tag::where('company_id', $companyId)->get();
return view('all-tickets', ['tickets' => $tickets, 'tags' => $tags]); return view('all-tickets', ['tickets' => $tickets, 'tags' => $tags]);
} }
@ -39,6 +40,7 @@ public function waiting()
public function showTicket($id) public function showTicket($id)
{ {
$companyId = getSelectedCompany();
$tickets = get_current_company_tickets([ $tickets = get_current_company_tickets([
'type' => 'inbox', 'type' => 'inbox',
@ -53,8 +55,15 @@ public function showTicket($id)
$messages = []; $messages = [];
$canned_response = $this->get_canned_responses(); $canned_response = $this->get_canned_responses();
$email_signature = CompanyMeta::where('company_id', $companyId)->where('type', 'Email Signature')->first();
return view('show-ticket', ['tickets' => $tickets, 'single_ticket' => $single_ticket, 'messages' => $messages, 'canned_response' => $canned_response]); return view('show-ticket', [
'tickets' => $tickets,
'single_ticket' => $single_ticket,
'messages' => $messages,
'canned_response' => $canned_response,
'email_signature' => $email_signature?$email_signature->value:''
]);
} }
public function updateStatus(Request $request, $ticketId) public function updateStatus(Request $request, $ticketId)
@ -92,9 +101,17 @@ public function storeTags(Request $request)
$ticket_id = $request->ticket_id; $ticket_id = $request->ticket_id;
$tags = json_decode($request->tags); $tags = json_decode($request->tags);
setTicketMeta($ticket_id,'tags',$tags);
TicketMeta::where('key','tags')->where('ticket_id',$ticket_id)->delete();
foreach($tags as $tag) foreach($tags as $tag)
{ {
TicketMeta::create(
['ticket_id' => $ticket_id, 'key' => 'tags',
'value' => $tag->value, 'type' => 'string']
);
//Update Tags Table //Update Tags Table
Tag::updateOrCreate([ Tag::updateOrCreate([
'company_id' => $company, 'company_id' => $company,
@ -105,6 +122,8 @@ public function storeTags(Request $request)
'type' => 'inbox' 'type' => 'inbox'
]); ]);
//Update Company Meta Table //Update Company Meta Table
@ -170,6 +189,12 @@ public function deleteTickets(Request $request)
TicketMeta::where('ticket_id', $ticket_id)->delete(); TicketMeta::where('ticket_id', $ticket_id)->delete();
Response::where('ticket_id', $ticket_id)->delete(); Response::where('ticket_id', $ticket_id)->delete();
TicketNote::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(); $ticket->delete();
} }
} }
@ -276,8 +301,13 @@ public function filter(Request $request)
$no_activity_tickets = $all_tickets->get(); $no_activity_tickets = $all_tickets->get();
return response()->json(['tickets' => $no_activity_tickets]); return response()->json(['tickets' => $no_activity_tickets]);
} elseif($request->filter == 'Spam') { } elseif($request->filter == 'Spam') {
$all_tickets = $tickets->where('status', $request->status)->get(); if($request->status == 'marked as spam') {
$all_tickets = $tickets->where('status', 'spam')->get();
return response()->json(['tickets' => $all_tickets]); return response()->json(['tickets' => $all_tickets]);
} else {
$all_tickets = $tickets->where('status', '!=', 'spam')->get();
return response()->json(['tickets' => $all_tickets]);
}
} elseif($request->filter == 'Status') { } elseif($request->filter == 'Status') {
$all_tickets = $tickets->where('status', $request->status)->get(); $all_tickets = $tickets->where('status', $request->status)->get();
return response()->json(['tickets' => $all_tickets]); return response()->json(['tickets' => $all_tickets]);

View File

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

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 = [];
}

View File

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

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');
});
}
};

37617
error_log

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ function initFomanticDropdown(selector, config, callback = null) {
} }
function slideTransition(selector, direction, shouldHide) { function slideTransition(selector, direction, shouldHide) {
$(selector).transition(`slide ${direction}`); //$(selector).transition(`slide ${direction}`);
if (shouldHide) { if (shouldHide) {
$(selector).addClass("hidden"); $(selector).addClass("hidden");
} else { } else {

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@ -190,12 +190,7 @@ function updateStatusOptions(selectedFilter) {
@foreach($company_users as $company_user) @foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>'; options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach @endforeach
// $('#status-select').html(`
// <option disabled value="">Select Users</option>`
// @foreah($company_users as $company_user)
// `<option value="`{{$company_user->user->id}}`">`{{$company_user->user->name}}`</option>
// <option value="Abdullah">Abdullah</option>
// `);
// Update the select element with the generated options // Update the select element with the generated options
$('#status-select').html(options); $('#status-select').html(options);
$('.filter_based__data').show(); $('.filter_based__data').show();
@ -343,6 +338,86 @@ function updateStatusOptions(selectedFilter) {
/* 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> </style>
<div class="content-wrapper"> <div class="content-wrapper">
@ -410,7 +485,7 @@ function updateStatusOptions(selectedFilter) {
<input type="checkbox" class="ticket-checkbox" id="ticket-{{$ticket->id}}"> <input type="checkbox" class="ticket-checkbox" id="ticket-{{$ticket->id}}">
</div> </div>
<div class="chat-user-img all-tickets position-relative"> <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 <div
class="chat-status-icon rounded-circle text-center align-content-center position-absolute"> class="chat-status-icon rounded-circle text-center align-content-center position-absolute">
<img src="{{ asset('images/icons/chat-round.svg') }}" alt="Chat Round"> <img src="{{ asset('images/icons/chat-round.svg') }}" alt="Chat Round">

View File

@ -623,6 +623,17 @@ class="form-control input-reply-textarea message_when_chat_is_closed">{!! $messa
<span style="background-color: {{ $background_color_of_sent_message_value }};"></span> <span style="background-color: {{ $background_color_of_sent_message_value }};"></span>
</div> </div>
</div> </div>
<div class="dev-box">
<h3>Background color of received messages</h3>
@php
$background_color_of_received_message = getChatSetting('background_color_of_received_message');
$background_color_of_received_message_value = $background_color_of_received_message->value ?? '#020400';
@endphp
<div class="dev-box-inner">
<input type="color" name="background_color_of_received_message" readonly placeholder="#020400" value="{{$background_color_of_received_message_value}}">
<span style="background-color: {{ $background_color_of_received_message_value }};"></span>
</div>
</div>
<div class="dev-box"> <div class="dev-box">
<h3>Text color of received messages</h3> <h3>Text color of received messages</h3>
@php @php
@ -785,7 +796,7 @@ class="form-control input-reply-textarea message_when_chat_is_closed">{!! $messa
<p>Select if users must click on a checkbox to approve policy before they can <p>Select if users must click on a checkbox to approve policy before they can
contact contact
you.</p> you.</p>
<form method="POST" action="{{ route('store.personal.data') }}"> <form style="max-width: none;" method="POST" action="{{ route('store.personal.data') }}">
@csrf @csrf
<div class="dev-input-group"> <div class="dev-input-group">
<label class="dev-checkbox-wrapper">Require active approval (check box) <label class="dev-checkbox-wrapper">Require active approval (check box)
@ -806,28 +817,34 @@ class="form-control input-reply-textarea message_when_chat_is_closed">{!! $messa
<div class="dev-input-group dev-input-group-input-info"> <div class="dev-input-group dev-input-group-input-info">
<label>Link text</label> <label>Link text</label>
@php @php
$link_text = getChatSetting('link_text') $link_text = '';
if(getChatSetting('link_text')){
$link_text = getChatSetting('link_text')->value;
}
@endphp @endphp
<input type="text" placeholder="Type here" name="link_text" required value="{{ $link_text->value ?? '' }}"> <textarea name="link_text" id="text_editor" rows="10" placeholder="Your Message"
class="form-control input-reply-textarea" required>{!! $link_text ?? '' !!}</textarea>
</div> </div>
<div class="dev-input-group dev-input-group-input-info"> <div class="dev-input-group dev-input-group-input-info">
<label>Preview</label> <label>Preview</label>
@php <a style="text-decoration: none;" href="{{ route('company.terms.conditions', getSelectedCompany()) }}" target="_blank">Terms & Conditions</a>
$preview = getChatSetting('preview')
@endphp
<input type="text" name="preview" value="{{ $preview->value ?? '' }}">
</div>
<div class="dev-input-group dev-input-group-input-info dev-custom-input-group">
<label>Policy for personal data</label>
<p>Custom policy</p>
<button type="button" class="dev-form-submit-btn">Edit</button>
</div> </div>
<!--<div class="dev-input-group dev-input-group-input-info dev-custom-input-group">-->
<!-- <label>Policy for personal data</label>-->
<!-- <p>Custom policy</p>-->
<!-- <button type="button" class="dev-form-submit-btn">Edit</button>-->
<!--</div>-->
<button type="submit" class="dev-form-submit-btn">Save</button> <button type="submit" class="dev-form-submit-btn">Save</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<script>
CKEDITOR.replace('text_editor');
</script>
<!-- --> <!-- -->
<!--<div class="dev-tabcontent dev-tabcontent-tags">--> <!--<div class="dev-tabcontent dev-tabcontent-tags">-->
<!-- <div class="dev-tabcontent-outers">--> <!-- <div class="dev-tabcontent-outers">-->

View File

@ -7,7 +7,17 @@
.scrollhint .item .single-user-content img,.scrollhint .item .sender-message-box img{ .scrollhint .item .single-user-content img,.scrollhint .item .sender-message-box img{
width:100%; 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> </style>
<!-- Support and Chat Fixed Buttons --> <!-- Support and Chat Fixed Buttons -->
@ -79,7 +89,7 @@
<!-- Support Drop down --> <!-- Support Drop down -->
<div class="ui floating bg-dark-green-color support-widget-wrapper icon dropdown button "> <div class="ui floating bg-dark-green-color support-widget-wrapper icon dropdown button ">
<img src="images/icons/support.svg" alt="Support Icon"> <img src="{{asset('images/icons/support.svg')}}" alt="Support Icon">
<div class="menu support-widget"> <div class="menu support-widget">
<div class="header support-header mt-0 text-center"> <div class="header support-header mt-0 text-center">
<h2 class="color-dark-green">Help & Support</h2> <h2 class="color-dark-green">Help & Support</h2>
@ -87,49 +97,49 @@
<div class="support-facilities-box d-flex justify-content-between flex-wrap"> <div class="support-facilities-box d-flex justify-content-between flex-wrap">
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/faq-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/faq-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green">FAQ</p> <p class="color-dark-green">FAQ</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/laptop-minimalistic-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/laptop-minimalistic-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green">Using Kundo</p> <p class="color-dark-green">Using Kundo</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/launch-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/launch-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green text-wrap">Launching Kundo</p> <p class="color-dark-green text-wrap">Launching Kundo</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/setting-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/setting-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green text-wrap">Technical Settings</p> <p class="color-dark-green text-wrap">Technical Settings</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/data-mapping-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/data-mapping-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green ">Integration</p> <p class="color-dark-green ">Integration</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/open-door-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/open-door-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green text-wrap">Privacy & Policy</p> <p class="color-dark-green text-wrap">Privacy & Policy</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/news-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/news-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green text-wrap">News & Updates</p> <p class="color-dark-green text-wrap">News & Updates</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/graduate-cap-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/graduate-cap-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green ">Training</p> <p class="color-dark-green ">Training</p>
</div> </div>
@ -142,13 +152,13 @@
<div class="contact-us-box d-flex justify-content-center"> <div class="contact-us-box d-flex justify-content-center">
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/email-14-svgrepo-com (1) 1.svg" alt=""> <img src="{{asset('images/icons/email-14-svgrepo-com (1) 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green text-wrap">Technical Questions</p> <p class="color-dark-green text-wrap">Technical Questions</p>
</div> </div>
<div class="item text-center"> <div class="item text-center">
<div class="support-img-box align-content-center"> <div class="support-img-box align-content-center">
<img src="images/icons/about-filled-svgrepo-com 1.svg" alt=""> <img src="{{asset('images/icons/about-filled-svgrepo-com 1.svg')}}" alt="">
</div> </div>
<p class="color-dark-green">About Kundo</p> <p class="color-dark-green">About Kundo</p>
</div> </div>
@ -570,3 +580,50 @@ function playMessageSound() {
</script> </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

@ -1,3 +1,93 @@
<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 --> <!-- Custom Modal post -->
<div id="customModal" class="modal"> <div id="customModal" class="modal">
<div class="modal-content"> <div class="modal-content">
@ -45,10 +135,15 @@
<div id="customModal3" class="modal"> <div id="customModal3" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="modal-close">&times;</span> <span class="modal-close">&times;</span>
<h5>Replay to multiple</h5> <h5>Reply to multiple</h5>
<form> <form>
<div class="mb-3 mt-4"> <div class="content d-flex align-items-end flex-column message-writing-content-area">
<p>Please choose only email conversations and try again</p> <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> </div>
</form> </form>
@ -56,6 +151,135 @@
</div> </div>
</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> <script>
$(document).ready(function() { $(document).ready(function() {
var $handleMultipleButton = $('.handle-multiple-btn'); var $handleMultipleButton = $('.handle-multiple-btn');
@ -278,3 +502,69 @@ function updateButtonStates() {
</script> </script>
<!--Update Status End--> <!--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

@ -61,13 +61,95 @@
.slider.round:before { .slider.round:before {
border-radius: 50%; 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> </style>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<header> <header>
<div class="row"> <div class="row">
<div class="col-sm-4 user-name-nav-area d-flex align-content-center"> <div class="col-sm-4 user-name-nav-area d-flex align-content-center">
<div class="dev-toggle-sidebar"> <div class="dev-toggle-sidebar">
<img src="{{ asset('images/icons/blocks-icon.svg') }}"> <img src="https://kundesone.no/images/logo_cropped.png">
</div> </div>
<h2 class="d-flex align-items-center">Hello {{auth()->user()->name}} <span>👋🏼</span>,</h2> <h2 class="d-flex align-items-center">Hello {{auth()->user()->name}} <span>👋🏼</span>,</h2>
</div> </div>
@ -77,11 +159,12 @@
<input type="text" class="color-dark-green" placeholder="Search..."> <input type="text" class="color-dark-green" placeholder="Search...">
</div> </div>
<div class="nav-links d-flex align-items-center"> <div class="nav-links d-flex align-items-center">
<span class="chat">Chat </span>
<label class="switch"> <label class="switch">
<input type="checkbox" id="toggleSwitch" @if(auth()->user()->is_available == 1) checked @endif> <input type="checkbox" id="toggleSwitch" @if(auth()->user()->is_available == 1) checked @endif>
<span class="slider round"></span> <span class="slider round">
</label> </label>
<form method="POST" action="{{route('logout')}}"> <form class="logout" method="POST" action="{{route('logout')}}">
@csrf @csrf
<button class="nav-btn bg-dark-green-color"> <button class="nav-btn bg-dark-green-color">
<img height="25" width="50" src="{{ asset('images/logout.png') }}" alt=""> <img height="25" width="50" src="{{ asset('images/logout.png') }}" alt="">
@ -146,6 +229,7 @@ class="chat-settings-btn-row text-center d-flex justify-content-center align-ite
<a <a
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a> class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</div> </div>
</div> </div>
<div class="item"> <div class="item">
<p class="action-heading-paragraph text-center align-content-center"> <p class="action-heading-paragraph text-center align-content-center">
@ -158,6 +242,14 @@ 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 class="ui secondary basic button tag-btn shadow-none">Tags</a>-->
<a href="{{ route('profile') }}" <a href="{{ route('profile') }}"
class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a> class="ui secondary basic button shadow-none setting-btn text-white align-content-center">Settings</a>
</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>
</div> </div>
@ -189,11 +281,16 @@ class="ui secondary basic button shadow-none setting-btn text-white align-conten
<!--chat avialability ajax--> <!--chat avialability ajax-->
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#toggleSwitch').on('change', function() { $('#toggleSwitch').off('change').on('change', function(e) {
const isChecked = $(this).is(':checked'); // 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);
if (isChecked) {
// Call route when toggle is ON
$.ajax({ $.ajax({
url: 'update/chat-availability', url: 'update/chat-availability',
method: 'POST', method: 'POST',
@ -201,41 +298,35 @@ class="ui secondary basic button shadow-none setting-btn text-white align-conten
'X-CSRF-TOKEN': "{{ csrf_token() }}" 'X-CSRF-TOKEN': "{{ csrf_token() }}"
}, },
data: { data: {
status: 'on' status: status
}, },
success: function(response) { success: function(response) {
console.log('Success:', response);
if(response.success) { if(response.success) {
toastr.success('Chat Availability Updated Successfully'); toastr.success('Chat Availability Updated Successfully');
} }
// Enable the checkbox again after the AJAX call completes
$('#toggleSwitch').prop('disabled', false);
}, },
error: function(xhr, status, error) { error: function(xhr, status, error) {
console.error('Error:', error); console.error('Error:', error);
} $('#toggleSwitch').prop('disabled', false);
});
} 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> </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,8 +1,8 @@
<div class="sidebar-area"> <div class="sidebar-area">
<aside class="bg-dark-green-color"> <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"> <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> </div>
<style> <style>
@ -15,6 +15,12 @@
} }
.bg-light-color .sidebar_icon{ .bg-light-color .sidebar_icon{
color: #383F33 !important; color: #383F33 !important;
}
.frame .dev-toggle-sidebar img {
width: 26px;
height: 26px;
vertical-align: top !important;
border-radius: 50%;
} }
</style> </style>
@ -49,7 +55,7 @@ class="side-bar-link d-flex align-items-center justify-content-between aw-a-wai
class="side-bar-link d-flex align-items-center justify-content-between aw-a-all"> 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"> <div class="link-left-content align-items-center d-flex">
<i class="fa fa-ticket sidebar_icon" aria-hidden="true"></i> <i class="fa fa-ticket sidebar_icon" aria-hidden="true"></i>
<h6 class="color-light">All Tickets</h6> <h6 class="color-light">Chats</h6>
</div> </div>
<div class="link-right-content"> <div class="link-right-content">
<img src="{{ asset('images/icons/chevron-right-light.png') }}" alt="chevron right"> <img src="{{ asset('images/icons/chevron-right-light.png') }}" alt="chevron right">
@ -114,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-row d-flex side-bar-link">
<div class="profile-nav-box"> <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>
<div class="user-info-box d-flex justify-content-between"> <div class="user-info-box d-flex justify-content-between">
<div class="info"> <div class="info">
<p class="color-light side-bar-user-name">Maxwell</p> <a style="text-decoration: none; color: white;" href="{{route('profile')}}"><p class="color-light side-bar-user-name">{{Auth::user()->name}}</p></a>
<p class="color-offset-white">Project Manager</p>
</div> </div>
<div class="icon align-self-center"> <div class="icon align-self-center">
<img src="{{ asset('images/icons/chevron-down 3.png') }}" alt="Chevron Down Icon"> <img src="{{ asset('images/icons/chevron-down 3.png') }}" alt="Chevron Down Icon">

View File

@ -10,56 +10,133 @@
<meta content="" name="description"> <meta content="" name="description">
<meta content="" name="keywords"> <meta content="" name="keywords">
<!-- Favicons -->
<link href="" rel="icon"> <link href="" rel="icon">
<link href="assets/img/apple-touch-icon.png" rel="apple-touch-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"> <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" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> 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" <link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,301,400,401,500,501,700,701,900,901&display=swap"
rel="stylesheet"> 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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<link rel="stylesheet" href="{{ asset('assets/auth.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"> <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> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>Instructions to verify domain. Read and apply carefully.</h1> <h1>Instructions to Verify Domain</h1>
<div class="domain-details"> <div class="domain-details">
<div class="alert alert-{{$domain->getDomain()->getState() == 'active'?'success':'danger'}}"> <div class="alert alert-{{$domain->getDomain()->getState() == 'active'?'success':'danger'}}">
<ul> <ul>
<li>Domain is {{$domain->getDomain()->getState()}}</li> <li>Domain is {{$domain->getDomain()->getState()}}</li>
</ul> </ul>
</div> </div>
<h2>Domain Information</h2> <h2>Domain Information</h2>
<p><strong>Name:</strong> {{ $domain->getDomain()->getName() }}</p> <p><strong>Name:</strong> {{ $domain->getDomain()->getName() }}</p>
<p><strong>State:</strong> {{ $domain->getDomain()->getState() }}</p> <p><strong>State:</strong> {{ $domain->getDomain()->getState() }}</p>
</div> </div>
<div class="dns-records"> <div class="dns-records">
<h2>Step 1: Add Forwarder</h2> <h2>Step 1: Add Forwarder</h2>
<div class="record"> <div class="record">
<p>Forward your email to internal email. i.e <span class="alert-success"><b>kundesone.{{ $domain->getDomain()->getName() }}@mailgun.kundesone.no</b></span>. Make sure you forward only your company email that you added on the time of registration.</p> <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> </div>
<h2>Step 2: Add Outbound DNS Records</h2> <h2>Step 2: Add Outbound DNS Records</h2>
@foreach($domain->getOutboundDnsRecords() as $record) @foreach($domain->getOutboundDnsRecords() as $record)
<div class="record"> <div class="record">
@ -69,7 +146,6 @@
</div> </div>
@endforeach @endforeach
<h2>Step 3: Add Inbound DNS Records</h2> <h2>Step 3: Add Inbound DNS Records</h2>
@foreach($domain->getInboundDnsRecords() as $record) @foreach($domain->getInboundDnsRecords() as $record)
<div class="record"> <div class="record">
@ -80,80 +156,20 @@
</div> </div>
@endforeach @endforeach
<h2>Note: DNS Propagation Time</h2> <h2>Note: DNS Propagation Time</h2>
<div class="record"> <div class="record">
<p>DNS Propagation can take upto 48 hours. In this case your domain will not be active.</p> <p>DNS propagation can take up to 48 hours. During this time, your domain may not be active.</p>
</div> </div>
</div> </div>
<form id="verify-form" action="{{route('verifyDomain')}}" method="post"> <form id="verify-form" action="{{route('verifyDomain')}}" method="post">
@csrf @csrf
<input type="hidden" name="domain" value="{{$domain->getDomain()->getName()}}"/> <input type="hidden" name="domain" value="{{$domain->getDomain()->getName()}}"/>
<div class="verify">
<button type="submit" class="btn signup">Verify Domain <button type="submit" class="btn signup">Verify Domain</button>
</button> </div>
</form> </form>
</div> </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> </body>
</html> </html>

View File

@ -14,7 +14,7 @@
<button type="button">Response</button> <button type="button">Response</button>
<button type="button">Canned Responses</button> <button type="button">Canned Responses</button>
<button type="button">Acknowledge</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">Spam handling</button>
<!--<button type="button">Tags</button>--> <!--<button type="button">Tags</button>-->
<!--<button type="button">Others</button>--> <!--<button type="button">Others</button>-->
@ -46,7 +46,7 @@
</div> </div>
<div class="dev-input-group dev-input-group-input-info"> <div class="dev-input-group dev-input-group-input-info">
<label>Inbox name</label> <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"> <div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info"> <img src="{{ asset('images/info.svg') }}" alt="info">
<span>Your internal name. I.e. the Inbox</span> <span>Your internal name. I.e. the Inbox</span>
@ -54,7 +54,7 @@
</div> </div>
<div class="dev-input-group dev-input-group-input-info"> <div class="dev-input-group dev-input-group-input-info">
<label>Sender name</label> <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"> <div class="dev-input-info">
<img src="{{ asset('images/info.svg') }}" alt="info"> <img src="{{ asset('images/info.svg') }}" alt="info">
<span>E.g. company name or department</span> <span>E.g. company name or department</span>
@ -69,7 +69,7 @@
<select name="language" required> <select name="language" required>
<option value="">Select Language</option> <option value="">Select Language</option>
@foreach($languages as $language) @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 @endforeach
</select> </select>
</div> </div>
@ -80,7 +80,7 @@
<select name="timezone" required> <select name="timezone" required>
<option value="">Select your Timezone</option> <option value="">Select your Timezone</option>
@foreach($timezones as $timezone) @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 @endforeach
</select> </select>
</div> </div>
@ -658,98 +658,98 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
</div> </div>
<!-- --> <!-- -->
<div class="dev-tabcontent dev-tabcontent-rules"> <!--<div class="dev-tabcontent dev-tabcontent-rules">-->
<div class="dev-tabcontent-outers"> <!-- <div class="dev-tabcontent-outers">-->
<div class="dev-title-row"> <!-- <div class="dev-title-row">-->
<h2>Automatic rules</h2> <!-- <h2>Automatic rules</h2>-->
<p> <!-- <p>-->
With automatic rules you can perform common tasks automatically, e.g. assign an <!-- 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 <!-- e-mail to a specific person if the subject contains a certain word. Automatic-->
rules consist of a filter and an effect. <!-- rules consist of a filter and an effect.-->
</p> <!-- </p>-->
</div> <!-- </div>-->
<h2>Create a new rule</h2> <!-- <h2>Create a new rule</h2>-->
<form method="POST" action="{{ route('update.rule') }}"> <!-- <form method="POST" action="{{ route('update.rule') }}">-->
@csrf <!-- @csrf-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>Name</label> <!-- <label>Name</label>-->
<input name="name" type="text" placeholder="Type here.." value="{{$rule->name ?? ''}}"> <!-- <input name="name" type="text" placeholder="Type here.." value="{{$rule->name ?? ''}}">-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>Tag everything from the sales department</span> <!-- <span>Tag everything from the sales department</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<h3>Filter</h3> <!-- <h3>Filter</h3>-->
<p>If you complete the From, To, and Subject fields, they must all match an email for <!-- <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. <!-- 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 <!-- If you specify multiple email addresses in the same field, it's enough for one of-->
them to match. <!-- them to match.-->
If, for example, you fill in <a href="#">support@kundo.se</a> and <a <!-- If, for example, you fill in <a href="#">support@kundo.se</a> and <a-->
href="#">info@kundo.se</a> in the From field, <!-- 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> <!-- and "hello" in the subject field, all e-mails from <a href="#">support@kundo.se</a>-->
OR <a href="#">info@kundo.se</a> <!-- OR <a href="#">info@kundo.se</a>-->
that ALSO contains "hello" in the subject field will match. <!-- 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 <!-- 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. <!-- addresses, you can write *@kundo.se in the "from" field.-->
</p> <!-- </p>-->
<div class="dev-form-inner"> <!-- <div class="dev-form-inner">-->
<div class="col-left"> <!-- <div class="col-left">-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>From</label> <!-- <label>From</label>-->
<input type="email" name="from" placeholder="Type here.." value="{{$rule->from ?? ''}}"> <!-- <input type="email" name="from" placeholder="Type here.." value="{{$rule->from ?? ''}}">-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>E.g. example@example.com or *@example.com</span> <!-- <span>E.g. example@example.com or *@example.com</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>To</label> <!-- <label>To</label>-->
<input type="email" name="to" placeholder="Type here.." value="{{$rule->to ?? ''}}"> <!-- <input type="email" name="to" placeholder="Type here.." value="{{$rule->to ?? ''}}">-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>E.g. test@example.com</span> <!-- <span>E.g. test@example.com</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="col-right"> <!-- <div class="col-right">-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>Subject Contains</label> <!-- <label>Subject Contains</label>-->
<input type="text" name="subject_contains" placeholder="Type here.." value="{{$rule->subject_contains ?? ''}}"> <!-- <input type="text" name="subject_contains" placeholder="Type here.." value="{{$rule->subject_contains ?? ''}}">-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>E.g. Great deals!</span> <!-- <span>E.g. Great deals!</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>Text Contains</label> <!-- <label>Text Contains</label>-->
<input type="text" name="text_contains" placeholder="Type here.." value="{{$rule->text_contains ?? ''}}"> <!-- <input type="text" name="text_contains" placeholder="Type here.." value="{{$rule->text_contains ?? ''}}">-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>E.g. Great deals!</span> <!-- <span>E.g. Great deals!</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="dev-input-group"> <!-- <div class="dev-input-group">-->
<label class="dev-checkbox-wrapper">All e-mails automatically marked as spam <!-- <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> <!-- <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> <!-- <span class="checkmark"></span>-->
</label> <!-- </label>-->
</div> <!-- </div>-->
<h3>Exceptions</h3> <!-- <h3>Exceptions</h3>-->
<p>Email that matches the filter above but for which the rule should not be activated. <!-- <p>Email that matches the filter above but for which the rule should not be activated.-->
</p> <!-- </p>-->
<div class="dev-form-inner"> <!-- <div class="dev-form-inner">-->
<div class="col-left"> <!-- <div class="col-left">-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>Subject Contains</label> <!-- <label>Subject Contains</label>-->
<textarea rows="6" name="subject1_contains">{{$rule->subject1_contains ?? ''}}</textarea> <!-- <textarea rows="6" name="subject1_contains">{{$rule->subject1_contains ?? ''}}</textarea>-->
<div class="dev-input-info"> <!-- <div class="dev-input-info">-->
<img src="{{ asset('images/info.svg') }}" alt="info"> <!-- <img src="{{ asset('images/info.svg') }}" alt="info">-->
<span>Order Confirmation</span> <!-- <span>Order Confirmation</span>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<!--<div class="col-right">--> <!--<div class="col-right">-->
<!-- <div class="dev-input-group dev-input-group-input-info">--> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<!-- <label>Text Contains</label>--> <!-- <label>Text Contains</label>-->
@ -760,76 +760,76 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
<!-- </div>--> <!-- </div>-->
<!-- </div>--> <!-- </div>-->
<!--</div>--> <!--</div>-->
</div> <!-- </div>-->
<h3>Effect</h3> <!-- <h3>Effect</h3>-->
<p>The effect describes what should happen when the filter above matches. It happens <!-- <p>The effect describes what should happen when the filter above matches. It happens-->
automatically, before the e-mail shows up in <!-- automatically, before the e-mail shows up in-->
the dashboard.</p> <!-- the dashboard.</p>-->
<div class="dev-content-schedule"> <!-- <div class="dev-content-schedule">-->
<label>Assign To</label> <!-- <label>Assign To</label>-->
<div class="schedule-box"> <!-- <div class="schedule-box">-->
<select name="assign_to"> <!-- <select name="assign_to">-->
@foreach($company_users as $company_user) <!-- @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> <!-- <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 <!-- @endforeach-->
</select> <!-- </select>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="dev-form-inner"> <!-- <div class="dev-form-inner">-->
<div class="col-left"> <!-- <div class="col-left">-->
<div class="dev-input-group dev-input-group-input-info"> <!-- <div class="dev-input-group dev-input-group-input-info">-->
<label>Message to assigned editor</label> <!-- <label>Message to assigned editor</label>-->
<textarea rows="6" name="message_to_assigned_editor">{{$rule->message_to_assigned_editor ?? ''}}</textarea> <!-- <textarea rows="6" name="message_to_assigned_editor">{{$rule->message_to_assigned_editor ?? ''}}</textarea>-->
</div> <!-- </div>-->
<!--<div class="dev-input-group">--> <!--<div class="dev-input-group">-->
<!-- <label class="dev-checkbox-wrapper">Remove and hide from the statistics --> <!-- <label class="dev-checkbox-wrapper">Remove and hide from the statistics -->
<!-- <input type="checkbox">--> <!-- <input type="checkbox">-->
<!-- <span class="checkmark"></span>--> <!-- <span class="checkmark"></span>-->
<!-- </label>--> <!-- </label>-->
<!--</div>--> <!--</div>-->
</div> <!-- </div>-->
<div class="col-right"> <!-- <div class="col-right">-->
<div class="dev-content-schedule"> <!-- <div class="dev-content-schedule">-->
<label>Add tags</label> <!-- <label>Add tags</label>-->
<div class="schedule-box"> <!-- <div class="schedule-box">-->
<select name="tag_id"> <!-- <select name="tag_id">-->
@foreach($tags as $tag) <!-- @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> <!-- <option value="{{$tag->id}}" @if($rule && !is_null($rule->tag_id) && $rule->tag_id == $tag->id) selected @endif>{{$tag->name}}</option>-->
@endforeach <!-- @endforeach-->
</select> <!-- </select>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="checkbox-box"> <!-- <div class="checkbox-box">-->
<div class="dev-input-group"> <!-- <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> <!-- <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> <!-- <label class="dev-checkbox-wrapper">Set as done</label>-->
</div> <!-- </div>-->
<div class="dev-input-group"> <!-- <div class="dev-input-group">-->
<label class="dev-checkbox-wrapper">Set highest priority</label> <!-- <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> <!-- <input type="radio" value="Set highest priority" name="priority" @if($rule && !is_null($rule->priority) && $rule->priority == 'Set highest priority') checked @endif>-->
</div> <!-- </div>-->
<div class="dev-input-group"> <!-- <div class="dev-input-group">-->
<label class="dev-checkbox-wrapper">Mark as spam</label> <!-- <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> <!-- <input type="radio" value="mask as spam" name="status" @if($rule && !is_null($rule->status) && $rule->status == 'mask as spam') checked @endif>-->
</div> <!-- </div>-->
<div class="dev-input-group"> <!-- <div class="dev-input-group">-->
<label class="dev-checkbox-wrapper">Set lowest priority</label> <!-- <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> <!-- <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>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<button type="submit" class="dev-form-submit-btn">Save</button> <!-- <button type="submit" class="dev-form-submit-btn">Save</button>-->
</form> <!-- </form>-->
</div> <!-- </div>-->
</div> <!--</div>-->
<!-- --> <!-- -->
<div class="dev-tabcontent dev-tabcontent-canned"> <div class="dev-tabcontent dev-tabcontent-canned">
<div class="dev-tabcontent-outers"> <div class="dev-tabcontent-outers">

View File

@ -190,13 +190,7 @@ function updateStatusOptions(selectedFilter) {
@foreach($company_users as $company_user) @foreach($company_users as $company_user)
options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>'; options += '<option value="{{ $company_user->user->id }}">{{ $company_user->user->name }}</option>';
@endforeach @endforeach
// $('#status-select').html(`
// <option disabled value="">Select Users</option>`
// @foreah($company_users as $company_user)
// `<option value="`{{$company_user->user->id}}`">`{{$company_user->user->name}}`</option>
// <option value="Abdullah">Abdullah</option>
// `);
// Update the select element with the generated options
$('#status-select').html(options); $('#status-select').html(options);
$('.filter_based__data').show(); $('.filter_based__data').show();
break; break;
@ -395,6 +389,76 @@ function updateStatusOptions(selectedFilter) {
/* 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> </style>
<div class="content-wrapper"> <div class="content-wrapper">
@ -625,7 +689,6 @@ function fetchTickets() {
}); });
</script> </script>
<x-custom-modals /> <x-custom-modals />

View File

@ -10,7 +10,7 @@
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script> <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"> <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 --> <!-- Bootstrap Styles -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
@ -50,65 +50,21 @@
</div> </div>
<!-- Jquery --> <!-- Jquery -->
<!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js" <script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> --> 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" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script> --> crossorigin="anonymous"></script>
<!-- Fomantic Ui Scripts --> <!-- 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 --> <!-- Main Custom Js -->
<script src="{{ asset('assets/script.js') }}"></script> <script src="{{ asset('assets/script.js') }}"></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>
</body> </body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

View File

@ -24,6 +24,15 @@
<!-- Main Styles --> <!-- Main Styles -->
<link rel="stylesheet" href="{{ asset('assets/style.css') }}"> <link rel="stylesheet" href="{{ asset('assets/style.css') }}">
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/png"> <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>
</head> </head>
@ -35,8 +44,8 @@
<!-- Sidebar --> <!-- Sidebar -->
<div class=" sidebar-area short-sidebar"> <div class=" sidebar-area short-sidebar">
<aside class="bg-dark-green-color align-items-center "> <aside class="bg-dark-green-color align-items-center ">
<div class="image-box d-flex justify-content-between"> <div class="image-box d-flex justify-content-between logo_be">
<img src="{{ asset('images/logo-white.png') }}" alt="Site Logo"> <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 class="dev-toggle-sidebar dev-close"><img src="{{ asset('images/icons/close-icon.svg') }}" alt=""></div>
</div> </div>
<div class="side-bar-links d-flex justify-content-center"> <div class="side-bar-links d-flex justify-content-center">

View File

@ -131,15 +131,15 @@
<?php <?php
$tags = []; $tags = [];
$db_tags = getTicketMeta($ticket->id,'tags'); $db_tags = getTicketMeta($ticket->id,'tags',false);
if($db_tags){ // if($db_tags){
foreach($db_tags as $tag){ // foreach($db_tags as $tag){
$tags[] = $tag->value; // $tags[] = $tag->value;
} // }
} // }
?> ?>
<input type="text" name="tags" id="tags" value="{{implode(',',$tags)}}" placeholder="Type and press Enter" <input type="text" name="tags" id="tags" value="{{implode(',',$tags)}}" placeholder="Type and press Enter"

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) @foreach($messages as $message)
<!-- Recepient Message --> <!-- Recepient Message -->
@if($message->user_id == 0) @if($message->user_id == 0)
@ -6,7 +68,19 @@
<img src="{{ asset('images/Avatar.png') }}" alt="User"> <img src="{{ asset('images/Avatar.png') }}" alt="User">
</div> </div>
<div class="single-message-chat"> <div class="single-message-chat">
<div class="user-message">{!!$message->message!!}</div> <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> <p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p>
</div> </div>
</div> </div>
@ -14,16 +88,15 @@
@elseif($message->user_id == 1) @elseif($message->user_id == 1)
<div class="chat-message chat-sender d-flex justify-content-end"> <div class="chat-message chat-sender d-flex justify-content-end">
<div class="single-message-chat"> <div class="single-message-chat">
@if(!containsHtml($message->message))
<p class="user-message bg-light-green-color color-light">{!!$message->message!!}</p> <div class="user-message bg-light-green-color color-light chat_style">{!!$message->message!!}</div>
@else <div class="chat-user-img-box align-self-end left_box">
{!! $message->message !!} <img src="{{ asset('images/Avatar.png') }}" alt="User">
@endif
<p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p> <p class="message-time">{{ \Carbon\Carbon::parse($message->created_at)->format('h:i A') }}</p>
</div> </div>
<div class="chat-user-img-box align-self-end">
<img src="{{ asset('images/Avatar.png') }}" alt="User">
</div> </div>
</div> </div>
@endif @endif
@endforeach @endforeach

View File

@ -4,6 +4,38 @@
@section('content') @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="content-wrapper">
<div class="dev-chat-tabs"> <div class="dev-chat-tabs">
<div class="dev-tabcontent dev-tabcontent-users"> <div class="dev-tabcontent dev-tabcontent-users">

View File

@ -7,6 +7,11 @@
<style> <style>
div.chat-inbox>.chat-content-wrapper>.chat-message>.single-message-chat>.user-message{ div.chat-inbox>.chat-content-wrapper>.chat-message>.single-message-chat>.user-message{
max-width:90%!important; max-width:90%!important;
width: 70%;
}
.single-message-chat{
width:100%;
} }
.receiver-message{ .receiver-message{
@ -16,6 +21,18 @@
width: 100% !important; width: 100% !important;
height: auto !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> </style>
<input type="hidden" value="{{$single_ticket->id}}" id="aw-ticket_id"/> <input type="hidden" value="{{$single_ticket->id}}" id="aw-ticket_id"/>
@ -133,17 +150,37 @@ class="form-control input-reply-textarea" id="editor1" required></textarea>
CKEDITOR.plugins.add('addcannedresponse', { CKEDITOR.plugins.add('addcannedresponse', {
init: function(editor) { init: function(editor) {
// Command for inserting canned response
editor.addCommand('addCannedResponseCmd', { editor.addCommand('addCannedResponseCmd', {
exec: function(editor) { exec: function(editor) {
// Show your modal or handle canned response insertion
document.getElementById('cannedResponseModal').style.display = 'block'; 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', { editor.ui.addButton('AddCannedResponse', {
label: 'Insert Canned Response', label: 'Insert Canned Response',
command: 'addCannedResponseCmd', command: 'addCannedResponseCmd',
icon: 'https://kundesone.no/images/canned.png', // Use an accessible icon URL or local path icon: 'https://kundesone.no/images/canned.png', // Use an accessible icon URL or local path
toolbar: 'insert,0' 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'
});
} }
}); });

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

@ -152,8 +152,68 @@
display: block; 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> </style>
<div class="content-wrapper"> <div class="content-wrapper">

View File

@ -25,8 +25,6 @@
| |
*/ */
Route::get('/', [LoginController::class, 'login'])->name('login.create'); Route::get('/', [LoginController::class, 'login'])->name('login.create');
Route::post('store/login', [LoginController::class, 'storeLogin'])->name('store.login'); Route::post('store/login', [LoginController::class, 'storeLogin'])->name('store.login');
Route::post('store/register', [RegisterController::class, 'storeRegister'])->name('store.register'); Route::post('store/register', [RegisterController::class, 'storeRegister'])->name('store.register');
@ -57,6 +55,7 @@
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('index')->middleware('verifyDomain');; Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('index')->middleware('verifyDomain');;
Route::get('/profile', [DashboardController::class, 'profile'])->name('profile'); 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('company-info', [CompanyController::class, 'getCompanyInfo'])->name('get.company.info');
Route::get('/waiting', [TicketController::class, 'waiting'])->name('waiting'); Route::get('/waiting', [TicketController::class, 'waiting'])->name('waiting');
Route::get('/all-tickets', [TicketController::class, 'allTickets'])->name('all.tickets'); Route::get('/all-tickets', [TicketController::class, 'allTickets'])->name('all.tickets');
@ -104,6 +103,7 @@
Route::post('store/chat-canned-responses', [ChatSettingController::class, 'storeChatCannedResponses'])->name('store.chat.canned.responses'); 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::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::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('store/tags', [ChatSettingController::class, 'storeTags'])->name('store.tags');
Route::post('setting/all-chat', [ChatSettingController::class, 'settingAllChat'])->name('setting.all.chat'); 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::post('block/ip-addresses', [ChatSettingController::class, 'blockIpAdresses'])->name('block.ip.addresses');