Added dynamic filtering

This commit is contained in:
Charles 2025-10-27 15:57:14 +01:00
parent ec3fc7f5ca
commit a219f0f067
2 changed files with 42 additions and 8 deletions

View File

@ -113,6 +113,7 @@ export default class extends Controller {
const first = (s) => (typeof s === "string" && s.length ? s.trim()[0].toUpperCase() : ""); const first = (s) => (typeof s === "string" && s.length ? s.trim()[0].toUpperCase() : "");
const initials = `${first(data.name)}${first(data.prenom)}`; const initials = `${first(data.name)}${first(data.prenom)}`;
// wrapper is for centering and circle clipping
const wrapper = document.createElement("div"); const wrapper = document.createElement("div");
wrapper.className = "avatar-wrapper"; wrapper.className = "avatar-wrapper";
// same size for both cases // same size for both cases
@ -282,7 +283,7 @@ export default class extends Controller {
}]; }];
const tabulator = new Tabulator("#tabulator-userList", { const tabulator = new Tabulator("#tabulator-userList", {
langs: TABULATOR_FR_LANG, langs: TABULATOR_FR_LANG,
locale: "fr", //'en' for English, 'fr' for French (en is default, no need to include it) locale: "fr",
ajaxURL: "/user/data", ajaxURL: "/user/data",
ajaxConfig: "GET", ajaxConfig: "GET",
pagination: true, pagination: true,
@ -295,9 +296,26 @@ export default class extends Controller {
ajaxSorting: true, ajaxSorting: true,
ajaxFiltering: true, ajaxFiltering: true,
rowHeight: 60, filterMode: "remote",
layout: "fitColumns", // activate French
// Add this to send filter data
ajaxURLGenerator: function(url, config, params) {
let queryParams = new URLSearchParams();
queryParams.append('page', params.page || 1);
queryParams.append('size', params.size || 10);
// Add filters
if (params.filter) {
params.filter.forEach(filter => {
queryParams.append(`filter[${filter.field}]`, filter.value);
});
}
return `${url}?${queryParams.toString()}`;
},
rowHeight: 60,
layout: "fitColumns",
columns columns
}); });
}; };

View File

@ -393,11 +393,29 @@ class UserController extends AbstractController
$page = max(1, (int)$request->query->get('page', 1)); $page = max(1, (int)$request->query->get('page', 1));
$size = max(1, (int)$request->query->get('size', 10)); $size = max(1, (int)$request->query->get('size', 10));
// Get filter parameters
$filters = $request->query->all('filter', []);
$repo = $this->userRepository; $repo = $this->userRepository;
// Base query: keep your constraints intact (isDeleted=false, isActive=true) // Base query
$qb = $repo->createQueryBuilder('u') $qb = $repo->createQueryBuilder('u')
->where('u.isDeleted = :del')->setParameter('del', false); ->where('u.isDeleted = :del')->setParameter('del', false);
// Apply filters
if (!empty($filters['name'])) {
$qb->andWhere('u.surname LIKE :name')
->setParameter('name', '%' . $filters['name'] . '%');
}
if (!empty($filters['prenom'])) {
$qb->andWhere('u.name LIKE :prenom')
->setParameter('prenom', '%' . $filters['prenom'] . '%');
}
if (!empty($filters['email'])) {
$qb->andWhere('u.email LIKE :email')
->setParameter('email', '%' . $filters['email'] . '%');
}
$countQb = clone $qb; $countQb = clone $qb;
$total = (int)$countQb->select('COUNT(u.id)')->getQuery()->getSingleScalarResult(); $total = (int)$countQb->select('COUNT(u.id)')->getQuery()->getSingleScalarResult();
@ -405,7 +423,7 @@ class UserController extends AbstractController
$offset = ($page - 1) * $size; $offset = ($page - 1) * $size;
$rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult(); $rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult();
// Map to array (keep isConnected) // Map to array
$data = array_map(function (User $user) { $data = array_map(function (User $user) {
return [ return [
'id' => $user->getId(), 'id' => $user->getId(),
@ -419,15 +437,13 @@ class UserController extends AbstractController
]; ];
}, $rows); }, $rows);
// Match organizations response shape
$lastPage = (int)ceil($total / $size); $lastPage = (int)ceil($total / $size);
return $this->json([ return $this->json([
'data' => $data, 'data' => $data,
'last_page' => $lastPage, 'last_page' => $lastPage,
'total' => $total, // optional but handy 'total' => $total,
]); ]);
} }
#[Route(path: '/indexTest', name: 'indexTest', methods: ['GET'])] #[Route(path: '/indexTest', name: 'indexTest', methods: ['GET'])]