Ver Fonte

Implementazione modulo presenze

Luca Parisio há 7 meses atrás
pai
commit
8bd6575f64

+ 22 - 0
app/Http/Livewire/Calendar.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+
+class Calendar extends Component
+{
+    public $records;
+
+    public function render()
+    {
+        $this->records = [];
+        $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);
+        }
+        return view('livewire.calendar');
+    }
+
+}

+ 75 - 2
app/Http/Livewire/Course.php

@@ -178,7 +178,7 @@ class Course extends Component
         $this->update = false;
     }
     */
-    public function store()
+    public function store($create=false)
     {
         $this->validate();
         try {
@@ -272,6 +272,9 @@ class Course extends Component
                 $course->sub_causal_id = $ci->id;
 
                 $course->save();
+
+                if ($create)
+                    $this->createCalendar($course);
                 
                 session()->flash('success','Corso creato');
                 $this->resetFields();
@@ -344,7 +347,7 @@ class Course extends Component
         }
     }
 
-    public function update()
+    public function update($create=false)
     {
         $this->validate();
         try {
@@ -371,6 +374,10 @@ class Course extends Component
                 'prices' => json_encode($this->prices),
                 'enabled' => $this->enabled
             ]);
+
+            if ($create)
+                $this->createCalendar(\App\Models\Course::findOrFail($this->dataId));
+
             session()->flash('success','Corso aggiornato');
             $this->resetFields();
             $this->update = false;
@@ -473,4 +480,70 @@ class Course extends Component
         unset($this->prices[$idx]);
     }
 
+    public function createCalendar($course)
+    {
+
+        $days = array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');
+
+        $from = $course->date_from;
+        $to = $course->date_to;
+
+        $endDate = strtotime($to);
+
+        foreach(json_decode($course->when) as $d)
+        {
+
+            foreach($d->day as $dd)
+            {
+
+                $day = '';
+                switch ($dd) {
+                    case 'lun':
+                        $day = $days[0];
+                        break;
+                    case 'mar':
+                        $day = $days[1];
+                        break;
+                    case 'mer':
+                        $day = $days[2];
+                        break;
+                    case 'gio':
+                        $day = $days[3];
+                        break;
+                    case 'ven':
+                        $day = $days[4];
+                        break;
+                    case 'sab':
+                        $day = $days[5];
+                        break;
+                    case 'dom':
+                        $day = $days[6];
+                        break;
+                    default:
+                        $day = '';
+                        break;
+                }
+                
+                if ($day != '')
+                {
+                    for($i = strtotime($day, strtotime($from)); $i <= $endDate; $i = strtotime('+1 week', $i))
+                    {
+                        
+                        $calendar = new \App\Models\Calendar();
+                        $calendar->course_id = $course->id;
+                        $calendar->court_id = null;
+                        $calendar->instructor_id = null;
+                        $calendar->from = date('Y-m-d ' . $d->from . ":00", $i);
+                        $calendar->to = date('Y-m-d ' . $d->to . ":00", $i);
+                        $calendar->note = '';
+                        $calendar->save();
+                        //
+                    }
+                }
+            }
+        }
+        
+
+    }
+
 }

+ 127 - 0
app/Http/Livewire/Court.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+
+class Court 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\Court::select('id', 'name', 'enabled')->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')->get();
+        $this->records = \App\Models\Court::select('id', 'name', 'enabled')->get();
+        return view('livewire.court');
+    }
+
+    public function add()
+    {
+        $this->resetFields();
+        $this->add = true;
+        $this->update = false;
+    }
+
+    public function store()
+    {
+        $this->validate();
+        try {
+            \App\Models\Court::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 {
+            $court = \App\Models\Court::findOrFail($id);
+            if( !$court) {
+                session()->flash('error','Campo non trovata');
+            } else {
+                $this->name = $court->name;
+                $this->enabled = $court->enabled;
+                $this->dataId = $court->id;
+                $this->update = true;
+                $this->add = false;
+            }
+        } catch (\Exception $ex) {
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function update()
+    {
+        $this->validate();
+        try {
+            \App\Models\Court::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\Court::find($id)->delete();
+            session()->flash('success',"Campo eliminata");
+            return redirect(request()->header('Referer'));
+        }catch(\Exception $e){
+            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        }
+    }
+}

+ 75 - 0
app/Http/Livewire/Presence.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+
+class Presence extends Component
+{
+
+    public $calendar;
+
+    public $records;
+
+    public $court_id, $instructor_id, $note;
+
+    public $courts = [];
+    public $instructors = [];
+
+    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();
+    }
+
+    public function render()
+    {
+        $this->records = [];
+        
+        // Carco tutti gli iscritti a quel corso
+        $members_courses = \App\Models\MemberCourse::where('course_id', $this->calendar->course_id)->pluck('member_id')->toArray();
+
+        $members = \App\Models\Member::whereIn('id', $members_courses)->get();
+
+        $presences = \App\Models\Presence::where('calendar_id', $this->calendar->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));
+        }
+
+        /*$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);
+        }*/
+        return view('livewire.presence');
+    }
+
+    public function save($ids)
+    {
+
+        $this->calendar->court_id = $this->court_id;
+        $this->calendar->instructor_id = $this->instructor_id;
+        $this->calendar->note = $this->note;
+        $this->calendar->save();
+
+        \App\Models\Presence::where('calendar_id', $this->calendar->id)->delete();
+        foreach($ids as $id)
+        {
+            $p = new \App\Models\Presence();
+            $p->member_id = $id;
+            $p->calendar_id = $this->calendar->id;
+            $p->save();
+        }
+        return redirect()->to('/calendar');
+
+    }
+
+}

+ 25 - 0
app/Models/Calendar.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Calendar extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'course_id',
+        'court_id',
+        'instructor_id',
+        'from',
+        'to',
+        'note',
+    ];
+
+    public function course()
+    {
+        return $this->belongsTo(\App\Models\Course::class);
+    }
+}

+ 16 - 0
app/Models/Court.php

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

+ 27 - 0
app/Models/Presence.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Presence extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'member_id',
+        'calendar_id',
+        'member_course_id',
+    ];
+
+    public function member()
+    {
+        return $this->belongsTo(\App\Models\Member::class);
+    }
+
+    public function calendar()
+    {
+        return $this->belongsTo(\App\Models\Calendar::class);
+    }
+}

BIN
database/.DS_Store


+ 34 - 0
database/migrations/2025_06_06_153500_create_courts_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('courts', 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('courts');
+    }
+};

+ 41 - 0
database/migrations/2025_06_06_153700_create_calendars_table.php

@@ -0,0 +1,41 @@
+<?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('calendars', function (Blueprint $table) {
+            $table->id();
+            $table->unsignedBigInteger('course_id')->nullable();
+            $table->foreign('course_id')->nullable()->references('id')->on('courses')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('court_id')->nullable();
+            $table->foreign('court_id')->nullable()->references('id')->on('courts')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('instructor_id')->nullable();
+            $table->foreign('instructor_id')->nullable()->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
+            $table->datetime('from')->nullable();
+            $table->datetime('to')->nullable();
+            $table->string('note')->nullable();
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('calendars');
+    }
+};

+ 39 - 0
database/migrations/2025_06_06_154000_create_presences_table.php

@@ -0,0 +1,39 @@
+<?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('presences', function (Blueprint $table) {
+            $table->id();
+            $table->unsignedBigInteger('calendar_id')->nullable();
+            $table->foreign('calendar_id')->nullable()->references('id')->on('calendars')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('member_id')->nullable();
+            $table->foreign('member_id')->nullable()->references('id')->on('members')->onUpdate('cascade')->onDelete('cascade');
+            $table->unsignedBigInteger('member_course_id')->nullable();
+            $table->foreign('member_course_id')->nullable()->references('id')->on('member_courses')->onUpdate('cascade')->onDelete('cascade');
+
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('presences');
+    }
+};

Diff do ficheiro suprimidas por serem muito extensas
+ 8 - 0
public/assets/js/fullcalendar.js


Diff do ficheiro suprimidas por serem muito extensas
+ 5 - 0
public/assets/js/fullcalendar_locales.js


+ 7 - 0
resources/views/layouts/app.blade.php

@@ -164,6 +164,8 @@
                 print "Corsi";
             if (Request::is('course_member'))
                 print "Iscritti corsi";
+            if (Request::is('calendar'))
+                print "Calendario";
             if (Request::is('course_list'))
                 print "Pagamento corsi";
             if (Request::is('reminders'))
@@ -324,6 +326,11 @@
                                             <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">

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

@@ -0,0 +1,103 @@
+<div class="col card--ui" id="card--dashboard">
+
+
+    <section id="resume-table">
+        
+        <div class="compare--chart_wrapper d-none"></div>
+
+        <div id='calendar'></div>
+
+    </section>
+
+    <a href="#" data-bs-toggle="modal" data-bs-target="#calendarModal" class="openModal"></a>
+
+    <div  wire:ignore.self class="modal" id="calendarModal" tabindex="-1" aria-labelledby="calendarModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="calendarModalLabel">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="course_subscription_id" class="form-label">Ora inizio</label>
+                            <h3 class="time">ORA</h3>
+                        </div>
+                        <div class="col-md-6">
+                            <label class="form-label date">Martdì aaa</label>
+                            <h3 class="title">Padel</h3>
+                        </div>
+                    </div>                    
+                </div>
+                <div class="modal-footer mt-2">
+                    <button class="btn--ui lightGrey" >Annulla Lezione</a>
+                    <button type="button" class="btn--ui btn-primary" onclick="goPresence()">Presenze</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+</div>
+
+@push('scripts')
+    
+    <script src="/assets/js/fullcalendar.js"></script>
+    <script src="/assets/js/fullcalendar_locales.js"></script>
+@endpush
+
+@push('scripts')
+    <script>
+
+        var currentCalendar = 0;
+        var params = '';
+
+        function goPresence()
+        {
+            document.location.href = '/presences' + params;
+        }
+
+        document.addEventListener('DOMContentLoaded', function() {
+            var calendarEl = document.getElementById('calendar');
+            var calendar = new FullCalendar.Calendar(calendarEl, {
+                initialView: 'timeGridWeek',
+                headerToolbar: {
+                    left: 'prevYear,prev,next,nextYear today',
+                    center: 'title',
+                            right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
+
+                },
+                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";
+                    var title = info.event.title;
+                    $(".title").html(title);
+                    $(".time").html(pad(eventDate.getHours(), 2) + ":" + pad(eventDate.getMinutes(), 2));
+                    $(".date").html(eventDate.toLocaleDateString('it-IT', { weekday: 'long' }) + " " + pad(eventDate.getDate(), 2) + " " + eventDate.toLocaleDateString('it-IT', { month: 'long' }));
+                    currentCalendar = info.event.id;
+                    params = '?calendarId=' + info.event.id;// + "&date=" + datestring; 
+                    $('.openModal').trigger('click');
+                },
+                locale: 'it',
+                events: @json($records),
+            });
+            calendar.render();
+        });
+
+        $(document).ready(function() {
+            
+        } );
+
+        Livewire.on('load-data-table', () => {
+            
+        });
+
+        function pad(num, size) {
+            num = num.toString();
+            while (num.length < size) num = "0" + num;
+            return num;
+        }
+
+        
+    </script>
+@endpush

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

@@ -377,9 +377,11 @@
                             <button type="button" class="btn--ui lightGrey" onclick="annulla()">Annulla</button>
                             @if($add)
                                 <button type="submit" class="btn--ui" wire:click.prevent="store()">Salva</button>
+                                <button type="submit" class="btn--ui" wire:click.prevent="store(true)">Salva e crea calendario</button>
                             @endif
                             @if($update)
                                 <button type="submit" class="btn--ui" wire:click.prevent="update()">Salva</button>
+                                <button type="submit" class="btn--ui" wire:click.prevent="update(true)">Salva e crea calendario</button>
                             @endif
                         </div>
 

+ 243 - 0
resources/views/livewire/court.blade.php

@@ -0,0 +1,243 @@
+<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">Campi</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="subheader" class="d-flex align-items-center justify-content-between">
+            <form action="" class="group--action d-flex align-items-center">
+            <select class="form-select form-select-lg me-1" aria-label=".form-select-lg example">
+                <option selected>Open this select menu</option>
+                <option value="1">One</option>
+                <option value="2">Two</option>
+                <option value="3">Three</option>
+                </select>
+                <button type="submit" class="btn--ui">applica</button>
+            </form>
+
+            <form action="" class="search--form d-flex align-items-center">
+                <div class="input-group mb-3">
+                    <input type="text" class="form-control" placeholder="Cerca utente" aria-label="cerca utent" aria-describedby="button-addon2">
+                    <button class="btn--ui" type="button" id="button-addon2"><i class="ico--ui search"></i>Cerca</button>
+                </div>
+            </form>
+        </section>
+        -->
+        <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>
+            <!--
+            <div class="paginator d-flex justify-content-center">
+                <nav aria-label="Page navigation example">
+                    <ul class="pagination">
+                        <li class="page-item">
+                        <a class="page-link" href="#" aria-label="Previous">
+                            <span aria-hidden="true"></span>
+                        </a>
+                        </li>
+                        <li class="page-item"><a class="page-link" href="#">1</a></li>
+                        <li class="page-item"><a class="page-link" href="#">2</a></li>
+                        <li class="page-item"><a class="page-link" href="#">3</a></li>
+                        <li class="page-item"><a class="page-link" href="#">3</a></li>
+
+                        <li class="page-item"><span class="more-page">...</span></li>
+
+                        <li class="page-item">
+                        <a class="page-link" href="#" aria-label="Next">
+                            <span aria-hidden="true"></span>
+                        </a>
+                        </li>
+                    </ul>
+                    </nav>
+            </div>
+            -->
+        </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: 'Campi',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'pdfHtml5',
+                                        title: 'Campi',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'print',
+                                        text: 'Stampa',
+                                        title: 'Campi',
+                                        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
+

+ 116 - 0
resources/views/livewire/presence.blade.php

@@ -0,0 +1,116 @@
+<div class="col card--ui" id="card--dashboard">
+
+
+    <section id="resume-table">
+        
+        <div class="compare--chart_wrapper d-none"></div>
+
+        <div class="row">
+            <div class="col-md-6">
+                <h3>{{$calendar->course->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>
+            </div>
+
+            <div class="col-md-6">
+                <label for="court_id" class="form-label">Campo</label>
+                <select class="form-select form-select-lg me-1 " wire:model="court_id">
+                    <option value="">
+                    @foreach($courts as $c)
+                        <option value="{{$c["id"]}}">{{$c["name"]}}</option>
+                    @endforeach
+                </select>
+            </div>
+            <div class="col-md-6">
+                <label for="instructor_id" class="form-label">Istruttore</label>
+                <select class="form-select form-select-lg me-1 " wire:model="instructor_id">
+                    <option value="">
+                    @foreach($instructors as $i)
+                        <option value="{{$i["id"]}}">{{$i["name"]}}</option>
+                    @endforeach
+                </select>
+            </div>
+
+            <div class="col-md-12 mt-3">
+                <textarea class="form-control" id="note" placeholder="Note" wire:model="note"></textarea>
+            </div>
+
+        </div>    
+        
+        <section id="resume-table" class="mt-3">
+            <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">#</th>
+                        <th scope="col">Cognome</th>
+                        <th scope="col">Nome</th>
+                        <th scope="col">Certificato</th>
+                        <th scope="col">Presenza</th>
+                    </tr>
+                </thead>
+                <tbody id="checkall-target">
+                    @foreach($records as $idx => $record)
+                        <tr>
+                            <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>
+                        </tr>
+                    @endforeach
+
+                </tbody>
+            </table>
+
+        </section>
+
+        <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>
+            </div>
+        </div>
+
+    </section>
+
+
+</div>
+
+@push('scripts')
+    
+    
+@endpush
+
+@push('scripts')
+    <script>
+
+        $(document).ready(function() {
+            
+        } );
+
+        Livewire.on('load-data-table', () => {
+            
+        });
+
+        function save()
+        {
+            var ids = [];
+            $('input[type=checkbox]').each(function () {
+                if ($(this).is(":checked")) 
+                {
+                    var val = $(this).val();
+                    ids.push(val);
+                }
+            });
+
+            @this.save(ids);
+        }
+        
+    </script>
+@endpush

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

@@ -59,6 +59,13 @@
                     </div>
                 </a>
                 <hr size="1">
+                <a href="/courts">
+                    <div class="row">
+                        <div class="col-md-11 p-2"><h5>Campi</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="/courses">
                     <div class="row">
                         <div class="col-md-11 p-2"><h5>Corsi</h5></div>

+ 3 - 0
routes/web.php

@@ -112,6 +112,9 @@ Route::group(['middleware' => 'auth'], function () {
     Route::get('/rates', \App\Http\Livewire\Rate::class);
     Route::get('/reports', \App\Http\Livewire\Reports::class);
     Route::get('/azienda', \App\Http\Livewire\Azienda::class);
+    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('/receipt/{id}', function ($id) {

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff