Backend Developmentcrm

Implementing CRM System With Laravel Part 12: Calendar Module

implementing crm with laravel calendar

The calendar module shows a full page calendar usually used to display the tasks status with the start and end dates, we will cover this module in this part.

 

 

Series Topics:

 

The calendar module is pretty simple it just has one page that displays a calendar, in that case we use Jquery fulcalendar plugin to display the tasks or events.

create a new controller using the artisan command:

php artisan make:controller CalendarController

Open app/Http/Controllers/CalendarController.php and update it with this code:

<?php

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class CalendarController extends Controller
{
    public function __construct()
    {
        $this->middleware('admin:index-show_calendar');
    }

    public function index()
    {
        $eventData = $this->getTaskStatusByDate();

        list($events, $countPending, $countInProgress, $countFinished) = $eventData;

        $events_js_script = '<script>var events = '.json_encode($events).'</script>';

        return view('pages.calendar.index', compact('events_js_script', 'countPending', 'countInProgress', 'countFinished'));
    }


    /**
     * get all tasks by date
     *
     * retrieves all tasks by dates and categorizes them into pending, in progress, finished
     * according to the date
     *
     * @return array
     */
    protected function getTaskStatusByDate()
    {
        $pending_tasks = Task::whereNotNull('start_date')->whereNotNull('end_date')->where('start_date', '>', date("m/d/Y"));

        $tasks_in_progress = Task::whereNotNull('start_date')->whereNotNull('end_date')->where('start_date', '<=', date("m/d/Y"))->where('end_date', '>=', date("m/d/Y"));

        $finished_tasks = Task::whereNotNull('start_date')->whereNotNull('end_date')->where('end_date', '<', date("m/d/Y"));


        // if not admin user show tasks if assigned to or created by that user
        if(Auth::user()->is_admin == 0) {
            $pending_tasks->where(function ($query) {
                $query->where('assigned_user_id', Auth::user()->id)
                    ->orWhere('created_by_id', Auth::user()->id);
            });

            $tasks_in_progress->where(function ($query) {
                $query->where('assigned_user_id', Auth::user()->id)
                    ->orWhere('created_by_id', Auth::user()->id);
            });

            $finished_tasks->where(function ($query) {
                $query->where('assigned_user_id', Auth::user()->id)
                    ->orWhere('created_by_id', Auth::user()->id);
            });
        }

        $pending_tasks = $pending_tasks->get();
        $tasks_in_progress = $tasks_in_progress->get();
        $finished_tasks = $finished_tasks->get();

        $pending_events = [];

        $in_progress_events = [];

        $finished_events = [];

        foreach ($pending_tasks as $task) {

            $pending_events[] = ["title" => $task->name . " - pending",
                "start" => date("Y-m-d", strtotime($task->start_date)),
                "end" => date("Y-m-d", strtotime($task->end_date)),
                "backgroundColor" => "#3c8dbc",
                "borderColor" => "#3c8dbc",
                "className" => "pending",
                "description" => "<strong>Title:</strong> " . $task->name . "<br/>" .
                    "<strong>Start date:</strong> " . date("Y-m-d", strtotime($task->start_date)) . "<br/>" .
                    "<strong>End date:</strong> " . date("Y-m-d", strtotime($task->end_date)) . "<br/>" .
                    "<strong>Type:</strong> " . $task->type->name . "<br/>"
                ];
        }

        foreach ($tasks_in_progress as $task) {

            $in_progress_events[] = ["title" => $task->name . " - in progress",
                "start" => date("Y-m-d", strtotime($task->start_date)),
                "end" => date("Y-m-d", strtotime($task->end_date)),
                "backgroundColor" => "#f39c12",
                "borderColor" => "#f39c12",
                "className" => "in-progress",
                "description" => "<strong>Title:</strong> " . $task->name . "<br/>" .
                    "<strong>Start date:</strong> " . date("Y-m-d", strtotime($task->start_date)) . "<br/>" .
                    "<strong>End date:</strong> " . date("Y-m-d", strtotime($task->end_date)) . "<br/>" .
                    "<strong>Type:</strong> " . $task->type->name . "<br/>"
            ];
        }

        foreach ($finished_tasks as $task) {

            $finished_events[] = ["title" => $task->name . " - finished",
                "start" => date("Y-m-d", strtotime($task->start_date)),
                "end" => date("Y-m-d", strtotime($task->end_date)),
                "backgroundColor" => "#00a65a",
                "borderColor" => "#00a65a",
                "className" => "finished",
                "description" => "<strong>Title:</strong> " . $task->name . "<br/>" .
                    "<strong>Start date:</strong> " . date("Y-m-d", strtotime($task->start_date)) . "<br/>" .
                    "<strong>End date:</strong> " . date("Y-m-d", strtotime($task->end_date)) . "<br/>" .
                    "<strong>Type:</strong> " . $task->type->name . "<br/>"
            ];
        }

        return [array_merge($pending_events, $in_progress_events, $finished_events),
            count($pending_events),
            count($in_progress_events),
            count($finished_events)
            ];
    }
}

The controller contains only two functions, the main function is the index() function which displays the calendar. We call another function getTaskStatusByDate() which retrieves tasks which have start and end dates.

We will consider three types of tasks:

  • Pending tasks: tasks that are not begin yet having start date greater than today.
  • Tasks in progress: tasks already working in the current time which have start and end dates between today.
  • Finished tasks: tasks which have end date passed.

If the user is super admin then we display all the tasks, else we display the tasks assigned to or created by the current user.

Then we looped over each collection saving them into a new array, why we do this because the Jquery fullcalendar expects an array of events similar to this one:

[
   {
       "title": "event name",
       "start": "",
       "end": "",
       "backgroundColor": "",
       "borderColor": "",
       "className": "",
       "description": ""
   },
   {
       "title": "event name",
       "start": "",
       "end": "",
       "backgroundColor": "",
       "borderColor": "",
       "className": "",
       "description": ""
   }
]

We sent this javacript code to the view:

$events_js_script = '<script>var events = '.json_encode($events).'</script>';

This variables will be passed to the fullcalendar Jquery plugin.

 

Calendar View

resources/views/pages/calendar/index.blade.php

@extends('layout.app')

@section('title', ' | Calendar')

@section('styles')
    <!-- fullCalendar -->
    <link rel="stylesheet" href="{{ url('theme/bower_components/fullcalendar/dist/fullcalendar.min.css') }}">
    <style>
        .external-event {
            cursor: pointer !important;
        }
    </style>
@endsection

@section('content')

    <section class="content-header">
        <h1>
            Calendar
        </h1>
        <ol class="breadcrumb">
            <li><a href="{{ url('/admin') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li>
            <li class="active">Calendar</li>
        </ol>
    </section>

    <section class="content">
        <div class="row">
            <div class="col-md-3">
                <div class="box box-solid">
                    <div class="box-header with-border">
                        <h4 class="box-title">Tasks</h4>
                    </div>
                    <div class="box-body">
                        <!-- the events -->
                        <div id="external-events">
                            @if($countPending)
                                <div class="external-event bg-light-blue">Pending tasks ({{$countPending}})</div>
                            @endif

                            @if($countInProgress)
                                <div class="external-event bg-yellow">In progress tasks ({{$countInProgress}})</div>
                            @endif

                            @if($countFinished)
                                <div class="external-event bg-green">Finished tasks ({{$countFinished}})</div>
                            @endif
                        </div>
                    </div>
                    <!-- /.box-body -->
                </div>
            </div>
            <!-- /.col -->

            <div class="col-md-9">
                <div class="box box-primary">
                    <div class="box-body no-padding">
                        <!-- THE CALENDAR -->
                        <div id="calendar"></div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    @include('pages.calendar.includes.event_modal')
@endsection

@section('scripts')

    <!-- fullCalendar -->
    <script src="{{ url('theme/bower_components/moment/moment.js') }}"></script>
    <script src="{{ url('theme/bower_components/fullcalendar/dist/fullcalendar.min.js') }}"></script>

    <?php echo $events_js_script ?>

    <script type="text/javascript" src="{{ url('theme/views/calendar/fullcalendar.js') }}"></script>

@endsection

I have includes the fullcalendar stylesheet and javascript and also included the fullcalendar script that i will show in the next section

resources/views/pages/calendar/includes/event_modal.blade.php

<div class="modal fade" id="modal-default">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>
                <h4 class="modal-title"></h4>
            </div>
            <div class="modal-body">
                <p></p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Close</button>
            </div>
        </div>
        <!-- /.modal-content -->
    </div>
    <!-- /.modal-dialog -->
</div>

 

Calendar Javascript

/**
 * Full calendar Api
 *
 */
$(function () {

    $('#calendar').fullCalendar({
        header    : {
            left  : 'prev,next today',
            center: 'title',
            right : 'month,agendaWeek,agendaDay'
        },
        buttonText: {
            today: 'today',
            month: 'month',
            week : 'week',
            day  : 'day'
        },
        //Random default events
        events    : events,
        editable  : true,
        eventClick: function(info) {
            console.log(info);

            $("#modal-default").find("h4.modal-title").text(info.title);

            $("#modal-default").find(".modal-body p").html(info.description);

            $("#modal-default").modal("show");
        }
    });


    // show or hide events based on category
    $(".bg-light-blue").on("click", function (e) {

        $('.fc-event-container a.pending').toggle();
    });

    $(".bg-yellow").on("click", function (e) {

        $('.fc-event-container a.in-progress').toggle();
    });

    $(".bg-green").on("click", function (e) {

        $('.fc-event-container a.finished').toggle();
    });

});

In the above code i have initialized the fullcalendar passing in the events variables that we described above. I used the fullcalendar clickEvent handler to listen for on click events then we showed a modal of the event details.

Also i added three listeners when i click any of the buttons which has class “bg-*” which toggles the display of the any event category like this one:

$(".bg-light-blue").on("click", function (e) {

        $('.fc-event-container a.pending').toggle();
    });

This code will toggle the pending events.

 

Sidebar

Update resources/views/layout/sidebar.blade.php

<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
    <!-- sidebar: style can be found in sidebar.less -->
    <section class="sidebar">
        <!-- Sidebar user panel -->
        <div class="user-panel">
            <div class="pull-left image">
                @if(\Auth::user()->image != null)
                    <img src="{{ url('uploads/users/' . \Auth::user()->image) }}" class="img-circle" alt="User Image">
                @else
                    <img src="{{ url('theme/dist/img/image_placeholder.png') }}" class="img-circle" alt="User Image">
                @endif
            </div>
            <div class="pull-left info">
                <p>{{ \Auth::user()->name }}</p>
            </div>
        </div>
        <!-- sidebar menu: : style can be found in sidebar.less -->
        <ul class="sidebar-menu" data-widget="tree">
            <li class="header">MAIN NAVIGATION</li>
            <li class="{{ Request::segment(2) == ""?"active":"" }}">
                <a href="{{ url('/admin') }}">
                    <i class="fa fa-dashboard"></i> <span>Dashboard</span>
                </a>
            </li>

            @if(user_can('list_contacts'))
                <li class="treeview {{ Request::segment(2) == 'contacts'? 'active':'' }}">
                    <a href="#">
                        <i class="fa fa-address-card"></i> <span>Accounts</span>
                        <span class="pull-right-container">
                            <i class="fa fa-angle-left pull-right"></i>
                        </span>
                    </a>
                    <ul class="treeview-menu">
                        <li class="{{ Request::segment(2) == "contacts" && request('status_name') == null?"active":"" }}">
                            <a href="{{ url('/admin/contacts') }}"><i class="fa fa-list"></i> All contacts</a>
                        </li>
                        <li class="{{ Request::segment(2) == "contacts" && request('status_name') == 'Lead'?"active":"" }}">
                            <a href="{{ url('/admin/contacts?status_name=Lead') }}"><i class="fa fa-leaf"></i> Leads</a>
                        </li>
                        <li class="{{ Request::segment(2) == "contacts" && request('status_name') == 'Opportunity'?"active":"" }}">
                            <a href="{{ url('/admin/contacts?status_name=Opportunity') }}"><i class="fa fa-flag"></i> Opportunities</a>
                        </li>
                        <li class="{{ Request::segment(2) == "contacts" && request('status_name') == 'Customer'?"active":"" }}">
                            <a href="{{ url('/admin/contacts?status_name=Customer') }}"><i class="fa fa-user-circle"></i> Customers</a>
                        </li>
                        <li class="{{ Request::segment(2) == "contacts" && request('status_name') == 'Close'?"active":"" }}">
                            <a href="{{ url('/admin/contacts?status_name=Close') }}"><i class="fa fa-ban"></i> Close</a>
                        </li>
                    </ul>
                </li>
            @endif

            @if(user_can('list_documents'))
                <li class="{{ Request::segment(2) == "documents"?"active":"" }}">
                    <a href="{{ url('/admin/documents') }}">
                        <i class="fa fa-file-word-o"></i> <span>Documents</span>
                    </a>
                </li>
            @endif

            @if(user_can('list_tasks'))
                <li class="{{ Request::segment(2) == "tasks"?"active":"" }}">
                    <a href="{{ url('/admin/tasks') }}">
                        <i class="fa fa-tasks"></i> <span>Tasks</span>
                    </a>
                </li>
            @endif

            @if(user_can('list_emails') || user_can('compose_email'))
                <li class="treeview {{ Request::segment(2) == 'mailbox' || strpos(Request::segment(2), "mailbox")!==FALSE? 'active':'' }}">
                    <a href="#">
                        <i class="fa fa-envelope"></i> <span>Mailbox</span>
                        <span class="pull-right-container">
                            <i class="fa fa-angle-left pull-right"></i>
                        </span>
                    </a>
                    <ul class="treeview-menu">
                        @if(user_can('list_emails'))
                            <li class="{{ Request::segment(2) == "mailbox" || Request::segment(3)=="" || Request::segment(3)=="Inbox"?"active":"" }}">
                                <a href="{{ url('/admin/mailbox') }}">
                                    Inbox
                                    @if(count(getUnreadMessages()) > 0)
                                        <span class="pull-right-container">
                                            <span class="label label-primary pull-right">{{count(getUnreadMessages())}}</span>
                                        </span>
                                    @endif
                                </a>
                            </li>
                        @endif
                        @if(user_can('compose_email'))
                            <li class="{{ Request::segment(2) == "mailbox-create"?"active":"" }}">
                                <a href="{{ url('/admin/mailbox-create') }}">
                                    Compose
                                </a>
                            </li>
                        @endif
                    </ul>
                </li>
            @endif

            @if(user_can('show_calendar'))
                <li class="{{ Request::segment(2) == "calendar"?"active":"" }}">
                    <a href="{{ url('/admin/calendar') }}">
                        <i class="fa fa-calendar"></i> <span>Calendar</span>
                    </a>
                </li>
            @endif

            @if(\Auth::user()->is_admin == 1)
                <li class="{{ in_array(Request::segment(2), ['users', 'permissions', 'roles'])?"active":"" }} treeview">
                    <a href="#">
                        <i class="fa fa-users"></i> <span>User Managment</span>
                        <span class="pull-right-container">
                            <i class="fa fa-angle-left pull-right"></i>
                        </span>
                    </a>
                    <ul class="treeview-menu">
                        <li class="{{ Request::segment(2) == "users"?"active":"" }}">
                            <a href="{{ url('/admin/users') }}"><i class="fa fa-user-o"></i> Users</a>
                        </li>

                        <li class="{{ Request::segment(2) == "permissions"?"active":"" }}">
                            <a href="{{ url('/admin/permissions') }}"><i class="fa fa-ban"></i> Permissions</a>
                        </li>
                        <li class="{{ Request::segment(2) == "roles"?"active":"" }}">
                            <a href="{{ url('/admin/roles') }}"><i class="fa fa-list"></i> Roles</a>
                        </li>
                    </ul>
                </li>
            @endif
        </ul>
    </section>
    <!-- /.sidebar -->
</aside>

 

 

Continue to Part 13: Finishing>>>

 

3 2 votes
Article Rating

What's your reaction?

Excited
1
Happy
1
Not Sure
1
Confused
2

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments