mirror of https://github.com/Devoalda/LaDo.git
perf(Project Loading):
Added Lazy load for project Restructured some files
This commit is contained in:
parent
59ffb4bc32
commit
99d37aafb6
|
@ -44,7 +44,7 @@ class DashboardController extends Controller
|
||||||
|
|
||||||
$todo_completed_count = $this->all_completed_todos()['completed_count'];
|
$todo_completed_count = $this->all_completed_todos()['completed_count'];
|
||||||
|
|
||||||
return view('dashboard', compact(
|
return view('dashboard.index', compact(
|
||||||
'todos',
|
'todos',
|
||||||
'incomplete_count',
|
'incomplete_count',
|
||||||
'project_count',
|
'project_count',
|
||||||
|
|
|
@ -8,9 +8,12 @@ use App\Models\Project;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
|
||||||
|
|
||||||
class ProjectController extends Controller
|
class ProjectController extends Controller
|
||||||
|
@ -18,15 +21,23 @@ class ProjectController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display Listing of all Projects.
|
* Display Listing of all Projects.
|
||||||
*/
|
*/
|
||||||
public function index(): Application|Factory|View
|
public function index(Request $request): Application|Factory|View|JsonResponse
|
||||||
{
|
{
|
||||||
$user = User::find(auth()->user()->id);
|
$user = User::find(auth()->user()->id);
|
||||||
$projects = $user->projects;
|
$projects = $user->projects()->paginate(4);
|
||||||
// Aggregate all todos for all projects
|
// Aggregate all todos for all projects
|
||||||
$todos = $projects->map(function ($project) {
|
$todos = $projects->map(function ($project) {
|
||||||
return $project->todos;
|
return $project->todos;
|
||||||
})->flatten();
|
})->flatten();
|
||||||
|
|
||||||
|
if ($request->ajax()){
|
||||||
|
$view = view('project.load-projects', compact('projects'))->render();
|
||||||
|
return Response::json([
|
||||||
|
'view' => $view,
|
||||||
|
'nextPageUrl' => $projects->nextPageUrl(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return view('project.index', [
|
return view('project.index', [
|
||||||
'projects' => $projects,
|
'projects' => $projects,
|
||||||
'todos' => $todos->whereNull('completed_at')->values(),
|
'todos' => $todos->whereNull('completed_at')->values(),
|
||||||
|
|
|
@ -12,6 +12,14 @@ use App\Models\{
|
||||||
|
|
||||||
class Pomos extends Component
|
class Pomos extends Component
|
||||||
{
|
{
|
||||||
|
public $perPage = 10;
|
||||||
|
|
||||||
|
public function loadMore()
|
||||||
|
{
|
||||||
|
$this->perPage += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$user = User::find(auth()->id());
|
$user = User::find(auth()->id());
|
||||||
|
|
|
@ -105,16 +105,16 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<livewire:dashboard.pomo-count />
|
<livewire:dashboard.pomo-count/>
|
||||||
|
|
||||||
<livewire:dashboard.pomo-time />
|
<livewire:dashboard.pomo-time/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- List out Todos and their details (time left/ago) + checkbox in form to toggle completed -->
|
<!-- List out Todos and their details (time left/ago) + checkbox in form to toggle completed -->
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 mt-4">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 mt-4 py-3">
|
||||||
<h2 class="text-2xl font-semibold mb-4 text-green-500 dark:text-green-400">
|
<h2 class="text-2xl font-semibold mb-4 text-green-500 dark:text-green-400">
|
||||||
Today's Todos
|
Today's Todos
|
||||||
({{ $incomplete_count }})
|
({{ $incomplete_count }})
|
||||||
|
@ -122,42 +122,41 @@
|
||||||
<div class="space-y-4" id="todo-container">
|
<div class="space-y-4" id="todo-container">
|
||||||
@include('dashboard.load-todo')
|
@include('dashboard.load-todo')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- Pagination with CSS -->
|
||||||
|
<div class="invisible">
|
||||||
<!-- Pagination with CSS -->
|
{{ $todos->links() }}
|
||||||
<div class="invisible">
|
</div>
|
||||||
{{ $todos->links() }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
let nextPageUrl = '{{ $todos->nextPageUrl() }}';
|
let nextPageUrl = '{{ $todos->nextPageUrl() }}';
|
||||||
|
|
||||||
$(window).scroll(function () {
|
$(window).scroll(function () {
|
||||||
if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100) {
|
if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100) {
|
||||||
if (nextPageUrl) {
|
if (nextPageUrl) {
|
||||||
loadMorePosts();
|
loadMoreTodos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadMorePosts() {
|
function loadMoreTodos() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: nextPageUrl,
|
url: nextPageUrl,
|
||||||
type: 'get',
|
type: 'get',
|
||||||
beforeSend: function () {
|
beforeSend: function () {
|
||||||
nextPageUrl = '';
|
nextPageUrl = '';
|
||||||
},
|
},
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
nextPageUrl = data.nextPageUrl;
|
nextPageUrl = data.nextPageUrl;
|
||||||
$('#todo-container').append(data.view);
|
$('#todo-container').append(data.view);
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
console.error("Error loading more posts:", error);
|
console.error("Error loading more posts:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</x-app-layout>
|
</x-app-layout>
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6">
|
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6">
|
||||||
<h3 class="text-xl font-semibold mb-4 text-blue-500 dark:text-blue-400">
|
<h3 class="text-xl font-semibold mb-4 text-blue-500 dark:text-blue-400">
|
||||||
<!-- SVG for Pomo Average Cound -->
|
<!-- SVG for Pomo Average Count -->
|
||||||
<svg class="inline-block h-6 w-6 text-blue-500 dark:text-blue-400"
|
<svg class="inline-block h-6 w-6 text-blue-500 dark:text-blue-400"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
@foreach ($pomos as $pomo)
|
||||||
|
<tr class="hover:bg-blue-100 dark:hover:bg-gray-700">
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
<a href="{{ route('project.todo.edit', ['project' => $pomo->todo->project->id, 'todo' => $pomo->todo->id]) }}">
|
||||||
|
{{ $pomo->todo->title }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<!-- Pomo Start and Pomo End -->
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
{{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->format('Y-m-d H:i:s') }}
|
||||||
|
</td>
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
{{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_end)->format('Y-m-d H:i:s') }}
|
||||||
|
</td>
|
||||||
|
<!-- Duration -->
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
{{
|
||||||
|
\Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->diffInMinutes(\Carbon\Carbon::createFromTimestamp($pomo->pomo_end))
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
<!-- Truncate notes to 32 characters -->
|
||||||
|
<div class="max-w-sm truncate">
|
||||||
|
{{ $pomo->notes }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
||||||
|
<!-- Edit and Delete form button groups -->
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<a href="{{ route('pomo.edit', $pomo->id) }}"
|
||||||
|
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Edit</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<form action="{{ route('pomo.destroy', $pomo->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit"
|
||||||
|
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Delete
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
|
@ -10,53 +10,8 @@
|
||||||
<th class="px-4 py-2">Actions</th>
|
<th class="px-4 py-2">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="pomo-container">
|
||||||
@foreach ($pomos as $pomo)
|
@include('livewire.pomo.load-pomo')
|
||||||
<tr class="hover:bg-blue-100 dark:hover:bg-gray-700">
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
<a href="{{ route('project.todo.edit', ['project' => $pomo->todo->project->id, 'todo' => $pomo->todo->id]) }}">
|
|
||||||
{{ $pomo->todo->title }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<!-- Pomo Start and Pomo End -->
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
{{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->format('Y-m-d H:i:s') }}
|
|
||||||
</td>
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
{{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_end)->format('Y-m-d H:i:s') }}
|
|
||||||
</td>
|
|
||||||
<!-- Duration -->
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
{{
|
|
||||||
\Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->diffInMinutes(\Carbon\Carbon::createFromTimestamp($pomo->pomo_end))
|
|
||||||
}}
|
|
||||||
</td>
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
<!-- Truncate notes to 32 characters -->
|
|
||||||
<div class="max-w-sm truncate">
|
|
||||||
{{ $pomo->notes }}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="border px-4 py-2 text-blue-900 dark:text-gray-100">
|
|
||||||
<!-- Edit and Delete form button groups -->
|
|
||||||
<div class="flex flex-row">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<a href="{{ route('pomo.edit', $pomo->id) }}"
|
|
||||||
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Edit</a>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<form action="{{ route('pomo.destroy', $pomo->id) }}" method="POST">
|
|
||||||
@csrf
|
|
||||||
@method('DELETE')
|
|
||||||
<button type="submit"
|
|
||||||
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Delete
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,53 +11,16 @@
|
||||||
|
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" id="project-container">
|
||||||
@foreach($projects as $project)
|
@include('project.load-projects')
|
||||||
<div class="relative">
|
|
||||||
<a href="{{ route('project.todo.index', $project) }}" class="card-link">
|
|
||||||
<div
|
|
||||||
class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 hover:shadow-md transition duration-300 ease-in-out transform hover:-translate-y-1">
|
|
||||||
<div class="text-gray-800 dark:text-gray-100">
|
|
||||||
<div class="mb-4">
|
|
||||||
<h3 class="font-semibold text-lg mb-2">{{ $project->name }}</h3>
|
|
||||||
<p class="text-gray-600 dark:text-gray-400">{{ $project->description }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<form action="{{ route('project.destroy', $project) }}" method="POST"
|
|
||||||
class="delete-project-form absolute top-1 right-1">
|
|
||||||
@csrf
|
|
||||||
@method('DELETE')
|
|
||||||
<button type="button"
|
|
||||||
class="delete-button text-red-600 hover:text-red-800 transition duration-300 ease-in-out">
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
||||||
d="M6 18L18 6M6 6l12 12"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div class="modal hidden">
|
|
||||||
<!-- Small Popover, with a background that is visible when modal is open -->
|
|
||||||
<div class="popover popover-sm bg-white dark:bg-gray-800 shadow-lg rounded-lg p-6">
|
|
||||||
<p class="mb-4">Are you sure you want to delete this project?</p>
|
|
||||||
<button type="submit"
|
|
||||||
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded mr-2">
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="cancel-button bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="invisible">
|
||||||
|
{{ $projects->links() }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const deleteButtons = document.querySelectorAll('.delete-button');
|
const deleteButtons = document.querySelectorAll('.delete-button');
|
||||||
const cancelButtons = document.querySelectorAll('.cancel-button');
|
const cancelButtons = document.querySelectorAll('.cancel-button');
|
||||||
|
@ -72,6 +35,35 @@
|
||||||
modals[index].classList.add('hidden');
|
modals[index].classList.add('hidden');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
let nextPageUrl = '{{ $projects->nextPageUrl() }}';
|
||||||
|
|
||||||
|
$(window).scroll(function () {
|
||||||
|
if ($(window).scrollTop() + $(window).height() >= $(document).height() - 2000) {
|
||||||
|
if (nextPageUrl) {
|
||||||
|
loadMoreProjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadMoreProjects() {
|
||||||
|
$.ajax({
|
||||||
|
url: nextPageUrl,
|
||||||
|
type: 'get',
|
||||||
|
beforeSend: function () {
|
||||||
|
nextPageUrl = '';
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
nextPageUrl = data.nextPageUrl;
|
||||||
|
$('#project-container').append(data.view);
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.error("Error loading more posts:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@include('todo.todo_list')
|
@include('todo.todo_list')
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
@foreach($projects as $project)
|
||||||
|
<div class="relative">
|
||||||
|
<a href="{{ route('project.todo.index', $project) }}" class="card-link">
|
||||||
|
<div
|
||||||
|
class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 hover:shadow-md transition duration-300 ease-in-out transform hover:-translate-y-1">
|
||||||
|
<div class="text-gray-800 dark:text-gray-100">
|
||||||
|
<div class="mb-4">
|
||||||
|
<h3 class="font-semibold text-lg mb-2">{{ $project->name }}</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400">{{ $project->description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<form action="{{ route('project.destroy', $project) }}" method="POST"
|
||||||
|
class="delete-project-form absolute top-1 right-1">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="button"
|
||||||
|
class="delete-button text-red-600 hover:text-red-800 transition duration-300 ease-in-out">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M6 18L18 6M6 6l12 12"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="modal hidden">
|
||||||
|
<!-- Small Popover, with a background that is visible when modal is open -->
|
||||||
|
<div class="popover popover-sm bg-white dark:bg-gray-800 shadow-lg rounded-lg p-6">
|
||||||
|
<p class="mb-4">Are you sure you want to delete this project?</p>
|
||||||
|
<button type="submit"
|
||||||
|
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded mr-2">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="cancel-button bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
|
@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Route;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return redirect(route('project.index'));
|
return redirect(route('dashboard'));
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/dashboard', [DashboardController::class, 'index'])
|
Route::get('/dashboard', [DashboardController::class, 'index'])
|
||||||
|
|
Loading…
Reference in New Issue