Jelajahi Sumber

Implementazione sezione presenze

Luca Parisio 7 bulan lalu
induk
melakukan
e4dd078f04

+ 60 - 2
app/Http/Livewire/Calendar.php

@@ -8,15 +8,73 @@ class Calendar extends Component
 {
     public $records;
 
+    public $course_types = [];
+    public $course_durations = [];
+    public $course_frequencies = [];
+    public $course_levels = [];
+
+    public $courts = [];
+    public $instructors = [];
+
+    public $name = null;
+    public $from = null;
+    public $to = null;
+    
+    public $course_type_id = null;
+    public $course_duration_id = null;
+    public $course_frequency_id = null;
+    public $course_level_id = null;
+
+    public function mount()
+    {
+        $this->course_types = \App\Models\CourseType::select('*')->where('enabled', true)->get();
+        $this->course_durations = \App\Models\CourseDuration::select('*')->where('enabled', true)->get();
+        $this->course_levels = \App\Models\CourseLevel::select('*')->where('enabled', true)->get();
+        $this->course_frequencies = \App\Models\CourseFrequency::select('*')->where('enabled', true)->get();
+        $this->courts = \App\Models\Court::select('*')->where('enabled', true)->get();
+        $this->instructors = \App\Models\User::select('*')->where('level', 2)->where('enabled', true)->get();
+    }
+
     public function render()
     {
         $this->records = [];
-        $calendars = \App\Models\Calendar::get();
+        if ($this->course_type_id != null && $this->course_type_id != "")
+        {
+            $course_ids = \App\Models\Course::where('course_type_id', $this->course_type_id)->pluck('id')->toArray();
+            $calendars = \App\Models\Calendar::whereIn('course_id', $course_ids)->get();
+        }
+        else
+            $calendars = \App\Models\Calendar::get();
         foreach($calendars as $c)
         {
-            $this->records[] = array('id' => $c->id, 'title' => $c->course->name, 'start' => $c->from, 'end' => $c->to);
+            $data = array('id' => $c->id, 'title' => $c->course ? $c->course->name : $c->name . ($c->status == 99 ? ' (annullata)' : ''), 'start' => $c->from, 'end' => $c->to);
+            if ($c->course && $c->course->color != '')
+                $data['color'] = $c->course->color;
+            $this->records[] = $data;
         }
         return view('livewire.calendar');
     }
 
+    public function createCalendar()
+    {
+
+        $calendar = new \App\Models\Calendar();
+        $calendar->course_id = null;
+        $calendar->court_id = null;
+        $calendar->name = $this->name;
+        $calendar->course_type_id = $this->course_type_id != '' ? $this->course_type_id : null;
+        $calendar->course_duration_id = $this->course_duration_id != '' ? $this->course_duration_id : null;
+        $calendar->course_frequency_id = $this->course_frequency_id != '' ? $this->course_frequency_id : null;
+        $calendar->course_level_id = $this->course_level_id != '' ? $this->course_level_id : null;
+        $calendar->instructor_id = null;
+        $calendar->from = $this->from;
+        $calendar->to = $this->to;
+        $calendar->note = '';
+        $calendar->status = 0;
+        $calendar->save();
+
+        return redirect()->to('/presences?calendarId=' . $calendar->id);
+
+    }
+
 }

+ 5 - 0
app/Http/Livewire/Course.php

@@ -26,6 +26,7 @@ class Course extends Component
         $when,
         $prices,
         $type,
+        $color,
         $date_from, $date_to;
 
     public $categories = array();
@@ -95,6 +96,7 @@ class Course extends Component
         $this->months = array();
         $this->enabled = true;
         $this->type = 'standard';
+        $this->color = '';
         $this->when = array();
         $this->when[] = array('day' => array(), 'from' => '', 'to' => '');
         $this->prices = [];
@@ -215,6 +217,7 @@ class Course extends Component
                 $course->subscription_price = currencyToDouble($this->subscription_price);
                 $course->months = json_encode($this->months);
                 $course->type = $this->type;
+                $course->color = $this->color;
                 $course->when = json_encode($this->when);
                 $course->prices = json_encode($this->prices);
                 $course->enabled = $this->enabled;
@@ -308,6 +311,7 @@ class Course extends Component
                 $this->max_members = $course->max_members;
                 $this->instructor_id = $course->instructor_id;
                 $this->year = $course->year;
+                $this->color = $course->color;
                 $this->price = formatPrice($course->price);
                 $this->subscription_price = formatPrice($course->subscription_price);
                 $this->months = json_decode($course->months);
@@ -370,6 +374,7 @@ class Course extends Component
                 'subscription_price' => currencyToDouble($this->subscription_price),
                 'months' => json_encode($this->months),
                 'type' => $this->type,
+                'color' => $this->color,
                 'when' => json_encode($this->when),
                 'prices' => json_encode($this->prices),
                 'enabled' => $this->enabled

+ 126 - 0
app/Http/Livewire/Motivation.php

@@ -0,0 +1,126 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+
+class Motivation extends Component
+{
+    public $records, $name, $enabled, $dataId, $update = false, $add = false;
+
+    protected $rules = [
+        'name' => 'required'
+    ];
+
+    protected $messages = [
+        'name.required' => 'Il nome è obbligatorio'
+    ];
+
+    public $sortField ='name';
+    public $sortAsc = true;
+
+    public function mount(){
+
+        if(\Auth::user()->level != env('LEVEL_ADMIN', 0))
+            return redirect()->to('/dashboard');
+
+    }
+
+    public function sortBy($field)
+    {
+        if($this->sortField === $field)
+        {
+            $this->sortAsc = ! $this->sortAsc;
+        } else {
+            $this->sortAsc = true;
+        }
+
+        $this->sortField = $field;
+    }
+
+    public function resetFields(){
+        $this->name = '';
+        $this->enabled = true;
+        $this->emit('load-data-table');
+    }
+
+    public function render()
+    {
+        $this->records = \App\Models\Motivation::select('id', 'name', 'enabled')->get();
+        return view('livewire.motivation');
+    }
+
+    public function add()
+    {
+        $this->resetFields();
+        $this->add = true;
+        $this->update = false;
+    }
+
+    public function store()
+    {
+        $this->validate();
+        try {
+            \App\Models\Motivation::create([
+                'name' => $this->name,
+                'enabled' => $this->enabled
+            ]);
+            session()->flash('success','Campo creata');
+            $this->resetFields();
+            $this->add = false;
+        } catch (\Exception $ex) {
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function edit($id){
+        try {
+            $motivation = \App\Models\Motivation::findOrFail($id);
+            if( !$motivation) {
+                session()->flash('error','Campo non trovata');
+            } else {
+                $this->name = $motivation->name;
+                $this->enabled = $motivation->enabled;
+                $this->dataId = $motivation->id;
+                $this->update = true;
+                $this->add = false;
+            }
+        } catch (\Exception $ex) {
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function update()
+    {
+        $this->validate();
+        try {
+            \App\Models\Motivation::whereId($this->dataId)->update([
+                'name' => $this->name,
+                'enabled' => $this->enabled
+            ]);
+            session()->flash('success','Campo aggiornata');
+            $this->resetFields();
+            $this->update = false;
+        } catch (\Exception $ex) {
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function cancel()
+    {
+        $this->add = false;
+        $this->update = false;
+        $this->resetFields();
+    }
+
+    public function delete($id)
+    {
+        try{
+            \App\Models\Motivation::find($id)->delete();
+            session()->flash('success',"Campo eliminata");
+            return redirect(request()->header('Referer'));
+        }catch(\Exception $e){
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+}

+ 102 - 4
app/Http/Livewire/Presence.php

@@ -11,25 +11,34 @@ class Presence extends Component
 
     public $records;
 
-    public $court_id, $instructor_id, $note;
+    public $court_id, $instructor_id, $motivation_id, $note;
 
     public $courts = [];
     public $instructors = [];
+    public $motivations = [];
+
+    public $members = [];
+
+    public $newMembers = [];
 
     public $ids = [];
 
     public function mount()
     {
+        
         $this->calendar = \App\Models\Calendar::findOrFail($_GET["calendarId"]);
         $this->court_id = $this->calendar->court_id;
         $this->instructor_id = $this->calendar->instructor_id;
         $this->note = $this->calendar->note;
         $this->courts = \App\Models\Court::select('*')->where('enabled', true)->get();
         $this->instructors = \App\Models\User::select('*')->where('level', 2)->where('enabled', true)->get();
+        $this->motivations = \App\Models\Motivation::select('*')->where('enabled', true)->get();
+        $this->members = \App\Models\Member::select(['id', 'first_name', 'last_name', 'fiscal_code'])->orderBy('last_name')->orderBy('first_name')->get();
     }
 
     public function render()
     {
+        
         $this->records = [];
         
         // Carco tutti gli iscritti a quel corso
@@ -37,11 +46,30 @@ class Presence extends Component
 
         $members = \App\Models\Member::whereIn('id', $members_courses)->get();
 
-        $presences = \App\Models\Presence::where('calendar_id', $this->calendar->id)->pluck('member_id')->toArray();
+        $presenceMembers = [];
+
+        // $presences = \App\Models\Presence::where('calendar_id', $this->calendar->id)->pluck('member_id')->toArray();
+        // $my_presences = \App\Models\Presence::where('calendar_id', $this->calendar->id)->where('user_id', \Auth::user()->id)->pluck('member_id')->toArray();
 
         foreach($members as $member)
         {
-            $this->records[] = array('id' => $member->id, 'first_name' => $member->first_name, 'last_name' => $member->first_name, 'certificate' => '', 'presence' => in_array($member->id, $presences));
+
+            $presenceMembers[] = $member->id;
+            $this->records[] = $this->getMember($member);
+        }
+
+        // Aggiungo i membri iscritti
+        $members_presences = \App\Models\Presence::where('calendar_id', $this->calendar->id)->whereNotIn('member_id', $presenceMembers)->pluck('member_id')->toArray();
+        $members = \App\Models\Member::whereIn('id', $members_presences)->get();
+        foreach($members as $member)
+        {
+            $this->records[] = $this->getMember($member);
+        }
+
+        foreach($this->newMembers as $m)
+        {
+            $member = \App\Models\Member::findOrFail($m);
+            $this->records[] = $this->getMember($member);
         }
 
         /*$calendars = \App\Models\Calendar::get();
@@ -52,24 +80,94 @@ class Presence extends Component
         return view('livewire.presence');
     }
 
+    public function getMember($member)
+    {
+        $latestCert = \App\Models\MemberCertificate::where('member_id', $member->id)
+            ->orderBy('expire_date', 'desc')
+            ->first();
+
+        $certificate = '';
+        if ($latestCert) 
+        {
+            $latest_date = $latestCert->expire_date;
+            $status = '';
+            if ($latest_date < date("Y-m-d")) {
+                $status = "0"; // Expired
+            } else if ($latest_date <= date("Y-m-d", strtotime("+1 month"))) {
+                $status = "1"; // Expiring soon
+            } else {
+                $status = "2"; // Valid
+            }
+            $y = $status . "|" . date("d/m/Y", strtotime($latest_date));
+        }
+
+        $presence = false;
+        $my_presence = false;
+        $status = 0;
+
+        $has_presence = \App\Models\Presence::where('calendar_id', $this->calendar->id)->where('member_id', $member->id)->first();
+        if ($has_presence)            
+        {
+            $presence = true;
+            $my_presence = $has_presence->user_id == \Auth::user()->id;
+            $status = $has_presence->status;
+        }
+
+        return array('id' => $member->id, 'first_name' => $member->first_name, 'last_name' => $member->last_name, 'certificate' => $y, 'presence' => $presence, 'my_presence' => $my_presence, 'status' => $status);
+
+    }
+
     public function save($ids)
     {
 
         $this->calendar->court_id = $this->court_id;
         $this->calendar->instructor_id = $this->instructor_id;
         $this->calendar->note = $this->note;
+        if ($this->motivation_id != "" && $this->motivation_id != null)
+            $this->calendar->motivation_id = $this->motivation_id;
         $this->calendar->save();
 
-        \App\Models\Presence::where('calendar_id', $this->calendar->id)->delete();
+        \App\Models\Presence::where('calendar_id', $this->calendar->id)->where('user_id', \Auth::user()->id)->delete();
         foreach($ids as $id)
         {
             $p = new \App\Models\Presence();
             $p->member_id = $id;
             $p->calendar_id = $this->calendar->id;
+            $p->user_id = \Auth::user()->id;
+            $p->status = 0;
             $p->save();
         }
         return redirect()->to('/calendar');
 
     }
 
+    public function cancel($ids)
+    {
+
+        $presences = \App\Models\Presence::where('calendar_id', $this->calendar->id)->whereIn('user_id', $ids)->get();
+        foreach($presences as $presence)
+        {
+            $presence->status = 99;
+            $presence->save();
+        }
+
+    }
+
+    public function addMember($id)
+    {
+
+        if (!in_array($id, $this->newMembers))
+            $this->newMembers[] = $id;
+        $this->emit('reload');
+
+    }
+
+    public function cancelCalendar()
+    {
+        $this->calendar->motivation_id = $this->motivation_id;
+        $this->calendar->status = 99;
+        $this->calendar->save();
+        return redirect()->to('/calendar');
+    }
+
 }

+ 6 - 0
app/Models/Calendar.php

@@ -16,6 +16,12 @@ class Calendar extends Model
         'from',
         'to',
         'note',
+        'motivation_id',
+        'status',
+        'course_type_id',
+        'course_duration_id',
+        'course_frequency_id',
+        'course_level_id',
     ];
 
     public function course()

+ 2 - 1
app/Models/Course.php

@@ -32,7 +32,8 @@ class Course extends Model
         'type',
         'when',
         'prices',
-        'instructor_id'
+        'instructor_id',
+        'color'
     ];
 
     public function parent()

+ 16 - 0
app/Models/Motivation.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Motivation extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'name',
+        'enabled'
+    ];
+}

+ 1 - 0
app/Models/Presence.php

@@ -13,6 +13,7 @@ class Presence extends Model
         'member_id',
         'calendar_id',
         'member_course_id',
+        'user_id',
     ];
 
     public function member()

+ 33 - 0
database/migrations/2025_06_23_101500_add_field_user_id_to_presences_table.php

@@ -0,0 +1,33 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+        /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('presences', function (Blueprint $table) {
+            $table->unsignedBigInteger('user_id')->nullable();
+            $table->foreign('user_id')->nullable()->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('presences', function (Blueprint $table) {
+            $table->dropColumn('user_id');
+        });
+    }
+};

+ 34 - 0
database/migrations/2025_06_23_103500_create_motivations_table.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('motivations', function (Blueprint $table) {
+            $table->id();
+            $table->string('name');
+            $table->integer('enabled')->default(1);
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('motivations');
+    }
+};

+ 35 - 0
database/migrations/2025_06_23_104500_add_fields_to_calendars_table.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+        /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('calendars', function (Blueprint $table) {
+            $table->unsignedBigInteger('motivation_id')->nullable();
+            $table->foreign('motivation_id')->nullable()->references('id')->on('motivations')->onUpdate('cascade')->onDelete('cascade');
+            $table->integer('status');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('calendars', function (Blueprint $table) {
+            $table->dropColumn('motivation_id');
+            $table->dropColumn('status');
+        });
+    }
+};

+ 32 - 0
database/migrations/2025_06_23_164000_add_color_to_courses_table.php

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

+ 32 - 0
database/migrations/2025_06_25_141000_add_status_to_presences_table.php

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

+ 45 - 0
database/migrations/2025_06_25_144500_add_more_fields_to_calendars_table.php

@@ -0,0 +1,45 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+        /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('calendars', function (Blueprint $table) {
+            $table->string('name')->nullable();
+            $table->unsignedBigInteger('course_type_id')->nullable();
+            $table->foreign('course_type_id')->nullable()->references('id')->on('course_types')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('course_duration_id')->nullable();
+            $table->foreign('course_duration_id')->nullable()->references('id')->on('course_durations')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('course_frequency_id')->nullable();
+            $table->foreign('course_frequency_id')->nullable()->references('id')->on('course_frequencies')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('course_level_id')->nullable();
+            $table->foreign('course_level_id')->nullable()->references('id')->on('course_levels')->onUpdate('cascade')->onDelete('cascade');
+            
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('calendars', function (Blueprint $table) {
+            $table->dropColumn('name');
+            $table->dropColumn('course_type_id');
+            $table->dropColumn('course_duration_id');
+            $table->dropColumn('course_frequency_id');
+            $table->dropColumn('course_level_id');
+        });
+    }
+};

TEMPAT SAMPAH
public/assets/js/.DS_Store


+ 1128 - 0
public/assets/js/jquery.minicolors.js

@@ -0,0 +1,1128 @@
+//
+// jQuery MiniColors: A tiny color picker built on jQuery
+//
+// Developed by Cory LaViska for A Beautiful Site, LLC
+//
+// Licensed under the MIT license: http://opensource.org/licenses/MIT
+//
+(function (factory) {
+  if(typeof define === 'function' && define.amd) {
+    // AMD. Register as an anonymous module.
+    define(['jquery'], factory);
+  } else if(typeof exports === 'object') {
+    // Node/CommonJS
+    module.exports = factory(require('jquery'));
+  } else {
+    // Browser globals
+    factory(jQuery);
+  }
+}(function ($) {
+  'use strict';
+
+  // Defaults
+  $.minicolors = {
+    defaults: {
+      animationSpeed: 50,
+      animationEasing: 'swing',
+      change: null,
+      changeDelay: 0,
+      control: 'hue',
+      defaultValue: '',
+      format: 'hex',
+      hide: null,
+      hideSpeed: 100,
+      inline: false,
+      keywords: '',
+      letterCase: 'lowercase',
+      opacity: false,
+      position: 'bottom',
+      show: null,
+      showSpeed: 100,
+      theme: 'default',
+      swatches: []
+    }
+  };
+
+  // Public methods
+  $.extend($.fn, {
+    minicolors: function(method, data) {
+
+      switch(method) {
+        // Destroy the control
+        case 'destroy':
+          $(this).each(function() {
+            destroy($(this));
+          });
+          return $(this);
+
+        // Hide the color picker
+        case 'hide':
+          hide();
+          return $(this);
+
+        // Get/set opacity
+        case 'opacity':
+          // Getter
+          if(data === undefined) {
+            // Getter
+            return $(this).attr('data-opacity');
+          } else {
+            // Setter
+            $(this).each(function() {
+              updateFromInput($(this).attr('data-opacity', data));
+            });
+          }
+          return $(this);
+
+        // Get an RGB(A) object based on the current color/opacity
+        case 'rgbObject':
+          return rgbObject($(this), method === 'rgbaObject');
+
+        // Get an RGB(A) string based on the current color/opacity
+        case 'rgbString':
+        case 'rgbaString':
+          return rgbString($(this), method === 'rgbaString');
+
+        // Get/set settings on the fly
+        case 'settings':
+          if(data === undefined) {
+            return $(this).data('minicolors-settings');
+          } else {
+            // Setter
+            $(this).each(function() {
+              var settings = $(this).data('minicolors-settings') || {};
+              destroy($(this));
+              $(this).minicolors($.extend(true, settings, data));
+            });
+          }
+          return $(this);
+
+        // Show the color picker
+        case 'show':
+          show($(this).eq(0));
+          return $(this);
+
+        // Get/set the hex color value
+        case 'value':
+          if(data === undefined) {
+            // Getter
+            return $(this).val();
+          } else {
+            // Setter
+            $(this).each(function() {
+              if(typeof(data) === 'object' && data !== null) {
+                if(data.opacity !== undefined) {
+                  $(this).attr('data-opacity', keepWithin(data.opacity, 0, 1));
+                }
+                if(data.color) {
+                  $(this).val(data.color);
+                }
+              } else {
+                $(this).val(data);
+              }
+              updateFromInput($(this));
+            });
+          }
+          return $(this);
+
+        // Initializes the control
+        default:
+          if(method !== 'create') data = method;
+          $(this).each(function() {
+            init($(this), data);
+          });
+          return $(this);
+
+      }
+
+    }
+  });
+
+  // Initialize input elements
+  function init(input, settings) {
+    var minicolors = $('<div class="minicolors" />');
+    var defaults = $.minicolors.defaults;
+    var name;
+    var size;
+    var swatches;
+    var swatch;
+    var swatchString;
+    var panel;
+    var i;
+
+    // Do nothing if already initialized
+    if(input.data('minicolors-initialized')) return;
+
+    // Handle settings
+    settings = $.extend(true, {}, defaults, settings);
+
+    // The wrapper
+    minicolors
+      .addClass('minicolors-theme-' + settings.theme)
+      .toggleClass('minicolors-with-opacity', settings.opacity);
+
+    // Custom positioning
+    if(settings.position !== undefined) {
+      $.each(settings.position.split(' '), function() {
+        minicolors.addClass('minicolors-position-' + this);
+      });
+    }
+
+    // Input size
+    if(settings.format === 'rgb') {
+      size = settings.opacity ? '25' : '20';
+    } else {
+      size = settings.keywords ? '11' : '7';
+    }
+
+    // The input
+    input
+      .addClass('minicolors-input')
+      .data('minicolors-initialized', false)
+      .data('minicolors-settings', settings)
+      .prop('size', size)
+      .wrap(minicolors)
+      .after(
+        '<div class="minicolors-panel minicolors-slider-' + settings.control + '">' +
+                '<div class="minicolors-slider minicolors-sprite">' +
+                  '<div class="minicolors-picker"></div>' +
+                '</div>' +
+                '<div class="minicolors-opacity-slider minicolors-sprite">' +
+                  '<div class="minicolors-picker"></div>' +
+                '</div>' +
+                '<div class="minicolors-grid minicolors-sprite">' +
+                  '<div class="minicolors-grid-inner"></div>' +
+                  '<div class="minicolors-picker"><div></div></div>' +
+                '</div>' +
+              '</div>'
+      );
+
+    // The swatch
+    if(!settings.inline) {
+      input.after('<span class="minicolors-swatch minicolors-sprite minicolors-input-swatch"><span class="minicolors-swatch-color"></span></span>');
+      input.next('.minicolors-input-swatch').on('click', function(event) {
+        event.preventDefault();
+        input.trigger('focus');
+      });
+    }
+
+    // Prevent text selection in IE
+    panel = input.parent().find('.minicolors-panel');
+    panel.on('selectstart', function() { return false; }).end();
+
+    // Swatches
+    if(settings.swatches && settings.swatches.length !== 0) {
+      panel.addClass('minicolors-with-swatches');
+      swatches = $('<ul class="minicolors-swatches"></ul>')
+        .appendTo(panel);
+      for(i = 0; i < settings.swatches.length; ++i) {
+        // allow for custom objects as swatches
+        if(typeof settings.swatches[i] === 'object') {
+          name = settings.swatches[i].name;
+          swatch = settings.swatches[i].color;
+        } else {
+          name = '';
+          swatch = settings.swatches[i];
+        }
+        swatchString = swatch;
+        swatch = isRgb(swatch) ? parseRgb(swatch, true) : hex2rgb(parseHex(swatch, true));
+        $('<li class="minicolors-swatch minicolors-sprite"><span class="minicolors-swatch-color"></span></li>')
+          .attr("title", name)
+          .appendTo(swatches)
+          .data('swatch-color', swatchString)
+          .find('.minicolors-swatch-color')
+          .css({
+            backgroundColor: ((swatchString !== 'transparent') ? rgb2hex(swatch) : 'transparent'),
+            opacity: String(swatch.a)
+          });
+        settings.swatches[i] = swatch;
+      }
+    }
+
+    // Inline controls
+    if(settings.inline) input.parent().addClass('minicolors-inline');
+
+    updateFromInput(input, false);
+
+    input.data('minicolors-initialized', true);
+  }
+
+  // Returns the input back to its original state
+  function destroy(input) {
+    var minicolors = input.parent();
+
+    // Revert the input element
+    input
+      .removeData('minicolors-initialized')
+      .removeData('minicolors-settings')
+      .removeProp('size')
+      .removeClass('minicolors-input');
+
+    // Remove the wrap and destroy whatever remains
+    minicolors.before(input).remove();
+  }
+
+  // Shows the specified dropdown panel
+  function show(input) {
+    var minicolors = input.parent();
+    var panel = minicolors.find('.minicolors-panel');
+    var settings = input.data('minicolors-settings');
+
+    // Do nothing if uninitialized, disabled, inline, or already open
+    if(
+      !input.data('minicolors-initialized') ||
+      input.prop('disabled') ||
+      minicolors.hasClass('minicolors-inline') ||
+      minicolors.hasClass('minicolors-focus')
+    ) return;
+
+    hide();
+
+    minicolors.addClass('minicolors-focus');
+    if (panel.animate) {
+      panel
+        .stop(true, true)
+        .fadeIn(settings.showSpeed, function () {
+          if (settings.show) settings.show.call(input.get(0));
+        });
+    } else {
+      panel.show();
+      if (settings.show) settings.show.call(input.get(0));
+    }
+  }
+
+  // Hides all dropdown panels
+  function hide() {
+    $('.minicolors-focus').each(function() {
+      var minicolors = $(this);
+      var input = minicolors.find('.minicolors-input');
+      var panel = minicolors.find('.minicolors-panel');
+      var settings = input.data('minicolors-settings');
+
+      if (panel.animate) {
+        panel.fadeOut(settings.hideSpeed, function () {
+          if (settings.hide) settings.hide.call(input.get(0));
+          minicolors.removeClass('minicolors-focus');
+        });
+      } else {
+        panel.hide();
+        if (settings.hide) settings.hide.call(input.get(0));
+        minicolors.removeClass('minicolors-focus');
+      }
+    });
+  }
+
+  // Moves the selected picker
+  function move(target, event, animate) {
+    var input = target.parents('.minicolors').find('.minicolors-input');
+    var settings = input.data('minicolors-settings');
+    var picker = target.find('[class$=-picker]');
+    var offsetX = target.offset().left;
+    var offsetY = target.offset().top;
+    var x = Math.round(event.pageX - offsetX);
+    var y = Math.round(event.pageY - offsetY);
+    var duration = animate ? settings.animationSpeed : 0;
+    var wx, wy, r, phi, styles;
+
+    // Touch support
+    if(event.originalEvent.changedTouches) {
+      x = event.originalEvent.changedTouches[0].pageX - offsetX;
+      y = event.originalEvent.changedTouches[0].pageY - offsetY;
+    }
+
+    // Constrain picker to its container
+    if(x < 0) x = 0;
+    if(y < 0) y = 0;
+    if(x > target.width()) x = target.width();
+    if(y > target.height()) y = target.height();
+
+    // Constrain color wheel values to the wheel
+    if(target.parent().is('.minicolors-slider-wheel') && picker.parent().is('.minicolors-grid')) {
+      wx = 75 - x;
+      wy = 75 - y;
+      r = Math.sqrt(wx * wx + wy * wy);
+      phi = Math.atan2(wy, wx);
+      if(phi < 0) phi += Math.PI * 2;
+      if(r > 75) {
+        r = 75;
+        x = 75 - (75 * Math.cos(phi));
+        y = 75 - (75 * Math.sin(phi));
+      }
+      x = Math.round(x);
+      y = Math.round(y);
+    }
+
+    // Move the picker
+    styles = {
+      top: y + 'px'
+    };
+    if(target.is('.minicolors-grid')) {
+      styles.left = x + 'px';
+    }
+    if (picker.animate) {
+      picker
+        .stop(true)
+        .animate(styles, duration, settings.animationEasing, function() {
+          updateFromControl(input, target);
+        });
+    } else {
+      picker
+        .css(styles);
+      updateFromControl(input, target);
+    }
+  }
+
+  // Sets the input based on the color picker values
+  function updateFromControl(input, target) {
+
+    function getCoords(picker, container) {
+      var left, top;
+      if(!picker.length || !container) return null;
+      left = picker.offset().left;
+      top = picker.offset().top;
+
+      return {
+        x: left - container.offset().left + (picker.outerWidth() / 2),
+        y: top - container.offset().top + (picker.outerHeight() / 2)
+      };
+    }
+
+    var hue, saturation, brightness, x, y, r, phi;
+    var hex = input.val();
+    var opacity = input.attr('data-opacity');
+
+    // Helpful references
+    var minicolors = input.parent();
+    var settings = input.data('minicolors-settings');
+    var swatch = minicolors.find('.minicolors-input-swatch');
+
+    // Panel objects
+    var grid = minicolors.find('.minicolors-grid');
+    var slider = minicolors.find('.minicolors-slider');
+    var opacitySlider = minicolors.find('.minicolors-opacity-slider');
+
+    // Picker objects
+    var gridPicker = grid.find('[class$=-picker]');
+    var sliderPicker = slider.find('[class$=-picker]');
+    var opacityPicker = opacitySlider.find('[class$=-picker]');
+
+    // Picker positions
+    var gridPos = getCoords(gridPicker, grid);
+    var sliderPos = getCoords(sliderPicker, slider);
+    var opacityPos = getCoords(opacityPicker, opacitySlider);
+
+    // Handle colors
+    if(target.is('.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider')) {
+
+      // Determine HSB values
+      switch(settings.control) {
+        case 'wheel':
+          // Calculate hue, saturation, and brightness
+          x = (grid.width() / 2) - gridPos.x;
+          y = (grid.height() / 2) - gridPos.y;
+          r = Math.sqrt(x * x + y * y);
+          phi = Math.atan2(y, x);
+          if(phi < 0) phi += Math.PI * 2;
+          if(r > 75) {
+            r = 75;
+            gridPos.x = 69 - (75 * Math.cos(phi));
+            gridPos.y = 69 - (75 * Math.sin(phi));
+          }
+          saturation = keepWithin(r / 0.75, 0, 100);
+          hue = keepWithin(phi * 180 / Math.PI, 0, 360);
+          brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
+          hex = hsb2hex({
+            h: hue,
+            s: saturation,
+            b: brightness
+          });
+
+          // Update UI
+          slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));
+          break;
+
+        case 'saturation':
+          // Calculate hue, saturation, and brightness
+          hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);
+          saturation = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
+          brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
+          hex = hsb2hex({
+            h: hue,
+            s: saturation,
+            b: brightness
+          });
+
+          // Update UI
+          slider.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: brightness }));
+          minicolors.find('.minicolors-grid-inner').css('opacity', saturation / 100);
+          break;
+
+        case 'brightness':
+          // Calculate hue, saturation, and brightness
+          hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);
+          saturation = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
+          brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
+          hex = hsb2hex({
+            h: hue,
+            s: saturation,
+            b: brightness
+          });
+
+          // Update UI
+          slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));
+          minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (brightness / 100));
+          break;
+
+        default:
+          // Calculate hue, saturation, and brightness
+          hue = keepWithin(360 - parseInt(sliderPos.y * (360 / slider.height()), 10), 0, 360);
+          saturation = keepWithin(Math.floor(gridPos.x * (100 / grid.width())), 0, 100);
+          brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
+          hex = hsb2hex({
+            h: hue,
+            s: saturation,
+            b: brightness
+          });
+
+          // Update UI
+          grid.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: 100 }));
+          break;
+      }
+
+      // Handle opacity
+      if(settings.opacity) {
+        opacity = parseFloat(1 - (opacityPos.y / opacitySlider.height())).toFixed(2);
+      } else {
+        opacity = 1;
+      }
+
+      updateInput(input, hex, opacity);
+    }
+    else {
+      // Set swatch color
+      swatch.find('span').css({
+        backgroundColor: hex,
+        opacity: String(opacity)
+      });
+
+      // Handle change event
+      doChange(input, hex, opacity);
+    }
+  }
+
+  // Sets the value of the input and does the appropriate conversions
+  // to respect settings, also updates the swatch
+  function updateInput(input, value, opacity) {
+    var rgb;
+
+    // Helpful references
+    var minicolors = input.parent();
+    var settings = input.data('minicolors-settings');
+    var swatch = minicolors.find('.minicolors-input-swatch');
+
+    if(settings.opacity) input.attr('data-opacity', opacity);
+
+    // Set color string
+    if(settings.format === 'rgb') {
+      // Returns RGB(A) string
+
+      // Checks for input format and does the conversion
+      if(isRgb(value)) {
+        rgb = parseRgb(value, true);
+      }
+      else {
+        rgb = hex2rgb(parseHex(value, true));
+      }
+
+      opacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1);
+      if(isNaN(opacity) || !settings.opacity) opacity = 1;
+
+      if(input.minicolors('rgbObject').a <= 1 && rgb && settings.opacity) {
+        // Set RGBA string if alpha
+        value = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')';
+      } else {
+        // Set RGB string (alpha = 1)
+        value = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')';
+      }
+    } else {
+      // Returns hex color
+
+      // Checks for input format and does the conversion
+      if(isRgb(value)) {
+        value = rgbString2hex(value);
+      }
+
+      value = convertCase(value, settings.letterCase);
+    }
+
+    // Update value from picker
+    input.val(value);
+
+    // Set swatch color
+    swatch.find('span').css({
+      backgroundColor: value,
+      opacity: String(opacity)
+    });
+
+    // Handle change event
+    doChange(input, value, opacity);
+  }
+
+  // Sets the color picker values from the input
+  function updateFromInput(input, preserveInputValue) {
+    var hex, hsb, opacity, keywords, alpha, value, x, y, r, phi;
+
+    // Helpful references
+    var minicolors = input.parent();
+    var settings = input.data('minicolors-settings');
+    var swatch = minicolors.find('.minicolors-input-swatch');
+
+    // Panel objects
+    var grid = minicolors.find('.minicolors-grid');
+    var slider = minicolors.find('.minicolors-slider');
+    var opacitySlider = minicolors.find('.minicolors-opacity-slider');
+
+    // Picker objects
+    var gridPicker = grid.find('[class$=-picker]');
+    var sliderPicker = slider.find('[class$=-picker]');
+    var opacityPicker = opacitySlider.find('[class$=-picker]');
+
+    // Determine hex/HSB values
+    if(isRgb(input.val())) {
+      // If input value is a rgb(a) string, convert it to hex color and update opacity
+      hex = rgbString2hex(input.val());
+      alpha = keepWithin(parseFloat(getAlpha(input.val())).toFixed(2), 0, 1);
+      if(alpha) {
+        input.attr('data-opacity', alpha);
+      }
+    } else {
+      hex = convertCase(parseHex(input.val(), true), settings.letterCase);
+    }
+
+    if(!hex){
+      hex = convertCase(parseInput(settings.defaultValue, true), settings.letterCase);
+    }
+    hsb = hex2hsb(hex);
+
+    // Get array of lowercase keywords
+    keywords = !settings.keywords ? [] : $.map(settings.keywords.split(','), function(a) {
+      return a.toLowerCase().trim();
+    });
+
+    // Set color string
+    if(input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1) {
+      value = convertCase(input.val());
+    } else {
+      value = isRgb(input.val()) ? parseRgb(input.val()) : hex;
+    }
+
+    // Update input value
+    if(!preserveInputValue) input.val(value);
+
+    // Determine opacity value
+    if(settings.opacity) {
+      // Get from data-opacity attribute and keep within 0-1 range
+      opacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1);
+      if(isNaN(opacity)) opacity = 1;
+      input.attr('data-opacity', opacity);
+      swatch.find('span').css('opacity', String(opacity));
+
+      // Set opacity picker position
+      y = keepWithin(opacitySlider.height() - (opacitySlider.height() * opacity), 0, opacitySlider.height());
+      opacityPicker.css('top', y + 'px');
+    }
+
+    // Set opacity to zero if input value is transparent
+    if(input.val().toLowerCase() === 'transparent') {
+      swatch.find('span').css('opacity', String(0));
+    }
+
+    // Update swatch
+    swatch.find('span').css('backgroundColor', hex);
+
+    // Determine picker locations
+    switch(settings.control) {
+      case 'wheel':
+        // Set grid position
+        r = keepWithin(Math.ceil(hsb.s * 0.75), 0, grid.height() / 2);
+        phi = hsb.h * Math.PI / 180;
+        x = keepWithin(75 - Math.cos(phi) * r, 0, grid.width());
+        y = keepWithin(75 - Math.sin(phi) * r, 0, grid.height());
+        gridPicker.css({
+          top: y + 'px',
+          left: x + 'px'
+        });
+
+        // Set slider position
+        y = 150 - (hsb.b / (100 / grid.height()));
+        if(hex === '') y = 0;
+        sliderPicker.css('top', y + 'px');
+        
+        // Update panel color
+        slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));
+        break;
+
+      case 'saturation':
+        // Set grid position
+        x = keepWithin((5 * hsb.h) / 12, 0, 150);
+        y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());
+        gridPicker.css({
+          top: y + 'px',
+          left: x + 'px'
+        });
+
+        // Set slider position
+        y = keepWithin(slider.height() - (hsb.s * (slider.height() / 100)), 0, slider.height());
+        sliderPicker.css('top', y + 'px');
+
+        // Update UI
+        slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: hsb.b }));
+        minicolors.find('.minicolors-grid-inner').css('opacity', hsb.s / 100);
+        break;
+
+      case 'brightness':
+        // Set grid position
+        x = keepWithin((5 * hsb.h) / 12, 0, 150);
+        y = keepWithin(grid.height() - Math.ceil(hsb.s / (100 / grid.height())), 0, grid.height());
+        gridPicker.css({
+          top: y + 'px',
+          left: x + 'px'
+        });
+
+        // Set slider position
+        y = keepWithin(slider.height() - (hsb.b * (slider.height() / 100)), 0, slider.height());
+        sliderPicker.css('top', y + 'px');
+
+        // Update UI
+        slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));
+        minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (hsb.b / 100));
+        break;
+
+      default:
+        // Set grid position
+        x = keepWithin(Math.ceil(hsb.s / (100 / grid.width())), 0, grid.width());
+        y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());
+        gridPicker.css({
+          top: y + 'px',
+          left: x + 'px'
+        });
+
+        // Set slider position
+        y = keepWithin(slider.height() - (hsb.h / (360 / slider.height())), 0, slider.height());
+        sliderPicker.css('top', y + 'px');
+
+        // Update panel color
+        grid.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: 100 }));
+        break;
+    }
+
+    // Fire change event, but only if minicolors is fully initialized
+    if(input.data('minicolors-initialized')) {
+      doChange(input, value, opacity);
+    }
+  }
+
+  // Runs the change and changeDelay callbacks
+  function doChange(input, value, opacity) {
+    var settings = input.data('minicolors-settings');
+    var lastChange = input.data('minicolors-lastChange');
+    var obj, sel, i;
+
+    // Only run if it actually changed
+    if(!lastChange || lastChange.value !== value || lastChange.opacity !== opacity) {
+
+      // Remember last-changed value
+      input.data('minicolors-lastChange', {
+        value: value,
+        opacity: opacity
+      });
+
+      // Check and select applicable swatch
+      if(settings.swatches && settings.swatches.length !== 0) {
+        if(!isRgb(value)) {
+          obj = hex2rgb(value);
+        }
+        else {
+          obj = parseRgb(value, true);
+        }
+        sel = -1;
+        for(i = 0; i < settings.swatches.length; ++i) {
+          if(obj.r === settings.swatches[i].r && obj.g === settings.swatches[i].g && obj.b === settings.swatches[i].b && obj.a === settings.swatches[i].a) {
+            sel = i;
+            break;
+          }
+        }
+
+        input.parent().find('.minicolors-swatches .minicolors-swatch').removeClass('selected');
+        if(sel !== -1) {
+          input.parent().find('.minicolors-swatches .minicolors-swatch').eq(i).addClass('selected');
+        }
+      }
+
+      // Fire change event
+      if(settings.change) {
+        if(settings.changeDelay) {
+          // Call after a delay
+          clearTimeout(input.data('minicolors-changeTimeout'));
+          input.data('minicolors-changeTimeout', setTimeout(function() {
+            settings.change.call(input.get(0), value, opacity);
+          }, settings.changeDelay));
+        } else {
+          // Call immediately
+          settings.change.call(input.get(0), value, opacity);
+        }
+      }
+      input.trigger('change').trigger('input');
+    }
+  }
+
+  // Generates an RGB(A) object based on the input's value
+  function rgbObject(input) {
+    var rgb,
+      opacity = $(input).attr('data-opacity');
+    if( isRgb($(input).val()) ) {
+      rgb = parseRgb($(input).val(), true);
+    } else {
+      var hex = parseHex($(input).val(), true);
+      rgb = hex2rgb(hex);
+    }
+    if( !rgb ) return null;
+    if( opacity !== undefined ) $.extend(rgb, { a: parseFloat(opacity) });
+    return rgb;
+  }
+
+  // Generates an RGB(A) string based on the input's value
+  function rgbString(input, alpha) {
+    var rgb,
+      opacity = $(input).attr('data-opacity');
+    if( isRgb($(input).val()) ) {
+      rgb = parseRgb($(input).val(), true);
+    } else {
+      var hex = parseHex($(input).val(), true);
+      rgb = hex2rgb(hex);
+    }
+    if( !rgb ) return null;
+    if( opacity === undefined ) opacity = 1;
+    if( alpha ) {
+      return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')';
+    } else {
+      return 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')';
+    }
+  }
+
+  // Converts to the letter case specified in settings
+  function convertCase(string, letterCase) {
+    return letterCase === 'uppercase' ? string.toUpperCase() : string.toLowerCase();
+  }
+
+  // Parses a string and returns a valid hex string when possible
+  function parseHex(string, expand) {
+    string = string.replace(/^#/g, '');
+    if(!string.match(/^[A-F0-9]{3,6}/ig)) return '';
+    if(string.length !== 3 && string.length !== 6) return '';
+    if(string.length === 3 && expand) {
+      string = string[0] + string[0] + string[1] + string[1] + string[2] + string[2];
+    }
+    return '#' + string;
+  }
+
+  // Parses a string and returns a valid RGB(A) string when possible
+  function parseRgb(string, obj) {
+    var values = string.replace(/[^\d,.]/g, '');
+    var rgba = values.split(',');
+
+    rgba[0] = keepWithin(parseInt(rgba[0], 10), 0, 255);
+    rgba[1] = keepWithin(parseInt(rgba[1], 10), 0, 255);
+    rgba[2] = keepWithin(parseInt(rgba[2], 10), 0, 255);
+    if(rgba[3] !== undefined) {
+      rgba[3] = keepWithin(parseFloat(rgba[3], 10), 0, 1);
+    }
+
+    // Return RGBA object
+    if( obj ) {
+      if (rgba[3] !== undefined) {
+        return {
+          r: rgba[0],
+          g: rgba[1],
+          b: rgba[2],
+          a: rgba[3]
+        };
+      } else {
+        return {
+          r: rgba[0],
+          g: rgba[1],
+          b: rgba[2]
+        };
+      }
+    }
+
+    // Return RGBA string
+    if(typeof(rgba[3]) !== 'undefined' && rgba[3] <= 1) {
+      return 'rgba(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ', ' + rgba[3] + ')';
+    } else {
+      return 'rgb(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ')';
+    }
+
+  }
+
+  // Parses a string and returns a valid color string when possible
+  function parseInput(string, expand) {
+    if(isRgb(string)) {
+      // Returns a valid rgb(a) string
+      return parseRgb(string);
+    } else {
+      return parseHex(string, expand);
+    }
+  }
+
+  // Keeps value within min and max
+  function keepWithin(value, min, max) {
+    if(value < min) value = min;
+    if(value > max) value = max;
+    return value;
+  }
+
+  // Checks if a string is a valid RGB(A) string
+  function isRgb(string) {
+    var rgb = string.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
+    return (rgb && rgb.length === 4) ? true : false;
+  }
+
+  // Function to get alpha from a RGB(A) string
+  function getAlpha(rgba) {
+    rgba = rgba.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+(\.\d{1,2})?|\.\d{1,2})[\s+]?/i);
+    return (rgba && rgba.length === 6) ? rgba[4] : '1';
+  }
+
+  // Converts an HSB object to an RGB object
+  function hsb2rgb(hsb) {
+    var rgb = {};
+    var h = Math.round(hsb.h);
+    var s = Math.round(hsb.s * 255 / 100);
+    var v = Math.round(hsb.b * 255 / 100);
+    if(s === 0) {
+      rgb.r = rgb.g = rgb.b = v;
+    } else {
+      var t1 = v;
+      var t2 = (255 - s) * v / 255;
+      var t3 = (t1 - t2) * (h % 60) / 60;
+      if(h === 360) h = 0;
+      if(h < 60) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; }
+      else if(h < 120) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; }
+      else if(h < 180) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; }
+      else if(h < 240) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; }
+      else if(h < 300) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; }
+      else if(h < 360) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; }
+      else { rgb.r = 0; rgb.g = 0; rgb.b = 0; }
+    }
+    return {
+      r: Math.round(rgb.r),
+      g: Math.round(rgb.g),
+      b: Math.round(rgb.b)
+    };
+  }
+
+  // Converts an RGB string to a hex string
+  function rgbString2hex(rgb){
+    rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
+    return (rgb && rgb.length === 4) ? '#' +
+      ('0' + parseInt(rgb[1],10).toString(16)).slice(-2) +
+      ('0' + parseInt(rgb[2],10).toString(16)).slice(-2) +
+      ('0' + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
+  }
+
+  // Converts an RGB object to a hex string
+  function rgb2hex(rgb) {
+    var hex = [
+      rgb.r.toString(16),
+      rgb.g.toString(16),
+      rgb.b.toString(16)
+    ];
+    $.each(hex, function(nr, val) {
+      if(val.length === 1) hex[nr] = '0' + val;
+    });
+    return '#' + hex.join('');
+  }
+
+  // Converts an HSB object to a hex string
+  function hsb2hex(hsb) {
+    return rgb2hex(hsb2rgb(hsb));
+  }
+
+  // Converts a hex string to an HSB object
+  function hex2hsb(hex) {
+    var hsb = rgb2hsb(hex2rgb(hex));
+    if(hsb.s === 0) hsb.h = 360;
+    return hsb;
+  }
+
+  // Converts an RGB object to an HSB object
+  function rgb2hsb(rgb) {
+    var hsb = { h: 0, s: 0, b: 0 };
+    var min = Math.min(rgb.r, rgb.g, rgb.b);
+    var max = Math.max(rgb.r, rgb.g, rgb.b);
+    var delta = max - min;
+    hsb.b = max;
+    hsb.s = max !== 0 ? 255 * delta / max : 0;
+    if(hsb.s !== 0) {
+      if(rgb.r === max) {
+        hsb.h = (rgb.g - rgb.b) / delta;
+      } else if(rgb.g === max) {
+        hsb.h = 2 + (rgb.b - rgb.r) / delta;
+      } else {
+        hsb.h = 4 + (rgb.r - rgb.g) / delta;
+      }
+    } else {
+      hsb.h = -1;
+    }
+    hsb.h *= 60;
+    if(hsb.h < 0) {
+      hsb.h += 360;
+    }
+    hsb.s *= 100/255;
+    hsb.b *= 100/255;
+    return hsb;
+  }
+
+  // Converts a hex string to an RGB object
+  function hex2rgb(hex) {
+    hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
+    return {
+      r: hex >> 16,
+      g: (hex & 0x00FF00) >> 8,
+      b: (hex & 0x0000FF)
+    };
+  }
+
+  // Handle events
+  $([document])
+    // Hide on clicks outside of the control
+    .on('mousedown.minicolors touchstart.minicolors', function(event) {
+      if(!$(event.target).parents().add(event.target).hasClass('minicolors')) {
+        hide();
+      }
+    })
+    // Start moving
+    .on('mousedown.minicolors touchstart.minicolors', '.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider', function(event) {
+      var target = $(this);
+      event.preventDefault();
+      $(event.delegateTarget).data('minicolors-target', target);
+      move(target, event, true);
+    })
+    // Move pickers
+    .on('mousemove.minicolors touchmove.minicolors', function(event) {
+      var target = $(event.delegateTarget).data('minicolors-target');
+      if(target) move(target, event);
+    })
+    // Stop moving
+    .on('mouseup.minicolors touchend.minicolors', function() {
+      $(this).removeData('minicolors-target');
+    })
+    // Selected a swatch
+    .on('click.minicolors', '.minicolors-swatches li', function(event) {
+      event.preventDefault();
+      var target = $(this), input = target.parents('.minicolors').find('.minicolors-input'), color = target.data('swatch-color');
+      updateInput(input, color, getAlpha(color));
+      updateFromInput(input);
+    })
+    // Show panel when swatch is clicked
+    .on('mousedown.minicolors touchstart.minicolors', '.minicolors-input-swatch', function(event) {
+      var input = $(this).parent().find('.minicolors-input');
+      event.preventDefault();
+      show(input);
+    })
+    // Show on focus
+    .on('focus.minicolors', '.minicolors-input', function() {
+      var input = $(this);
+      if(!input.data('minicolors-initialized')) return;
+      show(input);
+    })
+    // Update value on blur
+    .on('blur.minicolors', '.minicolors-input', function() {
+      var input = $(this);
+      var settings = input.data('minicolors-settings');
+      var keywords;
+      var hex;
+      var rgba;
+      var swatchOpacity;
+      var value;
+
+      if(!input.data('minicolors-initialized')) return;
+
+      // Get array of lowercase keywords
+      keywords = !settings.keywords ? [] : $.map(settings.keywords.split(','), function(a) {
+        return a.toLowerCase().trim();
+      });
+
+      // Set color string
+      if(input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1) {
+        value = input.val();
+      } else {
+        // Get RGBA values for easy conversion
+        if(isRgb(input.val())) {
+          rgba = parseRgb(input.val(), true);
+        } else {
+          hex = parseHex(input.val(), true);
+          rgba = hex ? hex2rgb(hex) : null;
+        }
+
+        // Convert to format
+        if(rgba === null) {
+          value = settings.defaultValue;
+        } else if(settings.format === 'rgb') {
+          value = settings.opacity ?
+            parseRgb('rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + input.attr('data-opacity') + ')') :
+            parseRgb('rgb(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ')');
+        } else {
+          value = rgb2hex(rgba);
+        }
+      }
+
+      // Update swatch opacity
+      swatchOpacity = settings.opacity ? input.attr('data-opacity') : 1;
+      if(value.toLowerCase() === 'transparent') swatchOpacity = 0;
+      input
+        .closest('.minicolors')
+        .find('.minicolors-input-swatch > span')
+        .css('opacity', String(swatchOpacity));
+
+      // Set input value
+      input.val(value);
+
+      // Is it blank?
+      if(input.val() === '') input.val(parseInput(settings.defaultValue, true));
+
+      // Adjust case
+      input.val(convertCase(input.val(), settings.letterCase));
+
+    })
+    // Handle keypresses
+    .on('keydown.minicolors', '.minicolors-input', function(event) {
+      var input = $(this);
+      if(!input.data('minicolors-initialized')) return;
+      switch(event.which) {
+        case 9: // tab
+          hide();
+          break;
+        case 13: // enter
+        case 27: // esc
+          hide();
+          input.blur();
+          break;
+      }
+    })
+    // Update on keyup
+    .on('keyup.minicolors', '.minicolors-input', function() {
+      var input = $(this);
+      if(!input.data('minicolors-initialized')) return;
+      updateFromInput(input, true);
+    })
+    // Update on paste
+    .on('paste.minicolors', '.minicolors-input', function() {
+      var input = $(this);
+      if(!input.data('minicolors-initialized')) return;
+      setTimeout(function() {
+        updateFromInput(input, true);
+      }, 1);
+    });
+}));

TEMPAT SAMPAH
public/css/.DS_Store


+ 445 - 0
public/css/jquery.minicolors.css

@@ -0,0 +1,445 @@
+.minicolors {
+  position: relative;
+}
+
+.minicolors-sprite {
+  background-image: url(jquery.minicolors.png);
+}
+
+.minicolors-swatch {
+  position: absolute;
+  vertical-align: middle;
+  background-position: -80px 0;
+  cursor: text;
+  padding: 0;
+  margin: 0;
+  display: inline-block;
+}
+
+.minicolors-swatch::after {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15);
+  border-radius: 2px;
+}
+
+.minicolors-swatch-color {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.minicolors input[type=hidden] + .minicolors-swatch {
+  width: 28px;
+  position: static;
+  cursor: pointer;
+}
+
+.minicolors input[type=hidden][disabled] + .minicolors-swatch {
+  cursor: default;
+}
+
+/* Panel */
+.minicolors-panel {
+  position: absolute;
+  width: 173px;
+  background: white;
+  border-radius: 2px;
+  box-shadow: 0 0 20px rgba(0, 0, 0, .2);
+  z-index: 99999;
+  box-sizing: content-box;
+  display: none;
+  touch-action: none;
+}
+
+.minicolors-panel.minicolors-visible {
+  display: block;
+}
+
+/* Panel positioning */
+.minicolors-position-top .minicolors-panel {
+  top: -154px;
+}
+
+.minicolors-position-right .minicolors-panel {
+  right: 0;
+}
+
+.minicolors-position-bottom .minicolors-panel {
+  top: auto;
+}
+
+.minicolors-position-left .minicolors-panel {
+  left: 0;
+}
+
+.minicolors-with-opacity .minicolors-panel {
+  width: 194px;
+}
+
+.minicolors .minicolors-grid {
+  position: relative;
+  top: 1px;
+  left: 1px; /* LTR */
+  width: 150px;
+  height: 150px;
+  margin-bottom: 2px;
+  background-position: -120px 0;
+  cursor: crosshair;
+}
+[dir=rtl] .minicolors .minicolors-grid {
+  right: 1px;
+}
+
+.minicolors .minicolors-grid-inner {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 150px;
+  height: 150px;
+}
+
+.minicolors-slider-saturation .minicolors-grid {
+  background-position: -420px 0;
+}
+
+.minicolors-slider-saturation .minicolors-grid-inner {
+  background-position: -270px 0;
+  background-image: inherit;
+}
+
+.minicolors-slider-brightness .minicolors-grid {
+  background-position: -570px 0;
+}
+
+.minicolors-slider-brightness .minicolors-grid-inner {
+  background-color: black;
+}
+
+.minicolors-slider-wheel .minicolors-grid {
+  background-position: -720px 0;
+}
+
+.minicolors-slider,
+.minicolors-opacity-slider {
+  position: absolute;
+  top: 1px;
+  left: 152px; /* LTR */
+  width: 20px;
+  height: 150px;
+  background-color: white;
+  background-position: 0 0;
+  cursor: row-resize;
+}
+[dir=rtl] .minicolors-slider,
+[dir=rtl] .minicolors-opacity-slider {
+  right: 152px;
+}
+
+.minicolors-slider-saturation .minicolors-slider {
+  background-position: -60px 0;
+}
+
+.minicolors-slider-brightness .minicolors-slider {
+  background-position: -20px 0;
+}
+
+.minicolors-slider-wheel .minicolors-slider {
+  background-position: -20px 0;
+}
+
+.minicolors-opacity-slider {
+  left: 173px; /* LTR */
+  background-position: -40px 0;
+  display: none;
+}
+[dir=rtl] .minicolors-opacity-slider {
+  right: 173px;
+}
+
+.minicolors-with-opacity .minicolors-opacity-slider {
+  display: block;
+}
+
+/* Pickers */
+.minicolors-grid .minicolors-picker {
+  position: absolute;
+  top: 70px;
+  left: 70px;
+  width: 12px;
+  height: 12px;
+  box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
+  border-radius: 10px;
+  margin-top: -6px;
+  margin-left: -6px;
+  background: none;
+}
+
+.minicolors-grid .minicolors-picker > div {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 8px;
+  height: 8px;
+  border-radius: 8px;
+  border: solid 2px white;
+  box-sizing: content-box;
+}
+
+.minicolors-picker {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 18px;
+  height: 3px;
+  background: white;
+  box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
+  border-radius: 2px;
+  margin-top: -2px;
+  margin-left: 1px;
+  box-sizing: content-box;
+}
+
+/* Swatches */
+.minicolors-swatches,
+.minicolors-swatches li {
+  margin: 5px 0 3px 5px; /* LTR */
+  padding: 0;
+  list-style: none;
+  overflow: hidden;
+}
+[dir=rtl] .minicolors-swatches,
+[dir=rtl] .minicolors-swatches li {
+  margin: 5px 5px 3px 0;
+}
+
+.minicolors-swatches .minicolors-swatch {
+  position: relative;
+  float: left; /* LTR */
+  cursor: pointer;
+  margin: 0 4px 0 0; /* LTR */
+}
+[dir=rtl] .minicolors-swatches .minicolors-swatch {
+  float: right;
+  margin: 0 0 0 4px;
+}
+
+.minicolors-with-opacity .minicolors-swatches .minicolors-swatch {
+  margin-right: 7px; /* LTR */
+}
+[dir=rtl] .minicolors-with-opacity .minicolors-swatches .minicolors-swatch {
+  margin-right: 0;
+  margin-left: 7px;
+}
+
+.minicolors-swatch.selected {
+  border-color: #000;
+}
+
+/* Inline controls */
+.minicolors-inline {
+  display: inline-block;
+}
+
+.minicolors-inline .minicolors-input {
+  display: none !important;
+}
+
+.minicolors-inline .minicolors-panel {
+  position: relative;
+  top: auto;
+  left: auto; /* LTR */
+  box-shadow: none;
+  z-index: auto;
+  display: inline-block;
+}
+[dir=rtl] .minicolors-inline .minicolors-panel {
+  right: auto;
+}
+
+/* Default theme */
+.minicolors-theme-default .minicolors-swatch {
+  top: 5px;
+  left: 5px; /* LTR */
+  width: 18px;
+  height: 18px;
+}
+[dir=rtl] .minicolors-theme-default .minicolors-swatch {
+  right: 5px;
+}
+.minicolors-theme-default .minicolors-swatches .minicolors-swatch {
+  margin-bottom: 2px;
+  top: 0;
+  left: 0; /* LTR */
+  width: 18px;
+  height: 18px;
+}
+[dir=rtl] .minicolors-theme-default .minicolors-swatches .minicolors-swatch {
+  right: 0;
+}
+.minicolors-theme-default.minicolors-position-right .minicolors-swatch {
+  left: auto; /* LTR */
+  right: 5px; /* LTR */
+}
+[dir=rtl] .minicolors-theme-default.minicolors-position-left .minicolors-swatch {
+  right: auto;
+  left: 5px;
+}
+.minicolors-theme-default.minicolors {
+  width: auto;
+  display: inline-block;
+}
+.minicolors-theme-default .minicolors-input {
+  height: 20px;
+  width: auto;
+  display: inline-block;
+  padding-left: 26px; /* LTR */
+}
+[dir=rtl] .minicolors-theme-default .minicolors-input {
+  text-align: right;
+  unicode-bidi: plaintext;
+  padding-left: 1px;
+  padding-right: 26px;
+}
+.minicolors-theme-default.minicolors-position-right .minicolors-input {
+  padding-right: 26px; /* LTR */
+  padding-left: inherit; /* LTR */
+}
+[dir=rtl] .minicolors-theme-default.minicolors-position-left .minicolors-input {
+  padding-right: inherit;
+  padding-left: 26px;
+}
+
+/* Bootstrap theme */
+.minicolors-theme-bootstrap .minicolors-swatch {
+  z-index: 2;
+  top: 3px;
+  left: 3px; /* LTR */
+  width: 28px;
+  height: 28px;
+  border-radius: 2px;
+}
+[dir=rtl] .minicolors-theme-bootstrap .minicolors-swatch {
+  right: 3px;
+}
+.minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {
+  margin-bottom: 2px;
+  top: 0;
+  left: 0; /* LTR */
+  width: 20px;
+  height: 20px;
+}
+[dir=rtl] .minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {
+  right: 0;
+}
+.minicolors-theme-bootstrap .minicolors-swatch-color {
+  border-radius: inherit;
+}
+.minicolors-theme-bootstrap.minicolors-position-right > .minicolors-swatch {
+  left: auto; /* LTR */
+  right: 3px; /* LTR */
+}
+[dir=rtl] .minicolors-theme-bootstrap.minicolors-position-left > .minicolors-swatch {
+  right: auto;
+  left: 3px;
+}
+.minicolors-theme-bootstrap .minicolors-input {
+  float: none;
+  padding-left: 44px; /* LTR */
+}
+[dir=rtl] .minicolors-theme-bootstrap .minicolors-input {
+  text-align: right;
+  unicode-bidi: plaintext;
+  padding-left: 12px;
+  padding-right: 44px;
+}
+.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {
+  padding-right: 44px; /* LTR */
+  padding-left: 12px; /* LTR */
+}
+[dir=rtl] .minicolors-theme-bootstrap.minicolors-position-left .minicolors-input {
+  padding-right: 12px;
+  padding-left: 44px;
+}
+.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {
+  top: 4px;
+  left: 4px; /* LTR */
+  width: 37px;
+  height: 37px;
+  border-radius: 5px;
+}
+[dir=rtl] .minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {
+  right: 4px;
+}
+.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch {
+  width: 24px;
+  height: 24px;
+}
+.minicolors-theme-bootstrap .minicolors-input.input-xs + .minicolors-swatch {
+  width: 18px;
+  height: 18px;
+}
+.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {
+  border-top-left-radius: 0; /* LTR */
+  border-bottom-left-radius: 0; /* LTR */
+}
+[dir=rtl] .input-group .minicolors-theme-bootstrap .minicolors-input {
+  border-radius: 4px;
+}
+[dir=rtl] .input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+[dir=rtl] .input-group .minicolors-theme-bootstrap:not(:last-child) .minicolors-input {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+/* bootstrap input-group rtl override */
+[dir=rtl] .input-group .form-control,
+[dir=rtl] .input-group-addon,
+[dir=rtl] .input-group-btn > .btn,
+[dir=rtl] .input-group-btn > .btn-group > .btn,
+[dir=rtl] .input-group-btn > .dropdown-toggle {
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+[dir=rtl] .input-group .form-control:first-child,
+[dir=rtl] .input-group-addon:first-child,
+[dir=rtl] .input-group-btn:first-child > .btn,
+[dir=rtl] .input-group-btn:first-child > .btn-group > .btn,
+[dir=rtl] .input-group-btn:first-child > .dropdown-toggle,
+[dir=rtl] .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+[dir=rtl] .input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+  border-left: 0;
+}
+[dir=rtl] .input-group .form-control:last-child,
+[dir=rtl] .input-group-addon:last-child,
+[dir=rtl] .input-group-btn:last-child > .btn,
+[dir=rtl] .input-group-btn:last-child > .btn-group > .btn,
+[dir=rtl] .input-group-btn:last-child > .dropdown-toggle,
+[dir=rtl] .input-group-btn:first-child > .btn:not(:first-child),
+[dir=rtl] .input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+/* Semantic Ui theme */
+.minicolors-theme-semanticui .minicolors-swatch {
+  top: 0;
+  left: 0; /* LTR */
+  padding: 18px;
+}
+[dir=rtl] .minicolors-theme-semanticui .minicolors-swatch {
+  right: 0;
+}
+.minicolors-theme-semanticui input {
+  text-indent: 30px;
+}

TEMPAT SAMPAH
public/css/jquery.minicolors.png


+ 136 - 133
resources/views/layouts/app.blade.php

@@ -223,167 +223,170 @@
 
     <div class="row flex-nowrap position-relative" id="sidebar--wrapper">
     <!-- sidebar menu -->
-        <div class="sidebar--ui px-0 filterWrapper filterWrapper_open" id="filter--section">
 
-            <a class="d-lg-none sidebar--opener" data-bs-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample">
-                    <i class="ico--ui hamburger--menu"></i>
-            </a>
+        @if(Auth::user()->level != env('LEVEL_INSTRUCTOR', 2))
+            <div class="sidebar--ui px-0 filterWrapper filterWrapper_open" id="filter--section">
 
-            <!-- <div class="d-flex flex-column align-items-center align-items-sm-start min-vh-100 offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel"> -->
-            <div class="d-flex flex-column align-items-center align-items-sm-start offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
-                @if(false)
-                    <a href="/dashboard" class="d-flex align-items-center pb-2 pt-2 mb-md-0 me-md-auto text-white text-decoration-none">
-                        <img src="{{env('LOGO2', env('LOGO', ''))}}" class="fs-5 d-none d-sm-inline img-fluid" alt="logo madonnella"  style="max-width:200px"/>
-                    </a>
-                @endif
+                <a class="d-lg-none sidebar--opener" data-bs-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample">
+                        <i class="ico--ui hamburger--menu"></i>
+                </a>
 
-                <div class="offcanvas-header">
-                    <img src="{{env('LOGO2', env('LOGO', ''))}}" class="fs-5 d-inline img-fluid" alt="logo madonnella"/>
-                        <a class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#offcanvasExample" aria-label="Chiudi">
+                <!-- <div class="d-flex flex-column align-items-center align-items-sm-start min-vh-100 offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel"> -->
+                <div class="d-flex flex-column align-items-center align-items-sm-start offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
+                    @if(false)
+                        <a href="/dashboard" class="d-flex align-items-center pb-2 pt-2 mb-md-0 me-md-auto text-white text-decoration-none">
+                            <img src="{{env('LOGO2', env('LOGO', ''))}}" class="fs-5 d-none d-sm-inline img-fluid" alt="logo madonnella"  style="max-width:200px"/>
                         </a>
-                </div>
+                    @endif
 
-                <div class="offcanvas-body w-100">
-                <div id="accordionExample" style="width:100%">
-                    <div class="accordion-item">
-                        <h2 class="accordion-header linkMenu" id="headingOne" style="margin-top:50px;">
-                            <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="{{Request::is('members') || Request::is('suppliers') ? 'true' : 'false'}}" aria-controls="collapseOne">
-                                Anagrafiche
-                            </button>
-                        </h2>
-                        <div id="collapseOne" class="accordion-collapse collapse {{Request::is('members') || Request::is('suppliers') ? 'show' : ''}}" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
-                            <div class="accordion-body">
-                                <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-anagrafica" style="margin-top:0px;">
-                                    <li class="nav-item" style="{{Request::is('members') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/members" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Utenti</span>
-                                        </a>
-                                    </li>
-                                    @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
-                                        <li class="nav-item"  style="{{Request::is('suppliers') ? 'background-color: #c5d9e6;' : ''}}">
-                                            <a href="/suppliers" class="nav-link d-flex align-items-center linkMenu">
-                                                <span class="ms-3 d-md-inline">Fornitori</span>
+                    <div class="offcanvas-header">
+                        <img src="{{env('LOGO2', env('LOGO', ''))}}" class="fs-5 d-inline img-fluid" alt="logo madonnella"/>
+                            <a class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#offcanvasExample" aria-label="Chiudi">
+                            </a>
+                    </div>
+
+                    <div class="offcanvas-body w-100">
+                    <div id="accordionExample" style="width:100%">
+                        <div class="accordion-item">
+                            <h2 class="accordion-header linkMenu" id="headingOne" style="margin-top:50px;">
+                                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="{{Request::is('members') || Request::is('suppliers') ? 'true' : 'false'}}" aria-controls="collapseOne">
+                                    Anagrafiche
+                                </button>
+                            </h2>
+                            <div id="collapseOne" class="accordion-collapse collapse {{Request::is('members') || Request::is('suppliers') ? 'show' : ''}}" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
+                                <div class="accordion-body">
+                                    <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-anagrafica" style="margin-top:0px;">
+                                        <li class="nav-item" style="{{Request::is('members') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/members" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Utenti</span>
                                             </a>
                                         </li>
-                                    @endif
-                                </ul>
+                                        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+                                            <li class="nav-item"  style="{{Request::is('suppliers') ? 'background-color: #c5d9e6;' : ''}}">
+                                                <a href="/suppliers" class="nav-link d-flex align-items-center linkMenu">
+                                                    <span class="ms-3 d-md-inline">Fornitori</span>
+                                                </a>
+                                            </li>
+                                        @endif
+                                    </ul>
+                                </div>
                             </div>
                         </div>
-                    </div>
-                    <div class="accordion-item">
-                        <h2 class="accordion-header linkMenu" id="headingTwo">
-                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="{{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') ? 'true' : 'false'}}" aria-controls="collapseTwo">
-                                Contabilità
-                            </button>
-                        </h2>
-                        <div id="collapseTwo" class="accordion-collapse collapse {{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') ? 'show' : ''}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
-                            <div class="accordion-body">
-                                <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-contabilita" style="margin-top:0px;">
-                                    <li class="nav-item" style="{{Request::is('in') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/in" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Entrate</span>
-                                        </a>
-                                    </li>
-                                    @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
-                                        <li class="nav-item" style="{{Request::is('out') ? 'background-color: #c5d9e6;' : ''}}">
-                                            <a href="/out" class="nav-link d-flex align-items-center linkMenu">
-                                                <span class="ms-3 d-md-inline">Uscite</span>
+                        <div class="accordion-item">
+                            <h2 class="accordion-header linkMenu" id="headingTwo">
+                                <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="{{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') ? 'true' : 'false'}}" aria-controls="collapseTwo">
+                                    Contabilità
+                                </button>
+                            </h2>
+                            <div id="collapseTwo" class="accordion-collapse collapse {{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') ? 'show' : ''}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
+                                <div class="accordion-body">
+                                    <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-contabilita" style="margin-top:0px;">
+                                        <li class="nav-item" style="{{Request::is('in') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/in" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Entrate</span>
                                             </a>
                                         </li>
-                                    @endif
-                                    <li class="nav-item" style="{{Request::is('receipts') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/receipts" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Ricevute</span>
-                                        </a>
-                                    </li>
-                                    @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
-                                        <li class="nav-item" style="{{Request::is('records_in_out') ? 'background-color: #c5d9e6;' : ''}}">
-                                            <a href="/records_in_out" class="nav-link d-flex align-items-center linkMenu">
-                                                <span class="ms-3 d-md-inline">Gestionale</span>
+                                        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+                                            <li class="nav-item" style="{{Request::is('out') ? 'background-color: #c5d9e6;' : ''}}">
+                                                <a href="/out" class="nav-link d-flex align-items-center linkMenu">
+                                                    <span class="ms-3 d-md-inline">Uscite</span>
+                                                </a>
+                                            </li>
+                                        @endif
+                                        <li class="nav-item" style="{{Request::is('receipts') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/receipts" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Ricevute</span>
                                             </a>
                                         </li>
-                                    @endif
-                                    <li class="nav-item" style="{{Request::is('records') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/records" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Prima Nota</span>
-                                        </a>
-                                    </li>
-                                </ul>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="accordion-item">
-                        <h2 class="accordion-header linkMenu" id="headingThree">
-                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="{{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_list') || Request::is('course_member') ? 'true' : 'false'}}" aria-controls="collapseThree">
-                                Corsi
-                            </button>
-                        </h2>
-                        <div id="collapseThree" class="accordion-collapse collapse {{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_list') || Request::is('course_member') ? 'show' : ''}}" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
-                            <div class="accordion-body">
-                                <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-contabilita" style="margin-top:0px;">
-                                    <li class="nav-item" style="{{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_member') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/course_member_one" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Iscritti</span>
-                                        </a>
-                                    </li>
-                                    <li class="nav-item" style="{{Request::is('calendar') ? 'background-color: #c5d9e6;' : ''}}">
-                                        <a href="/calendar" class="nav-link d-flex align-items-center linkMenu">
-                                            <span class="ms-3 d-md-inline">Calendario</span>
-                                        </a>
-                                    </li>
-                                    @if(false)
-                                        <li class="nav-item" style="{{Request::is('course_list') ? 'background-color: #c5d9e6;' : ''}}">
-                                            <a href="/course_list" class="nav-link d-flex align-items-center linkMenu">
-                                                <span class="ms-3 d-md-inline">Pagamenti</span>
+                                        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+                                            <li class="nav-item" style="{{Request::is('records_in_out') ? 'background-color: #c5d9e6;' : ''}}">
+                                                <a href="/records_in_out" class="nav-link d-flex align-items-center linkMenu">
+                                                    <span class="ms-3 d-md-inline">Gestionale</span>
+                                                </a>
+                                            </li>
+                                        @endif
+                                        <li class="nav-item" style="{{Request::is('records') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/records" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Prima Nota</span>
                                             </a>
                                         </li>
-                                    @endif
-                                </ul>
+                                    </ul>
+                                </div>
                             </div>
                         </div>
-                    </div>
-                    @if(false)
-                        <div class="accordion-item" style="{{Request::is('reminders') ? 'background-color: #c5d9e6;' : ''}}">
-                            <h2 class="accordion-header linkMenu">
-                                <a class="accordion-button collapsed" href="/reminders">
-                                    Scadenze
-                                </a>
-                            </h2>
-                        </div>
-                    @endif
-                    @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
-                        <div class="accordion-item " style="{{Request::is('settings') || Request::is('categories') || Request::is('disciplines') || Request::is('cards') || Request::is('course_subscriptions') || Request::is('courses') || Request::is('course_durations') || Request::is('course_frequencies') || Request::is('course_levels') || Request::is('course_types') || Request::is('banks') || Request::is('causals') || Request::is('vats') || Request::is('payment_methods') || Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
-                            <h2 class="accordion-header linkMenu">
-                                <a class="accordion-button collapsed" href="/settings">
-                                    Impostazioni
-                                </a>
+                        <div class="accordion-item">
+                            <h2 class="accordion-header linkMenu" id="headingThree">
+                                <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="{{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_list') || Request::is('course_member') ? 'true' : 'false'}}" aria-controls="collapseThree">
+                                    Corsi
+                                </button>
                             </h2>
+                            <div id="collapseThree" class="accordion-collapse collapse {{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_list') || Request::is('course_member') ? 'show' : ''}}" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
+                                <div class="accordion-body">
+                                    <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-contabilita" style="margin-top:0px;">
+                                        <li class="nav-item" style="{{Request::is('course_member_one') || Request::is('course_member_two') || Request::is('course_member') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/course_member_one" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Iscritti</span>
+                                            </a>
+                                        </li>
+                                        <li class="nav-item" style="{{Request::is('calendar') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/calendar" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Calendario</span>
+                                            </a>
+                                        </li>
+                                        @if(false)
+                                            <li class="nav-item" style="{{Request::is('course_list') ? 'background-color: #c5d9e6;' : ''}}">
+                                                <a href="/course_list" class="nav-link d-flex align-items-center linkMenu">
+                                                    <span class="ms-3 d-md-inline">Pagamenti</span>
+                                                </a>
+                                            </li>
+                                        @endif
+                                    </ul>
+                                </div>
+                            </div>
                         </div>
                         @if(false)
-                            <div class="accordion-item " style="{{Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
+                            <div class="accordion-item" style="{{Request::is('reminders') ? 'background-color: #c5d9e6;' : ''}}">
                                 <h2 class="accordion-header linkMenu">
-                                    <a class="accordion-button collapsed" href="/users">
-                                        Utenti
+                                    <a class="accordion-button collapsed" href="/reminders">
+                                        Scadenze
                                     </a>
                                 </h2>
                             </div>
                         @endif
-                    @endif
-                    @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
-                        <div class="accordion-item " style="{{Request::is('reports') || Request::is('categories') || Request::is('disciplines') || Request::is('cards') || Request::is('course_subscriptions') || Request::is('courses') || Request::is('course_durations') || Request::is('course_frequencies') || Request::is('course_levels') || Request::is('course_types') || Request::is('banks') || Request::is('causals') || Request::is('vats') || Request::is('payment_methods') || Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
-                            <h2 class="accordion-header linkMenu">
-                                <a class="accordion-button collapsed" href="/reports">
-                                    Reports
-                                </a>
-                            </h2>
-                        </div>
-                    @endif
-                </div>
+                        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+                            <div class="accordion-item " style="{{Request::is('settings') || Request::is('categories') || Request::is('disciplines') || Request::is('cards') || Request::is('course_subscriptions') || Request::is('courses') || Request::is('course_durations') || Request::is('course_frequencies') || Request::is('course_levels') || Request::is('course_types') || Request::is('banks') || Request::is('causals') || Request::is('vats') || Request::is('payment_methods') || Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
+                                <h2 class="accordion-header linkMenu">
+                                    <a class="accordion-button collapsed" href="/settings">
+                                        Impostazioni
+                                    </a>
+                                </h2>
+                            </div>
+                            @if(false)
+                                <div class="accordion-item " style="{{Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
+                                    <h2 class="accordion-header linkMenu">
+                                        <a class="accordion-button collapsed" href="/users">
+                                            Utenti
+                                        </a>
+                                    </h2>
+                                </div>
+                            @endif
+                        @endif
+                        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+                            <div class="accordion-item " style="{{Request::is('reports') || Request::is('categories') || Request::is('disciplines') || Request::is('cards') || Request::is('course_subscriptions') || Request::is('courses') || Request::is('course_durations') || Request::is('course_frequencies') || Request::is('course_levels') || Request::is('course_types') || Request::is('banks') || Request::is('causals') || Request::is('vats') || Request::is('payment_methods') || Request::is('users') ? 'background-color: #c5d9e6;' : ''}}">
+                                <h2 class="accordion-header linkMenu">
+                                    <a class="accordion-button collapsed" href="/reports">
+                                        Reports
+                                    </a>
+                                </h2>
+                            </div>
+                        @endif
+                    </div>
+                    </div>
                 </div>
             </div>
-        </div>
 
-        <button id="open-filter" onclick="pcsh1()"></button>
+            <button id="open-filter" onclick="pcsh1()"></button>
+        @endif
 
 
         <div class="col">

+ 138 - 0
resources/views/livewire/calendar.blade.php

@@ -5,6 +5,23 @@
         
         <div class="compare--chart_wrapper d-none"></div>
 
+        <div class="row">
+            <div class="col-6 mt-2">
+                <div class="form--item">
+                    <label for="inputName" class="form-label">Tipologia</label>
+                    <select class="form-select form-select-lg me-1" wire:model="course_type_id">
+                        <option value="">
+                        @foreach($course_types as $c)
+                            <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                        @endforeach
+                    </select>
+                </div>
+            </div>
+            <div class="col-6 text-end">
+                <a style="cursor:pointer" href="#" data-bs-toggle="modal" data-bs-target="#calendarNewModal" class="openNewModal addData btn--ui"><i class="fa-solid fa-plus"></i></a>
+            </div>
+        </div>
+
         <div id='calendar'></div>
 
     </section>
@@ -38,6 +55,102 @@
         </div>
     </div>
 
+    <!--
+    Giorno e data della lezione
+    Corso, livello, tipologia, frequenza, insegnante, campo, note
+    -->
+
+    <div  wire:ignore.self class="modal" id="calendarNewModal" tabindex="-1" aria-labelledby="calendarNewModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="calendarNewModalLabel">Dettaglio</h5>
+                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    <div class="row">
+                        <div class="col-md-6">
+                            <label for="date" class="form-label">Data</label>
+                            <input class="form-control" type="date" id="date" placeholder="Data">
+                        </div>
+                        <div class="col-md-6">
+                            <label for="date" class="form-label">Nome</label>
+                            <input class="form-control js-keyupTitle" type="name" id="name" placeholder="Nome">
+                        </div>
+                    </div>                    
+                    <div class="row">
+                        <div class="col-md-6">
+                            <label for="course_subscription_id" class="form-label">Ora inizio</label>
+                            <select class="form-select" id="from">
+                                <option value="">--Seleziona--
+                                @for($c=6;$c<=23;$c++)
+                                    <option value="{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:00">{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:00
+                                    <option value="{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:30">{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:30
+                                @endfor
+                            </select>
+                        </div>
+                        <div class="col-md-6">
+                            <label for="course_subscription_id" class="form-label">Ora fine</label>
+                            <select class="form-select" id="to">
+                                <option value="">--Seleziona--
+                                @for($c=6;$c<=23;$c++)
+                                    <option value="{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:00">{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:00
+                                    <option value="{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:30">{{str_pad($c, 2, "0", STR_PAD_LEFT)}}:30
+                                @endfor
+                            </select>
+                        </div>
+                    </div>                    
+                    <div class="row">
+                        <div class="col-md-6">
+                            <label for="course_type_id" class="form-label">Corso</label>
+                            <select class="form-select form-select-lg me-1" id="course_type_id">
+                                <option value="">
+                                @foreach($course_types as $c)
+                                    <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                                @endforeach
+                            </select>
+                        </div>
+                        <div class="col-md-6">
+                            <label for="course_duration_id" class="form-label">Darata</label>
+                            <select class="form-select form-select-lg me-1" id="course_duration_id">
+                                <option value="">
+                                @foreach($course_durations as $c)
+                                    <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                                @endforeach
+                            </select>
+                            
+                        </div>
+                    </div>    
+                    <div class="row">
+                        <div class="col-md-6">
+                            <label for="course_frequency_id" class="form-label">Frequenza</label>
+                            <select class="form-select form-select-lg me-1" id="course_frequency_id">
+                                <option value="">
+                                @foreach($course_frequencies as $c)
+                                    <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                                @endforeach
+                            </select>
+                        </div>
+                        <div class="col-md-6">
+                            <label for="course_level_id" class="form-label">Livello</label>
+                            <select class="form-select form-select-lg me-1" id="course_level_id">
+                                <option value="">
+                                @foreach($course_levels as $c)
+                                    <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                                @endforeach
+                            </select>
+                            
+                        </div>
+                    </div>                    
+                </div>
+                <div class="modal-footer mt-2">
+                    <button class="btn--ui lightGrey" >Annulla</a>
+                    <button type="button" class="btn--ui btn-primary" onclick="createCalendar()">Salva</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
 </div>
 
 @push('scripts')
@@ -57,6 +170,26 @@
             document.location.href = '/presences' + params;
         }
 
+        function createCalendar()
+        {                        
+            
+            console.log($("#course_type_id").val());
+            @this.set('course_type_id',$("#course_type_id").val());
+            console.log($("#course_duration_id").val());
+            @this.set('course_duration_id', $("#course_duration_id").val());
+            console.log($("#course_frequency_id").val());
+            @this.set('course_frequency_id', $("#course_frequency_id").val());
+            console.log($("#course_level_id").val());
+            @this.set('course_level_id', $("#course_level_id").val());
+            console.log($("#date").val() + " " + $("#from").val() + ":00");
+            @this.set('from', $("#date").val() + " " + $("#from").val() + ":00");
+            console.log($("#date").val() + " " + $("#to").val() + ":00");
+            @this.set('to', $("#date").val() + " " + $("#to").val() + ":00");
+            console.log($("#name").val());
+            @this.set('name', $("#name").val());
+            @this.createCalendar();
+        }
+
         document.addEventListener('DOMContentLoaded', function() {
             var calendarEl = document.getElementById('calendar');
             var calendar = new FullCalendar.Calendar(calendarEl, {
@@ -67,6 +200,11 @@
                             right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
 
                 },
+                dateClick: function(info) {
+                    var x = info.dateStr.split("T");
+                    $("#date").val(x[0]);
+                    $('.openNewModal').trigger('click');
+                },
                 eventClick: function(info) {
                     var eventDate = new Date(info.event.start); 
                     var datestring = eventDate.getFullYear() + "-" + pad(eventDate.getMonth()+1, 2) + "-" + pad(eventDate.getDate(), 2) + " " + pad(eventDate.getHours(), 2) + ":" + pad(eventDate.getMinutes(), 2) + ":00";

+ 11 - 2
resources/views/livewire/course.blade.php

@@ -16,10 +16,8 @@
 
     </header>
 
-
     @if(!$add && !$update)
 
-
         <a class="btn--ui lightGrey" href="/settings?type=corsi"><i class="fa-solid fa-arrow-left"></i></a><br>
 
         <div class="row  mt-3" style="margin-bottom:2rem !important;">
@@ -278,6 +276,14 @@
                                     @enderror
                                 </div>
                             </div>
+
+                            <div class="col-6 mt-2">
+                                <div class="form--item">
+                                    <label for="inputName" class="form-label">Colore calendario</label>
+                                    <input class="form-control" type="color" id="color" wire:model="color">
+                                </div>
+                            </div>
+                                                        
                             <div class="col-6">
                                 @foreach($prices as $idP => $p)
                                     <div class="row mt-2 ">
@@ -395,6 +401,7 @@
 
 @push('scripts')
     <link href="/css/datatables.css" rel="stylesheet" />
+    <link href="/css/jquery.minicolors.css" rel="stylesheet" />
     <style>
         a.notSelected
         {
@@ -464,6 +471,7 @@
     <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
+    <script src="/assets/js/jquery.minicolors.js"></script>
 @endpush
 
 @push('scripts')
@@ -622,6 +630,7 @@
                 console.log(courses);
             });
 
+
         }
 
     </script>

+ 200 - 0
resources/views/livewire/motivation.blade.php

@@ -0,0 +1,200 @@
+<div class="col card--ui" id="card--dashboard">
+    @if(!$add && !$update)
+
+        <!--<button id="open-filter" onclick="pcsh1()"></button>
+        <button id="close-filter" onclick="pcsh2()"></button>-->
+
+        <a class="btn--ui lightGrey" href="/settings?type=contabilita"><i class="fa-solid fa-arrow-left"></i></a><br>
+
+        <header id="title--section" style="display:none !important"  class="d-flex align-items-center justify-content-between">
+            <div class="title--section_name d-flex align-items-center justify-content-between">
+                <i class="ico--ui title_section utenti me-2"></i>
+                <h2 class="primary">Motivazioni annullamento</h2>
+            </div>
+
+            <div class="title--section_addButton"  wire:click="add()" style="cursor: pointer;">
+                <div class="btn--ui entrata d-flex justify-items-between">
+                    <a href="#" wire:click="add()" style="color:white">Aggiungi</a>
+                </div>
+            </div>
+
+        </header>
+        
+        <section id="resume-table">
+            <div class="compare--chart_wrapper d-none"></div>
+
+            <table class="table tablesaw tableHead tablesaw-stack" id="tablesaw-350" width="100%">
+                <thead>
+                    <tr>
+                        <th scope="col">Nome</th>
+                        <th scope="col">Abilitato</th>
+                        <th scope="col">...</th>
+                    </tr>
+                </thead>
+                <tbody id="checkall-target">
+                    @foreach($records as $record)
+                        <tr>
+                            <td>{{$record->name}}</td>
+                            <td> <span class="tablesaw-cell-content"><span class="badge tessera-badge {{$record->enabled ? 'active' : 'suspended'}}">{{$record->enabled ? 'attivo' : 'disattivo'}}</span></span></td>
+                            <td>
+                                <button type="button" class="btn" wire:click="edit({{ $record->id }})" data-bs-toggle="popover"  data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Modifica"><i class="fa-regular fa-pen-to-square"></i></button>
+                                <button type="button" class="btn" onclick="confirm('Sei sicuro?') || event.stopImmediatePropagation()" wire:click="delete({{ $record->id }})" data-bs-toggle="popover"  data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="cestina"><i class="fa-regular fa-trash-can"></i></button>
+                            </td>
+                        </tr>
+                    @endforeach
+
+                </tbody>
+            </table>
+          
+        </section>
+
+    @else
+
+        <div class="container">
+
+            <a class="btn--ui lightGrey" href="/banks"><i class="fa-solid fa-arrow-left"></i></a><br><br>
+
+            @if (session()->has('error'))
+                <div class="alert alert-danger" role="alert">
+                    {{ session()->get('error') }}
+                </div>
+            @endif
+
+            <div class="row">
+                <div class="col">
+
+                    <form action="">
+
+                        <div class="row mb-3">
+                            <div class="col">
+                                <div class="form--item">
+                                    <label for="inputName" class="form-label">Nome</label>
+                                    <input class="form-control js-keyupTitle @error('name') is-invalid @enderror" type="text" id="name" placeholder="Nome" wire:model="name">
+                                    @error('name')
+                                        <div class="invalid-feedback">{{ $message }}</div>
+                                    @enderror
+                                </div>
+                            </div>
+                            <div class="col">
+                                <div class="form--item">
+                                    <label for="enabled" class="form-label">Abilitato</label>
+                                    <input class="form-check-input form-control" style="width:22px; height:22px;" type="checkbox" id="enabled" wire:model="enabled">
+                                </div>
+                            </div>
+                        </div>
+
+                        <!-- // inline input field -->
+
+                        <div class="form--item">
+                            <button type="button" class="btn--ui lightGrey" wire:click="cancel()">Annulla</button>
+                        @if($add)
+                            <button type="submit" class="btn--ui" wire:click.prevent="store()">Salva</button>
+                        @endif
+                        @if($update)
+                            <button type="submit" class="btn--ui" wire:click.prevent="update()">Salva</button>
+                        @endif
+                        </div>
+
+                    </form>
+                </div>
+            </div>
+        </div>
+
+    @endif
+</div>
+
+@push('scripts')
+    <link href="/css/datatables.css" rel="stylesheet" />
+    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
+    <script src="/assets/js/datatables.js"></script>
+    <script src="https://cdn.datatables.net/buttons/3.0.2/js/buttons.dataTables.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
+@endpush
+
+@push('scripts')
+    <script>
+
+        $(document).ready(function() {
+            loadDataTable();
+        } );
+
+        Livewire.on('load-data-table', () => {
+            loadDataTable();
+        });
+
+        function loadDataTable(){
+            if ( $.fn.DataTable.isDataTable('#tablesaw-350') ) {
+                $('#tablesaw-350').DataTable().destroy();
+            }
+            $('#tablesaw-350').DataTable({
+                thead: {
+                'th': {'background-color': 'blue'}
+                },
+                layout: {
+                    topStart : null,
+                    topEnd : null,
+                    top1A: {
+                        buttons: [
+                            {
+                                extend: 'collection',
+                                text: 'ESPORTA',
+                                buttons: [
+                                    {
+                                    extend: 'excelHtml5',
+                                        title: 'Motivazioni annullamento',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'pdfHtml5',
+                                        title: 'Motivazioni annullamento',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'print',
+                                        text: 'Stampa',
+                                        title: 'Motivazioni annullamento',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    }
+                                ],
+                                dropup: true
+                            }
+                        ]
+                    },
+                    top1B : {
+                        pageLength: {
+                            menu: [[10, 25, 50, 100, 100000], [10, 25, 50, 100, "Tutti"]]
+                        }
+                    },
+                    top1C :'search',
+                },
+                pagingType: 'numbers',
+                "language": {
+                    "url": "/assets/js/Italian.json"
+                },
+                "fnInitComplete": function (oSettings, json) {
+                    var html = '&nbsp;<a href="#" class="addData btn--ui"><i class="fa-solid fa-plus"></i></a>';
+                    $(".dt-search").append(html);
+                }
+            });
+            $('#tablesaw-350 thead tr th').addClass('col');
+            $('#tablesaw-350 thead tr th').css("background-color", "#f6f8fa");
+
+            $(document).ready(function() {
+                $(document).on("click",".addData",function() {
+                    $(".title--section_addButton").trigger("click")
+                });
+            } );
+
+        }
+
+    </script>
+@endpush
+

+ 167 - 13
resources/views/livewire/presence.blade.php

@@ -1,5 +1,6 @@
 <div class="col card--ui" id="card--dashboard">
 
+    <a class="btn--ui lightGrey" href="/calendar"><i class="fa-solid fa-arrow-left"></i></a><br><br>
 
     <section id="resume-table">
         
@@ -7,7 +8,7 @@
 
         <div class="row">
             <div class="col-md-6">
-                <h3>{{$calendar->course->name}}</h3>
+                <h3>{{$calendar->course ? $calendar->course->name : $calendar->name}}</h3>
             </div>
             <div class="col-md-6">
                 <h3>{{date("l d F", strtotime($calendar->from))}}, ora inizio {{date("H:i", strtotime($calendar->from))}}</h3>
@@ -33,9 +34,21 @@
             </div>
 
             <div class="col-md-12 mt-3">
-                <textarea class="form-control" id="note" placeholder="Note" wire:model="note"></textarea>
+                <input class="form-control" id="note" placeholder="Note" wire:model="note"></input>
             </div>
 
+            @if($calendar->status == 0)
+                <div class="col-md-6">
+                    <label for="member_id" class="form-label">Aggiunge una persona</label>
+                    <select name="member_id" class="form-select memberClass" aria-label="Seleziona una persona" wire:model="member_id">
+                        <option value="">--Seleziona--
+                        @foreach($members as $member)
+                            <option value="{{$member->id}}">{{$member->last_name}} {{$member->first_name}} ({{$member->fiscal_code}})
+                        @endforeach
+                    </select>
+                </div>
+            @endif
+
         </div>    
         
         <section id="resume-table" class="mt-3">
@@ -57,8 +70,37 @@
                             <td>{{$idx}}</td>
                             <td>{{$record["first_name"]}}</td>
                             <td>{{$record["last_name"]}}</td>
-                            <td></td>
-                            <td><input class="member" type="checkbox" value="{{$record["id"]}}" {{$record["presence"] ? 'checked' : ''}}></td>
+                            <td>
+                                <span class="tablesaw-cell-content d-flex align-items-center">
+                                    @php
+                                    list($status, $date) = explode("|", $record["certificate"]);
+                                    @endphp
+                                    @if($status == 0)
+                                        <i class="ico--ui check suspended me-2"></i>Scaduto
+                                    @endif
+                                    @if($status == 1)
+                                        <i class="ico--ui check due me-2"></i>In scadenza
+                                    @endif
+                                    @if($status == 2)
+                                        <i class="ico--ui check active me-2"></i> Scadenza
+                                    @endif
+                                    {{$date}}
+                                </span>
+                            <td>
+                                @if ($record["status"] != 99)
+                                    @if ($record["presence"])
+                                        @if ($record["my_presence"])
+                                            <input class="member" type="checkbox" value="{{$record["id"]}}" {{$record["presence"] ? 'checked' : ''}}>
+                                        @else
+                                            V
+                                        @endif
+                                    @else
+                                        <input class="member" type="checkbox" value="{{$record["id"]}}" {{$record["presence"] ? 'checked' : ''}}>
+                                    @endif
+                                @else
+                                    Annullata
+                                @endif
+                            </td>
                         </tr>
                     @endforeach
 
@@ -69,13 +111,28 @@
 
         <div class="row">
             <div class="col-md-6">
-                <button type="button" class="btn--ui " style="background-color:red !important">Annulla Lezione</button>
-            </div>
-            <div class="col-md-6 text-end">
-                <button type="button" class="btn--ui lightGrey" onclick="document.location.href='/calendar'">Annulla</button>
-                <button type="button" class="btn--ui" onclick="save()">Salva</button>
+                <label for="motivation_id" class="form-label">Motivazione annullamento</label>
+                <select class="form-select form-select-lg me-1 " wire:model="motivation_id">
+                    <option value="">
+                    @foreach($motivations as $m)
+                        <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                    @endforeach
+                </select>
             </div>
         </div>
+        <div class="row mt-3">
+            @if($calendar->status == 0)
+                <div class="col-md-6">
+                    <button type="button" class="btn--ui " style="background-color:red !important" wire:click="cancelCalendar()">Annulla Lezione</button>
+                </div>
+                <div class="col-md-6 text-end">
+                    <button type="button" class="btn--ui" style="background-color:red !important" onclick="cancel()">Annulla lezione selezionati</button>
+                    <button type="button" class="btn--ui" onclick="save()">Salva</button>             
+                </div>
+            @else
+                LEZIONE ANNULLATA
+            @endif
+        </div>
 
     </section>
 
@@ -83,8 +140,72 @@
 </div>
 
 @push('scripts')
-    
-    
+    <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
+    <style>
+        table.tableHead thead {
+        /* Important */
+            position: sticky;
+            z-index: 100;
+            top: 0;
+        }
+        .select2-container--default .select2-selection--single{
+            background-color: #E9F0F5;
+            border: 0.0625rem solid #DFE5EB;
+            font-size: 0.75rem;
+        }
+        .select2-selection
+        {
+            height: 38px !important;
+        }
+        .select2-selection__rendered
+        {
+            padding-top:3px;
+        }
+        .select2 {
+            width:100% !important;
+        }
+        .page-link.active, .active > .page-link {
+            background-color:#006099 !important;
+        }
+
+        .select2-selection--multiple{
+            overflow: hidden !important;
+            height: auto !important;
+        }
+        .select2-container {
+            box-sizing: border-box;
+            display: inline-block;
+            margin: 0;
+            position: relative;
+            vertical-align: middle;
+        }
+        .select2-container .select2-selection--single {
+            box-sizing: border-box;
+            cursor: pointer;
+            display: block;
+            height: 38px;
+            user-select: none;
+            -webkit-user-select: none;
+        }
+        .select2-container .select2-selection--single .select2-selection__rendered {
+            display: block;
+            padding-left: 8px;
+            padding-right: 20px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+        /* .total.primary
+        {
+            font-size:38px !important;
+        } */
+        /* .total.primary.comp
+        {
+            font-size:32px !important;
+        } */
+    </style>
+    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
 @endpush
 
 @push('scripts')
@@ -92,10 +213,30 @@
 
         $(document).ready(function() {
             
+            setTimeout(() => {
+                $('.memberClass').select2({
+                    tags: false
+                });
+                $('.memberClass').on('change', function (e) {
+                    var data = $('.memberClass').select2("val");
+                    console.log(data);
+                    @this.addMember(data);
+                });                
+            }, 100);
+
         } );
 
-        Livewire.on('load-data-table', () => {
-            
+        Livewire.on('reload', () => {
+            setTimeout(() => {
+                $('.memberClass').select2({
+                    tags: false
+                });
+                $('.memberClass').on('change', function (e) {
+                    var data = $('.memberClass').select2("val");
+                    console.log(data);
+                    @this.addMember(data);
+                });                
+            }, 100);
         });
 
         function save()
@@ -111,6 +252,19 @@
 
             @this.save(ids);
         }
+
+        function cancel()
+        {
+            var ids = [];
+            $('input[type=checkbox]').each(function () {
+                if ($(this).is(":checked")) 
+                {
+                    var val = $(this).val();
+                    ids.push(val);
+                }
+            });
+            @this.cancel(ids);
+        }
         
     </script>
 @endpush

+ 7 - 0
resources/views/livewire/settings.blade.php

@@ -94,6 +94,13 @@
                     </div>
                 </a>
                 <hr size="1">
+                <a href="/motivations">
+                    <div class="row">
+                        <div class="col-md-11 p-2"><h5>Motivazioni annullamento</h5></div>
+                        <div class="col-md-1 p-2"><i class="fa-solid fa-chevron-circle-right"></i></div>
+                    </div>
+                </a>
+                <hr size="1">
                 <a href="/course_types">
                     <div class="row">
                         <div class="col-md-11 p-2"><h5>Tipologie</h5></div>

+ 8 - 2
routes/web.php

@@ -34,8 +34,13 @@ Route::get('/login', function () {
 
 Route::post('/login', function () {
 
-    if (Auth::attempt(array('email' => $_POST["email"], 'password' => $_POST["password"]))) {
-        return Redirect::to('/dashboard');
+    if (Auth::attempt(array('email' => $_POST["email"], 'password' => $_POST["password"]))) 
+    {
+        if (Auth::user()->level == ENV('LEVEL_INSTRUCTOR', 2))
+            return Redirect::to('/calendar');
+        else
+            return Redirect::to('/dashboard');
+
     } else {
         return Redirect::to('/?error=1');
     }
@@ -115,6 +120,7 @@ Route::group(['middleware' => 'auth'], function () {
     Route::get('/calendar', \App\Http\Livewire\Calendar::class);
     Route::get('/presences', \App\Http\Livewire\Presence::class);
     Route::get('/courts', \App\Http\Livewire\Court::class);
+    Route::get('/motivations', \App\Http\Livewire\Motivation::class);
 });
 
 Route::get('/receipt/{id}', function ($id) {