
In this part we will implement the most important module in a CRM system which is the contacts module which can be used to create a leads, opportunity or customer.
Series Topics:
- Part 1: Preparation
- Part 2: Database
- Part 3: Models & Relations
- Part 4: Preparing Login Page
- Part 5: Users Module
- Part 6: Roles & Permissions
- Part 7: Documents Module
- Part 8: Contacts Module
- Part 9: Tasks Module
- Part 10: Mailbox Module
- Part 11: Mailbox Module Complete
- Part 12: Calendar Module
- Part 13: Finishing
As usual we will use crud generator to generate the module controller and views, then we will modify those files to make them work properly.
Generate the views:
Run this command in terminal:
php artisan crud:view contacts --fields="first_name#string;middle_name#string;last_name#string;status#integer;referral_source#string;position_title#string;industry#string;project_type#string;project_description#string;company#string;description#string;budget#string;website#string;linkedin#string;address_street#string;address_city#string;address_state#string;address_country#string;address_zipcode#string;assigned_user_id#integer" --view-path="pages" --route-group=admin --form-helper=html
Generate the controller:
php artisan crud:controller ContactsController --crud-name=contacts --model-name=Contact --model-namespace="Models\\" --view-path="pages" --route-group=admin
Now i have made the the following updates to the below files:
Contacts Controller
app/Http/Controllers/ContactsController.php
<?php namespace App\Http\Controllers; use App\Helpers\MailerFactory; use App\Models\Contact; use App\Models\ContactDocument; use App\Models\ContactEmail; use App\Models\ContactPhone; use App\Models\ContactStatus; use App\Models\Document; use App\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class ContactsController extends Controller { protected $mailer; public function __construct(MailerFactory $mailer) { $this->middleware('admin:index-list_contacts|create-create_contact|show-view_contact|edit-edit_contact|destroy-delete_contact|getAssignContact-assign_contact', ['except' => ['store', 'update', 'postAssignContact']]); $this->mailer = $mailer; } /** * Display a listing of the resource. * * @return \Illuminate\View\View */ public function index(Request $request) { $keyword = $request->get('search'); $perPage = 25; if (!empty($keyword)) { $query = Contact::where('first_name', 'like', "%$keyword%")->orWhere('middle_name', 'like', "%$keyword%")->orWhere('last_name', 'like', "%$keyword%"); } else { $query = Contact::latest(); } if(\request('status_name') != null) { $query->where('status', '=', ContactStatus::where('name', \request('status_name'))->first()->id); } if(\request('assigned_user_id') != null) { $query->where('assigned_user_id', \request('assigned_user_id')); } // if not admin user show contacts if assigned to or created by that user if(Auth::user()->is_admin == 0) { $query->where(function ($query) { $query->where('assigned_user_id', Auth::user()->id) ->orWhere('created_by_id', Auth::user()->id); }); } $contacts = $query->paginate($perPage); return view('pages.contacts.index', compact('contacts')); } /** * Show the form for creating a new resource. * * @return \Illuminate\View\View */ public function create() { $data = $this->getFormData(); list($statuses, $users, $documents) = $data; return view('pages.contacts.create', compact('statuses', 'users', 'documents')); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function store(Request $request) { $this->do_validate($request); $requestData = $request->all(); $emails = $requestData['emails']; $phones = $request['phones']; unset($requestData['emails'], $requestData['phones']); if(isset($requestData['documents'])) { $documents = $requestData['documents']; unset($requestData['documents']); $documents = array_filter($documents, function ($value) { return !empty($value); }); } $requestData['created_by_id'] = Auth::user()->id; $contact = Contact::create($requestData); $emails = array_filter($emails, function ($value) { return !empty($value); }); $phones = array_filter($phones, function ($value) { return !empty($value); }); // insert emails & phones if($contact && $contact->id) { $this->insertEmails($emails, $contact->id); $this->insertPhones($phones, $contact->id); if(isset($documents)) { $this->insertDocuments($documents, $contact->id); } } // send notifications email if(getSetting("enable_email_notification") == 1 && isset($requestData['assigned_user_id'])) { $this->mailer->sendAssignContactEmail("Contact assigned to you", User::find($requestData['assigned_user_id']), $contact); } return redirect('admin/contacts')->with('flash_message', 'Contact added!'); } /** * Display the specified resource. * * @param int $id * * @return \Illuminate\View\View */ public function show($id) { $contact = Contact::findOrFail($id); return view('pages.contacts.show', compact('contact')); } /** * Show the form for editing the specified resource. * * @param int $id * * @return \Illuminate\View\View */ public function edit($id) { $data = $this->getFormData($id); list($statuses, $users, $documents, $contact, $selected_documents) = $data; return view('pages.contacts.edit', compact('contact', 'statuses', 'users', 'documents', 'selected_documents')); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function update(Request $request, $id) { $this->do_validate($request); $requestData = $request->all(); $emails = $requestData['emails']; $phones = $request['phones']; unset($requestData['emails'], $requestData['phones']); $emails = array_filter($emails, function ($value) { return !empty($value); }); $phones = array_filter($phones, function ($value) { return !empty($value); }); if(isset($requestData['documents'])) { $documents = $requestData['documents']; unset($requestData['documents']); $documents = array_filter($documents, function ($value) { return !empty($value); }); } $requestData['modified_by_id'] = Auth::user()->id; $contact = Contact::findOrFail($id); $old_assign_user_id = $contact->assigned_user_id; $old_contact_status = $contact->status; $contact->update($requestData); // delete emails if exist ContactEmail::where('contact_id', $id)->delete(); if($emails) { // insert $this->insertEmails($emails, $id); } // delete phones if exist ContactPhone::where('contact_id', $id)->delete(); if($phones) { // insert $this->insertPhones($phones, $id); } // delete documents if exist ContactDocument::where('contact_id', $id)->delete(); if(isset($documents)) { // insert $this->insertDocuments($documents, $id); } // send notifications email if(getSetting("enable_email_notification") == 1) { if (isset($requestData['assigned_user_id']) && $old_assign_user_id != $requestData['assigned_user_id']) { $this->mailer->sendAssignContactEmail("Contact assigned to you", User::find($requestData['assigned_user_id']), $contact); } // send two emails about the contact update one for the assigned user and one for the super admin if($old_contact_status != $requestData['status']) { $super_admin = User::where('is_admin', 1)->first(); if($super_admin->id == $contact->assigned_user_id) { $this->mailer->sendUpdateContactEmail("Contact status update", User::find($contact->assigned_user_id), $contact); } else { $this->mailer->sendUpdateContactEmail("Contact status update", User::find($contact->assigned_user_id), $contact); $this->mailer->sendUpdateContactEmail("Contact status update", $super_admin, $contact); } } } return redirect('admin/contacts')->with('flash_message', 'Contact updated!'); } /** * Remove the specified resource from storage. * * @param int $id * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function destroy($id) { $contact = Contact::find($id); Contact::destroy($id); if(getSetting("enable_email_notification") == 1) { $this->mailer->sendDeleteContactEmail("Contact deleted", User::find($contact->assigned_user_id), $contact); } return redirect('admin/contacts')->with('flash_message', 'Contact deleted!'); } public function getAssignContact($id) { $contact = Contact::find($id); $users = User::where('id', '!=', $contact->assigned_user_id)->get(); return view('pages.contacts.assign', compact('users', 'contact')); } public function postAssignContact(Request $request, $id) { $this->validate($request, [ 'assigned_user_id' => 'required' ]); $contact = Contact::find($id); $contact->update(['assigned_user_id' => $request->assigned_user_id]); if(getSetting("enable_email_notification") == 1) { $this->mailer->sendAssignContactEmail("Contact assigned to you", User::find($request->assigned_user_id), $contact); } return redirect('admin/contacts')->with('flash_message', 'Contact assigned!'); } /** * do_validate * * * @param $request */ protected function do_validate($request) { $this->validate($request, [ 'first_name' => 'required', 'last_name' => 'required' ]); } /** * insert emails * * * @param $emails * @param $contact_id */ protected function insertEmails($emails, $contact_id) { foreach ($emails as $email) { $contactEmail = new ContactEmail(); $contactEmail->email = $email; $contactEmail->contact_id = $contact_id; $contactEmail->save(); } } /** * insert phones * * * @param $phones * @param $contact_id */ protected function insertPhones($phones, $contact_id) { foreach ($phones as $phone) { $contactPhone = new ContactPhone(); $contactPhone->phone = $phone; $contactPhone->contact_id = $contact_id; $contactPhone->save(); } } /** * insert documents * * * @param $documents * @param $contact_id */ protected function insertDocuments($documents, $contact_id) { foreach ($documents as $document) { $contactDocument = new ContactDocument(); $contactDocument->document_id = $document; $contactDocument->contact_id = $contact_id; $contactDocument->save(); } } /** * get form data for the contacts form * * * * @param null $id * @return array */ protected function getFormData($id = null) { $statuses = ContactStatus::all(); $users = User::where('is_active', 1)->get(); if(Auth::user()->is_admin == 1) { $documents = Document::where('status', 1)->get(); } else { $super_admin = User::where('is_admin', 1)->first(); $documents = Document::where('status', 1)->where(function ($query) use ($super_admin) { $query->where('created_by_id', Auth::user()->id) ->orWhere('assigned_user_id', Auth::user()->id) ->orWhere('created_by_id', $super_admin->id) ->orWhere('assigned_user_id', $super_admin->id); })->get(); } if($id == null) { return [$statuses, $users, $documents]; } $contact = Contact::findOrFail($id); $selected_documents = $contact->documents()->pluck('document_id')->toArray(); return [$statuses, $users, $documents, $contact, $selected_documents]; } }
Contacts Views
resources/views/pages/contacts/create.blade.php
@extends('layout.app') @section('title', ' | Create contact') @section('content') <section class="content-header"> <h1> Create New contact </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/contacts') }}">Contacts</a></li> <li class="active">Create</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/contacts') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/contacts') }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ csrf_field() }} @include ('pages.contacts.form', ['formMode' => 'create']) </form> </div> </div> </div> </div> </section> @endsection @section('scripts') <script type="text/javascript" src="{{ url('theme/views/contacts/form.js') }}"></script> @stop
resources/views/pages/contacts/edit.blade.php
@extends('layout.app') @section('title', ' | Edit contact') @section('content') <section class="content-header"> <h1> Edit contact #{{ $contact->id }} </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/contacts') }}">Contacts</a></li> <li class="active">Edit</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/contacts') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/contacts/' . $contact->id) }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ method_field('PATCH') }} {{ csrf_field() }} @include ('pages.contacts.form', ['formMode' => 'edit']) </form> </div> </div> </div> </div> </section> @endsection @section('scripts') <script type="text/javascript" src="{{ url('theme/views/contacts/form.js') }}"></script> @stop
resources/views/pages/contacts/form.blade.php
<div class="panel panel-default"> <div class="panel-heading">Basic info</div> <div class="panel-body"> <div class="row"> <div class="col-md-3"> <div class="form-group {{ $errors->has('first_name') ? 'has-error' : ''}}"> <label for="first_name" class="control-label">{{ 'First Name' }}</label> <input class="form-control" name="first_name" type="text" id="first_name" value="{{ isset($contact->first_name) ? $contact->first_name : ''}}" > {!! $errors->first('first_name', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('middle_name') ? 'has-error' : ''}}"> <label for="middle_name" class="control-label">{{ 'Middle Name' }}</label> <input class="form-control" name="middle_name" type="text" id="middle_name" value="{{ isset($contact->middle_name) ? $contact->middle_name : ''}}" > {!! $errors->first('middle_name', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('last_name') ? 'has-error' : ''}}"> <label for="last_name" class="control-label">{{ 'Last Name' }}</label> <input class="form-control" name="last_name" type="text" id="last_name" value="{{ isset($contact->last_name) ? $contact->last_name : ''}}" > {!! $errors->first('last_name', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('status') ? 'has-error' : ''}}"> <label for="status" class="control-label">{{ 'Status' }}</label> <select name="status" id="status" class="form-control"> @foreach($statuses as $status) <option value="{{ $status->id }}" {{ isset($contact->status) && $contact->status == $status->id ? 'selected':'' }}>{{ $status->name }}</option> @endforeach </select> {!! $errors->first('status', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('referral_source') ? 'has-error' : ''}}"> <label for="referral_source" class="control-label">{{ 'Referral Source' }}</label> <input class="form-control" name="referral_source" type="text" id="referral_source" value="{{ isset($contact->referral_source) ? $contact->referral_source : ''}}" > {!! $errors->first('referral_source', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('position_title') ? 'has-error' : ''}}"> <label for="position_title" class="control-label">{{ 'Position Title' }}</label> <input class="form-control" name="position_title" type="text" id="position_title" value="{{ isset($contact->position_title) ? $contact->position_title : ''}}" > {!! $errors->first('position_title', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('company') ? 'has-error' : ''}}"> <label for="company" class="control-label">{{ 'Company' }}</label> <input class="form-control" name="company" type="text" id="company" value="{{ isset($contact->company) ? $contact->company : ''}}" > {!! $errors->first('company', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('industry') ? 'has-error' : ''}}"> <label for="inductry" class="control-label">{{ 'Industry' }}</label> <input class="form-control" name="industry" type="text" id="industry" value="{{ isset($contact->industry) ? $contact->industry : ''}}" > {!! $errors->first('industry', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-4"> <h4>Emails</h4> <div class="row"> <div class="col-md-10"> <div id="emails-wrapper"> @if(!isset($contact->emails) || count($contact->emails) == 0) <div class="row" style="margin-top: 5px;"> <div class="col-md-10"> <input type="text" name="emails[]" class="form-control" value="" /> </div> </div> @else @foreach($contact->emails as $email) <div class="row" style="margin-top: 5px;"> <div class="col-md-10"> <input type="text" name="emails[]" class="form-control" value="{{ $email->email }}" /> </div> @if($loop->iteration > 1) <div class="col-md-2"> <a href="javascript:void(0)" onclick="$(this).parent().parent().remove();"><i class="fa fa-remove"></i></a></div> @endif </div> @endforeach @endif </div> </div> <div class="col-md-2"> <a href="javascript:void(0)" id="new_email" class="btn btn-warning btn-sm" title="add new email"><i class="fa fa-plus"></i></a> </div> </div> </div> <div class="col-md-4"> <h4>Phones</h4> <div class="row"> <div class="col-md-10"> <div id="phones-wrapper"> @if(!isset($contact->phones) || count($contact->phones) == 0) <div class="row" style="margin-top: 5px;"> <div class="col-md-10"> <input type="text" name="phones[]" class="form-control" value="" /> </div> </div> @else @foreach($contact->phones as $phone) <div class="row" style="margin-top: 5px;"> <div class="col-md-10"> <input type="text" name="phones[]" class="form-control" value="{{ $phone->phone }}" /> </div> @if($loop->iteration > 1) <div class="col-md-2"> <a href="javascript:void(0)" onclick="$(this).parent().parent().remove();"><i class="fa fa-remove"></i></a></div> @endif </div> @endforeach @endif </div> </div> <div class="col-md-2"> <a href="javascript:void(0)" id="new_phone" class="btn btn-warning btn-sm" title="add new phone"><i class="fa fa-plus"></i></a> </div> </div> </div> </div> </div> </div> <div class="panel panel-default"> <div class="panel-heading">Project info</div> <div class="panel-body"> <div class="row"> <div class="col-md-3"> <div class="form-group {{ $errors->has('project_type') ? 'has-error' : ''}}"> <label for="project_type" class="control-label">{{ 'Project Type' }}</label> <input class="form-control" name="project_type" type="text" id="project_type" value="{{ isset($contact->project_type) ? $contact->project_type : ''}}" > {!! $errors->first('project_type', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('project_description') ? 'has-error' : ''}}"> <label for="project_description" class="control-label">{{ 'Project Description' }}</label> <input class="form-control" name="project_description" type="text" id="project_description" value="{{ isset($contact->project_description) ? $contact->project_description : ''}}" > {!! $errors->first('project_description', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('budget') ? 'has-error' : ''}}"> <label for="budget" class="control-label">{{ 'Budget' }}</label> <input class="form-control" name="budget" type="text" id="budget" value="{{ isset($contact->budget) ? $contact->budget : ''}}" > {!! $errors->first('budget', '<p class="help-block">:message</p>') !!} </div> </div> </div> </div> </div> <div class="panel panel-default"> <div class="panel-heading">Address info</div> <div class="panel-body"> <div class="row"> <div class="col-md-2"> <div class="form-group {{ $errors->has('address_country') ? 'has-error' : ''}}"> <label for="address_country" class="control-label">{{ 'Country' }}</label> <input class="form-control" name="address_country" type="text" id="address_country" value="{{ isset($contact->address_country) ? $contact->address_country : ''}}" > {!! $errors->first('address_country', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-2"> <div class="form-group {{ $errors->has('address_state') ? 'has-error' : ''}}"> <label for="address_state" class="control-label">{{ 'State' }}</label> <input class="form-control" name="address_state" type="text" id="address_state" value="{{ isset($contact->address_state) ? $contact->address_state : ''}}" > {!! $errors->first('address_state', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-2"> <div class="form-group {{ $errors->has('address_city') ? 'has-error' : ''}}"> <label for="address_city" class="control-label">{{ 'City' }}</label> <input class="form-control" name="address_city" type="text" id="address_city" value="{{ isset($contact->address_city) ? $contact->address_city : ''}}" > {!! $errors->first('address_city', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('address_street') ? 'has-error' : ''}}"> <label for="address_street" class="control-label">{{ 'Street' }}</label> <input class="form-control" name="address_street" type="text" id="address_street" value="{{ isset($contact->address_street) ? $contact->address_street : ''}}" > {!! $errors->first('address_street', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-2"> <div class="form-group {{ $errors->has('address_zipcode') ? 'has-error' : ''}}"> <label for="address_zipcode" class="control-label">{{ 'Zipcode' }}</label> <input class="form-control" name="address_zipcode" type="text" id="address_zipcode" value="{{ isset($contact->address_zipcode) ? $contact->address_zipcode : ''}}" > {!! $errors->first('address_zipcode', '<p class="help-block">:message</p>') !!} </div> </div> </div> </div> </div> <div class="panel panel-default"> <div class="panel-heading">Other info</div> <div class="panel-body"> <div class="row"> <div class="col-md-3"> <div class="form-group {{ $errors->has('website') ? 'has-error' : ''}}"> <label for="website" class="control-label">{{ 'Website' }}</label> <input class="form-control" name="website" type="text" id="website" value="{{ isset($contact->website) ? $contact->website : ''}}" > {!! $errors->first('website', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('linkedin') ? 'has-error' : ''}}"> <label for="linkedin" class="control-label">{{ 'Linkedin' }}</label> <input class="form-control" name="linkedin" type="text" id="linkedin" value="{{ isset($contact->linkedin) ? $contact->linkedin : ''}}" > {!! $errors->first('linkedin', '<p class="help-block">:message</p>') !!} </div> </div> <div class="col-md-3"> <div class="form-group {{ $errors->has('description') ? 'has-error' : ''}}"> <label for="description" class="control-label">{{ 'Description' }}</label> <textarea class="form-control" name="description" type="text" id="description">{{ isset($contact->description) ? $contact->description : ''}}</textarea> {!! $errors->first('description', '<p class="help-block">:message</p>') !!} </div> </div> </div> </div> </div> <div class="form-group"> <label for="documents" class="control-label">{{ 'Documents' }} <i class="fa fa-link"></i></label> <select name="documents[]" id="documents" multiple class="form-control"> @foreach($documents as $document) <option value="{{ $document->id }}" {{ isset($selected_documents) && in_array($document->id, $selected_documents)?"selected":"" }}>{{ $document->name }}</option> @endforeach </select> </div> @if(\Auth::user()->is_admin == 1) <div class="form-group {{ $errors->has('assigned_user_id') ? 'has-error' : ''}}"> <label for="assigned_user_id" class="control-label">{{ 'Assigned User' }}</label> <select name="assigned_user_id" id="assigned_user_id" class="form-control"> @foreach($users as $user) <option value="{{ $user->id }}" {{ isset($contact->assigned_user_id) && $contact->assigned_user_id == $user->id?"selected":"" }}>{{ $user->name }}</option> @endforeach </select> {!! $errors->first('assigned_user_id', '<p class="help-block">:message</p>') !!} </div> @endif <div class="form-group"> <input class="btn btn-primary" type="submit" value="{{ $formMode === 'edit' ? 'Update' : 'Create' }}"> </div>
resources/views/pages/contacts/index.blade.php
@extends('layout.app') @section('title', ' | List Contacts') @section('content') <section class="content-header"> <h1> Contacts </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li class="active">Contacts</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> @include('includes.flash_message') @if(user_can("create_contact")) <a href="{{ url('/admin/contacts/create') }}" class="btn btn-success btn-sm pull-right" title="Add New contact"> <i class="fa fa-plus" aria-hidden="true"></i> Add New </a> @endif <form method="GET" action="{{ url('/admin/contacts') }}" accept-charset="UTF-8" class="form-inline my-2 my-lg-0" role="search"> <div class="input-group"> <input type="text" class="form-control" name="search" placeholder="Search..." value="{{ request('search') }}"> <span class="input-group-btn"> <button class="btn btn-secondary" type="submit"> <i class="fa fa-search"></i> </button> </span> </div> </form> <br/> <br/> <div class="table-responsive"> <table class="table"> <thead> <tr> @if(\Auth::user()->is_admin == 1) <th>#</th> @endif <th>First Name</th> <th>Middle Name</th> <th>Last Name</th> <th>Status</th> @if(\Auth::user()->is_admin == 1) <th>Created by</th> @endif <th>Assigned to</th> <th>Created at</th> <th>Actions</th> </tr> </thead> <tbody> @foreach($contacts as $item) <tr> @if(\Auth::user()->is_admin == 1) <td>{{ $item->id }}</td> @endif <td>{{ $item->first_name }}</td> <td>{{ $item->middle_name }}</td> <td>{{ $item->last_name }}</td> <td><i class="btn bg-maroon">{{ $item->getStatus->name }}</i></td> @if(\Auth::user()->is_admin == 1) <td>{{ $item->createdBy->name }}</td> @endif <td>{{ $item->assignedTo != null ? $item->assignedTo->name : "not set" }}</td> <td>{{ $item->created_at }}</td> <td> @if(user_can('view_contact')) <a href="{{ url('/admin/contacts/' . $item->id) }}" title="View contact"><button class="btn btn-info btn-sm"><i class="fa fa-eye" aria-hidden="true"></i> View</button></a> @endif @if(user_can('edit_contact')) <a href="{{ url('/admin/contacts/' . $item->id . '/edit') }}" title="Edit contact"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> @endif @if(user_can('assign_contact')) <a href="{{ url('/admin/contacts/' . $item->id . '/assign') }}" title="Assign contact"><button class="btn btn-primary btn-sm"><i class="fa fa-envelope-o" aria-hidden="true"></i> Assign</button></a> @endif @if(user_can('delete_contact')) <form method="POST" action="{{ url('/admin/contacts' . '/' . $item->id) }}" accept-charset="UTF-8" style="display:inline"> {{ method_field('DELETE') }} {{ csrf_field() }} <button type="submit" class="btn btn-danger btn-sm" title="Delete contact" onclick="return confirm('Confirm delete?')"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</button> </form> @endif </td> </tr> @endforeach </tbody> </table> <div class="pagination-wrapper"> {!! $contacts->appends(['search' => Request::get('search')])->render() !!} </div> </div> </div> </div> </div> </div> </section> @endsection
resources/views/pages/contacts/show.blade.php
@extends('layout.app') @section('title', ' | Show contact') @section('content') <section class="content-header"> <h1> contact #{{ $contact->id }} </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/contacts') }}">Contacts</a></li> <li class="active">Show</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/contacts') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> @if(user_can('edit_contact')) <a href="{{ url('/admin/contacts/' . $contact->id . '/edit') }}" title="Edit contact"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> @endif @if(user_can('delete_contact')) <form method="POST" action="{{ url('admin/contacts' . '/' . $contact->id) }}" accept-charset="UTF-8" style="display:inline"> {{ method_field('DELETE') }} {{ csrf_field() }} <button type="submit" class="btn btn-danger btn-sm" title="Delete contact" onclick="return confirm('Confirm delete?')"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</button> </form> @endif <br/> <br/> <div class="table-responsive"> <table class="table"> <tbody> @if(\Auth::user()->is_admin == 1) <tr> <th>ID</th><td>{{ $contact->id }}</td> </tr> @endif <tr><th> First Name </th><td> {{ $contact->first_name }} </td> </tr><tr><th> Middle Name </th><td> {{ $contact->middle_name }} </td></tr> <tr><th> Last Name </th><td> {{ $contact->last_name }} </td></tr> <tr><th> Status </th><td> <i class="btn bg-maroon">{{ $contact->getStatus->name }}</i> </td></tr> <tr><th> Referral source </th><td> {{ $contact->referral_cource }} </td></tr> <tr><th> Position title </th><td> {{ $contact->position_title }} </td></tr> <tr><th> Industry </th><td> {{ $contact->industry }} </td></tr> <tr><th> Project type </th><td> {{ $contact->project_type }} </td></tr> <tr><th> Project description </th><td> {{ $contact->project_description }} </td></tr> <tr><th> Description </th><td> {{ $contact->description }} </td></tr> <tr><th> Company </th><td> {{ $contact->company }} </td></tr> <tr><th> Budget </th><td> {{ $contact->budget }} </td></tr> <tr><th> Website </th><td> {{ $contact->website }} </td></tr> <tr><th> Linkedin </th><td> {{ $contact->linkedin }} </td></tr> <tr><th> Street </th><td> {{ $contact->address_street }} </td></tr> <tr><th> City </th><td> {{ $contact->address_city }} </td></tr> <tr><th> State </th><td> {{ $contact->address_state }} </td></tr> <tr><th> Country </th><td> {{ $contact->address_country }} </td></tr> <tr><th> Zipcode </th><td> {{ $contact->address_zipcode }} </td></tr> @if(\Auth::user()->is_admin == 1) <tr><th> Created by </th><td>{{ $contact->createdBy->name }}</td></tr> <tr><th> Modified by </th><td>{{ isset($contact->modifiedBy->name)?$contact->modifiedBy->name:"" }}</td></tr> @endif <tr><th> Assigned to </th><td>{{ $contact->assignedTo != null ?$contact->assignedTo->name : "not set" }}</td></tr> <tr><th> Created at </th><td>{{ $contact->created_at }}</td></tr> <tr><th> Modified at </th><td>{{ $contact->updated_at }}</td></tr> @if($contact->emails->count() > 0) <tr><th>Emails </th> <td>{{ implode(", ", array_column($contact->emails->toArray(), "email")) }}</td></tr> @endif @if($contact->phones->count() > 0) <tr><th>Phones </th> <td>{{ implode(", ", array_column($contact->phones->toArray(), "phone")) }}</td></tr> @endif @if($contact->documents->count() > 0) <tr><th>Documents </th> <td>@foreach($contact->documents as $document) <a href="{{ url('uploads/documents/' . $document->file) }}">{{ $document->name }}</a> - @endforeach</td></tr> @endif </tbody> </table> </div> </div> </div> </div> </div> </section> @endsection
resources/views/pages/contacts/assign.blade.php
@extends('layout.app') @section('title', ' | Assign contact') @section('content') <section class="content-header"> <h1> Assign contact </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/contacts') }}">Contacts</a></li> <li class="active">Assign</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/contacts') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/contacts/' . $contact->id . '/assign') }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ csrf_field() }} {{ method_field("put") }} <div class="form-group {{ $errors->has('assigned_user_id') ? 'has-error' : ''}}"> <label for="assigned_user_id" class="control-label">{{ 'Assigned User' }}</label> <select name="assigned_user_id" id="assigned_user_id" class="form-control"> @foreach($users as $user) <option value="{{ $user->id }}">{{ $user->name }}</option> @endforeach </select> {!! $errors->first('assigned_user_id', '<p class="help-block">:message</p>') !!} </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="Assign"> </div> </form> </div> </div> </div> </div> </section> @endsection
public/theme/views/contacts/form.js
/** * Contacts Form Api */ $(function () { $("#new_email").on("click", function (e) { var clone = $("#emails-wrapper .row:first-child").clone(true); clone.find("input[type='text']").val(""); clone.append('<div class="col-md-2"> <a href="javascript:void(0)" onclick="$(this).parent().parent().remove();"><i class="fa fa-remove"></i></a></div>'); $("#emails-wrapper").append(clone); }); $("#new_phone").on("click", function (e) { var clone = $("#phones-wrapper .row:first-child").clone(true); clone.find("input[type='text']").val(""); clone.append('<div class="col-md-2"> <a href="javascript:void(0)" onclick="$(this).parent().parent().remove();"><i class="fa fa-remove"></i></a></div>'); $("#phones-wrapper").append(clone); }); $("#documents").select2(); });
Update the sidebar
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(\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>
Update the routes
routes/web.php
<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function () { Route::get('/', function () { return view('pages.home.index'); }); Route::resource('/users', 'UsersController'); Route::get('/my-profile', 'UsersController@getProfile'); Route::get('/my-profile/edit', 'UsersController@getEditProfile'); Route::patch('/my-profile/edit', 'UsersController@postEditProfile'); Route::resource('/permissions', 'PermissionsController'); Route::resource('/roles', 'RolesController'); Route::get('/users/role/{id}', 'UsersController@getRole'); Route::put('/users/role/{id}', 'UsersController@updateRole'); Route::resource('/documents', 'DocumentsController'); Route::get('/documents/{id}/assign', 'DocumentsController@getAssignDocument'); Route::put('/documents/{id}/assign', 'DocumentsController@postAssignDocument'); Route::resource('/contacts', 'ContactsController'); Route::get('/contacts/{id}/assign', 'ContactsController@getAssignContact'); Route::put('/contacts/{id}/assign', 'ContactsController@postAssignContact'); Route::get('/forbidden', function () { return view('pages.forbidden.forbidden_area'); }); }); Route::get('/', function () { return redirect()->to('/admin'); }); Auth::routes();
Modify app/Helpers/MailerFactory.php add these functions at the end of the class
..... ..... /** * send Assign Contact Email * * * @param $subject * @param $user * @param $contact */ public function sendAssignContactEmail($subject, $user, $contact) { try { $this->mailer->send("emails.assign_contact", ['user' => $user, 'contact' => $contact, 'subject' => $subject], function($message) use ($subject, $user) { $message->from($this->fromAddress, $this->fromName) ->to($user->email)->subject($subject); }); } catch (\Exception $ex) { die("Mailer Factory error: " . $ex->getMessage()); } } /** * send Update Contact Email * * * @param $subject * @param $user * @param $contact */ public function sendUpdateContactEmail($subject, $user, $contact) { try { $this->mailer->send("emails.update_contact", ['user' => $user, 'contact' => $contact, 'subject' => $subject], function($message) use ($subject, $user) { $message->from($this->fromAddress, $this->fromName) ->to($user->email)->subject($subject); }); } catch (\Exception $ex) { die("Mailer Factory error: " . $ex->getMessage()); } } /** * send Delete Contact Email * * * @param $subject * @param $user * @param $contact */ public function sendDeleteContactEmail($subject, $user, $contact) { try { $this->mailer->send("emails.delete_contact", ['user' => $user, 'contact' => $contact, 'subject' => $subject], function($message) use ($subject, $user) { $message->from($this->fromAddress, $this->fromName) ->to($user->email)->subject($subject); }); } catch (\Exception $ex) { die("Mailer Factory error: " . $ex->getMessage()); } } ..... .....
resources/views/emails/assign_contact.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $subject }}</title> </head> <body> <p> Hello {{ $user->name }}, </p> <p> You have been assigned a contact, go and check them here <a href="{{ url('admin/contacts/' . $contact->id) }}"> {{ url('admin/contacts/' . $contact->id) }} </a> </p> </body> </html>
resources/views/emails/update_contact.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $subject }}</title> </head> <body> <p> Hello {{ $user->name }}, </p> <p> The contact {{ $contact->first_name . " " . $contact->last_name }} have been updated to {{ $contact->getStatus->name }} you can view it here <a href="{{ url('admin/contacts/' . $contact->id) }}"> {{ url('admin/contacts/' . $contact->id) }} </a> </p> </body> </html>
resources/views/emails/delete_contact.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $subject }}</title> </head> <body> <p> Hello {{ $user->name }}, </p> <p> The contact {{ $contact->first_name . " " . $contact->last_name }} have been deleted. </p> </body> </html>
In the above code we have a lot of stuff, so at first in the listing page we make a check to list the contacts according to whether the user is super admin or not. If the user is super admin we display all contacts.
Otherwise if the user is not a super admin we list the contacts created by or assigned to the currently logged in user.
I have created a new function getFormData() to retrieve the form data for the contacts such as the documents and users to be used in case of creation and update. Note that for documents i retrieved the documents also according to whether the user is a super admin or not.
Next we updated the contacts creation form completely and separate it into sections, allso i added some javascript code to manipulate emails, phones and documents. The javascript code located in theme/views/contacts/form.js.
The store() and update() functions first do a simple validation then filters the phones, documents and emails from the main request array, save the data and finally we send some notification emails to the user.
Also we added the contacts module to the sidebar.blade.php and adjusted the permissions and the other related files to show the contacts to the authorized users only.
Continue to Part 9: tasks module>>>
Hi Wael, I’m implementing your crm-system proyect, but I am experiencing this error “Trying to get property ‘id’ of non-object” in line 46 of the ContactsController. I wish to get your advise please, thank you.
This means this line \request(‘status_name’))->first() return null.
May be you send invalid status_name parameter or the status_name not found in the table which causes this line to return null.
Also don’t forget to run the seeder as i described in the tutorial