Skip to content

Commit

Permalink
feat(bo): list territoires filter and dsfrV2 760
Browse files Browse the repository at this point in the history
  • Loading branch information
l-scherer committed Dec 11, 2024
1 parent e410f6e commit e5f2636
Show file tree
Hide file tree
Showing 11 changed files with 361 additions and 135 deletions.
2 changes: 1 addition & 1 deletion packages/backend/src/controllers/demandeSejour/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = async function get(req, res, next) {
total: demandes.total,
});
} catch (error) {
console.log(error);
log.w(error);
log.w("DONE with error");
return next(error);
}
Expand Down
18 changes: 13 additions & 5 deletions packages/backend/src/controllers/territoire/list.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
const Territoire = require("../../services/Territoire");

const logger = require("../../utils/logger");

const log = logger(module.filename);

module.exports = async function list(_req, res) {
module.exports = async function list(req, res, next) {
log.i("IN");
const territoires = await Territoire.fetch();
log.i("DONE");
return res.json({ territoires });
try {
const territoires = await Territoire.fetch(req.query);
log.d(territoires);
return res.status(200).json({
territoires: territoires.rows,
total: territoires.total,
});
} catch (error) {
log.w(error);
log.w("DONE with error");
return next(error);
}
};
3 changes: 2 additions & 1 deletion packages/backend/src/helpers/__tests__/queryParams.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ describe("queryParams", () => {
it("should apply filters to the query", () => {
const query = "SELECT * FROM users";
const filterParams = { age: "30", name: "John" };
const result = applyFilters(query, [], filterParams);
const groupBy = "";
const result = applyFilters(query, [], filterParams, groupBy);
// remove return at line to fix space pb
expect(result.query.replace(/\s+/g, " ").trim()).toContain(
"unaccent(age::text) ILIKE '%' || unaccent($1) || '%'",
Expand Down
14 changes: 9 additions & 5 deletions packages/backend/src/helpers/queryParams.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
module.exports = {
applyFilters: (query = "", initialParams = [], filterParams = {}) => {
applyFilters: (
query = "",
initialParams = [],
filterParams = {},
groupBy = "",
) => {
const params = [...initialParams];
if (Object.keys(filterParams).length === 0) {
return {
params: initialParams,
query,
query: `${query} ${groupBy}`,
};
}
const filters = Object.entries(filterParams)
Expand All @@ -18,7 +23,7 @@ module.exports = {
.join(" AND ");
return {
params,
query: `${query} AND ${filters}`,
query: `${query} AND ${filters} ${groupBy}`,
};
},
applyPagination: (
Expand All @@ -39,15 +44,14 @@ module.exports = {
const countQuery = `
SELECT COUNT(*) AS total FROM (${query}) AS subquery;
`;

return {
countQuery,
countQueryParams: params,
params: [...params, limit, offset],
query: paginatedQuery,
};
},
sanityzeFiltersParams: (queryParams, availableParams) =>
sanityzeFiltersParams: (queryParams, availableParams) =>
Object.entries(availableParams).reduce((acc, [key, value]) => {
if (queryParams[key]) {
acc[value] = queryParams[key];
Expand Down
8 changes: 7 additions & 1 deletion packages/backend/src/services/DemandeSejour.js
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,13 @@ module.exports.get = async (organismesId, queryParams) => {
);
const filterParams = sanityzeFiltersParams(queryParams, titles);
const queryGet = query.get();
const filterQuery = applyFilters(queryGet, [organismesId], filterParams);
const groupBy = "";
const filterQuery = applyFilters(
queryGet,
[organismesId],
filterParams,
groupBy,
);
const paginatedQuery = applyPagination(
filterQuery.query,
filterQuery.params,
Expand Down
66 changes: 48 additions & 18 deletions packages/backend/src/services/Territoire.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@ const logger = require("../utils/logger");
const pool = require("../utils/pgpool").getPool();

const log = logger(module.filename);
const {
sanityzePaginationParams,
sanityzeFiltersParams,
applyFilters,
applyPagination,
} = require("../helpers/queryParams");

const query = {
getFicheIdByTerCode: `
select
fte.id AS id
FROM back.fiche_territoire fte
WHERE ter_code = $1`,
getOne: `
select
fte.id AS territoire_id,
Expand All @@ -23,12 +34,8 @@ const query = {
FROM back.fiche_territoire fte
INNER JOIN geo.territoires ter ON fte.ter_code = ter.code
WHERE fte.id = $1`,
getFicheIdByTerCode: `
select
fte.id AS id
FROM back.fiche_territoire fte
WHERE ter_code = $1`,
select: `
select: () =>
`
select
fte.id AS territoire_id,
CASE (ter.code ~ '[0-9]')
Expand All @@ -45,9 +52,11 @@ const query = {
FROM geo.territoires ter
INNER JOIN back.fiche_territoire fte ON fte.ter_code = ter.code
LEFT JOIN back.users usr ON usr.ter_code = ter.code
WHERE code <> 'FRA'
WHERE ter.code <> 'FRA'`,
selectGroupBy: () =>
`
GROUP BY territoire_id,type,value,text,service_telephone,corresp_vao_nom,corresp_vao_prenom,service_mail
ORDER BY type, text ASC`,
`,
update: `
UPDATE back.fiche_territoire
SET
Expand All @@ -62,18 +71,39 @@ const query = {
`,
};

module.exports.fetch = async (criterias = {}) => {
log.i("fetch - IN");
const { rows } = await pool.query(query.select);

return rows.filter((territoire) => {
return Object.entries(criterias).every(
([key, value]) => territoire[key] == value,
);
});
module.exports.fetch = async (queryParams) => {
const titles = {
text: "ter.label",
value: "ter.code",
};
const { limit, offset, sortBy, sortDirection } = sanityzePaginationParams(
queryParams,
{
sortBy: titles,
},
);
const filterParams = sanityzeFiltersParams(queryParams, titles);
const groupBy = query.selectGroupBy();
const queryGet = query.select();
const filterQuery = applyFilters(queryGet, [], filterParams, groupBy);
const paginatedQuery = applyPagination(
filterQuery.query,
filterQuery.params,
limit,
offset,
sortBy,
sortDirection,
);
const result = await Promise.all([
pool.query(paginatedQuery.query, paginatedQuery.params),
pool.query(paginatedQuery.countQuery, paginatedQuery.countQueryParams),
]);
return {
rows: result[0].rows,
total: parseInt(result[1].rows[0].total, 10),
};
};


module.exports.readFicheIdByTerCode = async (territoireCode) => {
log.i("readFicheIdByTerCode - IN");
const { rows } = await pool.query(query.getFicheIdByTerCode, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ const updateData = () => {
...(isValidParams(sortDirection.value)
? { sortDirection: sortDirection.value.toUpperCase() }
: {}),
search: getSearchParams(),
...getSearchParams(),
};
demandeSejourStore.fetchDemandes(query);
Expand Down
181 changes: 181 additions & 0 deletions packages/frontend-bo/src/components/territoires/DefaultTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<template>
<TerritoiresDefaultTableFilters
v-model:text="text"
@filters-update="updateData"
/>
<DsfrDataTableV2Wrapper
v-model:limit="limit"
v-model:offset="offset"
v-model:sort="sort"
v-model:sort-direction="sortDirection"
:titles="titles"
:table-title="title"
:data="data"
:total="total"
row-id="territoireId"
is-sortable
@update-data="updateData"
>
<template #cell:typeTerritoire="{ row }">
{{ row.type === "DEP" ? "Département" : "Région" }}
</template>
<template #cell:custom-edit="{ row }">
<DsfrButton
:label="
['FRA', row.value, row.parent].includes(userStore.user.territoireCode)
? 'Editer la fiche territoire'
: 'Consulter la fiche territoire'
"
:icon="
['FRA', row.value, row.parent].includes(userStore.user.territoireCode)
? 'fr-icon-edit-fill'
: 'fr-icon-eye-fill'
"
icon-only
primary
size="small"
type="button"
@click="navigate(row)"
/>
</template>
</DsfrDataTableV2Wrapper>
</template>

<script setup>
import { DsfrDataTableV2Wrapper } from "@vao/shared";
const territoireStore = useTerritoireStore();
const userStore = useUserStore();
const route = useRoute();
const data = computed(() => territoireStore.territoires);
const total = computed(() => territoireStore.total);
const { query } = route;
const titles = [
{
key: "text",
label: "Libellé",
options: {
isSortable: true,
},
},
{
key: "typeTerritoire",
label: "Département/Région",
options: {
isSortable: false,
},
},
{
key: "nbUsersBO",
label: "Contacts",
sort: false,
},
{
key: "value",
label: "Code",
options: {
isSortable: true,
},
},
{
key: "correspVaoNom",
label: "Référent VAO",
options: {
isSortable: true,
},
},
{
key: "serviceTelephone",
label: "Téléphone",
options: {
isSortable: true,
},
},
{
key: "serviceMail",
label: "Boite fonctionnelle",
options: {
isSortable: true,
},
},
{
key: "custom-edit",
label: "Action",
},
];
const title = computed(
() => `Liste des territoires (${territoireStore.total})`,
);
const sortableTitles = titles.flatMap((title) =>
title.options?.isSortable ? [title.key] : [],
);
const text = ref(query.text ?? "");
const limit = ref(parseInt(query.limit, 10) || 10);
const offset = ref(parseInt(query.offset, 10) || 0);
const sort = ref(sortableTitles.includes(query.sort) ? query.sort : "");
const sortDirection = ref(
["", "ASC", "DESC"].includes(query.sortDirection) ? query.sortDirection : "",
);
const isValidParams = (params) =>
params !== undefined &&
params !== null &&
params !== "" &&
(!Array.isArray(params) || params.length > 0);
const getSearchParams = () =>
isValidParams(text.value) ? { text: text.value } : {};
let timeout = null;
const updateData = () => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
const query = {
limit: limit.value,
offset: offset.value,
...(isValidParams(sort.value) ? { sortBy: sort.value } : {}),
...(isValidParams(sortDirection.value)
? { sortDirection: sortDirection.value.toUpperCase() }
: {}),
...getSearchParams(),
};
territoireStore.fetch2(query);
navigateTo({
query: {
limit: limit.value,
offset: offset.value,
...(isValidParams(sort.value) ? { sortBy: sort.value } : {}),
...(isValidParams(sortDirection.value)
? { sortDirection: sortDirection.value }
: {}),
...getSearchParams(),
},
});
}, 300);
};
onUnmounted(() => {
if (timeout) {
clearTimeout(timeout);
}
});
updateData();
// actions
const navigate = (state) => {
navigateTo({
path: `/territoires/${state.territoireId}`,
});
};
</script>
Loading

0 comments on commit e5f2636

Please sign in to comment.