All pages updated with all features including filters

This commit is contained in:
tanmaychinchore
2025-10-08 20:08:52 +05:30
parent e07ac3f604
commit 8fe0ef8112
20 changed files with 3194 additions and 175 deletions

View File

@@ -0,0 +1,84 @@
<?php
namespace App\DataTables;
use App\Models\ActivitiesOrganised;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\Editor\Editor;
use Yajra\DataTables\Html\Editor\Fields;
use Yajra\DataTables\Services\DataTable;
class ActivitiesOrganisedDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->addColumn('action', 'activitiesorganised.action')
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(ActivitiesOrganised $model): QueryBuilder
{
return $model->newQuery();
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('activitiesorganised-table')
->columns($this->getColumns())
->minifiedAjax()
//->dom('Bfrtip')
->orderBy(1)
->selectStyleSingle()
->buttons([
Button::make('excel'),
Button::make('csv'),
Button::make('pdf'),
Button::make('print'),
Button::make('reset'),
Button::make('reload')
]);
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::computed('action')
->exportable(false)
->printable(false)
->width(60)
->addClass('text-center'),
Column::make('id'),
Column::make('add your columns'),
Column::make('created_at'),
Column::make('updated_at'),
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'ActivitiesOrganised_' . date('YmdHis');
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace App\DataTables;
use App\Models\BooksPublished;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\Editor\Editor;
use Yajra\DataTables\Html\Editor\Fields;
use Yajra\DataTables\Services\DataTable;
class BooksPublishedDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->addColumn('action', 'bookspublished.action')
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(BooksPublished $model): QueryBuilder
{
return $model->newQuery();
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('bookspublished-table')
->columns($this->getColumns())
->minifiedAjax()
//->dom('Bfrtip')
->orderBy(1)
->selectStyleSingle()
->buttons([
Button::make('excel'),
Button::make('csv'),
Button::make('pdf'),
Button::make('print'),
Button::make('reset'),
Button::make('reload')
]);
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::computed('action')
->exportable(false)
->printable(false)
->width(60)
->addClass('text-center'),
Column::make('id'),
Column::make('add your columns'),
Column::make('created_at'),
Column::make('updated_at'),
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'BooksPublished_' . date('YmdHis');
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace App\DataTables;
use App\Models\IndustrialVisitOrganised;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\Editor\Editor;
use Yajra\DataTables\Html\Editor\Fields;
use Yajra\DataTables\Services\DataTable;
class IndustrialVisitOrganisedDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->addColumn('action', 'industrialvisitorganised.action')
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(IndustrialVisitOrganised $model): QueryBuilder
{
return $model->newQuery();
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('industrialvisitorganised-table')
->columns($this->getColumns())
->minifiedAjax()
//->dom('Bfrtip')
->orderBy(1)
->selectStyleSingle()
->buttons([
Button::make('excel'),
Button::make('csv'),
Button::make('pdf'),
Button::make('print'),
Button::make('reset'),
Button::make('reload')
]);
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::computed('action')
->exportable(false)
->printable(false)
->width(60)
->addClass('text-center'),
Column::make('id'),
Column::make('add your columns'),
Column::make('created_at'),
Column::make('updated_at'),
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'IndustrialVisitOrganised_' . date('YmdHis');
}
}

View File

@@ -105,7 +105,7 @@ class BooksPublishedController extends Controller
return response()->json(['success' => 'Publication deleted successfully']); return response()->json(['success' => 'Publication deleted successfully']);
} }
public function getBooksPublishedResponses() public function getBooksPublishedResponses(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$isAdmin = $user->role->name === 'Admin'; $isAdmin = $user->role->name === 'Admin';
@@ -127,6 +127,21 @@ class BooksPublishedController extends Controller
->where('faculty_id', $user->id); ->where('faculty_id', $user->id);
} }
// Apply filters
if ($request->has('department_id') && !empty($request->department_id)) {
$booksPublisheds->whereHas('department', function ($query) use ($request) {
$query->where('id', $request->department_id);
});
}
if ($request->has('publisher') && !empty($request->publisher)) {
$booksPublisheds->where('publisher', $request->publisher);
}
if ($request->has('date_of_publication') && !empty($request->date_of_publication)) {
$booksPublisheds->where('date_of_publication', $request->date_of_publication);
}
return DataTables::of($booksPublisheds) return DataTables::of($booksPublisheds)
->addColumn('user_name', function ($booksPublished) { ->addColumn('user_name', function ($booksPublished) {
return $booksPublished->user->name ?? 'Unknown'; return $booksPublished->user->name ?? 'Unknown';
@@ -149,14 +164,26 @@ class BooksPublishedController extends Controller
->addColumn('date_of_publication', function ($booksPublished) { ->addColumn('date_of_publication', function ($booksPublished) {
return \Carbon\Carbon::parse($booksPublished->date_of_publication)->format('d-m-Y'); return \Carbon\Carbon::parse($booksPublished->date_of_publication)->format('d-m-Y');
}) })
->filterColumn('user_name', function($query, $keyword) {
$query->whereHas('user', fn($q) => $q->where('name', 'like', "%{$keyword}%"));
})
->filterColumn('author', fn($query, $keyword) =>
$query->where('author', 'like', "%{$keyword}%")
)
->filterColumn('title', fn($query, $keyword) =>
$query->where('title', 'like', "%{$keyword}%")
)
->filterColumn('issn', fn($query, $keyword) =>
$query->where('issn', 'like', "%{$keyword}%")
)
->addColumn('action', function ($booksPublished) { ->addColumn('action', function ($booksPublished) {
$actions = []; $actions = [];
// View proof button for everyone // View proof button for everyone
if ($booksPublished->proof) { if ($booksPublished->proof) {
$actions[] = '<a href="' . asset('storage/' . $booksPublished->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>'; $actions[] = '<a href="' . asset('storage/' . $booksPublished->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1"><i class="fas fa-eye"></i></a>';
} else { } else {
$actions[] = 'No Proof'; $actions[] = '<span class="text-muted"><i class="fas fa-times-circle"></i></span>';
} }
// Edit button with role-appropriate route // Edit button with role-appropriate route
@@ -170,10 +197,10 @@ class BooksPublishedController extends Controller
$editRoute = route('faculty.BooksPublished.edit', $booksPublished->id); $editRoute = route('faculty.BooksPublished.edit', $booksPublished->id);
} }
$actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1">Edit</a>'; $actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1"><i class="fas fa-edit"></i></a>';
$deleteRoute = route('booksPublished.destroy', $booksPublished->id); $deleteRoute = route('booksPublished.destroy', $booksPublished->id);
$actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $booksPublished->id . '" data-url="' . $deleteRoute . '">Delete</button>'; $actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $booksPublished->id . '" data-url="' . $deleteRoute . '"><i class="fas fa-trash"></i></button>';
return implode(' ', $actions); return implode(' ', $actions);
}) })

View File

@@ -31,6 +31,10 @@ class ExternalEngagementController extends Controller
'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip', 'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip',
]); ]);
// Combine start date and time
$startDateTime = date('Y-m-d H:i:s', strtotime("{$validated['start_date']} {$validated['start_time']}"));
$endDateTime = date('Y-m-d H:i:s', strtotime("{$validated['end_date']} {$validated['end_time']}"));
// Handle the file upload if a new file is provided // Handle the file upload if a new file is provided
if ($request->hasFile('proof')) { if ($request->hasFile('proof')) {
// Delete old file if exists // Delete old file if exists
@@ -94,7 +98,7 @@ class ExternalEngagementController extends Controller
return response()->json(['success' => 'External Engagement record deleted successfully']); return response()->json(['success' => 'External Engagement record deleted successfully']);
} }
public function getExternalEngagementResponses() public function getExternalEngagementResponses(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$isAdmin = $user->role->name === 'Admin'; $isAdmin = $user->role->name === 'Admin';
@@ -116,6 +120,24 @@ class ExternalEngagementController extends Controller
->where('faculty_id', $user->id); ->where('faculty_id', $user->id);
} }
// Apply filters
if ($request->has('department') && !empty($request->department)) {
$externalEngagements->whereHas('department', function ($query) use ($request) {
$query->where('id', $request->department);
});
}
if ($request->has('activity') && !empty($request->activity)) {
$externalEngagements->where('activity', $request->activity);
}
if ($request->has('dateFrom') && !empty($request->dateFrom)) {
$externalEngagements->where('start_date', '>=', $request->dateFrom);
}
if ($request->has('dateTo') && !empty($request->dateTo)) {
$externalEngagements->where('end_date', '<=', $request->dateTo);
}
return DataTables::of($externalEngagements) return DataTables::of($externalEngagements)
->addColumn('user_name', function ($externalEngagement) { ->addColumn('user_name', function ($externalEngagement) {
@@ -142,6 +164,20 @@ class ExternalEngagementController extends Controller
->addColumn('num_days', function ($externalEngagement) { ->addColumn('num_days', function ($externalEngagement) {
return $externalEngagement->num_days ?? 'Unknown'; return $externalEngagement->num_days ?? 'Unknown';
}) })
->filterColumn('user_name', function($query, $keyword) {
$query->whereHas('user', function($q) use ($keyword) {
$q->where('name', 'like', "%{$keyword}%");
});
})
->filterColumn('activity_description', function($query, $keyword) {
$query->where('activity_description', 'like', "%{$keyword}%");
})
->filterColumn('inviting_organization', function($query, $keyword) {
$query->where('inviting_organization', 'like', "%{$keyword}%");
})
->filterColumn('num_days', function($query, $keyword) {
$query->where('num_days', 'like', "%{$keyword}%");
})
->addColumn('action', function ($externalEngagement) { ->addColumn('action', function ($externalEngagement) {
$actions = []; $actions = [];
@@ -149,7 +185,7 @@ class ExternalEngagementController extends Controller
if ($externalEngagement->proof) { if ($externalEngagement->proof) {
$actions[] = '<a href="' . asset('storage/' . $externalEngagement->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>'; $actions[] = '<a href="' . asset('storage/' . $externalEngagement->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>';
} else { } else {
$actions[] = 'No Proof'; $actions[] = '<span class="text-muted"><i class="fas fa-times-circle"></i></span>';
} }
// Edit button with role-appropriate route // Edit button with role-appropriate route
@@ -163,10 +199,10 @@ class ExternalEngagementController extends Controller
$editRoute = route('faculty.ExternalEngagement.edit', $externalEngagement->id); $editRoute = route('faculty.ExternalEngagement.edit', $externalEngagement->id);
} }
$actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1">Edit</a>'; $actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1"><i class="fas fa-edit"></i></a>';
$deleteRoute = route('externalEngagement.destroy', $externalEngagement->id); $deleteRoute = route('externalEngagement.destroy', $externalEngagement->id);
$actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $externalEngagement->id . '" data-url="' . $deleteRoute . '">Delete</button>'; $actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $externalEngagement->id . '" data-url="' . $deleteRoute . '"><i class="fas fa-trash"></i></button>';
return implode(' ', $actions); return implode(' ', $actions);
}) })

View File

@@ -52,6 +52,7 @@ class IvOrganisedController extends Controller
// Extract year from start_date // Extract year from start_date
$year = date('Y', strtotime($validated['start_date'])); $year = date('Y', strtotime($validated['start_date']));
$username = $response->user->name; $username = $response->user->name;
$userId = $response->user->id;
$originalName = $request->file('proof')->getClientOriginalName(); $originalName = $request->file('proof')->getClientOriginalName();
$fileName = $username . '_' . $originalName; $fileName = $username . '_' . $originalName;
@@ -109,12 +110,12 @@ class IvOrganisedController extends Controller
return response()->json(['success' => 'Industrial visit record deleted successfully']); return response()->json(['success' => 'Industrial visit record deleted successfully']);
} }
public function getIvOrganisedResponses() public function getIvOrganisedResponses(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$isAdmin = $user->role->name === 'Admin'; $isAdmin = $user->role->name === 'Admin';
$isCoordinator = $user->role->name === 'Coordinator'; $isCoordinator = $user->role->name === 'Coordinator';
// Query based on role // Query based on role
if ($isAdmin) { if ($isAdmin) {
// Admin sees all records // Admin sees all records
@@ -131,6 +132,25 @@ class IvOrganisedController extends Controller
->where('faculty_id', $user->id); ->where('faculty_id', $user->id);
} }
// Apply filters
if ($request->has('department') && !empty($request->department)) {
$responses->whereHas('department', function ($query) use ($request) {
$query->where('id', $request->department);
});
}
if ($request->has('target_audience') && !empty($request->target_audience)) {
$responses->where('target_audience', $request->target_audience);
}
if ($request->has('dateFrom') && !empty($request->dateFrom)) {
$responses->where('start_date', '>=', $request->dateFrom);
}
if ($request->has('dateTo') && !empty($request->dateTo)) {
$responses->where('end_date', '<=', $request->dateTo);
}
return DataTables::of($responses) return DataTables::of($responses)
->addColumn('user_name', function ($response) { ->addColumn('user_name', function ($response) {
return $response->user->name ?? 'Unknown'; return $response->user->name ?? 'Unknown';
@@ -157,7 +177,7 @@ class IvOrganisedController extends Controller
if ($response->proof) { if ($response->proof) {
$actions[] = '<a href="' . asset('storage/' . $response->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>'; $actions[] = '<a href="' . asset('storage/' . $response->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>';
} else { } else {
$actions[] = 'No Proof'; $actions[] = '<span class="text-muted"><i class="fas fa-times-circle"></i></span>';
} }
// Edit button with role-appropriate route // Edit button with role-appropriate route
@@ -171,10 +191,10 @@ class IvOrganisedController extends Controller
$editRoute = route('faculty.IvOrganised.edit', $response->id); $editRoute = route('faculty.IvOrganised.edit', $response->id);
} }
$actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1">Edit</a>'; $actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1"><i class="fas fa-edit"></i></a>';
$deleteRoute = route('ivOrganised.destroy', $response->id); $deleteRoute = route('ivOrganised.destroy', $response->id);
$actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $response->id . '" data-url="' . $deleteRoute . '">Delete</button>'; $actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $response->id . '" data-url="' . $deleteRoute . '"><i class="fas fa-trash"></i></button>';
return implode(' ', $actions); return implode(' ', $actions);
}) })
@@ -201,7 +221,7 @@ class IvOrganisedController extends Controller
'end_time' => 'required|date_format:H:i', 'end_time' => 'required|date_format:H:i',
'faculty_id' => 'required|exists:users,id', 'faculty_id' => 'required|exists:users,id',
'department_id' => 'required|exists:departments,id', 'department_id' => 'required|exists:departments,id',
'proof' => 'required|mimes:jpg,jpeg,png,pdf,doc,docx,zip', 'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip',
]); ]);
// Combine start date and time // Combine start date and time

View File

@@ -30,6 +30,10 @@ class OnlineCoursesController extends Controller
'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip', 'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip',
]); ]);
// Combine start date and time
$startDateTime = date('Y-m-d H:i:s', strtotime("{$validated['start_date']} {$validated['start_time']}"));
$endDateTime = date('Y-m-d H:i:s', strtotime("{$validated['end_date']} {$validated['end_time']}"));
// Handle the file upload if a new file is provided // Handle the file upload if a new file is provided
if ($request->hasFile('proof')) { if ($request->hasFile('proof')) {
// Delete old file if exists // Delete old file if exists
@@ -40,6 +44,7 @@ class OnlineCoursesController extends Controller
// Extract year from start_date // Extract year from start_date
$year = date('Y', strtotime($validated['start_date'])); $year = date('Y', strtotime($validated['start_date']));
$username = $onlineCourse->user->name; $username = $onlineCourse->user->name;
$userId = $onlineCourse->user->id;
$originalName = $request->file('proof')->getClientOriginalName(); $originalName = $request->file('proof')->getClientOriginalName();
$fileName = $username . '_' . $originalName; $fileName = $username . '_' . $originalName;
@@ -92,7 +97,7 @@ class OnlineCoursesController extends Controller
return response()->json(['success' => 'online Course record deleted successfully']); return response()->json(['success' => 'online Course record deleted successfully']);
} }
public function getOnlineCoursesResponses() public function getOnlineCoursesResponses(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$isAdmin = $user->role->name === 'Admin'; $isAdmin = $user->role->name === 'Admin';
@@ -114,6 +119,24 @@ class OnlineCoursesController extends Controller
->where('faculty_id', $user->id); ->where('faculty_id', $user->id);
} }
// Apply filters
if ($request->has('department') && !empty($request->department)) {
$onlineCourses->whereHas('department', function ($query) use ($request) {
$query->where('id', $request->department);
});
}
if ($request->has('offered_by') && !empty($request->offered_by)) {
$onlineCourses->where('offered_by', $request->offered_by);
}
if ($request->has('dateFrom') && !empty($request->dateFrom)) {
$onlineCourses->where('start_date', '>=', $request->dateFrom);
}
if ($request->has('dateTo') && !empty($request->dateTo)) {
$onlineCourses->where('end_date', '<=', $request->dateTo);
}
return DataTables::of($onlineCourses) return DataTables::of($onlineCourses)
->addColumn('user_name', function ($onlineCourse) { ->addColumn('user_name', function ($onlineCourse) {
@@ -122,9 +145,17 @@ class OnlineCoursesController extends Controller
->addColumn('department_name', function ($onlineCourse) { ->addColumn('department_name', function ($onlineCourse) {
return $onlineCourse->department->name ?? 'Unknown'; return $onlineCourse->department->name ?? 'Unknown';
}) })
->filterColumn('user_name', function($query, $keyword) {
$query->whereHas('user', function($q) use ($keyword) {
$q->where('name', 'like', "%{$keyword}%");
});
})
->addColumn('course', function ($onlineCourse) { ->addColumn('course', function ($onlineCourse) {
return $onlineCourse->course ?? 'Unknown'; return $onlineCourse->course ?? 'Unknown';
}) })
->filterColumn('course', function($query, $keyword) {
$query->where('course', 'like', "%{$keyword}%");
})
->addColumn('offered_by', function ($onlineCourse) { ->addColumn('offered_by', function ($onlineCourse) {
return $onlineCourse->offered_by ?? 'Unknown'; return $onlineCourse->offered_by ?? 'Unknown';
}) })
@@ -137,14 +168,17 @@ class OnlineCoursesController extends Controller
->addColumn('num_days', function ($onlineCourse) { ->addColumn('num_days', function ($onlineCourse) {
return $onlineCourse->num_days ?? 'Unknown'; return $onlineCourse->num_days ?? 'Unknown';
}) })
->filterColumn('num_days', function($query, $keyword) {
$query->where('num_days', 'like', "%{$keyword}%");
})
->addColumn('action', function ($onlineCourse) { ->addColumn('action', function ($onlineCourse) {
$actions = []; $actions = [];
// View proof button for everyone // View proof button for everyone
if ($onlineCourse->proof) { if ($onlineCourse->proof) {
$actions[] = '<a href="' . asset('storage/' . $onlineCourse->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>'; $actions[] = '<a href="' . asset('storage/' . $onlineCourse->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1"><i class="fas fa-eye"></i></a>';
} else { } else {
$actions[] = 'No Proof'; $actions[] = '<span class="text-muted"><i class="fas fa-times-circle"></i></span>';
} }
// Edit button with role-appropriate route // Edit button with role-appropriate route
@@ -158,10 +192,10 @@ class OnlineCoursesController extends Controller
$editRoute = route('faculty.OnlineCourses.edit', $onlineCourse->id); $editRoute = route('faculty.OnlineCourses.edit', $onlineCourse->id);
} }
$actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1">Edit</a>'; $actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1"><i class="fas fa-edit"></i></a>';
$deleteRoute = route('onlineCourses.destroy', $onlineCourse->id); $deleteRoute = route('onlineCourses.destroy', $onlineCourse->id);
$actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $onlineCourse->id . '" data-url="' . $deleteRoute . '">Delete</button>'; $actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $onlineCourse->id . '" data-url="' . $deleteRoute . '"><i class="fas fa-trash"></i></button>';
return implode(' ', $actions); return implode(' ', $actions);
}) })

View File

@@ -2,10 +2,9 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\OnlineCourse;
use App\Models\Patent;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables; use Yajra\DataTables\Facades\DataTables;
use App\Models\Patent;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
class PatentsController extends Controller class PatentsController extends Controller
@@ -13,8 +12,11 @@ class PatentsController extends Controller
public function edit($id) public function edit($id)
{ {
$patent = Patent::findOrFail($id); $patent = Patent::findOrFail($id);
$organisingInstitutes = Publication::select('organizing_institute')
->distinct()
->pluck('organizing_institute');
return view('pages.patents.edit', compact('patent')); return view('pages.patents.edit', compact('patent', 'organisingInstitutes'));
} }
public function update(Request $request, $id) public function update(Request $request, $id)
@@ -33,6 +35,10 @@ class PatentsController extends Controller
'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip', 'proof' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx,zip',
]); ]);
// Combine start date and time
$startDateTime = date('Y-m-d H:i:s', strtotime("{$validated['start_date']} {$validated['start_time']}"));
$endDateTime = date('Y-m-d H:i:s', strtotime("{$validated['end_date']} {$validated['end_time']}"));
// Handle the file upload if a new file is provided // Handle the file upload if a new file is provided
if ($request->hasFile('proof')) { if ($request->hasFile('proof')) {
// Delete old file if exists // Delete old file if exists
@@ -43,6 +49,7 @@ class PatentsController extends Controller
// Extract year from start_date // Extract year from start_date
$year = date('Y', strtotime($validated['date_of_submission'])); $year = date('Y', strtotime($validated['date_of_submission']));
$username = $patent->user->name; $username = $patent->user->name;
$userId = $patent->user->id;
$originalName = $request->file('proof')->getClientOriginalName(); $originalName = $request->file('proof')->getClientOriginalName();
$fileName = $username . '_' . $originalName; $fileName = $username . '_' . $originalName;
@@ -97,7 +104,7 @@ class PatentsController extends Controller
return response()->json(['success' => 'patent record deleted successfully']); return response()->json(['success' => 'patent record deleted successfully']);
} }
public function getPatentsResponses() public function getPatentsResponses(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$isAdmin = $user->role->name === 'Admin'; $isAdmin = $user->role->name === 'Admin';
@@ -119,6 +126,24 @@ class PatentsController extends Controller
->where('faculty_id', $user->id); ->where('faculty_id', $user->id);
} }
// Apply filters
if ($request->has('department') && !empty($request->department)) {
$patents->whereHas('department', function ($query) use ($request) {
$query->where('id', $request->department);
});
}
if ($request->has('status') && !empty($request->status)) {
$patents->where('status', $request->status);
}
if ($request->has('dateFrom') && !empty($request->dateFrom)) {
$patents->where('date_of_submission', '>=', $request->dateFrom);
}
if ($request->has('dateTo') && !empty($request->dateTo)) {
$patents->where('date_of_submission', '<=', $request->dateTo);
}
return DataTables::of($patents) return DataTables::of($patents)
->addColumn('user_name', function ($patent) { ->addColumn('user_name', function ($patent) {
@@ -148,14 +173,31 @@ class PatentsController extends Controller
->addColumn('status', function ($patent) { ->addColumn('status', function ($patent) {
return $patent->status ?? 'Unknown'; return $patent->status ?? 'Unknown';
}) })
->filterColumn('user_name', function($query, $keyword) {
$query->whereHas('user', function($q) use ($keyword) {
$q->where('name', 'like', "%{$keyword}%");
});
})
->filterColumn('title', function($query, $keyword) {
$query->where('title', 'like', "%{$keyword}%");
})
->filterColumn('investigator', function($query, $keyword) {
$query->where('investigator', 'like', "%{$keyword}%");
})
->filterColumn('application_no', function($query, $keyword) {
$query->where('application_no', 'like', "%{$keyword}%");
})
->filterColumn('type', function($query, $keyword) {
$query->where('type', 'like', "%{$keyword}%");
})
->addColumn('action', function ($patent) { ->addColumn('action', function ($patent) {
$actions = []; $actions = [];
// View proof button for everyone // View proof button for everyone
if ($patent->proof) { if ($patent->proof) {
$actions[] = '<a href="' . asset('storage/' . $patent->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1">View</a>'; $actions[] = '<a href="' . asset('storage/' . $patent->proof) . '" target="_blank" class="btn btn-sm btn-primary mr-1"><i class="fas fa-eye"></i></a>';
} else { } else {
$actions[] = 'No Proof'; $actions[] = '<span class="text-muted"><i class="fas fa-times-circle"></i></span>';
} }
// Edit button with role-appropriate route // Edit button with role-appropriate route
@@ -169,10 +211,10 @@ class PatentsController extends Controller
$editRoute = route('faculty.Patents.edit', $patent->id); $editRoute = route('faculty.Patents.edit', $patent->id);
} }
$actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1">Edit</a>'; $actions[] = '<a href="' . $editRoute . '" class="btn btn-sm btn-info mx-1"><i class="fas fa-edit"></i></a>';
$deleteRoute = route('patents.destroy', $patent->id); $deleteRoute = route('patents.destroy', $patent->id);
$actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $patent->id . '" data-url="' . $deleteRoute . '">Delete</button>'; $actions[] = '<button type="button" class="btn btn-sm btn-danger delete-btn" data-id="' . $patent->id . '" data-url="' . $deleteRoute . '"><i class="fas fa-trash"></i></button>';
return implode(' ', $actions); return implode(' ', $actions);
}) })

View File

@@ -111,7 +111,7 @@
</div> </div>
<div> <div>
<label for="proof" class="block text-sm font-medium text-gray-700">Upload Proof/Document</label> <label for="proof" class="block text-sm font-medium text-gray-700">Upload Proof/Document</label>
<input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip" required> <input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -77,7 +77,7 @@
<!-- proof File --> <!-- proof File -->
<div> <div>
<label for="proof_file" class="block text-sm font-medium text-gray-700">Upload Proof</label> <label for="proof_file" class="block text-sm font-medium text-gray-700">Upload Proof</label>
<input type="file" name="proof_file" id="proof_file" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip" required> <input type="file" name="proof_file" id="proof_file" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip">
<p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p> <p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p>
</div> </div>
</div> </div>

View File

@@ -77,7 +77,7 @@
<!-- proof --> <!-- proof -->
<div> <div>
<label for="proof" class="block text-sm font-medium text-gray-700">Upload Paper</label> <label for="proof" class="block text-sm font-medium text-gray-700">Upload Paper</label>
<input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip" required> <input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip">
<p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p> <p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p>
</div> </div>
</div> </div>

View File

@@ -113,7 +113,7 @@
<!-- Proof Document --> <!-- Proof Document -->
<div> <div>
<label for="proof" class="block text-sm font-medium text-gray-700">Upload Proof/Document</label> <label for="proof" class="block text-sm font-medium text-gray-700">Upload Proof/Document</label>
<input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip" required> <input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip">
<p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p> <p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p>
</div> </div>
</div> </div>

View File

@@ -71,7 +71,7 @@
<!-- proof --> <!-- proof -->
<div> <div>
<label for="proof" class="block text-sm font-medium text-gray-700">Upload Paper</label> <label for="proof" class="block text-sm font-medium text-gray-700">Upload Paper</label>
<input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip" required> <input type="file" name="proof" id="proof" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.zip">
<p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p> <p class="mt-1 text-xs text-gray-500">Accepted formats: JPG, JPEG, PNG, PDF, DOC, DOCX, ZIP</p>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-list-alt me-2 text-danger"></i>All Responses <i class="fas fa-list-alt me-2 text-danger"></i>All Activities Attended
</h3> </h3>
<x-send-email /> <x-send-email />
@@ -18,12 +18,22 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="input-group"> <div class="input-group">
<span class="input-group-text bg-light">Department</span> <span class="input-group-text bg-light">Department</span>
<select id="department-filter" class="form-select"> @if(auth()->user()->role_id == 1)
<option value="">All Departments</option> {{-- Admin: can choose any department --}}
@foreach($departments as $department) <select id="department-filter" class="form-select">
<option value="{{ $department->id }}">{{ $department->name }}</option> <option value="">All Departments</option>
@endforeach @foreach($departments as $department)
</select> <option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div> </div>
</div> </div>
@@ -150,7 +160,7 @@
}); });
} }
const sheetName = "Responses Report"; const sheetName = "Activities Attended Report";
let table; // Declare table variable in the outer scope let table; // Declare table variable in the outer scope
function exportOptions() { function exportOptions() {
@@ -206,83 +216,29 @@
d.dateTo = $('#date-to').val(); d.dateTo = $('#date-to').val();
} }
}, },
columns: [{ columns: [
{
data: null, data: null,
defaultContent: '', defaultContent: '',
orderable: false, orderable: false,
searchable: false searchable: false
}, },
{ { data: 'id', name: 'id', searchable: false },
data: 'id', { data: 'title', name: 'title', orderable: false },
name: 'id', { data: 'organising_institute', name: 'organising_institute', orderable: false },
searchable: false { data: 'address', name: 'address', orderable: false },
}, { data: 'department_name', name: 'department_name', orderable: false, searchable: false },
{ { data: 'user_name', name: 'user_name', orderable: false },
data: 'title', { data: 'start_date', name: 'start_date', orderable: false },
name: 'title', { data: 'end_date', name: 'end_date', orderable: false },
orderable: false { data: 'num_days', name: 'num_days', orderable: false },
}, { data: 'activity_type', name: 'activity_type', orderable: false },
{ { data: 'category', name: 'category', orderable: false, searchable: false },
data: 'organising_institute', { data: 'level', name: 'level', orderable: false },
name: 'organising_institute', { data: 'action', name: 'proof', orderable: false, searchable: false }
orderable: false
},
{
data: 'address',
name: 'address',
orderable: false
},
{
data: 'department_name',
name: 'department_name',
orderable: false,
searchable: false
},
{
data: 'user_name',
name: 'user_name',
orderable: false
},
{
data: 'start_date',
name: 'start_date',
orderable: false
},
{
data: 'end_date',
name: 'end_date',
orderable: false
},
{
data: 'num_days',
name: 'num_days',
orderable: false
},
{
data: 'activity_type',
name: 'activity_type',
orderable: false
},
{
data: 'category',
name: 'category',
orderable: false,
searchable: false
},
{
data: 'level',
name: 'level',
orderable: false
},
{
data: 'action',
name: 'proof',
orderable: false,
searchable: false
}
], ],
columnDefs: [{ columnDefs: [
{
targets: 0, targets: 0,
orderable: false, orderable: false,
className: 'select-checkbox', className: 'select-checkbox',
@@ -306,7 +262,8 @@
} }
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [{ buttons: [
{
extend: 'copy', extend: 'copy',
text: '<i class="fas fa-copy me-1"></i> Copy', text: '<i class="fas fa-copy me-1"></i> Copy',
className: 'btn btn-sm btn-outline-white', className: 'btn btn-sm btn-outline-white',
@@ -486,13 +443,13 @@
toastEl.setAttribute('aria-atomic', 'true'); toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = ` toastEl.innerHTML = `
<div class="d-flex"> <div class="d-flex">
<div class="toast-body"> <div class="toast-body">
${message} ${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div> </div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button> `;
</div>
`;
toastContainer.appendChild(toastEl); toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer); document.body.appendChild(toastContainer);

View File

@@ -18,12 +18,22 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="input-group"> <div class="input-group">
<span class="input-group-text bg-light">Department</span> <span class="input-group-text bg-light">Department</span>
<select id="department-filter" class="form-select"> @if(auth()->user()->role_id == 1)
<option value="">All Departments</option> {{-- Admin: can choose any department --}}
@foreach($departments as $department) <select id="department-filter" class="form-select">
<option value="{{ $department->id }}">{{ $department->name }}</option> <option value="">All Departments</option>
@endforeach @foreach($departments as $department)
</select> <option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div> </div>
</div> </div>
@@ -237,7 +247,10 @@
'<input type="checkbox" disabled>'; '<input type="checkbox" disabled>';
} }
}, },
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: '_all',
className: 'text-center wrap-text'
},
{ {
targets: 13, targets: 13,
render: function(data, type, row) { render: function(data, type, row) {
@@ -471,6 +484,9 @@
toggleColumnVisibility(); toggleColumnVisibility();
}); });
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button // Select all columns button
$('#select-all-columns').click(function() { $('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change'); $('.column-checkbox').prop('checked', true).trigger('change');
@@ -589,6 +605,7 @@
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
} }
/* Ensure the table container is responsive */ /* Ensure the table container is responsive */
.table-responsive { .table-responsive {
overflow-x: auto; overflow-x: auto;

View File

@@ -9,13 +9,86 @@
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-book me-2 text-primary"></i>All Books Published <i class="fas fa-book me-2 text-primary"></i>All Books Published
</h3> </h3>
<!-- Include the reusable send-email component -->
<x-send-email />
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- Filter Controls -->
<div class="row mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Department</span>
@if(auth()->user()->role_id == 1)
{{-- Admin: can choose any department --}}
<select id="department-filter" class="form-select">
<option value="">All Departments</option>
@foreach($departments as $department)
<option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Publisher</span>
<select id="publisher-filter" class="form-select">
<option value="">All Publishers</option>
<option value="Bloomsbury Publishing">Bloomsbury Publishing</option>
<option value="Scholastic India">Scholastic India</option>
<option value="Penguin Random House">Penguin Random House</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Date of Publication</span>
<input type="date" id="date-filter" class="form-control">
</div>
</div>
</div>
<!-- Column Selector -->
<div class="flex justify-between col-md-12 mt-3 mb-4">
<!-- Include the reusable download-proofs component -->
<x-download-proofs :route="route('admin.downloadProofs')" :model="'BooksPublished'" />
@php
use Illuminate\Support\Str;
$labels = [
'Title',
'Author',
'Publisher',
'Date of Publication',
'ISSN/eISSN number',
'Department',
];
$columns = [];
foreach ($labels as $i => $label) {
$columns[] = [
'label' => $label,
'id' => 'column-' . Str::slug($label, '-'),
'value' => $i + 2,
'checked' => true,
];
}
@endphp
<x-column-selector :columns="$columns" />
</div>
<!-- Table --> <!-- Table -->
<div class="table-responsive"> <div class="table-responsive">
<table id="booksPublished-table" class="table table-striped table-hover"> <table id="booksPublished-table" class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th class="select-checkbox"></th>
<th>ID</th> <th>ID</th>
<th>Title</th> <th>Title</th>
<th>Author</th> <th>Author</th>
@@ -39,31 +112,132 @@
@endsection @endsection
@section('scripts') @section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" integrity="sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
const downloadProofsRoute = "{{ route('admin.downloadProofs') }}";
const currentModel = "{{ isset($model) ? $model : 'BooksPublished' }}";
const csrf_token = "{{ csrf_token() }}";
$(document).ready(function() { $(document).ready(function() {
const sheetName = "Books Published"; // Handle "Select All" checkbox for missing proofs modal
$('#selectAll').change(function() {
const isChecked = $(this).prop('checked');
$('input[name="categories[]"]').prop('checked', isChecked);
});
// Update "Select All" when individual checkboxes change
$('input[name="categories[]"]').change(function() {
const totalCheckboxes = $('input[name="categories[]"]').length;
const checkedCheckboxes = $('input[name="categories[]"]:checked').length;
$('#selectAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Form validation for the modal
const form = document.getElementById('missingProofsForm');
if (form) {
form.addEventListener('submit', function(e) {
const checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length === 0) {
e.preventDefault();
alert('Please select at least one category before sending emails.');
}
});
}
const sheetName = "Books Published Report";
let table; // Declare table variable in the outer scope
function exportOptions() {
return {
columns: ':visible',
format: {
body: function(data, row, column, node) {
if ($(node).find('select').length) {
return $(node).find("select option:selected").text();
}
return $(node).text();
}
}
};
}
// Function to toggle column visibility
function toggleColumnVisibility() {
$('.column-checkbox').each(function() {
const columnIndex = $(this).val();
const isChecked = $(this).is(':checked');
// Show or hide the column based on checkbox state
if (table) {
table.column(columnIndex).visible(isChecked);
}
});
// Adjust table layout only if table and responsive are initialized
if (table && table.responsive) {
table.columns.adjust().responsive.recalc();
} else if (table) {
table.columns.adjust();
}
}
var initAjaxRoute = function(route) { var initAjaxRoute = function(route) {
// If table already exists, destroy it before re-initializing
if ($.fn.DataTable.isDataTable('#booksPublished-table')) {
$('#booksPublished-table').DataTable().destroy();
}
table = $("#booksPublished-table").DataTable({ table = $("#booksPublished-table").DataTable({
fnDestroy: true,
processing: true, processing: true,
serverSide: true, serverSide: true,
responsive: true, responsive: true,
ajax: { ajax: {
url: route, url: route,
data: function(d) {
d.department_id = $('#department-filter').val();
d.publisher = $('#publisher-filter').val();
d.date_of_publication = $('#date-filter').val();
}
}, },
columns: [ columns: [
{
data: null,
defaultContent: '',
orderable: false,
searchable: false
},
{ data: 'id', name: 'id', searchable: false }, { data: 'id', name: 'id', searchable: false },
{ data: 'title', name: 'title', orderable: true }, { data: 'title', name: 'title', orderable: true },
{ data: 'author', name: 'author', orderable: true }, { data: 'author', name: 'author', orderable: true },
{ data: 'publisher', name: 'publisher', orderable: true }, { data: 'publisher', name: 'publisher', orderable: true },
{ data: 'date_of_publication', name: 'date_of_publication', orderable: true }, { data: 'date_of_publication', name: 'date_of_publication', orderable: true },
{ data: 'issn', name: 'issn', orderable: false }, { data: 'issn', name: 'issn', orderable: true },
{ data: 'department_name', name: 'department_name', orderable: false }, { data: 'department_name', name: 'department_name', orderable: true },
{ data: 'action', name: 'action', orderable: false, searchable: false }, { data: 'action', name: 'action', orderable: false, searchable: false },
], ],
columnDefs: [ columnDefs: [
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: 0,
orderable: false,
className: 'select-checkbox',
render: function(data, type, row) {
return row.proof ?
'<input type="checkbox" class="row-checkbox" data-id="' + row.id + '">' :
'<input type="checkbox" disabled>';
}
},
{
targets: '_all',
className: 'text-center wrap-text'
},
{
targets: 8,
render: function(data, type, row) {
return '<div class="btn-group" role="group">' +
data +
'</div>';
}
}
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [ buttons: [
@@ -84,8 +258,160 @@
next: "<i class='fas fa-angle-right'></i>", next: "<i class='fas fa-angle-right'></i>",
previous: "<i class='fas fa-angle-left'></i>" previous: "<i class='fas fa-angle-left'></i>"
} }
},
// Initialize the column visibility after table is drawn
initComplete: function() {
// Set column visibility
toggleColumnVisibility();
// Add select-all checkbox
addSelectAllCheckbox();
},
drawCallback: function() {
// Ensure select-all checkbox is present on redraw
addSelectAllCheckbox();
} }
}); });
// Apply filters when they change
$('#department-filter, #publisher-filter, #date-filter').change(function() {
table.ajax.reload();
});
return table;
};
// Delete button handler
$('#booksPublished-table').on('click', '.delete-btn', function() {
if (confirm('Are you sure you want to delete this record?')) {
const id = $(this).data('id');
const url = $(this).data('url');
$.ajax({
url: url,
type: 'DELETE',
data: {
"_token": "{{ csrf_token() }}"
},
success: function(result) {
table.ajax.reload();
showToast('Record deleted successfully', 'success');
},
error: function(error) {
console.error(error);
showToast('Error deleting record', 'danger');
}
});
}
});
// Handle row selection and Download button state
$('#booksPublished-table').on('change', '.row-checkbox', function() {
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
// Download proofs button handler
$('#download-proofs').on('click', function() {
const selectedIds = [];
$('.row-checkbox:checked').each(function() {
const id = $(this).data('id');
if (id) selectedIds.push(id);
});
if (selectedIds.length > 0) {
// Create a form to submit the request
const form = $('<form></form>')
.attr('method', 'POST')
.attr('action', downloadProofsRoute)
.css('display', 'none');
// Add CSRF token
$('<input>')
.attr('type', 'hidden')
.attr('name', '_token')
.attr('value', csrf_token)
.appendTo(form);
// Add selected IDs
$('<input>')
.attr('type', 'hidden')
.attr('name', 'ids')
.attr('value', JSON.stringify(selectedIds))
.appendTo(form);
// Add model name
$('<input>')
.attr('type', 'hidden')
.attr('name', 'model')
.attr('value', currentModel)
.appendTo(form);
$('body').append(form);
form.submit();
}
});
// Function to add select-all checkbox to the table header
function addSelectAllCheckbox() {
// Only add if it doesn't exist yet
if ($('#select-all-checkbox').length === 0) {
const selectAllCheckbox = $('<input>', {
type: 'checkbox',
id: 'select-all-checkbox',
class: 'form-check-input'
});
// Add to the first header column
$('#booksPublished-table thead th.select-checkbox').html(selectAllCheckbox);
// Handle the select all functionality
$('#select-all-checkbox').on('change', function() {
const isChecked = $(this).prop('checked');
$('.row-checkbox:not(:disabled)').prop('checked', isChecked);
// Update download button state
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
}
}
// Toast notification function
function showToast(message, type) {
const toastContainer = document.createElement('div');
toastContainer.className = 'position-fixed bottom-0 start-0 p-3';
toastContainer.style.zIndex = '1050';
const toastEl = document.createElement('div');
toastEl.className = `toast align-items-center text-white bg-${type} border-0`;
toastEl.setAttribute('role', 'alert');
toastEl.setAttribute('aria-live', 'assertive');
toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer);
const toast = new bootstrap.Toast(toastEl, {
autohide: true,
delay: 3000
});
toast.show();
toastEl.addEventListener('hidden.bs.toast', function() {
document.body.removeChild(toastContainer);
});
}; };
// Set appropriate route based on user role // Set appropriate route based on user role
@@ -99,7 +425,178 @@
dataRoute = "{{ route('faculty.BooksPublishedResponses.data') }}"; dataRoute = "{{ route('faculty.BooksPublishedResponses.data') }}";
} }
initAjaxRoute(dataRoute); // Initialize the data table
table = initAjaxRoute(dataRoute);
// Attach change event listener to column visibility checkboxes
$('.column-checkbox').on('change', function() {
toggleColumnVisibility();
});
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button
$('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change');
});
// Deselect all columns button
$('#deselect-all-columns').click(function() {
$('.column-checkbox').prop('checked', false).trigger('change');
});
// Prevent dropdown from closing when clicking inside it
$('.dropdown-menu').on('click', function(e) {
e.stopPropagation();
});
// Set department filter from query string if present
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const departmentId = urlParams.get('department_id');
if (departmentId) {
$('#department-filter').val(departmentId).trigger('change');
}
});
}); });
</script> </script>
<style>
.form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.dropdown-menu .form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu .form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus-visible {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.form-switch .form-check-input {
width: 2.5em;
margin-left: -2.8em;
position: relative;
}
.form-switch .form-check-input:focus {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
transition: background-position 0.15s ease-in-out;
}
/* Enhance the toggle appearance */
.form-switch .form-check-input {
background-size: contain;
transition: 0.2s;
}
.dropdown-menu {
max-height: 400px;
overflow-y: auto;
}
/* Ensure the table container is responsive */
.table-responsive {
overflow-x: auto;
white-space: nowrap;
}
/* Ensure the table fits within the container */
#booksPublished-table {
width: 100% !important;
}
.select-checkbox {
width: 30px;
text-align: center;
}
.select-checkbox input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.select-checkbox input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Style the Download button */
#download-proofs {
background-color: #28a745;
border-color: #28a745;
}
#download-proofs:hover:not(:disabled) {
background-color: #218838;
border-color: #218838;
}
#download-proofs:disabled {
opacity: 0.65;
cursor: not-allowed;
}
</style>
@endsection @endsection

View File

@@ -9,13 +9,93 @@
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-handshake me-2 text-primary"></i>All External Engagements <i class="fas fa-handshake me-2 text-primary"></i>All External Engagements
</h3> </h3>
<!-- Include the reusable send-email component -->
<x-send-email />
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- Filter Controls -->
<div class="row mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Department</span>
@if(auth()->user()->role_id == 1)
{{-- Admin: can choose any department --}}
<select id="department-filter" class="form-select">
<option value="">All Departments</option>
@foreach($departments as $department)
<option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Activity</span>
<select id="activity-filter" class="form-select">
<option value="">All Activities</option>
<option value="Research Collaboration Meet">Research Collaboration Meet</option>
<option value="Workshop Facilitator">Workshop Facilitator</option>
<option value="Technical Seminar">Technical Seminar</option>
<option value="Industry Training Program">Industry Training Program</option>
<option value="Guest Lecture">Guest Lecture</option>
<option value="Conference Speaker">Conference Speaker</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Date Range</span>
<input type="date" id="date-from" class="form-control">
<span class="input-group-text bg-light">to</span>
<input type="date" id="date-to" class="form-control">
</div>
</div>
</div>
<!-- Column Selector -->
<div class="flex justify-between col-md-12 mt-3 mb-4">
<!-- Include the reusable download-proofs component -->
<x-download-proofs :route="route('admin.downloadProofs')" :model="'ActivitiesOrganised'" />
@php
use Illuminate\Support\Str;
$labels = [
'Faculty',
'Department',
'Activity',
'Activity Description',
'Inviting Organization',
'Start Date',
'End Date',
'Num Days',
];
$columns = [];
foreach ($labels as $i => $label) {
$columns[] = [
'label' => $label,
'id' => 'column-' . Str::slug($label, '-'),
'value' => $i + 2,
'checked' => true,
];
}
@endphp
<x-column-selector :columns="$columns" />
</div>
<!-- Table --> <!-- Table -->
<div class="table-responsive"> <div class="table-responsive">
<table id="externalEngagement-table" class="table table-striped table-hover"> <table id="externalEngagement-table" class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th class="select-checkbox"></th>
<th>ID</th> <th>ID</th>
<th>Faculty</th> <th>Faculty</th>
<th>Department</th> <th>Department</th>
@@ -41,41 +121,173 @@
@endsection @endsection
@section('scripts') @section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" integrity="sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
const downloadProofsRoute = "{{ route('admin.downloadProofs') }}";
const currentModel = "{{ isset($model) ? $model : 'ExternalEngagement' }}";
const csrf_token = "{{ csrf_token() }}";
$(document).ready(function() { $(document).ready(function() {
const sheetName = "External Engagements"; // Handle "Select All" checkbox for missing proofs modal
$('#selectAll').change(function() {
const isChecked = $(this).prop('checked');
$('input[name="categories[]"]').prop('checked', isChecked);
});
// Update "Select All" when individual checkboxes change
$('input[name="categories[]"]').change(function() {
const totalCheckboxes = $('input[name="categories[]"]').length;
const checkedCheckboxes = $('input[name="categories[]"]:checked').length;
$('#selectAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Form validation for the modal
const form = document.getElementById('missingProofsForm');
if (form) {
form.addEventListener('submit', function(e) {
const checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length === 0) {
e.preventDefault();
alert('Please select at least one category before sending emails.');
}
});
}
const sheetName = "External Engagements Report";
let table; // Declare table variable in the outer scope
function exportOptions() {
return {
columns: ':visible',
format: {
body: function(data, row, column, node) {
if ($(node).find('select').length) {
return $(node).find("select option:selected").text();
}
return $(node).text();
}
}
};
}
// Function to toggle column visibility
function toggleColumnVisibility() {
$('.column-checkbox').each(function() {
const columnIndex = $(this).val();
const isChecked = $(this).is(':checked');
// Show or hide the column based on checkbox state
if (table) {
table.column(columnIndex).visible(isChecked);
}
});
// Adjust table layout only if table and responsive are initialized
if (table && table.responsive) {
table.columns.adjust().responsive.recalc();
} else if (table) {
table.columns.adjust();
}
}
var initAjaxRoute = function(route) { var initAjaxRoute = function(route) {
// If table already exists, destroy it before re-initializing
if ($.fn.DataTable.isDataTable('#externalEngagement-table')) {
$('#externalEngagement-table').DataTable().destroy();
}
table = $("#externalEngagement-table").DataTable({ table = $("#externalEngagement-table").DataTable({
fnDestroy: true,
processing: true, processing: true,
serverSide: true, serverSide: true,
responsive: true, responsive: true,
ajax: { ajax: {
url: route, url: route,
data: function(d) {
d.department = $('#department-filter').val();
d.activity = $('#activity-filter').val();
d.dateFrom = $('#date-from').val();
d.dateTo = $('#date-to').val();
}
}, },
columns: [ columns: [
{
data: null,
defaultContent: '',
orderable: false,
searchable: false
},
{ data: 'id', name: 'id', searchable: false }, { data: 'id', name: 'id', searchable: false },
{ data: 'user_name', name: 'user_name', orderable: true }, { data: 'user_name', name: 'user_name', orderable: true, searchable: true },
{ data: 'department_name', name: 'department_name', orderable: true }, { data: 'department_name', name: 'department_name', orderable: true },
{ data: 'activity', name: 'activity', orderable: true }, { data: 'activity', name: 'activity', orderable: true, searchable: true },
{ data: 'activity_description', name: 'activity_description', orderable: true }, { data: 'activity_description', name: 'activity_description', orderable: true, searchable: true },
{ data: 'inviting_organization', name: 'inviting_organization', orderable: false }, { data: 'inviting_organization', name: 'inviting_organization', orderable: true,searchable: true },
{ data: 'start_date', name: 'start_date', orderable: false }, { data: 'start_date', name: 'start_date', orderable: false, searchable: false },
{ data: 'end_date', name: 'end_date', orderable: false }, { data: 'end_date', name: 'end_date', orderable: false, searchable: false },
{ data: 'num_days', name: 'num_days', orderable: false }, { data: 'num_days', name: 'num_days', orderable: false, searchable: false },
{ data: 'action', name: 'action', orderable: false, searchable: false }, { data: 'action', name: 'action', orderable: false, searchable: false },
], ],
columnDefs: [ columnDefs: [
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: 0,
orderable: false,
className: 'select-checkbox',
render: function(data, type, row) {
return row.proof ?
'<input type="checkbox" class="row-checkbox" data-id="' + row.id + '">' :
'<input type="checkbox" disabled>';
}
},
{
targets: '_all',
className: 'text-center wrap-text'
},
{
targets: 10,
render: function(data, type, row) {
return '<div class="btn-group" role="group">' +
data +
'</div>';
}
}
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [ buttons: [
{ extend: 'copy', text: '<i class="fas fa-copy me-1"></i> Copy', className: 'btn btn-sm btn-outline-white', title: sheetName }, {
{ extend: 'csv', text: '<i class="fas fa-file-csv me-1"></i> CSV', className: 'btn btn-sm btn-outline-white', title: sheetName }, extend: 'copy',
{ extend: 'excel', text: '<i class="fas fa-file-excel me-1"></i> Excel', className: 'btn btn-sm btn-outline-white', title: sheetName }, text: '<i class="fas fa-copy me-1"></i> Copy',
{ extend: 'pdf', text: '<i class="fas fa-file-pdf me-1"></i> PDF', className: 'btn btn-sm btn-outline-white', title: sheetName }, className: 'btn btn-sm btn-outline-white',
{ extend: 'print', text: '<i class="fas fa-print me-1"></i> Print', className: 'btn btn-sm btn-outline-white', title: sheetName }, title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'csv',
text: '<i class="fas fa-file-csv me-1"></i> CSV',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'excel',
text: '<i class="fas fa-file-excel me-1"></i> Excel',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'pdf',
text: '<i class="fas fa-file-pdf me-1"></i> PDF',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'print',
text: '<i class="fas fa-print me-1"></i> Print',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
}
], ],
language: { language: {
search: "<i class='fas fa-search'></i> _INPUT_", search: "<i class='fas fa-search'></i> _INPUT_",
@@ -88,10 +300,162 @@
next: "<i class='fas fa-angle-right'></i>", next: "<i class='fas fa-angle-right'></i>",
previous: "<i class='fas fa-angle-left'></i>" previous: "<i class='fas fa-angle-left'></i>"
} }
},
// Initialize the column visibility after table is drawn
initComplete: function() {
// Set column visibility
toggleColumnVisibility();
// Add select-all checkbox
addSelectAllCheckbox();
},
drawCallback: function() {
// Ensure select-all checkbox is present on redraw
addSelectAllCheckbox();
} }
}); });
// Apply filters when they change
$('#department-filter, #activity-filter, #date-from, #date-to').change(function() {
table.ajax.reload();
});
return table;
}; };
// Delete button handler
$('#externalEngagement-table').on('click', '.delete-btn', function() {
if (confirm('Are you sure you want to delete this record?')) {
const id = $(this).data('id');
const url = $(this).data('url');
$.ajax({
url: url,
type: 'DELETE',
data: {
"_token": "{{ csrf_token() }}"
},
success: function(result) {
table.ajax.reload();
showToast('Record deleted successfully', 'success');
},
error: function(error) {
console.error(error);
showToast('Error deleting record', 'danger');
}
});
}
});
// Handle row selection and Download button state
$('#externalEngagement-table').on('change', '.row-checkbox', function() {
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
// Download proofs button handler
$('#download-proofs').on('click', function() {
const selectedIds = [];
$('.row-checkbox:checked').each(function() {
const id = $(this).data('id');
if (id) selectedIds.push(id);
});
if (selectedIds.length > 0) {
// Create a form to submit the request
const form = $('<form></form>')
.attr('method', 'POST')
.attr('action', downloadProofsRoute)
.css('display', 'none');
// Add CSRF token
$('<input>')
.attr('type', 'hidden')
.attr('name', '_token')
.attr('value', csrf_token)
.appendTo(form);
// Add selected IDs
$('<input>')
.attr('type', 'hidden')
.attr('name', 'ids')
.attr('value', JSON.stringify(selectedIds))
.appendTo(form);
// Add model name
$('<input>')
.attr('type', 'hidden')
.attr('name', 'model')
.attr('value', currentModel)
.appendTo(form);
$('body').append(form);
form.submit();
}
});
// Function to add select-all checkbox to the table header
function addSelectAllCheckbox() {
// Only add if it doesn't exist yet
if ($('#select-all-checkbox').length === 0) {
const selectAllCheckbox = $('<input>', {
type: 'checkbox',
id: 'select-all-checkbox',
class: 'form-check-input'
});
// Add to the first header column
$('#externalEngagement-table thead th.select-checkbox').html(selectAllCheckbox);
// Handle the select all functionality
$('#select-all-checkbox').on('change', function() {
const isChecked = $(this).prop('checked');
$('.row-checkbox:not(:disabled)').prop('checked', isChecked);
// Update download button state
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
}
}
// Toast notification function
function showToast(message, type) {
const toastContainer = document.createElement('div');
toastContainer.className = 'position-fixed bottom-0 start-0 p-3';
toastContainer.style.zIndex = '1050';
const toastEl = document.createElement('div');
toastEl.className = `toast align-items-center text-white bg-${type} border-0`;
toastEl.setAttribute('role', 'alert');
toastEl.setAttribute('aria-live', 'assertive');
toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer);
const toast = new bootstrap.Toast(toastEl, {
autohide: true,
delay: 3000
});
toast.show();
toastEl.addEventListener('hidden.bs.toast', function() {
document.body.removeChild(toastContainer);
});
}
// Set appropriate route based on user role // Set appropriate route based on user role
const userRole = "{{ auth()->user()->role->name }}"; const userRole = "{{ auth()->user()->role->name }}";
let dataRoute = "{{ route('admin.ExternalEngagementResponses.data') }}"; let dataRoute = "{{ route('admin.ExternalEngagementResponses.data') }}";
@@ -103,7 +467,178 @@
dataRoute = "{{ route('faculty.ExternalEngagementResponses.data') }}"; dataRoute = "{{ route('faculty.ExternalEngagementResponses.data') }}";
} }
initAjaxRoute(dataRoute); // Initialize the data table
table = initAjaxRoute(dataRoute);
// Attach change event listener to column visibility checkboxes
$('.column-checkbox').on('change', function() {
toggleColumnVisibility();
});
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button
$('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change');
});
// Deselect all columns button
$('#deselect-all-columns').click(function() {
$('.column-checkbox').prop('checked', false).trigger('change');
});
// Prevent dropdown from closing when clicking inside it
$('.dropdown-menu').on('click', function(e) {
e.stopPropagation();
});
// Set department filter from query string if present
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const departmentId = urlParams.get('department_id');
if (departmentId) {
$('#department-filter').val(departmentId).trigger('change');
}
});
}); });
</script> </script>
<style>
.form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.dropdown-menu .form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu .form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus-visible {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.form-switch .form-check-input {
width: 2.5em;
margin-left: -2.8em;
position: relative;
}
.form-switch .form-check-input:focus {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
transition: background-position 0.15s ease-in-out;
}
/* Enhance the toggle appearance */
.form-switch .form-check-input {
background-size: contain;
transition: 0.2s;
}
.dropdown-menu {
max-height: 400px;
overflow-y: auto;
}
/* Ensure the table container is responsive */
.table-responsive {
overflow-x: auto;
white-space: nowrap;
}
/* Ensure the table fits within the container */
#externalEngagement-table {
width: 100% !important;
}
.select-checkbox {
width: 30px;
text-align: center;
}
.select-checkbox input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.select-checkbox input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Style the Download button */
#download-proofs {
background-color: #28a745;
border-color: #28a745;
}
#download-proofs:hover:not(:disabled) {
background-color: #218838;
border-color: #218838;
}
#download-proofs:disabled {
opacity: 0.65;
cursor: not-allowed;
}
</style>
@endsection @endsection

View File

@@ -9,13 +9,91 @@
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-industry me-2 text-primary"></i>All Industrial Visits Organised <i class="fas fa-industry me-2 text-primary"></i>All Industrial Visits Organised
</h3> </h3>
<!-- Include the reusable send-email component -->
<x-send-email />
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- Filter Controls -->
<div class="row mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Department</span>
@if(auth()->user()->role_id == 1)
{{-- Admin: can choose any department --}}
<select id="department-filter" class="form-select">
<option value="">All Departments</option>
@foreach($departments as $department)
<option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Target Audience</span>
<select id="audience-filter" class="form-select">
<option value="">All Audience</option>
<option value="Faculty">Faculty</option>
<option value="Students">Students</option>
<!-- Category options would be populated dynamically -->
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Date Range</span>
<input type="date" id="date-from" class="form-control">
<span class="input-group-text bg-light">to</span>
<input type="date" id="date-to" class="form-control">
</div>
</div>
</div>
<!-- Column Selector -->
<div class="flex justify-between col-md-12 mt-3 mb-4">
<!-- Include the reusable download-proofs component -->
<x-download-proofs :route="route('admin.downloadProofs')" :model="'IvOrganised'" />
@php
use Illuminate\Support\Str;
$labels = [
'Company Name',
'Resource Person',
'Target Audience',
'Department',
'Faculty',
'Start Date',
'End Date',
'Student Year',
'Participants',
];
$columns = [];
foreach ($labels as $i => $label) {
$columns[] = [
'label' => $label,
'id' => 'column-' . Str::slug($label, '-'),
'value' => $i + 2,
'checked' => $label !== 'Student Year',
];
}
@endphp
<x-column-selector :columns="$columns" />
</div>
<!-- Table --> <!-- Table -->
<div class="table-responsive"> <div class="table-responsive">
<table id="ivOrganised-table" class="table table-striped table-hover"> <table id="ivOrganised-table" class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th class="select-checkbox"></th>
<th>ID</th> <th>ID</th>
<th>Company Name</th> <th>Company Name</th>
<th>Resource Person</th> <th>Resource Person</th>
@@ -42,22 +120,103 @@
@endsection @endsection
@section('scripts') @section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" integrity="sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
const downloadProofsRoute = "{{ route('admin.downloadProofs') }}";
const currentModel = "{{ isset($model) ? $model : 'ivOrganised' }}";
const csrf_token = "{{ csrf_token() }}";
$(document).ready(function() { $(document).ready(function() {
const sheetName = "Industrial Visits Organised"; // Handle "Select All" checkbox for missing proofs modal
$('#selectAll').change(function() {
const isChecked = $(this).prop('checked');
$('input[name="categories[]"]').prop('checked', isChecked);
});
// Update "Select All" when individual checkboxes change
$('input[name="categories[]"]').change(function() {
const totalCheckboxes = $('input[name="categories[]"]').length;
const checkedCheckboxes = $('input[name="categories[]"]:checked').length;
$('#selectAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Form validation for the modal
const form = document.getElementById('missingProofsForm');
if (form) {
form.addEventListener('submit', function(e) {
const checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length === 0) {
e.preventDefault();
alert('Please select at least one category before sending emails.');
}
});
}
const sheetName = "Industrial Visits Organised Report";
let table; // Declare table variable in the outer scope
function exportOptions() {
return {
columns: ':visible',
format: {
body: function(data, row, column, node) {
if ($(node).find('select').length) {
return $(node).find("select option:selected").text();
}
return $(node).text();
}
}
};
}
// Function to toggle column visibility
function toggleColumnVisibility() {
$('.column-checkbox').each(function() {
const columnIndex = $(this).val();
const isChecked = $(this).is(':checked');
// Show or hide the column based on checkbox state
if (table) {
table.column(columnIndex).visible(isChecked);
}
});
// Adjust table layout only if table and responsive are initialized
if (table && table.responsive) {
table.columns.adjust().responsive.recalc();
} else if (table) {
table.columns.adjust();
}
}
var initAjaxRoute = function(route) { var initAjaxRoute = function(route) {
// If table already exists, destroy it before re-initializing
if ($.fn.DataTable.isDataTable('#ivOrganised-table')) {
$('#ivOrganised-table').DataTable().destroy();
}
table = $("#ivOrganised-table").DataTable({ table = $("#ivOrganised-table").DataTable({
fnDestroy: true,
processing: true, processing: true,
serverSide: true, serverSide: true,
responsive: true, responsive: true,
ajax: { ajax: {
url: route, url: route,
data: function(d) {
d.department = $('#department-filter').val();
d.target_audience = $('#audience-filter').val();
d.dateFrom = $('#date-from').val();
d.dateTo = $('#date-to').val();
}
}, },
columns: [ columns: [
{
data: null,
defaultContent: '',
orderable: false,
searchable: false
},
{ data: 'id', name: 'id', searchable: false }, { data: 'id', name: 'id', searchable: false },
{ data: 'company_name', name: 'company_name', orderable: true }, { data: 'company_name', name: 'company_name', orderable: false },
{ data: 'resource_person_name', name: 'resource_person_name', orderable: true }, { data: 'resource_person_name', name: 'resource_person_name', orderable: true },
{ data: 'target_audience', name: 'target_audience', orderable: true }, { data: 'target_audience', name: 'target_audience', orderable: true },
{ data: 'department_name', name: 'department_name', orderable: true }, { data: 'department_name', name: 'department_name', orderable: true },
@@ -69,15 +228,66 @@
{ data: 'action', name: 'action', orderable: false, searchable: false }, { data: 'action', name: 'action', orderable: false, searchable: false },
], ],
columnDefs: [ columnDefs: [
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: 0,
orderable: false,
className: 'select-checkbox',
render: function(data, type, row) {
return row.proof ?
'<input type="checkbox" class="row-checkbox" data-id="' + row.id + '">' :
'<input type="checkbox" disabled>';
}
},
{
targets: '_all',
className: 'text-center wrap-text'
},
{
targets: 11,
render: function(data, type, row) {
return '<div class="btn-group" role="group">' +
data +
'</div>';
}
}
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [ buttons: [
{ extend: 'copy', text: '<i class="fas fa-copy me-1"></i> Copy', className: 'btn btn-sm btn-outline-white', title: sheetName }, {
{ extend: 'csv', text: '<i class="fas fa-file-csv me-1"></i> CSV', className: 'btn btn-sm btn-outline-white', title: sheetName }, extend: 'copy',
{ extend: 'excel', text: '<i class="fas fa-file-excel me-1"></i> Excel', className: 'btn btn-sm btn-outline-white', title: sheetName }, text: '<i class="fas fa-copy me-1"></i> Copy',
{ extend: 'pdf', text: '<i class="fas fa-file-pdf me-1"></i> PDF', className: 'btn btn-sm btn-outline-white', title: sheetName }, className: 'btn btn-sm btn-outline-white',
{ extend: 'print', text: '<i class="fas fa-print me-1"></i> Print', className: 'btn btn-sm btn-outline-white', title: sheetName }, title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'csv',
text: '<i class="fas fa-file-csv me-1"></i> CSV',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'excel',
text: '<i class="fas fa-file-excel me-1"></i> Excel',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'pdf',
text: '<i class="fas fa-file-pdf me-1"></i> PDF',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'print',
text: '<i class="fas fa-print me-1"></i> Print',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
}
], ],
language: { language: {
search: "<i class='fas fa-search'></i> _INPUT_", search: "<i class='fas fa-search'></i> _INPUT_",
@@ -90,8 +300,160 @@
next: "<i class='fas fa-angle-right'></i>", next: "<i class='fas fa-angle-right'></i>",
previous: "<i class='fas fa-angle-left'></i>" previous: "<i class='fas fa-angle-left'></i>"
} }
},
// Initialize the column visibility after table is drawn
initComplete: function() {
// Set column visibility
toggleColumnVisibility();
// Add select-all checkbox
addSelectAllCheckbox();
},
drawCallback: function() {
// Ensure select-all checkbox is present on redraw
addSelectAllCheckbox();
} }
}); });
// Apply filters when they change
$('#department-filter, #audience-filter, #date-from, #date-to').change(function() {
table.ajax.reload();
});
return table;
};
// Delete button handler
$('#ivOrganised-table').on('click', '.delete-btn', function() {
if (confirm('Are you sure you want to delete this record?')) {
const id = $(this).data('id');
const url = $(this).data('url');
$.ajax({
url: url,
type: 'DELETE',
data: {
"_token": "{{ csrf_token() }}"
},
success: function(result) {
table.ajax.reload();
showToast('Record deleted successfully', 'success');
},
error: function(error) {
console.error(error);
showToast('Error deleting record', 'danger');
}
});
}
});
// Handle row selection and Download button state
$('#ivOrganised-table').on('change', '.row-checkbox', function() {
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
// Download proofs button handler
$('#download-proofs').on('click', function() {
const selectedIds = [];
$('.row-checkbox:checked').each(function() {
const id = $(this).data('id');
if (id) selectedIds.push(id);
});
if (selectedIds.length > 0) {
// Create a form to submit the request
const form = $('<form></form>')
.attr('method', 'POST')
.attr('action', downloadProofsRoute)
.css('display', 'none');
// Add CSRF token
$('<input>')
.attr('type', 'hidden')
.attr('name', '_token')
.attr('value', csrf_token)
.appendTo(form);
// Add selected IDs
$('<input>')
.attr('type', 'hidden')
.attr('name', 'ids')
.attr('value', JSON.stringify(selectedIds))
.appendTo(form);
// Add model name
$('<input>')
.attr('type', 'hidden')
.attr('name', 'model')
.attr('value', currentModel)
.appendTo(form);
$('body').append(form);
form.submit();
}
});
// Function to add select-all checkbox to the table header
function addSelectAllCheckbox() {
// Only add if it doesn't exist yet
if ($('#select-all-checkbox').length === 0) {
const selectAllCheckbox = $('<input>', {
type: 'checkbox',
id: 'select-all-checkbox',
class: 'form-check-input'
});
// Add to the first header column
$('#ivOrganised-table thead th.select-checkbox').html(selectAllCheckbox);
// Handle the select all functionality
$('#select-all-checkbox').on('change', function() {
const isChecked = $(this).prop('checked');
$('.row-checkbox:not(:disabled)').prop('checked', isChecked);
// Update download button state
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
}
}
// Toast notification function
function showToast(message, type) {
const toastContainer = document.createElement('div');
toastContainer.className = 'position-fixed bottom-0 start-0 p-3';
toastContainer.style.zIndex = '1050';
const toastEl = document.createElement('div');
toastEl.className = `toast align-items-center text-white bg-${type} border-0`;
toastEl.setAttribute('role', 'alert');
toastEl.setAttribute('aria-live', 'assertive');
toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer);
const toast = new bootstrap.Toast(toastEl, {
autohide: true,
delay: 3000
});
toast.show();
toastEl.addEventListener('hidden.bs.toast', function() {
document.body.removeChild(toastContainer);
});
}; };
// Set appropriate route based on user role // Set appropriate route based on user role
@@ -105,7 +467,179 @@
dataRoute = "{{ route('faculty.IvOrganisedResponses.data') }}"; dataRoute = "{{ route('faculty.IvOrganisedResponses.data') }}";
} }
initAjaxRoute(dataRoute); // Initialize the data table
table = initAjaxRoute(dataRoute);
// Attach change event listener to column visibility checkboxes
$('.column-checkbox').on('change', function() {
toggleColumnVisibility();
});
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button
$('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change');
});
// Deselect all columns button
$('#deselect-all-columns').click(function() {
$('.column-checkbox').prop('checked', false).trigger('change');
});
// Prevent dropdown from closing when clicking inside it
$('.dropdown-menu').on('click', function(e) {
e.stopPropagation();
});
// Set department filter from query string if present
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const departmentId = urlParams.get('department_id');
if (departmentId) {
$('#department-filter').val(departmentId).trigger('change');
}
});
}); });
</script> </script>
<style>
.form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.dropdown-menu .form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu .form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus-visible {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.form-switch .form-check-input {
width: 2.5em;
margin-left: -2.8em;
position: relative;
}
.form-switch .form-check-input:focus {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
transition: background-position 0.15s ease-in-out;
}
/* Enhance the toggle appearance */
.form-switch .form-check-input {
background-size: contain;
transition: 0.2s;
}
.dropdown-menu {
max-height: 400px;
overflow-y: auto;
}
/* Ensure the table container is responsive */
.table-responsive {
overflow-x: auto;
white-space: nowrap;
}
/* Ensure the table fits within the container */
#ivOrganised-table {
width: 100% !important;
}
.select-checkbox {
width: 30px;
text-align: center;
}
.select-checkbox input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.select-checkbox input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Style the Download button */
#download-proofs {
background-color: #28a745;
border-color: #28a745;
}
#download-proofs:hover:not(:disabled) {
background-color: #218838;
border-color: #218838;
}
#download-proofs:disabled {
opacity: 0.65;
cursor: not-allowed;
}
</style>
@endsection @endsection

View File

@@ -9,13 +9,93 @@
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-laptop-code me-2 text-primary"></i>All Online Courses <i class="fas fa-laptop-code me-2 text-primary"></i>All Online Courses
</h3> </h3>
<!-- Include the reusable send-email component -->
<x-send-email />
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- Filter Controls -->
<div class="row mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Department</span>
@if(auth()->user()->role_id == 1)
{{-- Admin: can choose any department --}}
<select id="department-filter" class="form-select">
<option value="">All Departments</option>
@foreach($departments as $department)
<option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Course Offered By</span>
<select id="offered_by-filter" class="form-select">
<option value="">All Platforms</option>
<option value="NPTEL">NPTEL</option>
<option value="Google Digital Garage">Google Digital Garage</option>
<option value="LinkedIn Learning">LinkedIn Learning</option>
<option value="Microsoft Learn">Microsoft Learn</option>
<option value="Coursera">Coursera</option>
<option value="edX">edX</option>
<option value="Udemy">Udemy</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Date Range</span>
<input type="date" id="date-from" class="form-control">
<span class="input-group-text bg-light">to</span>
<input type="date" id="date-to" class="form-control">
</div>
</div>
</div>
<!-- Column Selector -->
<div class="flex justify-between col-md-12 mt-3 mb-4">
<!-- Include the reusable download-proofs component -->
<x-download-proofs :route="route('admin.downloadProofs')" :model="'ActivitiesOrganised'" />
@php
use Illuminate\Support\Str;
$labels = [
'Faculty',
'Department',
'Course',
'Offered By',
'Start Date',
'End Date',
'Num Days',
];
$columns = [];
foreach ($labels as $i => $label) {
$columns[] = [
'label' => $label,
'id' => 'column-' . Str::slug($label, '-'),
'value' => $i + 2,
'checked' => $label !== 'Num Days',
];
}
@endphp
<x-column-selector :columns="$columns" />
</div>
<!-- Table --> <!-- Table -->
<div class="table-responsive"> <div class="table-responsive">
<table id="onlineCourse-table" class="table table-striped table-hover"> <table id="onlineCourse-table" class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th class="select-checkbox"></th>
<th>ID</th> <th>ID</th>
<th>Faculty</th> <th>Faculty</th>
<th>Department</th> <th>Department</th>
@@ -40,20 +120,101 @@
@endsection @endsection
@section('scripts') @section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" integrity="sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
const downloadProofsRoute = "{{ route('admin.downloadProofs') }}";
const currentModel = "{{ isset($model) ? $model : 'OnlineCourse' }}";
const csrf_token = "{{ csrf_token() }}";
$(document).ready(function() { $(document).ready(function() {
const sheetName = "Online Courses"; // Handle "Select All" checkbox for missing proofs modal
$('#selectAll').change(function() {
const isChecked = $(this).prop('checked');
$('input[name="categories[]"]').prop('checked', isChecked);
});
// Update "Select All" when individual checkboxes change
$('input[name="categories[]"]').change(function() {
const totalCheckboxes = $('input[name="categories[]"]').length;
const checkedCheckboxes = $('input[name="categories[]"]:checked').length;
$('#selectAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Form validation for the modal
const form = document.getElementById('missingProofsForm');
if (form) {
form.addEventListener('submit', function(e) {
const checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length === 0) {
e.preventDefault();
alert('Please select at least one category before sending emails.');
}
});
}
const sheetName = "Online Courses Report";
let table; // Declare table variable in the outer scope
function exportOptions() {
return {
columns: ':visible',
format: {
body: function(data, row, column, node) {
if ($(node).find('select').length) {
return $(node).find("select option:selected").text();
}
return $(node).text();
}
}
};
}
// Function to toggle column visibility
function toggleColumnVisibility() {
$('.column-checkbox').each(function() {
const columnIndex = $(this).val();
const isChecked = $(this).is(':checked');
// Show or hide the column based on checkbox state
if (table) {
table.column(columnIndex).visible(isChecked);
}
});
// Adjust table layout only if table and responsive are initialized
if (table && table.responsive) {
table.columns.adjust().responsive.recalc();
} else if (table) {
table.columns.adjust();
}
}
var initAjaxRoute = function(route) { var initAjaxRoute = function(route) {
// If table already exists, destroy it before re-initializing
if ($.fn.DataTable.isDataTable('#onlineCourse-table')) {
$('#onlineCourse-table').DataTable().destroy();
}
table = $("#onlineCourse-table").DataTable({ table = $("#onlineCourse-table").DataTable({
fnDestroy: true,
processing: true, processing: true,
serverSide: true, serverSide: true,
responsive: true, responsive: true,
ajax: { ajax: {
url: route, url: route,
data: function(d) {
d.department = $('#department-filter').val();
d.offered_by = $('#offered_by-filter').val();
d.dateFrom = $('#date-from').val();
d.dateTo = $('#date-to').val();
}
}, },
columns: [ columns: [
{
data: null,
defaultContent: '',
orderable: false,
searchable: false
},
{ data: 'id', name: 'id', searchable: false }, { data: 'id', name: 'id', searchable: false },
{ data: 'user_name', name: 'user_name', orderable: true }, { data: 'user_name', name: 'user_name', orderable: true },
{ data: 'department_name', name: 'department_name', orderable: true }, { data: 'department_name', name: 'department_name', orderable: true },
@@ -65,15 +226,66 @@
{ data: 'action', name: 'action', orderable: false, searchable: false }, { data: 'action', name: 'action', orderable: false, searchable: false },
], ],
columnDefs: [ columnDefs: [
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: 0,
orderable: false,
className: 'select-checkbox',
render: function(data, type, row) {
return row.proof ?
'<input type="checkbox" class="row-checkbox" data-id="' + row.id + '">' :
'<input type="checkbox" disabled>';
}
},
{
targets: '_all',
className: 'text-center wrap-text'
},
{
targets: 9,
render: function(data, type, row) {
return '<div class="btn-group" role="group">' +
data +
'</div>';
}
}
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [ buttons: [
{ extend: 'copy', text: '<i class="fas fa-copy me-1"></i> Copy', className: 'btn btn-sm btn-outline-white', title: sheetName }, {
{ extend: 'csv', text: '<i class="fas fa-file-csv me-1"></i> CSV', className: 'btn btn-sm btn-outline-white', title: sheetName }, extend: 'copy',
{ extend: 'excel', text: '<i class="fas fa-file-excel me-1"></i> Excel', className: 'btn btn-sm btn-outline-white', title: sheetName }, text: '<i class="fas fa-copy me-1"></i> Copy',
{ extend: 'pdf', text: '<i class="fas fa-file-pdf me-1"></i> PDF', className: 'btn btn-sm btn-outline-white', title: sheetName }, className: 'btn btn-sm btn-outline-white',
{ extend: 'print', text: '<i class="fas fa-print me-1"></i> Print', className: 'btn btn-sm btn-outline-white', title: sheetName }, title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'csv',
text: '<i class="fas fa-file-csv me-1"></i> CSV',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'excel',
text: '<i class="fas fa-file-excel me-1"></i> Excel',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'pdf',
text: '<i class="fas fa-file-pdf me-1"></i> PDF',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'print',
text: '<i class="fas fa-print me-1"></i> Print',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
}
], ],
language: { language: {
search: "<i class='fas fa-search'></i> _INPUT_", search: "<i class='fas fa-search'></i> _INPUT_",
@@ -86,10 +298,162 @@
next: "<i class='fas fa-angle-right'></i>", next: "<i class='fas fa-angle-right'></i>",
previous: "<i class='fas fa-angle-left'></i>" previous: "<i class='fas fa-angle-left'></i>"
} }
},
// Initialize the column visibility after table is drawn
initComplete: function() {
// Set column visibility
toggleColumnVisibility();
// Add select-all checkbox
addSelectAllCheckbox();
},
drawCallback: function() {
// Ensure select-all checkbox is present on redraw
addSelectAllCheckbox();
} }
}); });
// Apply filters when they change
$('#department-filter, #offered_by-filter, #date-from, #date-to').change(function() {
table.ajax.reload();
});
return table;
}; };
// Delete button handler
$('#onlineCourse-table').on('click', '.delete-btn', function() {
if (confirm('Are you sure you want to delete this record?')) {
const id = $(this).data('id');
const url = $(this).data('url');
$.ajax({
url: url,
type: 'DELETE',
data: {
"_token": "{{ csrf_token() }}"
},
success: function(result) {
table.ajax.reload();
showToast('Record deleted successfully', 'success');
},
error: function(error) {
console.error(error);
showToast('Error deleting record', 'danger');
}
});
}
});
// Handle row selection and Download button state
$('#responses-table').on('change', '.row-checkbox', function() {
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
// Download proofs button handler
$('#download-proofs').on('click', function() {
const selectedIds = [];
$('.row-checkbox:checked').each(function() {
const id = $(this).data('id');
if (id) selectedIds.push(id);
});
if (selectedIds.length > 0) {
// Create a form to submit the request
const form = $('<form></form>')
.attr('method', 'POST')
.attr('action', downloadProofsRoute)
.css('display', 'none');
// Add CSRF token
$('<input>')
.attr('type', 'hidden')
.attr('name', '_token')
.attr('value', csrf_token)
.appendTo(form);
// Add selected IDs
$('<input>')
.attr('type', 'hidden')
.attr('name', 'ids')
.attr('value', JSON.stringify(selectedIds))
.appendTo(form);
// Add model name
$('<input>')
.attr('type', 'hidden')
.attr('name', 'model')
.attr('value', currentModel)
.appendTo(form);
$('body').append(form);
form.submit();
}
});
// Function to add select-all checkbox to the table header
function addSelectAllCheckbox() {
// Only add if it doesn't exist yet
if ($('#select-all-checkbox').length === 0) {
const selectAllCheckbox = $('<input>', {
type: 'checkbox',
id: 'select-all-checkbox',
class: 'form-check-input'
});
// Add to the first header column
$('#responses-table thead th.select-checkbox').html(selectAllCheckbox);
// Handle the select all functionality
$('#select-all-checkbox').on('change', function() {
const isChecked = $(this).prop('checked');
$('.row-checkbox:not(:disabled)').prop('checked', isChecked);
// Update download button state
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
}
}
// Toast notification function
function showToast(message, type) {
const toastContainer = document.createElement('div');
toastContainer.className = 'position-fixed bottom-0 start-0 p-3';
toastContainer.style.zIndex = '1050';
const toastEl = document.createElement('div');
toastEl.className = `toast align-items-center text-white bg-${type} border-0`;
toastEl.setAttribute('role', 'alert');
toastEl.setAttribute('aria-live', 'assertive');
toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer);
const toast = new bootstrap.Toast(toastEl, {
autohide: true,
delay: 3000
});
toast.show();
toastEl.addEventListener('hidden.bs.toast', function() {
document.body.removeChild(toastContainer);
});
}
// Set appropriate route based on user role // Set appropriate route based on user role
const userRole = "{{ auth()->user()->role->name }}"; const userRole = "{{ auth()->user()->role->name }}";
let dataRoute = "{{ route('admin.OnlineCoursesResponses.data') }}"; let dataRoute = "{{ route('admin.OnlineCoursesResponses.data') }}";
@@ -101,7 +465,178 @@
dataRoute = "{{ route('faculty.OnlineCoursesResponses.data') }}"; dataRoute = "{{ route('faculty.OnlineCoursesResponses.data') }}";
} }
initAjaxRoute(dataRoute); // Initialize the data table
table = initAjaxRoute(dataRoute);
// Attach change event listener to column visibility checkboxes
$('.column-checkbox').on('change', function() {
toggleColumnVisibility();
});
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button
$('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change');
});
// Deselect all columns button
$('#deselect-all-columns').click(function() {
$('.column-checkbox').prop('checked', false).trigger('change');
});
// Prevent dropdown from closing when clicking inside it
$('.dropdown-menu').on('click', function(e) {
e.stopPropagation();
});
// Set department filter from query string if present
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const departmentId = urlParams.get('department_id');
if (departmentId) {
$('#department-filter').val(departmentId).trigger('change');
}
});
}); });
</script> </script>
<style>
.form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.dropdown-menu .form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu .form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus-visible {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.form-switch .form-check-input {
width: 2.5em;
margin-left: -2.8em;
position: relative;
}
.form-switch .form-check-input:focus {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
transition: background-position 0.15s ease-in-out;
}
/* Enhance the toggle appearance */
.form-switch .form-check-input {
background-size: contain;
transition: 0.2s;
}
.dropdown-menu {
max-height: 400px;
overflow-y: auto;
}
/* Ensure the table container is responsive */
.table-responsive {
overflow-x: auto;
white-space: nowrap;
}
/* Ensure the table fits within the container */
#onlineCourse-table {
width: 100% !important;
}
.select-checkbox {
width: 30px;
text-align: center;
}
.select-checkbox input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.select-checkbox input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Style the Download button */
#download-proofs {
background-color: #28a745;
border-color: #28a745;
}
#download-proofs:hover:not(:disabled) {
background-color: #218838;
border-color: #218838;
}
#download-proofs:disabled {
opacity: 0.65;
cursor: not-allowed;
}
</style>
@endsection @endsection

View File

@@ -9,13 +9,90 @@
<h3 class="page-title m-0"> <h3 class="page-title m-0">
<i class="fas fa-file-alt me-2 text-primary"></i>All Patents <i class="fas fa-file-alt me-2 text-primary"></i>All Patents
</h3> </h3>
<!-- Include the reusable send-email component -->
<x-send-email />
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- Filter Controls -->
<div class="row mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Department</span>
@if(auth()->user()->role_id == 1)
{{-- Admin: can choose any department --}}
<select id="department-filter" class="form-select">
<option value="">All Departments</option>
@foreach($departments as $department)
<option value="{{ $department->id }}">{{ $department->name }}</option>
@endforeach
</select>
@else
{{-- Coordinator/Faculty: department is fixed --}}
<select id="department-filter" class="form-select" disabled>
<option value="{{ auth()->user()->department_id }}">
{{ auth()->user()->department->name }}
</option>
</select>
@endif
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Status</span>
<select id="status-filter" class="form-select">
<option value="">Both</option>
<option value="Granted">Granted</option>
<option value="Filed">Filed</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light">Date Range</span>
<input type="date" id="date-from" class="form-control">
<span class="input-group-text bg-light">to</span>
<input type="date" id="date-to" class="form-control">
</div>
</div>
</div>
<!-- Column Selector -->
<div class="flex justify-between col-md-12 mt-3 mb-4">
<!-- Include the reusable download-proofs component -->
<x-download-proofs :route="route('admin.downloadProofs')" :model="'Patent'" />
@php
use Illuminate\Support\Str;
$labels = [
'Faculty',
'Department',
'Title',
'Investigator',
'Application No',
'Type',
'Date Of Submission',
'Date Of Filling',
'Status',
];
$columns = [];
foreach ($labels as $i => $label) {
$columns[] = [
'label' => $label,
'id' => 'column-' . Str::slug($label, '-'),
'value' => $i + 2,
'checked' => $label !== 'Date Of Filling',
];
}
@endphp
<x-column-selector :columns="$columns" />
</div>
<!-- Table --> <!-- Table -->
<div class="table-responsive"> <div class="table-responsive">
<table id="patents-table" class="table table-striped table-hover"> <table id="patents-table" class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th class="select-checkbox"></th>
<th>ID</th> <th>ID</th>
<th>Faculty</th> <th>Faculty</th>
<th>Department</th> <th>Department</th>
@@ -42,11 +119,81 @@
@endsection @endsection
@section('scripts') @section('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" integrity="sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
const downloadProofsRoute = "{{ route('admin.downloadProofs') }}";
const currentModel = "{{ isset($model) ? $model : 'Patent' }}";
const csrf_token = "{{ csrf_token() }}";
$(document).ready(function() { $(document).ready(function() {
const sheetName = "Patents"; // Handle "Select All" checkbox for missing proofs modal
$('#selectAll').change(function() {
const isChecked = $(this).prop('checked');
$('input[name="categories[]"]').prop('checked', isChecked);
});
// Update "Select All" when individual checkboxes change
$('input[name="categories[]"]').change(function() {
const totalCheckboxes = $('input[name="categories[]"]').length;
const checkedCheckboxes = $('input[name="categories[]"]:checked').length;
$('#selectAll').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Form validation for the modal
const form = document.getElementById('missingProofsForm');
if (form) {
form.addEventListener('submit', function(e) {
const checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length === 0) {
e.preventDefault();
alert('Please select at least one category before sending emails.');
}
});
}
const sheetName = "Patents Report";
let table; // Declare table variable in the outer scope
function exportOptions() {
return {
columns: ':visible',
format: {
body: function(data, row, column, node) {
if ($(node).find('select').length) {
return $(node).find("select option:selected").text();
}
return $(node).text();
}
}
};
}
// Function to toggle column visibility
function toggleColumnVisibility() {
$('.column-checkbox').each(function() {
const columnIndex = $(this).val();
const isChecked = $(this).is(':checked');
// Show or hide the column based on checkbox state
if (table) {
table.column(columnIndex).visible(isChecked);
}
});
// Adjust table layout only if table and responsive are initialized
if (table && table.responsive) {
table.columns.adjust().responsive.recalc();
} else if (table) {
table.columns.adjust();
}
}
var initAjaxRoute = function(route) { var initAjaxRoute = function(route) {
// If table already exists, destroy it before re-initializing
if ($.fn.DataTable.isDataTable('#patents-table')) {
$('#patents-table').DataTable().destroy();
}
table = $("#patents-table").DataTable({ table = $("#patents-table").DataTable({
fnDestroy: true, fnDestroy: true,
processing: true, processing: true,
@@ -54,8 +201,20 @@
responsive: true, responsive: true,
ajax: { ajax: {
url: route, url: route,
data: function(d) {
d.department = $('#department-filter').val();
d.status = $('#status-filter').val();
d.dateFrom = $('#date-from').val();
d.dateTo = $('#date-to').val();
}
}, },
columns: [ columns: [
{
data: null,
defaultContent: '',
orderable: false,
searchable: false
},
{ data: 'id', name: 'id', searchable: false }, { data: 'id', name: 'id', searchable: false },
{ data: 'user_name', name: 'user_name', orderable: true }, { data: 'user_name', name: 'user_name', orderable: true },
{ data: 'department_name', name: 'department_name', orderable: true }, { data: 'department_name', name: 'department_name', orderable: true },
@@ -69,15 +228,66 @@
{ data: 'action', name: 'action', orderable: false, searchable: false }, { data: 'action', name: 'action', orderable: false, searchable: false },
], ],
columnDefs: [ columnDefs: [
{ targets: '_all', className: 'text-center wrap-text' }, {
targets: 0,
orderable: false,
className: 'select-checkbox',
render: function(data, type, row) {
return row.proof ?
'<input type="checkbox" class="row-checkbox" data-id="' + row.id + '">' :
'<input type="checkbox" disabled>';
}
},
{
targets: '_all',
className: 'text-center wrap-text'
},
{
targets: 11,
render: function(data, type, row) {
return '<div class="btn-group" role="group">' +
data +
'</div>';
}
}
], ],
dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip', dom: '<"d-flex justify-content-between align-items-center mb-3"<"d-flex align-items-center"l><"d-flex"f<"ms-2"B>>>rtip',
buttons: [ buttons: [
{ extend: 'copy', text: '<i class="fas fa-copy me-1"></i> Copy', className: 'btn btn-sm btn-outline-white', title: sheetName }, {
{ extend: 'csv', text: '<i class="fas fa-file-csv me-1"></i> CSV', className: 'btn btn-sm btn-outline-white', title: sheetName }, extend: 'copy',
{ extend: 'excel', text: '<i class="fas fa-file-excel me-1"></i> Excel', className: 'btn btn-sm btn-outline-white', title: sheetName }, text: '<i class="fas fa-copy me-1"></i> Copy',
{ extend: 'pdf', text: '<i class="fas fa-file-pdf me-1"></i> PDF', className: 'btn btn-sm btn-outline-white', title: sheetName }, className: 'btn btn-sm btn-outline-white',
{ extend: 'print', text: '<i class="fas fa-print me-1"></i> Print', className: 'btn btn-sm btn-outline-white', title: sheetName }, title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'csv',
text: '<i class="fas fa-file-csv me-1"></i> CSV',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'excel',
text: '<i class="fas fa-file-excel me-1"></i> Excel',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'pdf',
text: '<i class="fas fa-file-pdf me-1"></i> PDF',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
},
{
extend: 'print',
text: '<i class="fas fa-print me-1"></i> Print',
className: 'btn btn-sm btn-outline-white',
title: sheetName,
exportOptions: exportOptions()
}
], ],
language: { language: {
search: "<i class='fas fa-search'></i> _INPUT_", search: "<i class='fas fa-search'></i> _INPUT_",
@@ -90,10 +300,162 @@
next: "<i class='fas fa-angle-right'></i>", next: "<i class='fas fa-angle-right'></i>",
previous: "<i class='fas fa-angle-left'></i>" previous: "<i class='fas fa-angle-left'></i>"
} }
},
// Initialize the column visibility after table is drawn
initComplete: function() {
// Set column visibility
toggleColumnVisibility();
// Add select-all checkbox
addSelectAllCheckbox();
},
drawCallback: function() {
// Ensure select-all checkbox is present on redraw
addSelectAllCheckbox();
} }
}); });
// Apply filters when they change
$('#department-filter, #status-filter, #date-from, #date-to').change(function() {
table.ajax.reload();
});
return table;
}; };
// Delete button handler
$('#patents-table').on('click', '.delete-btn', function() {
if (confirm('Are you sure you want to delete this record?')) {
const id = $(this).data('id');
const url = $(this).data('url');
$.ajax({
url: url,
type: 'DELETE',
data: {
"_token": "{{ csrf_token() }}"
},
success: function(result) {
table.ajax.reload();
showToast('Record deleted successfully', 'success');
},
error: function(error) {
console.error(error);
showToast('Error deleting record', 'danger');
}
});
}
});
// Handle row selection and Download button state
$('#patents-table').on('change', '.row-checkbox', function() {
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
// Download proofs button handler
$('#download-proofs').on('click', function() {
const selectedIds = [];
$('.row-checkbox:checked').each(function() {
const id = $(this).data('id');
if (id) selectedIds.push(id);
});
if (selectedIds.length > 0) {
// Create a form to submit the request
const form = $('<form></form>')
.attr('method', 'POST')
.attr('action', downloadProofsRoute)
.css('display', 'none');
// Add CSRF token
$('<input>')
.attr('type', 'hidden')
.attr('name', '_token')
.attr('value', csrf_token)
.appendTo(form);
// Add selected IDs
$('<input>')
.attr('type', 'hidden')
.attr('name', 'ids')
.attr('value', JSON.stringify(selectedIds))
.appendTo(form);
// Add model name
$('<input>')
.attr('type', 'hidden')
.attr('name', 'model')
.attr('value', currentModel)
.appendTo(form);
$('body').append(form);
form.submit();
}
});
// Function to add select-all checkbox to the table header
function addSelectAllCheckbox() {
// Only add if it doesn't exist yet
if ($('#select-all-checkbox').length === 0) {
const selectAllCheckbox = $('<input>', {
type: 'checkbox',
id: 'select-all-checkbox',
class: 'form-check-input'
});
// Add to the first header column
$('#patents-table thead th.select-checkbox').html(selectAllCheckbox);
// Handle the select all functionality
$('#select-all-checkbox').on('change', function() {
const isChecked = $(this).prop('checked');
$('.row-checkbox:not(:disabled)').prop('checked', isChecked);
// Update download button state
const selectedRows = $('.row-checkbox:checked').length;
$('#download-proofs').prop('disabled', selectedRows === 0);
});
}
}
// Toast notification function
function showToast(message, type) {
const toastContainer = document.createElement('div');
toastContainer.className = 'position-fixed bottom-0 start-0 p-3';
toastContainer.style.zIndex = '1050';
const toastEl = document.createElement('div');
toastEl.className = `toast align-items-center text-white bg-${type} border-0`;
toastEl.setAttribute('role', 'alert');
toastEl.setAttribute('aria-live', 'assertive');
toastEl.setAttribute('aria-atomic', 'true');
toastEl.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toastEl);
document.body.appendChild(toastContainer);
const toast = new bootstrap.Toast(toastEl, {
autohide: true,
delay: 3000
});
toast.show();
toastEl.addEventListener('hidden.bs.toast', function() {
document.body.removeChild(toastContainer);
});
}
// Set appropriate route based on user role // Set appropriate route based on user role
const userRole = "{{ auth()->user()->role->name }}"; const userRole = "{{ auth()->user()->role->name }}";
let dataRoute = "{{ route('admin.PatentsResponses.data') }}"; let dataRoute = "{{ route('admin.PatentsResponses.data') }}";
@@ -105,7 +467,178 @@
dataRoute = "{{ route('faculty.PatentsResponses.data') }}"; dataRoute = "{{ route('faculty.PatentsResponses.data') }}";
} }
initAjaxRoute(dataRoute); // Initialize the data table
table = initAjaxRoute(dataRoute);
// Attach change event listener to column visibility checkboxes
$('.column-checkbox').on('change', function() {
toggleColumnVisibility();
});
// Ensure "Actions" column is always visible
$('#column-actions').prop('disabled', true);
// Select all columns button
$('#select-all-columns').click(function() {
$('.column-checkbox').prop('checked', true).trigger('change');
});
// Deselect all columns button
$('#deselect-all-columns').click(function() {
$('.column-checkbox').prop('checked', false).trigger('change');
});
// Prevent dropdown from closing when clicking inside it
$('.dropdown-menu').on('click', function(e) {
e.stopPropagation();
});
// Set department filter from query string if present
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const departmentId = urlParams.get('department_id');
if (departmentId) {
$('#department-filter').val(departmentId).trigger('change');
}
});
}); });
</script> </script>
<style>
.form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu {
background-color: #fff;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.dropdown-menu .form-check-input:checked {
background-color: #b7202e;
border-color: #ed1c24;
}
.dropdown-menu .form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:checked:focus-visible {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):checked {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.dropdown-menu .form-check-input:focus-visible:not(:checked):not(:checked):not(:checked):not(:checked) {
box-shadow: 0 0 0 0.2rem rgba(189, 72, 46, 0.25);
}
.form-switch .form-check-input {
width: 2.5em;
margin-left: -2.8em;
position: relative;
}
.form-switch .form-check-input:focus {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
background-position: right center;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
transition: background-position 0.15s ease-in-out;
}
/* Enhance the toggle appearance */
.form-switch .form-check-input {
background-size: contain;
transition: 0.2s;
}
.dropdown-menu {
max-height: 400px;
overflow-y: auto;
}
/* Ensure the table container is responsive */
.table-responsive {
overflow-x: auto;
white-space: nowrap;
}
/* Ensure the table fits within the container */
#patents-table {
width: 100% !important;
}
.select-checkbox {
width: 30px;
text-align: center;
}
.select-checkbox input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.select-checkbox input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Style the Download button */
#download-proofs {
background-color: #28a745;
border-color: #28a745;
}
#download-proofs:hover:not(:disabled) {
background-color: #218838;
border-color: #218838;
}
#download-proofs:disabled {
opacity: 0.65;
cursor: not-allowed;
}
</style>
@endsection @endsection