diff --git a/package.json b/package.json
index c706491433ac7e31c08ae506d715918096870261..7c9b4baa75322ec979b12337dcd459fa6ac65247 100644
--- a/package.json
+++ b/package.json
@@ -13,13 +13,17 @@
     "@material-ui/lab": "^4.0.0-alpha.48",
     "@material-ui/styles": "^4.10.0",
     "downloadjs": "^1.4.7",
+    "i18next": "^23.11.2",
+    "i18next-http-backend": "^2.5.1",
     "moment": "^2.27.0",
     "mui-datatables": "^3.4.0",
     "ol": "^6.3.2-dev.1594217558556",
+    "proj4": "^2.11.0",
     "react": "^16.13.1",
     "react-dom": "^16.13.1",
     "react-hanger": "^2.2.1",
     "react-html-parser": "^2.0.2",
+    "react-i18next": "^14.1.1",
     "react-router-dom": "^5.2.0",
     "react-scripts": "^3.3.0"
   },
@@ -45,12 +49,12 @@
     ]
   },
   "devDependencies": {
-    "jscs": "^3.0.7",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-prettier": "^5.1.3",
     "husky": "8.0.3",
+    "jscs": "^3.0.7",
     "lint-staged": "14.0.1",
-    "prettier": "^3.2.5",
-    "eslint-config-prettier": "^9.1.0",
-    "eslint-plugin-prettier": "^5.1.3"
+    "prettier": "^3.2.5"
   },
   "husky": {
     "hooks": {
diff --git a/public/index.html b/public/index.html
index 38223fe591121af96fe75b88c0b43242e7ad2dd6..5e6c56481c2b2e5db90e8168d6f8261aab9e9f72 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,17 +1,11 @@
 <!DOCTYPE html>
 <html lang="en">
-
 <head>
   <meta charset="utf-8" />
-  <!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> -->
+  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <meta name="theme-color" content="#000000" />
-  <!--
-      manifest.json provides metadata used when your web app is installed on a
-      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-    -->
   <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
-
   <!--
       Notice the use of %PUBLIC_URL% in the tags above.
       It will be replaced with the URL of the `public` folder during the build.
@@ -21,23 +15,11 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-  <title>IN-SYLVA SEARCH</title>
+  <title>IN-SYLVA Search</title>
   <script src="%PUBLIC_URL%/env-config.js"></script>
 </head>
-
 <body>
   <noscript>You need to enable JavaScript to run this app.</noscript>
   <div id="root"></div>
-  <!--
-      This HTML file is a template.
-      If you open it directly in the browser, you will see an empty page.
-
-      You can add webfonts, meta tags, or analytics to this file.
-      The build step will place the bundled scripts into the <body> tag.
-
-      To begin the development, run `npm start` or `yarn start`.
-      To create a production bundle, use `npm run build` or `yarn build`.
-    -->
 </body>
-
 </html>
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
new file mode 100644
index 0000000000000000000000000000000000000000..506293c381c1ba92b8c840aaea2d59b85ba3c993
--- /dev/null
+++ b/public/locales/en/common.json
@@ -0,0 +1,13 @@
+{
+  "languages": {
+    "en": "English",
+    "fr": "French"
+  },
+  "inSylvaLogoAlt": "In-Sylva logo",
+  "validationActions": {
+    "cancel": "Cancel",
+    "send": "Send",
+    "save": "Save",
+    "validate": "Validate"
+  }
+}
diff --git a/public/locales/en/header.json b/public/locales/en/header.json
new file mode 100644
index 0000000000000000000000000000000000000000..889a13d8020dc576da3ac10b65ed7e7c394204f6
--- /dev/null
+++ b/public/locales/en/header.json
@@ -0,0 +1,11 @@
+{
+  "tabs": {
+    "home": "Home",
+    "search": "Search"
+  },
+  "userMenu": {
+    "title": "User profile",
+    "editProfileButton": "Edit profile",
+    "logOutButton": "Log out"
+  }
+}
diff --git a/public/locales/en/home.json b/public/locales/en/home.json
new file mode 100644
index 0000000000000000000000000000000000000000..d1038e005f2484a8a1e436071e369bfadee70574
--- /dev/null
+++ b/public/locales/en/home.json
@@ -0,0 +1,11 @@
+{
+  "pageTitle": "Welcome on In-Sylva search module's homepage.",
+  "searchToolDescription": {
+    "part1": "As a reminder, it should be remembered that the metadata stored in IN-SYLVA IS are structured around the IN-SYLVA standard.",
+    "part2": "This standard is composed of metadata fields. A metadata record is therefore made up of a series of fields accompanied by their value.",
+    "part3": "With this part of the interface you will be able to search for metadata records (previously loaded via the portal), by defining a certain number of criteria.",
+    "part4": "By default the \"search\" interface opens to a \"plain text\" search, ie the records returned in the result are those which, in one of the field values, contains the supplied character string.",
+    "part5": "A click on the Advanced search button gives access to a more complete form via which you can do more precise searches on one or more targeted fields.",
+    "part6": "Click on the \"Search\" tab to access the search interface."
+  }
+}
diff --git a/public/locales/en/maps.json b/public/locales/en/maps.json
new file mode 100644
index 0000000000000000000000000000000000000000..555595d382f4cd15870bd7552c8bb2d287ca77bd
--- /dev/null
+++ b/public/locales/en/maps.json
@@ -0,0 +1,28 @@
+{
+  "layersTableHeaders": {
+    "cartography": "Cartography",
+    "filters": "Filters",
+    "tools": "Tools"
+  },
+  "layersTable": {
+    "openStreetMap": "Open Street Map",
+    "bingAerial": "Bing Aerial",
+    "IGN": "IGN map",
+    "queryResults": "Query results",
+    "regions": "Regions",
+    "departments": "Departments",
+    "sylvoEcoRegions": "SylvoEcoRegions",
+    "selectFilterOption": "Select a single option",
+    "zoomHelperText": "Use ctrl + scroll to zoom the map",
+    "selectionTool": {
+      "title": "Point selection mode",
+      "select": "Add",
+      "unselect": "Remove",
+      "unselectAll": "Unselect all points"
+    }
+  },
+  "selectedPointsList": {
+    "title": "Selected resources list",
+    "empty": "Select resources to display them here."
+  }
+}
diff --git a/public/locales/en/profile.json b/public/locales/en/profile.json
new file mode 100644
index 0000000000000000000000000000000000000000..76ab2db9f4c52d0a9f25098cf4c7cc302f038eac
--- /dev/null
+++ b/public/locales/en/profile.json
@@ -0,0 +1,23 @@
+{
+  "pageTitle": "Profile management",
+  "groups": {
+    "groupsList": "Group list",
+    "groupName": "Name",
+    "groupDescription": "Description"
+  },
+  "requestsList": {
+    "requestsList": "Requests list",
+    "requestsMessage": "Message",
+    "processed": "Processed",
+    "cancelRequest": "Cancel this request"
+  },
+  "groupRequests": {
+    "requestGroupAssignment": "Request a group assignment",
+    "currentGroups": "You currently belong to (or have a pending request for) these groups:",
+    "noGroup": "You currently don't belong to any group."
+  },
+  "roleRequests": {
+    "requestRoleAssignment": "Request an application role",
+    "currentRole": "You currently have (or have a pending request for) this role:"
+  }
+}
diff --git a/public/locales/en/results.json b/public/locales/en/results.json
new file mode 100644
index 0000000000000000000000000000000000000000..baaaa092998cf918fd7cbb01b758a76a4cc257f6
--- /dev/null
+++ b/public/locales/en/results.json
@@ -0,0 +1,47 @@
+{
+  "clickOnRowTip": "Click on a row to display metadata.",
+  "downloadResultsButton": {
+    "JSON": "Download as JSON"
+  },
+  "table": {
+    "title": "Search results from query: <strong>{{searchQuery}}</strong>",
+    "search": "Search among results",
+    "displaySelectedRowsButton": "Sort selection",
+    "textLabels": {
+      "body": {
+        "noMatch": "No matching records found",
+        "toolTip": "Sort"
+      },
+      "pagination": {
+        "next": "Next Page",
+        "previous": "Previous Page",
+        "rowsPerPage": "Rows per page:",
+        "displayRows": "of",
+        "jumpToPage": "Page:"
+      },
+      "toolbar": {
+        "search": "Search",
+        "viewColumns": "View Columns",
+        "filterTable": "Filter Table"
+      },
+      "filter": {
+        "all": "All",
+        "title": "FILTERS",
+        "reset": "RESET"
+      },
+      "viewColumns": {
+        "title": "Show Columns",
+        "titleAria": "Show/Hide Table Columns"
+      },
+      "selectedRows": {
+        "text": "row(s) selected"
+      }
+    }
+  },
+  "flyout": {
+    "label": "Resource data sheet",
+    "JSON": {
+      "title": "Resource JSON data"
+    }
+  }
+}
diff --git a/public/locales/en/search.json b/public/locales/en/search.json
new file mode 100644
index 0000000000000000000000000000000000000000..cebc9ebd923a6e84a544c21650da1a833a2c1bea
--- /dev/null
+++ b/public/locales/en/search.json
@@ -0,0 +1,78 @@
+{
+  "pageTitle": "In-Sylva Metadata Search Platform",
+  "tabs": {
+    "composeSearch": "Compose search",
+    "results": "Results",
+    "map": "Map"
+  },
+  "sendSearchButton": "Search",
+  "basicSearch": {
+    "switchSearchMode": "Switch to advanced search",
+    "searchInputPlaceholder": "Search..."
+  },
+  "advancedSearch": {
+    "switchSearchMode": "Switch to basic search",
+    "textQueryPlaceholder": "Add fields...",
+    "countResultsButton": "Count results",
+    "resultsCount_one": "{{count}} result",
+    "resultsCount_other": "{{count}} results",
+    "editableSearchButton": "Editable",
+    "errorInvalidOption": "\"{{value}}\" is not a valid option.",
+    "fields": {
+      "title": "Field search",
+      "loadingFields": "Loading fields...",
+      "removeFieldButton": "Remove field",
+      "clearValues": "Clear values",
+      "addFieldPopover": {
+        "openPopoverButton": "Add field",
+        "title": "Select a field",
+        "button": "Add this field",
+        "selectSection": "Select a section"
+      },
+      "fieldContentPopover": {
+        "addFieldValues": "Add field values",
+        "addValue": "Add value",
+        "firstValue": "1st value",
+        "secondValue": "2nd value",
+        "inputTextValue": "Type value",
+        "betweenDate": "between",
+        "andDate": "and",
+        "selectValues": "Select values"
+      }
+    },
+    "searchHistory": {
+      "placeholder": "Load a previous request",
+      "saveSearch": "Save search",
+      "addSavedSearchName": "Search name",
+      "addSavedSearchDescription": "Description (optional)",
+      "addSavedSearchDescriptionPlaceholder": "Search description..."
+    },
+    "searchOptions": {
+      "title": "Search option",
+      "matchAll": "Match all criterias",
+      "matchAtLeastOne": "Match at least one criteria"
+    },
+    "partnerSources": {
+      "title": "Partner sources",
+      "allSourcesSelected": "By default, all sources are selected",
+      "noSourceAvailable": "No source available."
+    },
+    "policyToast": {
+      "title": "Private field selected",
+      "content": [
+        "You selected a private field.",
+        "Access to this field was granted for specific sources, which means that your search will be restricted to those.",
+        "Please check the sources list before searching."
+      ]
+    },
+    "editableQueryToast": {
+      "title": "Proceed with caution",
+      "content": {
+        "part1": "Manually editing can spoil query results. Syntax must be respected:",
+        "part2": "Fields and their values should be put between brackets: { } - Make sure every opened bracket is closed",
+        "part3": "\"AND\" and \"OR\" should be capitalized between fields and lowercase within a field expression",
+        "part4": "Make sure to check for typing errors"
+      }
+    }
+  }
+}
diff --git a/public/locales/en/validation.json b/public/locales/en/validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..b12bd6a67aead265e9d0262c00b61d58d51137f7
--- /dev/null
+++ b/public/locales/en/validation.json
@@ -0,0 +1,3 @@
+{
+  "requestSent": "Your request has been sent to the administrators."
+}
diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json
new file mode 100644
index 0000000000000000000000000000000000000000..8e9085fbe434c4ceab454e939e90ab0139dbef0e
--- /dev/null
+++ b/public/locales/fr/common.json
@@ -0,0 +1,13 @@
+{
+  "languages": {
+    "en": "Anglais",
+    "fr": "Français"
+  },
+  "inSylvaLogoAlt": "Logo In-Sylva",
+  "validationActions": {
+    "cancel": "Annuler",
+    "send": "Envoyer",
+    "save": "Sauvegarder",
+    "validate": "Valider"
+  }
+}
diff --git a/public/locales/fr/header.json b/public/locales/fr/header.json
new file mode 100644
index 0000000000000000000000000000000000000000..a5e28a5e7bc627ee31d4145c909be2da802a29d4
--- /dev/null
+++ b/public/locales/fr/header.json
@@ -0,0 +1,11 @@
+{
+  "tabs": {
+    "home": "Page d'accueil",
+    "search": "Recherche"
+  },
+  "userMenu": {
+    "title": "Profil utilisateur",
+    "editProfileButton": "Modifier mon profil",
+    "logOutButton": "Déconnexion"
+  }
+}
diff --git a/public/locales/fr/home.json b/public/locales/fr/home.json
new file mode 100644
index 0000000000000000000000000000000000000000..f9bdcd684df9cd4074239e84b369a5a97893ffcc
--- /dev/null
+++ b/public/locales/fr/home.json
@@ -0,0 +1,11 @@
+{
+  "pageTitle": "Bienvenue sur la page d'accueil du module de recherche du Système d'Information In-Sylva",
+  "searchToolDescription": {
+    "part1": "Il est important de rappeler que les métadonnées stockées dans le SI In-Sylva sont structurées autour du standard établi par In-Sylva.",
+    "part2": "Il est composé de champs de métadonnées. Une fiche de métadonnées est donc constituée d'une série de champs accompagnés de leur valeur.",
+    "part3": "Cette interface vous permettra de rechercher des fiches de métadonnées (chargées au préalable par le Portal), en définissant un certain nombre de critères.",
+    "part4": "L'interface \"Recherche\" ouvre une zone de texte de \"Recherche basique\". Les résultats correspondent aux fiches de métadonnées contenant, dans un de leurs champs, la chaîne de caractère renseignée.",
+    "part5": "Un click sur le bouton \"Recherche avancée\" vous permets d'accéder à un formulaire plus complet qui vous permettra des recherches plus précises sur un ou plusieurs champs donnés.",
+    "part6": "Clickez sur l'onglet \"Recherche\" pour accéder à l'interface de recherche."
+  }
+}
diff --git a/public/locales/fr/maps.json b/public/locales/fr/maps.json
new file mode 100644
index 0000000000000000000000000000000000000000..fdbcd9b0ae3c35b92d6b57e63c62952ec5d92e76
--- /dev/null
+++ b/public/locales/fr/maps.json
@@ -0,0 +1,28 @@
+{
+  "layersTableHeaders": {
+    "cartography": "Cartographie",
+    "filters": "Filtres",
+    "tools": "Outils"
+  },
+  "layersTable": {
+    "openStreetMap": "Open Street Map",
+    "bingAerial": "Bing vue aérienne",
+    "IGN": "Plan IGN",
+    "queryResults": "Résultats de la requête",
+    "regions": "Régions",
+    "departments": "Départements",
+    "sylvoEcoRegions": "SylvoEcoRégions",
+    "selectFilterOption": "Sélectionnez une option",
+    "zoomHelperText": "Utilisez ctrl + scroll pour zoomer",
+    "selectionTool": {
+      "title": "Mode de sélection de points",
+      "select": "Ajout",
+      "unselect": "Suppression",
+      "unselectAll": "Vider la sélection"
+    }
+  },
+  "selectedPointsList": {
+    "title": "Liste des ressources sélectionnées",
+    "empty": "Sélectionnez des ressources pour les afficher ici"
+  }
+}
diff --git a/public/locales/fr/profile.json b/public/locales/fr/profile.json
new file mode 100644
index 0000000000000000000000000000000000000000..9f30ddb283a8147bd3dff379de9a808674709736
--- /dev/null
+++ b/public/locales/fr/profile.json
@@ -0,0 +1,23 @@
+{
+  "pageTitle": "Gestion du profil",
+  "groups": {
+    "groupsList": "Liste des groupes",
+    "groupName": "Nom",
+    "groupDescription": "Description"
+  },
+  "requestsList": {
+    "requestsList": "Liste des requêtes",
+    "requestsMessage": "Message",
+    "processed": "Traitée",
+    "cancelRequest": "Annuler cette requête"
+  },
+  "groupRequests": {
+    "requestGroupAssignment": "Demander à faire parti d'un groupe",
+    "currentGroups": "Vous faites actuellement parti (ou avez une demande pour) de ces groupes :",
+    "noGroup": "Vous ne faites actuellement parti d'aucun groupe."
+  },
+  "roleRequests": {
+    "requestRoleAssignment": "Demander un rôle",
+    "currentRole": "Votre rôle actuel (ou demande en cours):"
+  }
+}
diff --git a/public/locales/fr/results.json b/public/locales/fr/results.json
new file mode 100644
index 0000000000000000000000000000000000000000..1237c231591e493969bca0aa7d0b3451f9ea6db2
--- /dev/null
+++ b/public/locales/fr/results.json
@@ -0,0 +1,47 @@
+{
+  "clickOnRowTip": "Clickez sur une ligne du tableau pour afficher ses métadonnées.",
+  "downloadResultsButton": {
+    "JSON": "Télécharger en JSON"
+  },
+  "table": {
+    "title": "Résultats de la requête : <strong>{{searchQuery}}</strong>",
+    "search": "Chercher parmi les résultats",
+    "displaySelectedRowsButton": "Trier la sélection",
+    "textLabels": {
+      "body": {
+        "noMatch": "Aucun résultat pour cette requête",
+        "toolTip": "Trier"
+      },
+      "pagination": {
+        "next": "Page suivante",
+        "previous": "Page précédente",
+        "rowsPerPage": "Lignes par page :",
+        "displayRows": "sur",
+        "jumpToPage": "Page :"
+      },
+      "toolbar": {
+        "search": "Rechercher",
+        "viewColumns": "Visualisation des colonnes",
+        "filterTable": "Filtrer les résultats"
+      },
+      "filter": {
+        "all": "Tout",
+        "title": "FILTRES",
+        "reset": "REINITIALISER"
+      },
+      "viewColumns": {
+        "title": "Visualisation des colonnes",
+        "titleAria": "Montrer/cacher les colonnes"
+      },
+      "selectedRows": {
+        "text": "ligne(s) sélectionnées"
+      }
+    }
+  },
+  "flyout": {
+    "label": "Fiche de données de la ressource",
+    "JSON": {
+      "title": "Données JSON de la ressource"
+    }
+  }
+}
diff --git a/public/locales/fr/search.json b/public/locales/fr/search.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f6ab3907ccd0c6176b0d8b81d03c3f1d808f28b
--- /dev/null
+++ b/public/locales/fr/search.json
@@ -0,0 +1,78 @@
+{
+  "pageTitle": "Plateforme de recherche de métadonnées In-Sylva",
+  "tabs": {
+    "composeSearch": "Composer une recherche",
+    "results": "Résultats",
+    "map": "Carte"
+  },
+  "sendSearchButton": "Lancer la recherche",
+  "basicSearch": {
+    "switchSearchMode": "Passer en recherche avancée",
+    "searchInputPlaceholder": "Chercher..."
+  },
+  "advancedSearch": {
+    "switchSearchMode": "Passer en recherche basique",
+    "textQueryPlaceholder": "Ajoutez des champs...",
+    "countResultsButton": "Compter les résultats",
+    "resultsCount_one": "{{count}} résultat",
+    "resultsCount_other": "{{count}} résultats",
+    "editableSearchButton": "Modifiable",
+    "errorInvalidOption": "\"{{value}}\" n'est pas une option valide.",
+    "fields": {
+      "title": "Recherche de champ",
+      "loadingFields": "Chargement des champs...",
+      "removeFieldButton": "Supprimer le champ",
+      "clearValues": "Vider les valeurs",
+      "addFieldPopover": {
+        "openPopoverButton": "Selectionnez un champ",
+        "title": "Ajouter ce champ",
+        "button": "Selectionnez une section",
+        "selectSection": "Ajouter un champ"
+      },
+      "fieldContentPopover": {
+        "addValue": "Ajouter une valeur",
+        "addFieldValues": "Ajouter des valeurs de champ",
+        "firstValue": "1ère valeur",
+        "secondValue": "2ème valeur",
+        "inputTextValue": "Entrez une valeur",
+        "betweenDate": "entre",
+        "andDate": "et",
+        "selectValues": "Sélectionnez au moins une valeur"
+      }
+    },
+    "searchHistory": {
+      "placeholder": "Charger une recherche précédente",
+      "saveSearch": "Sauvegarder ma recherche",
+      "addSavedSearchName": "Nom de la recherche",
+      "addSavedSearchDescription": "Description (optionel)",
+      "addSavedSearchDescriptionPlaceholder": "Description de la recherche..."
+    },
+    "searchOptions": {
+      "title": "Option de recherche",
+      "matchAll": "Répondre à tous les critères",
+      "matchAtLeastOne": "Répondre à au moins un critère"
+    },
+    "partnerSources": {
+      "title": "Liste des sources de partenaires",
+      "allSourcesSelected": "Toutes les sources sont sélectionnées par défaut",
+      "noSourceAvailable": "Pas de source disponible."
+    },
+    "policyToast": {
+      "title": "Champ privé sélectionné",
+      "content": [
+        "Vous avez sélectionné un champ privé.",
+        "L'accès à ce champ à été donné par certaines sources, ce qui veut dire que votre recherche va être limitée à celles-ci.",
+        "Veuillez prếter attention à la liste des sources avant de continuer."
+      ]
+    },
+    "editableQueryToast": {
+      "title": "Procéder avec prudence",
+      "content": {
+        "part1": "En éditant manuellement la recherche, vous pouvez facilement gâcher les résultats. Veuillez respecter la syntaxe :",
+        "part2": "Les champs et leurs valeurs doivent être comprises entre accolade: { } - Bien fermer toute accolade ouverte",
+        "part3": "\"AND\" et \"OR\" en majuscule entre les champs et en minuscule à l'intérieur d'une valeur de champ",
+        "part4": "Attention à corriger vos fautes de frappe"
+      }
+    }
+  }
+}
diff --git a/public/locales/fr/validation.json b/public/locales/fr/validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..0f29592894aacffcd6d069a539ed50c510cc7661
--- /dev/null
+++ b/public/locales/fr/validation.json
@@ -0,0 +1,3 @@
+{
+  "requestSent": "Votre requête à bien été envoyée."
+}
diff --git a/src/App.js b/src/App.js
index b73433f8138b04bf0f5d38a783fbf2a95c48970a..5d03570a71be6a36aa411c1f5608a974927660ad 100644
--- a/src/App.js
+++ b/src/App.js
@@ -5,13 +5,12 @@ import Layout from './components/Layout';
 
 const App = () => {
   return (
-    <EuiPage restrictWidth={false}>
+    <EuiPage style={{ padding: '0px' }} restrictWidth={false}>
       <EuiPageBody>
         <HashRouter>
           <Switch>
             <Route exact path="/" render={() => <Redirect to="/app/home" />} />
             <Route component={Layout} />
-            <Route component={Error} />
           </Switch>
         </HashRouter>
       </EuiPageBody>
diff --git a/src/Utils.js b/src/Utils.js
index b36276204824efa394ca81a3d9d8d3f45d950135..3c4f4727b2209ff47dc4505960004c258bdf839a 100644
--- a/src/Utils.js
+++ b/src/Utils.js
@@ -594,14 +594,14 @@ export const createBasicQueriesBySource = (
 
   sourcesLists.forEach((sourcesArray, index) => {
     let sourceParam = `"_source": [`;
-    fieldsLists[index].forEach((fieldname) => {
-      sourceParam = `${sourceParam} "${fieldname}", `;
+    fieldsLists[index].forEach((fieldName) => {
+      sourceParam = `${sourceParam} "${fieldName}", `;
     });
     if (sourceParam.endsWith(', ')) {
       sourceParam = sourceParam.substring(0, sourceParam.length - 2);
     }
     sourceParam = `${sourceParam}],`;
-    let query = `{ ${sourceParam} "query": { "multi_match": { "query": "${searchRequest}" } } }`;
+    let query = `{ ${sourceParam} "query": { "multi_match": { "query": "${searchRequest}", "operator": "AND", "type": "cross_fields" } } }`;
     queries.push({ indicesId: indicesLists[index], query: JSON.parse(query) });
   });
   return queries;
diff --git a/src/Map.svg b/src/assets/Map.svg
similarity index 100%
rename from src/Map.svg
rename to src/assets/Map.svg
diff --git a/src/favicon.svg b/src/assets/favicon.svg
similarity index 100%
rename from src/favicon.svg
rename to src/assets/favicon.svg
diff --git a/src/logo.svg b/src/assets/logo.svg
similarity index 100%
rename from src/logo.svg
rename to src/assets/logo.svg
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
index f1e74d049f358e01ef1b3056e39b97508da1a37c..6e571d618929954064d06861039b3b0639c4b278 100644
--- a/src/components/Header/Header.js
+++ b/src/components/Header/Header.js
@@ -7,49 +7,52 @@ import {
   EuiHeaderLinks,
   EuiHeaderLink,
 } from '@elastic/eui';
-import HeaderUserMenu from './header_user_menu';
+import HeaderUserMenu from './HeaderUserMenu';
 import style from './styles';
-import logoInSylva from '../../favicon.svg';
+import logoInSylva from '../../assets/favicon.svg';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from '../LanguageSwitcher/LanguageSwitcher';
 
 const structure = [
   {
     id: 0,
-    label: 'Home',
+    label: 'home',
     href: '/app/home',
     icon: '',
   },
   {
     id: 1,
-    label: 'Search',
+    label: 'search',
     href: '/app/search',
     icon: '',
   },
 ];
 
 const Header = () => {
+  const { t } = useTranslation(['header', 'common']);
+
   return (
     <>
       <EuiHeader>
         <EuiHeaderSection grow={true}>
-          <EuiHeaderSectionItem border="right">
-            <img
-              style={style}
-              src={logoInSylva}
-              width="75"
-              height="45"
-              alt="Logo INRAE"
-            />
+          <EuiHeaderSectionItem>
+            <img style={style.logo} src={logoInSylva} alt={t('common:inSylvaLogoAlt')} />
           </EuiHeaderSectionItem>
-          <EuiHeaderLinks border="right">
+          <EuiHeaderLinks>
             {structure.map((link) => (
               <EuiHeaderLink iconType="empty" key={link.id}>
-                <Link to={link.href}>{link.label}</Link>
+                <Link to={link.href}>{t(`tabs.${link.label}`)}</Link>
               </EuiHeaderLink>
             ))}
           </EuiHeaderLinks>
         </EuiHeaderSection>
         <EuiHeaderSection side="right">
-          <EuiHeaderSectionItem>{HeaderUserMenu()}</EuiHeaderSectionItem>
+          <EuiHeaderSectionItem style={style.languageSwitcherItem} border={'none'}>
+            <LanguageSwitcher />
+          </EuiHeaderSectionItem>
+          <EuiHeaderSectionItem style={style.userMenuItem} border={'none'}>
+            <HeaderUserMenu />
+          </EuiHeaderSectionItem>
         </EuiHeaderSection>
       </EuiHeader>
     </>
diff --git a/src/components/Header/HeaderUserMenu.js b/src/components/Header/HeaderUserMenu.js
new file mode 100644
index 0000000000000000000000000000000000000000..2235573629ac2c2fa85fe3614f5e5b5dca6a43df
--- /dev/null
+++ b/src/components/Header/HeaderUserMenu.js
@@ -0,0 +1,94 @@
+import React, { useEffect, useState } from 'react';
+import {
+  EuiAvatar,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiLink,
+  EuiText,
+  EuiSpacer,
+  EuiPopover,
+  EuiButtonIcon,
+} from '@elastic/eui';
+import { signOut } from '../../context/UserContext';
+import { findOneUser } from '../../actions/user';
+import { useTranslation } from 'react-i18next';
+
+const HeaderUserMenu = () => {
+  const { t } = useTranslation('header');
+  const [isOpen, setIsOpen] = useState(false);
+  const [user, setUser] = useState({});
+
+  const onMenuButtonClick = () => {
+    setIsOpen(!isOpen);
+  };
+
+  const closeMenu = () => {
+    setIsOpen(false);
+  };
+
+  useEffect(() => {
+    const loadUser = () => {
+      if (sessionStorage.getItem('user_id')) {
+        findOneUser(sessionStorage.getItem('user_id')).then((user) => {
+          setUser(user);
+        });
+      }
+    };
+
+    loadUser();
+  }, []);
+
+  const HeaderUserButton = (
+    <EuiButtonIcon
+      size="s"
+      onClick={onMenuButtonClick}
+      iconType="user"
+      title={t('userMenu.title')}
+      aria-label={t('userMenu.title')}
+    />
+  );
+
+  return user.username ? (
+    <EuiPopover
+      id="headerUserMenu"
+      ownFocus
+      button={HeaderUserButton}
+      isOpen={isOpen}
+      anchorPosition="downRight"
+      closePopover={closeMenu}
+      panelPaddingSize="none"
+    >
+      <div>
+        <EuiFlexGroup gutterSize="m" className="euiHeaderProfile" responsive={false}>
+          <EuiFlexItem grow={false}>
+            <EuiAvatar name={user.username} size="xl" />
+          </EuiFlexItem>
+          <EuiFlexItem>
+            <EuiText>{user.username}</EuiText>
+            <EuiSpacer size="m" />
+            <EuiFlexGroup>
+              <EuiFlexItem>
+                <EuiFlexGroup justifyContent="spaceBetween">
+                  <EuiFlexItem grow={false}>
+                    <EuiLink href="#/app/profile">
+                      {t('userMenu.editProfileButton')}
+                    </EuiLink>
+                  </EuiFlexItem>
+                  <EuiFlexItem grow={false}>
+                    <EuiLink onClick={() => signOut()}>
+                      {t('userMenu.logOutButton')}
+                    </EuiLink>
+                  </EuiFlexItem>
+                </EuiFlexGroup>
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          </EuiFlexItem>
+        </EuiFlexGroup>
+      </div>
+    </EuiPopover>
+  ) : (
+    <></>
+  );
+};
+
+export default HeaderUserMenu;
diff --git a/src/components/Header/header_user_menu.js b/src/components/Header/header_user_menu.js
deleted file mode 100644
index feb51bb45544c887a679289dab19aa1fa8401652..0000000000000000000000000000000000000000
--- a/src/components/Header/header_user_menu.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import {
-  EuiAvatar,
-  EuiFlexGroup,
-  EuiFlexItem,
-  EuiLink,
-  EuiText,
-  EuiSpacer,
-  EuiPopover,
-  EuiButtonIcon,
-} from '@elastic/eui';
-import { signOut } from '../../context/UserContext';
-import { findOneUser } from '../../actions/user';
-
-export default function HeaderUserMenu() {
-  const [isOpen, setIsOpen] = useState(false);
-  const [user, setUser] = useState({});
-
-  const onMenuButtonClick = () => {
-    setIsOpen(!isOpen);
-  };
-
-  const closeMenu = () => {
-    setIsOpen(false);
-  };
-
-  const loadUser = () => {
-    if (sessionStorage.getItem('user_id')) {
-      findOneUser(sessionStorage.getItem('user_id')).then((user) => {
-        setUser(user);
-      });
-    }
-  };
-
-  useEffect(() => {
-    loadUser();
-  }, []);
-
-  const HeaderUserButton = (
-    <EuiButtonIcon
-      size="s"
-      onClick={onMenuButtonClick}
-      iconType="user"
-      title="User profile"
-      aria-label="User profile"
-    />
-  );
-
-  return (
-    user.username && (
-      <EuiPopover
-        id="headerUserMenu"
-        ownFocus
-        button={HeaderUserButton}
-        isOpen={isOpen}
-        anchorPosition="downRight"
-        closePopover={closeMenu}
-        panelPaddingSize="none"
-      >
-        <div style={{ width: 320 }}>
-          <EuiFlexGroup gutterSize="m" className="euiHeaderProfile" responsive={false}>
-            <EuiFlexItem grow={false}>
-              <EuiAvatar name={user.username} size="xl" />
-            </EuiFlexItem>
-            <EuiFlexItem>
-              <EuiText>{user.username}</EuiText>
-              <EuiSpacer size="m" />
-              <EuiFlexGroup>
-                <EuiFlexItem>
-                  <EuiFlexGroup justifyContent="spaceBetween">
-                    <EuiFlexItem grow={false}>
-                      <EuiLink href="#/app/profile">Edit profile</EuiLink>
-                    </EuiFlexItem>
-                    <EuiFlexItem grow={false}>
-                      <EuiLink onClick={() => signOut()}>Log out</EuiLink>
-                    </EuiFlexItem>
-                  </EuiFlexGroup>
-                </EuiFlexItem>
-              </EuiFlexGroup>
-            </EuiFlexItem>
-          </EuiFlexGroup>
-        </div>
-      </EuiPopover>
-    )
-  );
-}
diff --git a/src/components/Header/styles.js b/src/components/Header/styles.js
index 2515727ce2391dc110ed0e581dfe850c9968dde9..94f8ecf22cfa183f26e33b3f3c7ae6086c4730ee 100644
--- a/src/components/Header/styles.js
+++ b/src/components/Header/styles.js
@@ -1,8 +1,15 @@
 const headerStyle = {
-  paddingTop: '10px',
-  paddingBottom: '-6px',
-  paddingRight: '10px',
-  paddingLeft: '10px',
+  logo: {
+    width: '75px',
+    height: '75px',
+    padding: '10px',
+  },
+  languageSwitcherItem: {
+    margin: '10px',
+  },
+  userMenuItem: {
+    marginRight: '10px',
+  },
 };
 
 export default headerStyle;
diff --git a/src/components/LanguageSwitcher/LanguageSwitcher.js b/src/components/LanguageSwitcher/LanguageSwitcher.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fb068cd82dad00d1b5b180728c1754869c3daf6
--- /dev/null
+++ b/src/components/LanguageSwitcher/LanguageSwitcher.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import styles from './styles';
+import { EuiSelect } from '@elastic/eui';
+
+const LanguageSwitcher = () => {
+  const { t, i18n } = useTranslation('common');
+
+  const options = [
+    { text: t('languages.en'), value: 'en' },
+    { text: t('languages.fr'), value: 'fr' },
+  ];
+
+  const changeLanguage = (newLng) => {
+    i18n.changeLanguage(newLng).then();
+  };
+
+  return (
+    <EuiSelect
+      style={styles.select}
+      options={options}
+      compressed={true}
+      value={i18n.resolvedLanguage}
+      onChange={(e) => changeLanguage(e.target.value)}
+    />
+  );
+};
+
+export default LanguageSwitcher;
diff --git a/src/components/LanguageSwitcher/styles.js b/src/components/LanguageSwitcher/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c4c4bb7ae6b5014574eb8d32698e75136b9bcae
--- /dev/null
+++ b/src/components/LanguageSwitcher/styles.js
@@ -0,0 +1,7 @@
+const styles = {
+  select: {
+    borderRadius: '6px',
+  },
+};
+
+export default styles;
diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js
index ddfcb8639542d0484050318d8aa67f6103a496a2..af5be085de322c47d3c135e68cab48602f40bc23 100644
--- a/src/components/Layout/Layout.js
+++ b/src/components/Layout/Layout.js
@@ -4,16 +4,20 @@ import Header from '../../components/Header';
 import Search from '../../pages/search';
 import Home from '../../pages/home';
 import Profile from '../../pages/profile';
+import { EuiPageContent } from '@elastic/eui';
+import styles from './styles.js';
 
 const Layout = () => {
   return (
     <>
       <Header />
-      <Switch>
-        <Route path="/app/home" component={Home} />
-        <Route path="/app/search" component={Search} />
-        <Route path="/app/profile" component={Profile} />
-      </Switch>
+      <EuiPageContent style={styles.pageContent}>
+        <Switch>
+          <Route path="/app/home" component={Home} />
+          <Route path="/app/search" component={Search} />
+          <Route path="/app/profile" component={Profile} />
+        </Switch>
+      </EuiPageContent>
     </>
   );
 };
diff --git a/src/components/Layout/styles.js b/src/components/Layout/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..787354eaa2957de1cc981112fa072887a75d71ca
--- /dev/null
+++ b/src/components/Layout/styles.js
@@ -0,0 +1,9 @@
+const styles = {
+  pageContent: {
+    borderRadius: 0,
+    border: 0,
+    boxShadow: 'none',
+  },
+};
+
+export default styles;
diff --git a/src/components/Loading/Loading.js b/src/components/Loading/Loading.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5213a7dd183cad47b2cd4f933abd3a36fca42df
--- /dev/null
+++ b/src/components/Loading/Loading.js
@@ -0,0 +1,12 @@
+import React from 'react';
+import styles from './styles';
+
+const Loading = () => {
+  return (
+    <div style={styles.container}>
+      <h1>Loading...</h1>
+    </div>
+  );
+};
+
+export default Loading;
diff --git a/src/components/Loading/package.json b/src/components/Loading/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b4c70453df6e4755baccb4ff5e3783d092bca4e8
--- /dev/null
+++ b/src/components/Loading/package.json
@@ -0,0 +1,6 @@
+{
+  "name": "Loading",
+  "version": "1.0.0",
+  "private": true,
+  "main": "Loading.js"
+}
diff --git a/src/components/Loading/styles.js b/src/components/Loading/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c4d2706c3230a1d87dde4f06a41bcc1024c802f
--- /dev/null
+++ b/src/components/Loading/styles.js
@@ -0,0 +1,11 @@
+const styles = {
+  container: {
+    width: '100vw',
+    height: '100vh',
+    display: 'flex',
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+};
+
+export default styles;
diff --git a/src/context/InSylvaKeycloakClient.js b/src/context/InSylvaKeycloakClient.js
index c5980429eac474a69ea0cfb484c05fcc6cb3e91c..5a20fd65b1658b6b64c5bffe202cbbdaa517a61f 100644
--- a/src/context/InSylvaKeycloakClient.js
+++ b/src/context/InSylvaKeycloakClient.js
@@ -2,17 +2,11 @@ import { getLoginUrl } from '../Utils';
 
 class InSylvaKeycloakClient {
   async post(path, requestContent) {
-    // const access_token = sessionStorage.getItem("access_token");
     const headers = {
       'Content-Type': 'application/x-www-form-urlencoded',
       // "Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
       // "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization"
     };
-    /*
-        if (access_token) {
-            headers["Authorization"] = "Bearer " + access_token
-        }
-        */
     let formBody = [];
     for (const property in requestContent) {
       const encodedKey = encodeURIComponent(property);
@@ -26,18 +20,14 @@ class InSylvaKeycloakClient {
       body: formBody,
       mode: 'cors',
     });
-    if (response.ok === true) {
-      // ok
-    } else {
+    if (!response.ok) {
       await this.logout();
       sessionStorage.removeItem('user_id');
       sessionStorage.removeItem('access_token');
       sessionStorage.removeItem('refresh_token');
       window.location.replace(getLoginUrl() + '?requestType=search');
     }
-    if (response.statusText === 'No Content') {
-      // ok
-    } else {
+    if (response.statusText !== 'No Content') {
       return await response.json();
     }
   }
@@ -58,11 +48,11 @@ class InSylvaKeycloakClient {
     return { token };
   }
 
-  async logout({ realm = this.realm, client_id = this.client_id }) {
+  async logout() {
     const refresh_token = sessionStorage.getItem('refresh_token');
-    const path = `/auth/realms/${realm}/protocol/openid-connect/logout`;
     if (refresh_token) {
-      await this.post(`${path}`, {
+      const client_id = this.client_id;
+      await this.post(`/auth/realms/${this.realm}/protocol/openid-connect/logout`, {
         client_id,
         refresh_token,
       });
diff --git a/src/context/InSylvaSearchClient.js b/src/context/InSylvaSearchClient.js
index 6d702e250a32dd15308a0ef13ce9182a2957fbb5..ffdc831b72ef715a652caadace18b8e3f2c09730 100644
--- a/src/context/InSylvaSearchClient.js
+++ b/src/context/InSylvaSearchClient.js
@@ -35,8 +35,7 @@ class InSylvaSearchClient {
     for (let i = 0; i < queries.length; i++) {
       const indicesId = queries[i].indicesId;
       const query = queries[i].query;
-      const path = `/scroll-search`;
-      const result = await this.post('POST', `${path}`, {
+      const result = await this.post('POST', '/scroll-search', {
         indicesId,
         query,
       });
diff --git a/src/context/UserContext.js b/src/context/UserContext.js
index 2d7b83dda5f22f5b484641bbebde7a92a2804728..d7578beb7e379f791fa08656d458dcb272e4193c 100644
--- a/src/context/UserContext.js
+++ b/src/context/UserContext.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import React, { createContext, useContext, useReducer } from 'react';
 import { InSylvaGatekeeperClient } from './InSylvaGatekeeperClient';
 import { InSylvaKeycloakClient } from './InSylvaKeycloakClient';
 import { getLoginUrl } from '../Utils';
 
-const UserStateContext = React.createContext();
-const UserDispatchContext = React.createContext();
+const UserStateContext = createContext(null);
+const UserDispatchContext = createContext(null);
 
 const igClient = new InSylvaGatekeeperClient();
 igClient.baseUrl = process.env.REACT_APP_IN_SYLVA_GATEKEEPER_PORT
@@ -46,7 +46,7 @@ function userReducer(state, action) {
 }
 
 function UserProvider({ children }) {
-  const [state, dispatch] = React.useReducer(userReducer, {
+  const [state, dispatch] = useReducer(userReducer, {
     isAuthenticated: !!sessionStorage.getItem('access_token'),
   });
 
@@ -60,7 +60,7 @@ function UserProvider({ children }) {
 }
 
 function useUserState() {
-  const context = React.useContext(UserStateContext);
+  const context = useContext(UserStateContext);
   if (context === undefined) {
     throw new Error('useUserState must be used within a UserProvider');
   }
@@ -68,7 +68,7 @@ function useUserState() {
 }
 
 function useUserDispatch() {
-  const context = React.useContext(UserDispatchContext);
+  const context = useContext(UserDispatchContext);
   if (context === undefined) {
     throw new Error('useUserDispatch must be used within a UserProvider');
   }
@@ -85,7 +85,7 @@ async function checkUserLogin(userId, accessToken, refreshToken) {
     // Load the user result filters from Result_Filter(userId) endpoints
     // Load the user policies from Policy(userId) endpoint
     if (!sessionStorage.getItem('token_refresh_time')) {
-      sessionStorage.setItem('token_refresh_time', Date.now());
+      sessionStorage.setItem('token_refresh_time', Date.now().toString());
     }
     // dispatch({ type: "USER_LOGGED_IN" });
   } else {
@@ -101,7 +101,7 @@ async function refreshToken() {
       });
       if (result) {
         sessionStorage.setItem('access_token', result.token.access_token);
-        sessionStorage.setItem('token_refresh_time', Date.now());
+        sessionStorage.setItem('token_refresh_time', Date.now().toString());
         // dispatch({ type: "USER_LOGGED_IN" });
       } else {
         // dispatch({ type: "LOGIN_FAILURE" });
@@ -113,7 +113,7 @@ async function refreshToken() {
 }
 
 async function signOut() {
-  await ikcClient.logout({});
+  await ikcClient.logout();
   sessionStorage.removeItem('user_id');
   sessionStorage.removeItem('access_token');
   sessionStorage.removeItem('refresh_token');
diff --git a/src/i18n.js b/src/i18n.js
new file mode 100644
index 0000000000000000000000000000000000000000..236acc5804dc20022e3b4d769204a2cf81f67c06
--- /dev/null
+++ b/src/i18n.js
@@ -0,0 +1,22 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import Backend from 'i18next-http-backend';
+
+i18n
+  .use(Backend)
+  .use(initReactI18next)
+  .init({
+    lng: 'fr',
+    fallbackLng: 'fr',
+    ns: 'common',
+    defaultNS: 'common',
+    debug: true,
+    load: 'languageOnly',
+    loadPath: 'locales/{{lng}}/{{ns}}.json',
+    interpolation: {
+      // not needed for react as it escapes by default
+      escapeValue: false,
+    },
+  });
+
+export default i18n;
diff --git a/src/index.js b/src/index.js
index ab31dbff2807f9889d87325b74923ae2ce76a431..285bd62b697c75b71cb71332d329aa4a2f62f677 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,9 +1,11 @@
-import React from 'react';
+import React, { Suspense } from 'react';
 import ReactDOM from 'react-dom';
 import '@elastic/eui/dist/eui_theme_light.css';
 import { UserProvider, checkUserLogin } from './context/UserContext';
 import App from './App';
 import { getLoginUrl, getUrlParam, redirect } from './Utils.js';
+import './i18n';
+import Loading from './components/Loading';
 
 const userId = getUrlParam('kcId', '');
 const accessToken = getUrlParam('accessToken', '');
@@ -16,7 +18,9 @@ checkUserLogin(userId, accessToken, refreshToken);
 if (sessionStorage.getItem('access_token')) {
   ReactDOM.render(
     <UserProvider>
-      <App userId={userId} accessToken={accessToken} refreshToken={refreshToken} />
+      <Suspense fallback={<Loading />}>
+        <App userId={userId} accessToken={accessToken} refreshToken={refreshToken} />
+      </Suspense>
     </UserProvider>,
     document.getElementById('root')
   );
diff --git a/src/pages/home/Home.js b/src/pages/home/Home.js
index c54f9082634e36a5f12a16691c28c76b8dd5efc5..1be5b26d3dc9ecbb638f16d2ee895aedd5a85722 100644
--- a/src/pages/home/Home.js
+++ b/src/pages/home/Home.js
@@ -1,58 +1,34 @@
 import React from 'react';
 import {
-  EuiPageContent,
   EuiPageContentHeader,
   EuiPageContentHeaderSection,
-  EuiPageContentBody,
   EuiTitle,
 } from '@elastic/eui';
+import { useTranslation } from 'react-i18next';
 
 const Home = () => {
+  const { t } = useTranslation('home');
+
   return (
-    <>
-      <EuiPageContent>
-        <EuiPageContentHeader>
-          <EuiPageContentHeaderSection>
-            <EuiTitle>
-              <h2>Welcome to the IN-SYLVA IS application search module</h2>
-            </EuiTitle>
-            <br />
-            <br />
-            <p>
-              As a reminder, it should be remembered that the metadata stored in IN-SYLVA
-              IS are structured around the IN-SYLVA standard.
-            </p>
-            <br />
-            <p>
-              This standard is composed of metadata fields. A metadata record is therefore
-              made up of a series of fields accompanied by their value.
-            </p>
-            <br />
-            <br />
-            <p>
-              With this part of the interface you will be able to search for metadata
-              records (previously loaded via the portal), by defining a certain number of
-              criteria.
-            </p>
-            <br />
-            <p>
-              By default the "search" interface opens to a "plain text" search, ie the
-              records returned in the result are those which, in one of the field values,
-              contains the supplied character string.
-            </p>
-            <br />
-            <p>
-              A click on the Advanced search button gives access to a more complete form
-              via which you can do more precise searches on one or more targeted fields.
-            </p>
-            <br />
-            <br />
-            <p>Click on the "Search" tab to access the search interface.</p>
-          </EuiPageContentHeaderSection>
-        </EuiPageContentHeader>
-        <EuiPageContentBody></EuiPageContentBody>
-      </EuiPageContent>
-    </>
+    <EuiPageContentHeader>
+      <EuiPageContentHeaderSection>
+        <EuiTitle>
+          <h2>{t('pageTitle')}</h2>
+        </EuiTitle>
+        <br />
+        <p>{t('searchToolDescription.part1')}</p>
+        <br />
+        <p>{t('searchToolDescription.part2')}</p>
+        <br />
+        <p>{t('searchToolDescription.part3')}</p>
+        <br />
+        <p>{t('searchToolDescription.part4')}</p>
+        <br />
+        <p>{t('searchToolDescription.part5')}</p>
+        <br />
+        <p>{t('searchToolDescription.part6')}</p>
+      </EuiPageContentHeaderSection>
+    </EuiPageContentHeader>
   );
 };
 
diff --git a/src/pages/maps/SearchMap.js b/src/pages/maps/SearchMap.js
index 958af49b1d74cea9ea376f9a618d1ccd98ef792f..5784009df60149119180f5bc09ad45b820bd95f6 100644
--- a/src/pages/maps/SearchMap.js
+++ b/src/pages/maps/SearchMap.js
@@ -1,479 +1,748 @@
-import React, { useState, useEffect } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
 import { Map, View } from 'ol';
-// import TileLayer from "ol/layer/Tile";
 import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
-import ImageLayer from 'ol/layer/Image';
+import { Fill, Stroke, Style, Text } from 'ol/style';
 import SourceOSM from 'ol/source/OSM';
 import BingMaps from 'ol/source/BingMaps';
 import { Vector as VectorSource } from 'ol/source';
 import WMTS from 'ol/source/WMTS';
 import WMTSTileGrid from 'ol/tilegrid/WMTS';
-//import {fromLonLat, get as getProjection} from 'ol/proj.js';
 import { getWidth } from 'ol/extent';
-import ImageWMS from 'ol/source/ImageWMS';
+import { platformModifierKeyOnly } from 'ol/events/condition';
 import GeoJSON from 'ol/format/GeoJSON';
-//import { Circle as CircleStyle, Fill, Stroke, Style, Text, Icon } from 'ol/style';
-import { Fill, Stroke, Style, Text, Icon } from 'ol/style';
-import { Circle, Point, Polygon } from 'ol/geom';
+import { defaults, DragBox, MouseWheelZoom, Select } from 'ol/interaction';
+import { Circle, Point } from 'ol/geom';
 import Feature from 'ol/Feature';
-import * as proj from 'ol/proj';
 import {
-  ScaleLine,
-  MousePosition,
-  OverviewMap,
   defaults as defaultControls,
+  FullScreen,
+  OverviewMap,
+  ScaleLine,
+  Zoom,
 } from 'ol/control';
-import { toStringXY } from 'ol/coordinate';
 import 'ol/ol.css';
-import { EuiCheckbox } from '@elastic/eui';
+import {
+  EuiButton,
+  EuiButtonGroup,
+  EuiCheckbox,
+  EuiComboBox,
+  EuiProgress,
+  EuiSpacer,
+  EuiText,
+  EuiTitle,
+} from '@elastic/eui';
 import { htmlIdGenerator } from '@elastic/eui/lib/services';
 import { updateArrayElement } from '../../Utils.js';
+import { useTranslation } from 'react-i18next';
+import styles from './styles.js';
+import * as proj from 'ol/proj';
+import proj4 from 'proj4';
+import { register } from 'ol/proj/proj4';
 
-const SearchMap = (props) => {
-  /*var image = new CircleStyle({
-        radius: 5,
-        fill: null,
-        stroke: new Stroke({ color: 'red', width: 1 }),
-    });*/
-  const styles = {
-    Point: new Style({
-      image: new Icon({
-        anchor: [0.5, 46],
-        anchorXUnits: 'fraction',
-        anchorYUnits: 'pixels',
-        src: 'https://openlayers.org/en/v3.20.1/examples/data/icon.png',
-      }),
-    }),
-    /* 'Circle': new Style({
-            image: new Circle({
-                radius: 7,
-                fill: new Fill({
-                    color: 'green'
-                }),
-                stroke: new Stroke({
-                    color: 'blue',
-                    width: 2
-                })
-            })
-        }),*/
-    Circle: new Style({
-      stroke: new Stroke({
-        color: 'blue',
-        width: 2,
-      }),
-      //radius: 1000,
-      fill: new Fill({
-        color: 'rgba(0,0,255,0.3)',
-      }),
-    }),
-    /* 'LineString': new Style({
-            stroke: new Stroke({
-                color: 'green',
-                width: 1,
-            }),
-        }),
-        'MultiLineString': new Style({
-            stroke: new Stroke({
-                color: 'green',
-                width: 1,
-            }),
-        }),
-        'MultiPoint': new Style({
-            image: image,
-        }),
-        'MultiPolygon': new Style({
-            stroke: new Stroke({
-                color: 'yellow',
-                width: 1,
-            }),
-            fill: new Fill({
-                color: 'rgba(255, 255, 0, 0.1)',
-            }),
-        }),
-        'Polygon': new Style({
-            stroke: new Stroke({
-                color: 'blue',
-                lineDash: [4],
-                width: 3,
-            }),
-            fill: new Fill({
-                color: 'rgba(0, 0, 255, 0.1)',
-            }),
-        }),
-        'GeometryCollection': new Style({
-            stroke: new Stroke({
-                color: 'magenta',
-                width: 2,
-            }),
-            fill: new Fill({
-                color: 'magenta',
-            }),
-            image: new CircleStyle({
-                radius: 10,
-                fill: null,
-                stroke: new Stroke({
-                    color: 'magenta',
-                }),
-            }),
-        }),
-        'Circle': new Style({
-            stroke: new Stroke({
-                color: 'red',
-                width: 2,
-            }),
-            fill: new Fill({
-                color: 'rgba(255,0,0,0.2)',
-            }),
-        }),
-        bluecircle: {
-            width: 30,
-            height: 30,
-            border: "1px solid #088",
-            bordeRadius: "15",
-            backgroundColor: "#0ff",
-            opacity: 0.5,
-            zIndex: 9999
-        }, */
-    mapContainer: {
-      height: '80vh',
-      width: '60vw',
-    },
-    layerTree: {
-      cursor: 'pointer',
-    },
-  };
-  const source = new SourceOSM();
-  const overviewMapControl = new OverviewMap({
-    layers: [
-      new TileLayer({
-        source: source,
-      }),
-    ],
-  });
-  const [center, setCenter] = useState(proj.fromLonLat([2.5, 46.5]));
-  const [zoom, setZoom] = useState(6);
-  const styleFunction = function (feature) {
-    return styles[feature.getGeometry().getType()];
-  };
-
-  /* const newPoint = {
-        'type': 'Feature',
-        'geometry': {
-            'type': 'Point',
-            'coordinates': proj.fromLonLat([6.37777777778, 43.1938888889]),
-        },
-        'properties': {
-            'Site': 'TEST'
-        }
-    }
-
-    const geojsonObject = {
-        'type': 'FeatureCollection',
-        'crs': {
-            'type': 'name',
-            'properties': {
-                'name': 'EPSG:4326',
-            },
-        },
-        'features': [
-            // newPoint
-        ],
-    } */
-
-  const vectorSource = new VectorSource({
-    /*features: new GeoJSON().readFeatures(geojsonObject),*/
-    projection: 'EPSG:4326',
-  });
-
-  // vectorSource.addFeature(new Feature(new Polygon([[proj.fromLonLat([0, 45]), proj.fromLonLat([0, 50]), proj.fromLonLat([5, 50]), proj.fromLonLat([5, 45])]])));
-
-  const vectorLayer = new VectorLayer({
-    name: 'query_results',
-    source: vectorSource,
-    style: styleFunction,
-  });
+const proj3857 = proj.get('EPSG:3857');
+proj4.defs(
+  'EPSG:2154',
+  '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'
+);
+register(proj4);
 
+const initResolutions = () => {
   const resolutions = [];
-  const matrixIds = [];
-  const proj3857 = proj.get('EPSG:3857');
   const maxResolution = getWidth(proj3857.getExtent()) / 256;
+  for (let i = 0; i < 20; i++) {
+    resolutions[i] = maxResolution / Math.pow(2, i);
+  }
+  return resolutions;
+};
 
+const initMatrixIds = () => {
+  const matrixIds = [];
   for (let i = 0; i < 20; i++) {
     matrixIds[i] = i.toString();
-    resolutions[i] = maxResolution / Math.pow(2, i);
   }
+  return matrixIds;
+};
 
-  const tileGrid = new WMTSTileGrid({
-    origin: [-20037508, 20037508],
-    resolutions: resolutions,
-    matrixIds: matrixIds,
-  });
+const pointBaseStyle = new Style({
+  fill: new Fill({
+    color: 'rgba(80, 200, 120, 0.6)',
+  }),
+  stroke: new Stroke({
+    color: 'rgba(80, 200, 120, 0.8)',
+    width: 2,
+  }),
+  text: new Text({
+    textAlign: 'center',
+    textBaseline: 'middle',
+    font: '12px Arial',
+    fill: new Fill({
+      color: 'rgba(0, 0, 0, 1)',
+    }),
+    stroke: new Stroke({
+      color: 'rgba(255, 255, 255, 1)',
+      width: 1,
+    }),
+    offsetX: 0,
+    offsetY: 0,
+    rotation: 0,
+  }),
+});
 
+const SearchMap = ({ searchResults, selectedPointsIds, setSelectedPointsIds }) => {
+  const { t } = useTranslation('maps');
+  // ref for handling zoomHelperText display
+  const timerRef = useRef(null);
+  const [isLoading, setIsLoading] = useState(false);
+  const [center, setCenter] = useState(proj.fromLonLat([2.5, 46.5]));
+  const [zoom, setZoom] = useState(6);
+  // Selection tool mode: false = select points ; true = unselect points.
+  const [selectionToolMode, setSelectionToolMode] = useState(false);
+  const filterOptions = [
+    { label: t('maps:layersTable.queryResults'), value: 'ResRequete' },
+    { label: t('maps:layersTable.regions'), value: 'regions' },
+    { label: t('maps:layersTable.departments'), value: 'departments' },
+    { label: t('maps:layersTable.sylvoEcoRegions'), value: 'sylvoEcoRegions' },
+  ];
+  const [selectedFilterOptions, setSelectedFilterOptions] = useState([filterOptions[0]]);
+  const [zoomHelperTextFeature, setZoomHelperTextFeature] = useState(
+    new Feature({
+      geometry: new Point(center),
+    })
+  );
+
+  const pointStyle = (feature, resolution) => {
+    // Change color if point is selected
+    if (feature.get('isSelected')) {
+      pointBaseStyle.getFill().setColor('rgba(120, 80, 200, 0.6)');
+      pointBaseStyle.getStroke().setColor('rgba(120, 80, 200, 0.8)');
+    } else {
+      pointBaseStyle.getFill().setColor('rgba(80, 200, 120, 0.6)');
+      pointBaseStyle.getStroke().setColor('rgba(80, 200, 120, 0.8)');
+    }
+    // Display label text if map is enough zoomed in
+    const zoomLevel = map.getView().getZoomForResolution(resolution);
+    const label = zoomLevel >= 9 ? feature.get('nom') : null;
+    pointBaseStyle.getText().setText(label);
+    return pointBaseStyle;
+  };
+
+  const mapFilters = {
+    ResRequete: new VectorLayer({
+      name: 'ResRequete',
+      source: new VectorSource({}),
+    }),
+    selectedPointsLayer: new VectorLayer({
+      name: 'selectedPointsSource',
+      source: new VectorSource({}),
+      visible: true,
+    }),
+    regions: new VectorLayer({
+      name: 'regions',
+      source: new VectorSource({
+        url: 'https://data.geopf.fr/wfs/ows?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&typeName=ADMINEXPRESS-COG-CARTO.LATEST:region&outputFormat=application/json',
+        format: new GeoJSON(),
+      }),
+      style: styles.filterLayer,
+    }),
+    departments: new VectorLayer({
+      name: 'departments',
+      source: new VectorSource({
+        url: 'https://data.geopf.fr/wfs/ows?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&typeName=ADMINEXPRESS-COG-CARTO.LATEST:departement&outputFormat=application/json',
+        format: new GeoJSON(),
+      }),
+      style: styles.filterLayer,
+    }),
+    sylvoEcoRegions: new VectorLayer({
+      name: 'sylvoEcoRegions',
+      source: new VectorSource({
+        url: 'https://w3.avignon.inrae.fr/geoserver/urfm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=urfm:ser_l93&srs=EPSG:2154&outputFormat=application/json',
+        format: new GeoJSON(),
+        projection: 'EPSG:2154',
+        crossOrigin: 'anonymous',
+      }),
+      style: styles.filterLayer,
+    }),
+  };
+  const sourceOSM = new SourceOSM();
   const [mapLayers, setMapLayers] = useState([
     new TileLayer({
       name: 'osm-layer',
-      source: source,
+      visible: true,
+      source: sourceOSM,
     }),
-    /* Bing Aerial */
     new TileLayer({
       name: 'Bing Aerial',
+      visible: false,
       preload: Infinity,
       source: new BingMaps({
         key: 'AtdZQap9X-lowJjvdPhTgr1BctJuGGm-ZoVw9wO6dHt1VDURjRKEkssetwOe31Xt',
         imagerySet: 'Aerial',
       }),
-      //visible: false
     }),
     new TileLayer({
       name: 'IGN',
+      visible: false,
       source: new WMTS({
         url: 'https://wxs.ign.fr/choisirgeoportail/geoportail/wmts',
         layer: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
         matrixSet: 'PM',
         format: 'image/png',
-        projection: 'EPSG:3857',
-        tileGrid: tileGrid,
+        projection: proj3857,
+        tileGrid: new WMTSTileGrid({
+          origin: [-20037508, 20037508],
+          resolutions: initResolutions(),
+          matrixIds: initMatrixIds(),
+        }),
         style: 'normal',
         attributions:
           '<a href="https://www.ign.fr/" target="_blank">' +
-          '<img src="https://wxs.ign.fr/static/logos/IGN/IGN.gif" title="Institut national de l\'' +
-          'information géographique et forestière" alt="IGN"></a>',
+          '<img src="https://www.ign.fr/files/default/styles/thumbnail/public/2020-06/logoIGN_300x200.png?itok=V80_0fm-" title="Institut national de l\'information géographique et forestière" alt="IGN"></a>',
+      }),
+    }),
+    new VectorLayer({
+      name: 'queryResults',
+      visible: true,
+      source: new VectorSource({}),
+    }),
+    mapFilters['selectedPointsLayer'],
+    new VectorLayer({
+      name: 'zoomHelperText',
+      visible: false,
+      background: 'rgba(0, 0, 0, 0.5)',
+      source: new VectorSource({
+        features: [zoomHelperTextFeature],
       }),
     }),
-    vectorLayer,
-
-    // new ImageLayer({
-    //     name: 'donuts-insylva-layer',
-    //     source: new ImageWMS({
-    //         url: 'http: //w3.avignon.inra.fr/geoserver/wms',
-    //         params: { 'LAYERS': 'urfm:donut_view' },
-    //         ratio: 1
-    //     })
-    // })
   ]);
 
-  const [mapLayersVisibility, setMapLayersVisibility] = useState(
-    new Array(mapLayers.length).fill(true)
+  const getLayerIndex = useCallback(
+    (name) => {
+      let index = 0;
+      mapLayers.forEach((layer) => {
+        if (layer.get('name') === name) {
+          index = mapLayers.indexOf(layer);
+        }
+      });
+      return index;
+    },
+    [mapLayers]
   );
 
-  // const posGreenwich = proj.fromLonLat([0, 51.47]);
-  // set initial map objects
-  const view = new View({
-    center: center,
-    zoom: zoom,
-  });
+  // Two layers are set to visible on page load
+  const initMapLayersVisibility = () => {
+    let initialMapLayersVisibility = new Array(mapLayers.length).fill(false);
+    initialMapLayersVisibility[getLayerIndex('osm-layer')] = true;
+    initialMapLayersVisibility[getLayerIndex('selectedPointsSource')] = true;
+    initialMapLayersVisibility[getLayerIndex('queryResults')] = true;
+    return initialMapLayersVisibility;
+  };
+  const [mapLayersVisibility, setMapLayersVisibility] = useState(
+    initMapLayersVisibility()
+  );
 
   const [map] = useState(
     new Map({
       target: null,
       layers: mapLayers,
-      controls: defaultControls().extend([
-        new MousePosition({
-          projection: 'EPSG:4326',
+      interactions: defaults({ mouseWheelZoom: false }).extend([
+        new MouseWheelZoom({
+          condition: platformModifierKeyOnly,
         }),
+      ]),
+      controls: defaultControls({
+        zoom: false,
+      }).extend([
+        new FullScreen(),
+        new Zoom(),
         new ScaleLine(),
-        overviewMapControl,
+        new OverviewMap({
+          layers: [
+            new TileLayer({
+              source: sourceOSM,
+            }),
+          ],
+        }),
       ]),
-      view: view,
+      view: new View({
+        center: center,
+        zoom: zoom,
+      }),
+    })
+  );
+
+  useEffect(() => {
+    const zoomHelperTextStyle = new Style({
+      text: new Text({
+        font: '24px Arial',
+        text: t('maps:layersTable.zoomHelperText'),
+        fill: new Fill({
+          color: 'white',
+        }),
+      }),
+    });
+    let tmpZoomHelperTextFeature = new Feature({
+      geometry: new Point(center),
+    });
+    tmpZoomHelperTextFeature.setStyle(zoomHelperTextStyle);
+    setZoomHelperTextFeature(tmpZoomHelperTextFeature);
+  }, [t, center]);
+
+  useEffect(() => {
+    const zoomHelperTextSource = map
+      .getLayers()
+      .item(getLayerIndex('zoomHelperText'))
+      .getSource();
+    zoomHelperTextSource.clear();
+    zoomHelperTextSource.addFeature(zoomHelperTextFeature);
+  }, [zoomHelperTextFeature]);
+
+  // a select interaction object to handle click
+  const select = new Select({
+    style: styles.selectTool,
+  });
+  const [selectedFeatures, setSelectedFeatures] = useState(select.getFeatures());
+  const [polygonSource, setPolygonSource] = useState(new VectorSource({}));
+  const [dragBox, setDragBox] = useState(
+    new DragBox({
+      condition: platformModifierKeyOnly,
     })
   );
 
-  const processData = (props) => {
-    if (props.searchResults) {
-      props.searchResults.forEach((result) => {
+  // Map configuration and search results processing
+  useEffect(() => {
+    map.setTarget('map');
+    map.addInteraction(select);
+    map.on('loadstart', () => {
+      setIsLoading(true);
+    });
+    map.on('loadend', () => {
+      setIsLoading(false);
+    });
+    map.on('moveend', () => onMapMoveEndCallback());
+    map.on('wheel', (e) => onMapWheelScrollCallback(e));
+    map.on('pointermove', (e) => onMapPointerMoveCallback(e));
+    processData();
+  }, [map, selectedFeatures]);
+
+  // Create a new dragBox instance when polygonSource changes
+  useEffect(() => {
+    setDragBox(
+      new DragBox({
+        condition: platformModifierKeyOnly,
+      })
+    );
+  }, [polygonSource, selectionToolMode]);
+
+  // Create event listeners for dragBox when it changes
+  useEffect(() => {
+    // Remove previous DragBox instances before adding the new one
+    map.getInteractions().forEach((interaction) => {
+      if (interaction?.box_?.element_?.className === 'ol-box ol-dragbox') {
+        map.removeInteraction(interaction);
+      }
+    });
+    dragBox.on('boxstart', () => onBoxStartCallback());
+    dragBox.on('boxend', () => onBoxEndCallback());
+    map.addInteraction(dragBox);
+  }, [dragBox]);
+
+  // Update state on filters selection
+  useEffect(() => {
+    const layers = map.getLayers();
+    for (let i = 0; i < filterOptions.length; i++) {
+      for (let j = 0; j < layers.getLength(); j++) {
+        const mapLayer = map.getLayers().item(j);
+        const mapLayerName = mapLayer.get('name');
         if (
-          result.experimental_site.geo_point &&
-          result.experimental_site.geo_point.longitude &&
-          result.experimental_site.geo_point.latitude
+          selectedFilterOptions.length !== 0 &&
+          mapLayerName === selectedFilterOptions[0].value
         ) {
-          //vectorSource.addFeature(new Feature(new Point(proj.fromLonLat([result.experimental_site.geo_point.longitude, result.experimental_site.geo_point.latitude]))))
-          //vectorSource.addFeature(new Feature(new Circle(toStringXY([result.experimental_site.geo_point.longitude, result.experimental_site.geo_point.latitude],1),10)))
-          const coord = [
-            result.experimental_site.geo_point.longitude,
-            result.experimental_site.geo_point.latitude,
-          ];
-          vectorSource.addFeature(new Feature(new Circle(proj.fromLonLat(coord), 1000)));
-          //vectorSource.addFeature(new Feature(new Circle([result.experimental_site.geo_point.longitude, result.experimental_site.geo_point.latitude],10)))
+          // If same filter as before is selected, do nothing
+          return;
         }
-      });
+        if (filterOptions[i].value === mapLayerName) {
+          // Remove previously selected filter
+          map.removeLayer(mapLayer);
+        }
+      }
+    }
+    // If no filter selected, return
+    if (selectedFilterOptions.length === 0) {
+      return;
+    }
+    if (selectedFilterOptions[0].value === 'ResRequete') {
+      // Update polygonSource object for dragBox selection
+      setPolygonSource(map.getLayers().item(getLayerIndex('queryResults')).getSource());
+      // Only toggle query results filter if already hidden
+      if (!mapLayersVisibility[getLayerIndex('queryResults')]) {
+        setLayerDisplay('queryResults', true);
+      }
+    } else {
+      // Update polygonSource object for dragBox selection
+      setPolygonSource(mapFilters[selectedFilterOptions[0].value].get('source'));
+      // Display newly selected filter
+      map.addLayer(mapFilters[selectedFilterOptions[0].value]);
     }
+  }, [selectedFilterOptions]);
+
+  // pointData.id set to 0 means that the point is a selected point
+  const createPointFeature = (pointData, coordinates, radius, isSelected) => {
+    const pointFeature = new Feature({
+      geometry: new Circle(coordinates, radius),
+    });
+    pointFeature.set('id', pointData.id);
+    pointFeature.set('nom', pointData.name);
+    pointFeature.set('isSelected', isSelected);
+    pointFeature.setStyle(pointStyle);
+    return pointFeature;
   };
 
-  // useEffect Hooks
-  // [] = component did mount
-  // set the initial map targets
-  useEffect(() => {
-    map.setTarget('map');
-    map.on('moveend', () => {
-      setCenter(map.getView().getCenter());
-      setZoom(map.getView().getZoom());
+  // On new selection start, unselect features
+  const onBoxStartCallback = () => {
+    clearSelectedFeatures();
+    setIsLoading(true);
+  };
+
+  // On new selection end, add all previously selected features
+  const onBoxEndCallback = () => {
+    let newSelectedPointsIds = selectedPointsIds;
+    const boxExtent = dragBox.getGeometry().getExtent();
+    // if the extent crosses the antimeridian process each world separately
+    const worldExtent = map.getView().getProjection().getExtent();
+    const worldWidth = getWidth(worldExtent);
+    const startWorld = Math.floor((boxExtent[0] - worldExtent[0]) / worldWidth);
+    const endWorld = Math.floor((boxExtent[2] - worldExtent[0]) / worldWidth);
+    for (let world = startWorld; world <= endWorld; ++world) {
+      const left = Math.max(boxExtent[0] - world * worldWidth, worldExtent[0]);
+      const right = Math.min(boxExtent[2] - world * worldWidth, worldExtent[2]);
+      const extent = [left, boxExtent[1], right, boxExtent[3]];
+      // Retrieve features (points) from source (depending on selected filter).
+      // Only unselected points and contained in dragBox
+      const boxFeatures = polygonSource
+        .getFeaturesInExtent(extent)
+        .filter(
+          (feature) =>
+            !selectedFeatures.getArray().includes(feature) &&
+            feature.getGeometry().intersectsExtent(extent)
+        );
+      const pointsFeatures = map
+        .getLayers()
+        .item(getLayerIndex('queryResults'))
+        .getSource()
+        .getFeatures();
+      const selectedPointsSource = map
+        .getLayers()
+        .item(getLayerIndex('selectedPointsSource'))
+        .getSource();
+      for (let polygon = 0; polygon < boxFeatures.length; polygon++) {
+        const polygonGeometry = boxFeatures[polygon].getGeometry();
+        // If selection tool is in select mode
+        if (!selectionToolMode) {
+          for (let point = 0; point < pointsFeatures.length; point++) {
+            const pointGeom = pointsFeatures[point].getGeometry();
+            const coords = pointGeom.getCenter();
+            if (polygonGeometry.intersectsCoordinate(coords)) {
+              const pointName = pointsFeatures[point].get('nom');
+              const pointId = pointsFeatures[point].get('id');
+              if (!getSelectedPointsNames(selectedPointsSource).includes(pointName)) {
+                // Add new selected features
+                const pointFeature = createPointFeature(
+                  {
+                    id: 0,
+                    name: pointName,
+                  },
+                  coords,
+                  5000,
+                  true
+                );
+                selectedPointsSource.addFeature(pointFeature);
+                // Add point id to selected points Ids
+                newSelectedPointsIds.push(pointId);
+              }
+            }
+          }
+          // If selection tool is in unselect mode
+        } else {
+          const selectedPointsFeatures = selectedPointsSource.getFeatures();
+          if (selectedPointsFeatures.length > 0) {
+            for (let point = 0; point < selectedPointsFeatures.length; point++) {
+              const pointGeom = selectedPointsFeatures[point].getGeometry();
+              const coords = pointGeom.getCenter();
+              if (polygonGeometry.intersectsCoordinate(coords)) {
+                // Remove previously selected features
+                selectedPointsSource.removeFeature(selectedPointsFeatures[point]);
+                newSelectedPointsIds = newSelectedPointsIds.splice(
+                  newSelectedPointsIds.indexOf(selectedPointsFeatures[point].get('id')),
+                  1
+                );
+              }
+            }
+          }
+        }
+      }
+      if (!selectionToolMode) {
+        let tmpSelectedFeatures = selectedFeatures;
+        setSelectedFeatures(null);
+        tmpSelectedFeatures.extend(boxFeatures);
+        setSelectedFeatures(tmpSelectedFeatures);
+      } else {
+        clearSelectedFeatures();
+      }
+    }
+    // Update selected features list
+    setSelectedPointsIds(newSelectedPointsIds);
+    setIsLoading(false);
+  };
+
+  const processData = () => {
+    if (!searchResults) {
+      return;
+    }
+    const resultPointsSource = map
+      .getLayers()
+      .item(getLayerIndex('queryResults'))
+      .getSource();
+    // Create points from search results
+    searchResults.forEach((result) => {
+      const geoPoint = result.experimental_site.geo_point;
+      if (geoPoint && geoPoint.longitude && geoPoint.latitude) {
+        const pointFeature = createPointFeature(
+          {
+            id: result.id,
+            name: result?.resource?.identifier,
+          },
+          proj.fromLonLat([geoPoint.longitude, geoPoint.latitude]),
+          3500,
+          false
+        );
+        resultPointsSource.addFeature(pointFeature);
+      }
     });
+    const selectedPointsSource = mapFilters.selectedPointsLayer.getSource();
+    // Create selected points from id list
+    selectedPointsIds.forEach((id) => {
+      const point = searchResults.find((result) => result.id === id);
+      if (point) {
+        const geoPoint = point.experimental_site.geo_point;
+        const pointName = point.resource.identifier;
+        if (geoPoint && geoPoint.longitude && geoPoint.latitude) {
+          if (!getSelectedPointsNames(selectedPointsSource).includes(pointName)) {
+            const pointFeature = createPointFeature(
+              {
+                id: 0,
+                name: pointName,
+              },
+              proj.fromLonLat([geoPoint.longitude, geoPoint.latitude]),
+              5000,
+              true
+            );
+            selectedPointsSource.addFeature(pointFeature);
+          }
+        }
+      }
+    });
+  };
 
-    /* map.getCurrentScale = function () {
-            //var map = this.getMap();
-            var map = this;
-            var view = map.getView();
-            var resolution = view.getResolution();
-            var units = map.getView().getProjection().getUnits();
-            var dpi = 25.4 / 0.28;
-            var mpu = proj.METERS_PER_UNIT[units];
-            var scale = resolution * mpu * 39.37 * dpi;
-            return scale;
-
-        };
-        map.getView().on('change:resolution', function(evt){
-
-        var divScale = 10;// to adjusting
-        var radius =  map.getCurrentScale()/divScale;
-        Circle.getStyle().getGeometry().setRadius(radius);
-        }); */
-
-    // Basic overlay to show where i want the new center to be
-    /* const overlay = new Overlay({
-            position: posGreenwich,
-            element: overlayRef.current,
-            positioning: "center-center",
-            stopEvent: false
-        });
-        map.addOverlay(overlay); */
-    map.getView().animate({ zoom: zoom }, { center: center }, { duration: 2000 });
-
-    processData(props);
-    // clean up upon component unmount
-    /* return () => {
-            map.setTarget(null);
-        }; */
-  }, [props]);
-
-  const getLayerIndex = (name) => {
-    let index = 0;
-    mapLayers.forEach((layer) => {
-      if (layer.get('name') === name) {
-        index = mapLayers.indexOf(layer);
+  const clearSelectedFeatures = () => {
+    let tmpSelectedFeatures = selectedFeatures;
+    if (tmpSelectedFeatures) {
+      tmpSelectedFeatures.clear();
+    }
+    setSelectedFeatures(tmpSelectedFeatures);
+  };
+
+  const onMapMoveEndCallback = () => {
+    setCenter(map.getView().getCenter());
+    setZoom(map.getView().getZoom());
+  };
+
+  // Display helper text inside map on mouse wheel scroll
+  const onMapWheelScrollCallback = (e) => {
+    // Return if user is zooming correctly
+    if (e.originalEvent.ctrlKey) {
+      return;
+    }
+    if (!mapLayersVisibility['zoomHelperText']) {
+      setLayerDisplay('zoomHelperText', true);
+      timerRef.current = setTimeout(() => {
+        setLayerDisplay('zoomHelperText', false);
+      }, 1500);
+    }
+  };
+
+  // Clear timer ref on unmount
+  useEffect(() => {
+    return () => clearTimeout(timerRef.current);
+  }, []);
+
+  // Display pointer cursor on feature hover
+  const onMapPointerMoveCallback = (e) => {
+    const pixel = map.getEventPixel(e.originalEvent);
+    const hit = map.hasFeatureAtPixel(pixel);
+    map.getViewport().style.cursor = hit ? 'pointer' : '';
+  };
+
+  const toggleSelectionToolMode = () => {
+    setSelectionToolMode((prev) => !prev);
+  };
+
+  const onFilterSelectChange = (newSelectedOptions) => {
+    setSelectedFilterOptions(newSelectedOptions);
+  };
+
+  const getSelectedPointsNames = (source) => {
+    let featureNames = [];
+    source.getFeatures().forEach((feature) => {
+      const name = feature.get('nom');
+      if (name) {
+        featureNames.push(name);
       }
     });
-    return index;
+    return featureNames;
   };
 
-  const toggleLayer = (name) => {
-    let updatedLayers = mapLayers;
+  const setLayerDisplay = (name, isShown) => {
     const layerIndex = getLayerIndex(name);
-    // let updatedLayer = updatedLayers[getLayerIndex(name)]
-    setMapLayersVisibility(
-      updateArrayElement(
-        mapLayersVisibility,
-        layerIndex,
-        !mapLayersVisibility[layerIndex]
-      )
-    );
-    updatedLayers[layerIndex].setVisible(!updatedLayers[layerIndex].getVisible());
+    let updatedLayers = mapLayers;
+    setMapLayersVisibility(updateArrayElement(mapLayersVisibility, layerIndex, isShown));
+    updatedLayers[layerIndex].setVisible(isShown);
     setMapLayers(updatedLayers);
   };
 
-  // helpers
-  /* const btnAction = () => {
-        // when button is clicked, recentre map
-        // this does not work :(
-        setCenter(posGreenwich);
-        setZoom(6);
-    }; */
-  // render
+  // Display selected points names
+  const SelectedPointsList = () => {
+    const selectedPointsLayer = map
+      .getLayers()
+      .item(getLayerIndex('selectedPointsSource'));
+    let selectedPointsList = <></>;
+    let selectedPoints = 0;
+    if (selectedPointsLayer) {
+      selectedPoints = getSelectedPointsNames(selectedPointsLayer.getSource());
+      if (selectedPoints.length === 0) {
+        selectedPointsList = <p>{t('maps:selectedPointsList.empty')}</p>;
+      } else {
+        selectedPointsList = selectedPoints.map((pointName, index) => {
+          return <p key={index}>{pointName}</p>;
+        });
+      }
+    }
+
+    return (
+      <div style={styles.selectedPointsListContainer}>
+        <EuiTitle size="s">
+          <h3>
+            {t('maps:selectedPointsList.title')} ({selectedPoints.length})
+          </h3>
+        </EuiTitle>
+        <EuiSpacer size="m" />
+        <EuiText style={styles.selectedPointsList}>{selectedPointsList}</EuiText>
+      </div>
+    );
+  };
+
+  const selectionToolOptions = [
+    {
+      id: 'selectionToolButton__0',
+      label: t('maps:layersTable.selectionTool.select'),
+    },
+    {
+      id: 'selectionToolButton__1',
+      label: t('maps:layersTable.selectionTool.unselect'),
+    },
+  ];
+
+  const unselectPoints = () => {
+    // Empty point selection
+    clearSelectedFeatures();
+    // Remove displayed points from layer's source
+    map.getLayers().item(getLayerIndex('selectedPointsSource')).getSource().clear();
+    setSelectedPointsIds([]);
+  };
+
   return (
-    <div>
-      <div id="map" style={styles.mapContainer}></div>
-      <div id="layertree">
-        <br />
-        <h5>Cliquez sur les couches pour modifier leur visibilité.</h5>
-        <br />
-        <table>
-          <thead>
-            <tr>
-              <th>Fonds carto ou vecteur</th>
-              {/*<th align="center">Couches INSYLVA</th>
-    <th>Infos attributs</th>*/}
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <td>
-                <ul>
-                  <li>
-                    <EuiCheckbox
-                      id={htmlIdGenerator()()}
-                      label="Query result"
-                      checked={mapLayersVisibility[getLayerIndex('query_results')]}
-                      onChange={(e) => toggleLayer('query_results')}
-                    />
-                  </li>
-                  <li>
-                    <EuiCheckbox
-                      id={htmlIdGenerator()()}
-                      label="Open Street Map"
-                      checked={mapLayersVisibility[getLayerIndex('osm-layer')]}
-                      onChange={(e) => toggleLayer('osm-layer')}
-                    />
-                  </li>
-                  <li>
-                    <EuiCheckbox
-                      id={htmlIdGenerator()()}
-                      label="Bing Aerial"
-                      checked={mapLayersVisibility[getLayerIndex('Bing Aerial')]}
-                      onChange={(e) => toggleLayer('Bing Aerial')}
-                    />
-                  </li>
-                  <li>
-                    <EuiCheckbox
-                      id={htmlIdGenerator()()}
-                      label="PLAN IGN"
-                      checked={mapLayersVisibility[getLayerIndex('IGN')]}
-                      onChange={(e) => toggleLayer('IGN')}
-                    />
-                  </li>
-                  {/*<li>
-                                    <EuiCheckbox
-                                        id={htmlIdGenerator()()}
-                                        label="Départements"
-                                        checked={mapLayersVisibility[getLayerIndex("dept-layer")]}
-                                        onChange={e => toggleLayer("dept-layer")}
-                                    />
-                                </li>
-                                <li>
-                                    <EuiCheckbox
-                                        id={htmlIdGenerator()()}
-                                        label="Régions"
-                                        checked={mapLayersVisibility[getLayerIndex("regs-layer")]}
-                                        onChange={e => toggleLayer("regs-layer")}
-                                    />
-                                </li>*/}
-                </ul>
-              </td>
-              <td>
-                <div id="info">&nbsp;</div>
-              </td>
-            </tr>
-          </tbody>
-        </table>
+    <>
+      <div style={styles.container}>
+        <div id="map" style={styles.mapContainer}></div>
+        <SelectedPointsList />
+      </div>
+      <div style={styles.loadingContainer}>
+        {isLoading && <EuiProgress size="l" color="accent" />}
       </div>
-      {/*<div
-                style={styles.bluecircle}
-                ref={overlayRef}
-                id="overlay"
-                title="overlay"
-            />*/}
-      {/*<button
-                style={{
-                    position: "absolute",
-                    right: 10,
-                    top: 10,
-                    backgroundColor: "white"
-                }}
-                onClick={() => {
-                    btnAction();
-                }}
-            >
-                CLICK
-            </button>*/}
-    </div>
+      <EuiSpacer size={'m'} />
+      <table style={styles.layersTable}>
+        <thead>
+          <tr>
+            <th>{t('maps:layersTableHeaders.cartography')}</th>
+            <th>{t('maps:layersTableHeaders.filters')}</th>
+            <th>{t('maps:layersTableHeaders.tools')}</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td style={styles.layersTableCells}>
+              <EuiCheckbox
+                id={htmlIdGenerator()()}
+                label={t('maps:layersTable.openStreetMap')}
+                checked={mapLayersVisibility[getLayerIndex('osm-layer')]}
+                onChange={(e) => setLayerDisplay('osm-layer', e.target.checked)}
+              />
+              <EuiCheckbox
+                id={htmlIdGenerator()()}
+                label={t('maps:layersTable.bingAerial')}
+                checked={mapLayersVisibility[getLayerIndex('Bing Aerial')]}
+                onChange={(e) => setLayerDisplay('Bing Aerial', e.target.checked)}
+              />
+              <EuiCheckbox
+                id={htmlIdGenerator()()}
+                label={t('maps:layersTable.IGN')}
+                checked={mapLayersVisibility[getLayerIndex('IGN')]}
+                onChange={(e) => setLayerDisplay('IGN', e.target.checked)}
+              />
+            </td>
+            <td style={styles.layersTableCells}>
+              <EuiCheckbox
+                id={htmlIdGenerator()()}
+                label={t('maps:layersTable.queryResults')}
+                checked={mapLayersVisibility[getLayerIndex('queryResults')]}
+                onChange={(e) => setLayerDisplay('queryResults', e.target.checked)}
+              />
+              <br />
+              <EuiComboBox
+                aria-label={t('maps:layersTable.selectFilterOption')}
+                placeholder={t('maps:layersTable.selectFilterOption')}
+                singleSelection={{ asPlainText: true }}
+                options={filterOptions}
+                selectedOptions={selectedFilterOptions}
+                onChange={onFilterSelectChange}
+                styles={styles.filtersSelect}
+              />
+            </td>
+            <td style={styles.layersTableCells}>
+              <EuiTitle size="xxs">
+                <h6>{t('maps:layersTable.selectionTool.title')}</h6>
+              </EuiTitle>
+              <EuiButtonGroup
+                legend={t('maps:layersTable.selectionTool.title')}
+                options={selectionToolOptions}
+                onChange={toggleSelectionToolMode}
+                idSelected={
+                  selectionToolMode ? 'selectionToolButton__1' : 'selectionToolButton__0'
+                }
+                color={'primary'}
+                isFullWidth
+              />
+              <EuiSpacer size="s" />
+              <EuiButton
+                onClick={() => unselectPoints()}
+                style={styles.unselectAllButton}
+              >
+                {t('maps:layersTable.selectionTool.unselectAll')}
+              </EuiButton>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </>
   );
 };
 
diff --git a/src/pages/maps/styles.js b/src/pages/maps/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..f1a31a2543a8ba9e6c428c1789e57eada06deabb
--- /dev/null
+++ b/src/pages/maps/styles.js
@@ -0,0 +1,64 @@
+import { Fill, Stroke, Style } from 'ol/style';
+
+const styles = {
+  filterLayer: new Style({
+    fill: new Fill({
+      color: 'rgba(128, 128, 128, 0.25)',
+    }),
+    stroke: new Stroke({
+      width: 1,
+      lineDash: [4],
+      color: 'rgba(0, 0, 0, 0.5)',
+    }),
+  }),
+  selectTool: new Style({
+    fill: new Fill({
+      color: 'rgba(80, 200, 120, 0.6)',
+    }),
+    stroke: new Stroke({
+      color: 'rgba(255, 255, 255, 0.7)',
+      width: 2,
+    }),
+  }),
+  container: {
+    width: '100%',
+    display: 'flex',
+    justifyContent: 'start',
+    minHeight: '60vh',
+    maxHeight: '60vh',
+  },
+  mapContainer: {
+    minWidth: '60vw',
+    minHeight: '100%',
+  },
+  loadingContainer: {
+    maxWidth: '60vw',
+  },
+  selectedPointsListContainer: {
+    display: 'flex',
+    flexDirection: 'column',
+    width: '100%',
+    textAlign: 'center',
+    padding: '10px',
+  },
+  selectedPointsList: {
+    overflow: 'auto',
+    maxHeight: '100%',
+  },
+  layersTable: {
+    width: '60vw',
+    cursor: 'pointer',
+    marginTop: '10px',
+  },
+  layersTableCells: {
+    padding: '10px',
+  },
+  filtersSelect: {
+    maxWidth: '50%',
+  },
+  unselectAllButton: {
+    minWidth: '100%',
+  },
+};
+
+export default styles;
diff --git a/src/pages/profile/Profile.js b/src/pages/profile/Profile.js
index d6fecd338609b352e8e558aff61e4d54d576bb79..72c213856125829e5423fe6d0a2d51f9a2b18c61 100644
--- a/src/pages/profile/Profile.js
+++ b/src/pages/profile/Profile.js
@@ -1,6 +1,5 @@
 import React, { useState, useEffect } from 'react';
 import {
-  EuiPageContent,
   EuiPageContentHeader,
   EuiPageContentHeaderSection,
   EuiPageContentBody,
@@ -23,20 +22,11 @@ import {
   createUserRequest,
   deleteUserRequest,
 } from '../../actions/user';
-
-/* const fieldsGridOptions = {
-    filter: true,
-    filterType: "dropdown",
-    responsive: "stacked",
-    selectableRows: 'multiple',
-    selectableRowsOnClick: true,
-    onRowsSelect: (rowsSelected, allRows) => {
-    },
-    onRowClick: (rowData, rowState) => {
-    },
-}; */
+import { useTranslation } from 'react-i18next';
+import styles from './styles';
 
 const Profile = () => {
+  const { t } = useTranslation(['profile', 'common', 'validation']);
   const [user, setUser] = useState({});
   const [userRole, setUserRole] = useState('');
   const [groups, setGroups] = useState([]);
@@ -47,15 +37,36 @@ const Profile = () => {
   const [valueError, setValueError] = useState(undefined);
 
   useEffect(() => {
+    const loadUser = () => {
+      if (sessionStorage.getItem('user_id')) {
+        findOneUser(sessionStorage.getItem('user_id')).then((user) => {
+          setUser(user);
+        });
+        findOneUserWithGroupAndRole(sessionStorage.getItem('user_id')).then((result) => {
+          const userGroupList = userGroups;
+          result.forEach((user) => {
+            if (user.groupname) {
+              userGroupList.push({
+                id: user.groupid,
+                label: user.groupname,
+                description: user.groupdescription,
+              });
+            }
+            setUserRole(user.rolename);
+          });
+          setUserGroups(userGroupList);
+        });
+      }
+    };
     loadUser();
     getUserRequests();
     getUserGroups();
     getUserRoles();
-  }, []);
+  }, [userGroups]);
 
   const groupColumns = [
-    { field: 'label', name: 'Group Name', width: '30%' },
-    { field: 'description', name: 'Group description' },
+    { field: 'label', name: t('groups.groupName'), width: '30%' },
+    { field: 'description', name: t('groups.groupDescription') },
   ];
 
   const getUserRoles = () => {
@@ -98,8 +109,8 @@ const Profile = () => {
 
   const requestActions = [
     {
-      name: 'Cancel',
-      description: 'Cancel this request',
+      name: t('common:validationActions.cancel'),
+      description: t('requestsList.cancelRequest'),
       icon: 'trash',
       type: 'icon',
       onClick: onDeleteRequest,
@@ -107,33 +118,15 @@ const Profile = () => {
   ];
 
   const requestsColumns = [
-    { field: 'request_message', name: 'Message', width: '90%' },
-    { field: 'is_processed', name: 'Processed' },
-    { name: 'Delete', actions: requestActions },
+    {
+      field: 'request_message',
+      name: t('requestsList.requestsMessage'),
+      width: '85%',
+    },
+    { field: 'is_processed', name: t('requestsList.processed') },
+    { name: t('common:validationActions.cancel'), actions: requestActions },
   ];
 
-  const loadUser = () => {
-    if (sessionStorage.getItem('user_id')) {
-      findOneUser(sessionStorage.getItem('user_id')).then((user) => {
-        setUser(user);
-      });
-      findOneUserWithGroupAndRole(sessionStorage.getItem('user_id')).then((result) => {
-        const userGroupList = userGroups;
-        result.forEach((user) => {
-          if (user.groupname) {
-            userGroupList.push({
-              id: user.groupid,
-              label: user.groupname,
-              description: user.groupdescription,
-            });
-          }
-          setUserRole(user.rolename);
-        });
-        setUserGroups(userGroupList);
-      });
-    }
-  };
-
   const getUserGroupLabels = () => {
     let labelList = '';
     if (!!userGroups) {
@@ -155,111 +148,118 @@ const Profile = () => {
     );
   };
 
+  const onSendRoleRequest = () => {
+    if (selectedRole) {
+      const message = `The user ${user.username} (${user.email}) has made a request to get the role : ${selectedRole}.`;
+      createUserRequest(user.id, message);
+      sendMail('User role request', message);
+      alert(t('validation:requestSent'));
+    }
+    getUserRequests();
+  };
+
+  const onSendGroupRequest = () => {
+    const groupList = [];
+    if (userGroups) {
+      userGroups.forEach((group) => {
+        groupList.push(group.label);
+      });
+      const message = `The user ${user.username} (${user.email}) has made a request to be part of these groups : ${groupList}.`;
+      createUserRequest(user.id, message);
+      sendMail('User group request', message);
+      alert(t('validation:requestSent'));
+    }
+    getUserRequests();
+  };
+
   return (
     <>
-      <EuiPageContent>
-        <EuiPageContentHeader>
-          <EuiPageContentHeaderSection>
-            <EuiTitle>
-              <h2>Profile management</h2>
-            </EuiTitle>
-          </EuiPageContentHeaderSection>
-        </EuiPageContentHeader>
-        <EuiPageContentBody>
-          <EuiForm component="form">
-            <EuiTitle size="s">
-              <h3>Group list</h3>
-            </EuiTitle>
-            <EuiFormRow fullWidth label="">
-              <EuiBasicTable items={groups} columns={groupColumns} />
-            </EuiFormRow>
-            <EuiSpacer size="l" />
-            <EuiTitle size="s">
-              <h3>Requests list</h3>
-            </EuiTitle>
-            <EuiFormRow fullWidth label="">
-              <EuiBasicTable items={userRequests} columns={requestsColumns} />
-            </EuiFormRow>
-            <EuiSpacer size="l" />
-            <EuiTitle size="s">
-              <h3>Request group assignment modifications</h3>
-            </EuiTitle>
-            {getUserGroupLabels() ? (
-              <p>
-                You currently belong to (or have a pending demand for) these groups :{' '}
-                {getUserGroupLabels()}{' '}
-              </p>
-            ) : (
-              <p>You currently belong to no group</p>
-            )}
-            <EuiFormRow error={valueError} isInvalid={valueError !== undefined}>
-              <EuiComboBox
-                placeholder={'Select groups'}
-                options={groups}
-                selectedOptions={userGroups}
-                onChange={(selectedOptions) => {
-                  setValueError(undefined);
-                  setUserGroups(selectedOptions);
-                }}
-                onSearchChange={onValueSearchChange}
-              />
-            </EuiFormRow>
-            <EuiSpacer size="m" />
-            <EuiButton
-              onClick={() => {
-                if (userGroups) {
-                  const groupList = [];
-                  userGroups.forEach((group) => {
-                    groupList.push(group.label);
-                  });
-                  const message = `The user ${user.username} (${user.email}) has made a request to be part of these groups : ${groupList}.`;
-                  createUserRequest(user.id, message);
-                  sendMail('User group request', message);
-                  alert('Your group request has been sent to the administrators.');
-                }
-                getUserRequests();
+      <EuiPageContentHeader>
+        <EuiPageContentHeaderSection>
+          <EuiTitle>
+            <h2>{t('pageTitle')}</h2>
+          </EuiTitle>
+        </EuiPageContentHeaderSection>
+      </EuiPageContentHeader>
+      <EuiPageContentBody>
+        <EuiForm component="form">
+          <EuiTitle size="s">
+            <h3>{t('groups.groupsList')}</h3>
+          </EuiTitle>
+          <EuiFormRow fullWidth label="">
+            <EuiBasicTable items={groups} columns={groupColumns} />
+          </EuiFormRow>
+          <EuiSpacer size="l" />
+          <EuiTitle size="s">
+            <h3>{t('requestsList.requestsList')}</h3>
+          </EuiTitle>
+          <EuiFormRow fullWidth label="">
+            <EuiBasicTable items={userRequests} columns={requestsColumns} />
+          </EuiFormRow>
+          <EuiSpacer size="l" />
+          <EuiTitle size="s">
+            <h3>{t('groupRequests.requestGroupAssignment')}</h3>
+          </EuiTitle>
+          {getUserGroupLabels() ? (
+            <p
+              style={styles.currentRoleOrGroupText}
+            >{`${t('groupRequests.currentGroups')} ${getUserGroupLabels()}`}</p>
+          ) : (
+            <p>{t('groupRequests.noGroup')}</p>
+          )}
+          <EuiFormRow error={valueError} isInvalid={valueError !== undefined}>
+            <EuiComboBox
+              placeholder={'Select groups'}
+              options={groups}
+              selectedOptions={userGroups}
+              onChange={(selectedOptions) => {
+                setValueError(undefined);
+                setUserGroups(selectedOptions);
               }}
-              fill
-            >
-              Send request
-            </EuiButton>
-            <EuiSpacer size="l" />
-            <EuiTitle size="s">
-              <h3>Request an application role</h3>
-            </EuiTitle>
-            {userRole ? (
-              <p>Your current role is (or have a pending demand for) {userRole}</p>
-            ) : (
-              <></>
-            )}
-            <EuiFormRow>
-              <EuiSelect
-                hasNoInitialSelection
-                options={roles}
-                value={selectedRole}
-                onChange={(e) => {
-                  setSelectedRole(e.target.value);
-                }}
-              />
-            </EuiFormRow>
-            <EuiSpacer size="m" />
-            <EuiButton
-              onClick={() => {
-                if (selectedRole) {
-                  const message = `The user ${user.username} (${user.email}) has made a request to get the role : ${selectedRole}.`;
-                  createUserRequest(user.id, message);
-                  sendMail('User role request', message);
-                  alert('Your role request has been sent to the administrators.');
-                }
-                getUserRequests();
+              onSearchChange={onValueSearchChange}
+            />
+          </EuiFormRow>
+          <EuiSpacer size="m" />
+          <EuiButton
+            onClick={() => {
+              onSendGroupRequest();
+            }}
+            fill
+          >
+            {t('common:validationActions.send')}
+          </EuiButton>
+          <EuiSpacer size="l" />
+          <EuiTitle size="s">
+            <h3>{t('roleRequests.requestRoleAssignment')}</h3>
+          </EuiTitle>
+          {userRole ? (
+            <p
+              style={styles.currentRoleOrGroupText}
+            >{`${t('roleRequests.currentRole')} ${userRole}`}</p>
+          ) : (
+            <></>
+          )}
+          <EuiFormRow>
+            <EuiSelect
+              hasNoInitialSelection
+              options={roles}
+              value={selectedRole}
+              onChange={(e) => {
+                setSelectedRole(e.target.value);
               }}
-              fill
-            >
-              Send request
-            </EuiButton>
-          </EuiForm>
-        </EuiPageContentBody>
-      </EuiPageContent>
+            />
+          </EuiFormRow>
+          <EuiSpacer size="m" />
+          <EuiButton
+            onClick={() => {
+              onSendRoleRequest();
+            }}
+            fill
+          >
+            {t('common:validationActions.send')}
+          </EuiButton>
+        </EuiForm>
+      </EuiPageContentBody>
     </>
   );
 };
diff --git a/src/pages/profile/styles.js b/src/pages/profile/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c2776e98c63a6bf9e919a8f152504dccba201f4
--- /dev/null
+++ b/src/pages/profile/styles.js
@@ -0,0 +1,8 @@
+const style = {
+  currentRoleOrGroupText: {
+    marginTop: '10px',
+    marginBottom: '10px',
+  },
+};
+
+export default style;
diff --git a/src/pages/results/ResourceFlyout.js b/src/pages/results/ResourceFlyout.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd7522b49a5f5d3e9a26490d78ecd1b48b4d71f9
--- /dev/null
+++ b/src/pages/results/ResourceFlyout.js
@@ -0,0 +1,44 @@
+import React, { Fragment } from 'react';
+import { EuiFlyout, EuiFlyoutBody, EuiText } from '@elastic/eui';
+import { useTranslation } from 'react-i18next';
+import JsonView from '@in-sylva/json-view';
+
+const ResourceFlyout = ({
+  resourceFlyoutData,
+  setResourceFlyoutData,
+  isResourceFlyoutOpen,
+  setIsResourceFlyoutOpen,
+}) => {
+  const { t } = useTranslation('results');
+
+  const closeResourceFlyout = () => {
+    setResourceFlyoutData({});
+    setIsResourceFlyoutOpen(false);
+  };
+
+  return (
+    isResourceFlyoutOpen && (
+      <EuiFlyout
+        onClose={() => closeResourceFlyout()}
+        aria-labelledby={t('results:flyout.label')}
+      >
+        <EuiFlyoutBody>
+          <EuiText size="s">
+            <Fragment>
+              <JsonView
+                src={resourceFlyoutData}
+                name={t('results:flyout.JSON.title')}
+                collapsed={true}
+                iconStyle={'triangle'}
+                enableClipboard={false}
+                displayDataTypes={false}
+              />
+            </Fragment>
+          </EuiText>
+        </EuiFlyoutBody>
+      </EuiFlyout>
+    )
+  );
+};
+
+export default ResourceFlyout;
diff --git a/src/pages/results/Results.js b/src/pages/results/Results.js
index c54481e0a83b3d9be02a63e6c191c8544493ce56..3584081fabcbfa6d66e69d1b6a3f34996b4bd6ac 100644
--- a/src/pages/results/Results.js
+++ b/src/pages/results/Results.js
@@ -1,367 +1,38 @@
-import React, { Fragment, useEffect, useState } from 'react';
-import {
-  EuiButton,
-  EuiCallOut,
-  EuiFlexGroup,
-  EuiFlexItem,
-  EuiFlyout,
-  EuiFlyoutBody,
-  EuiIcon,
-  EuiSpacer,
-  EuiText,
-  EuiTitle,
-} from '@elastic/eui';
-import { createTheme, MuiThemeProvider } from '@material-ui/core/styles';
-import MUIDataTable from 'mui-datatables';
-import JsonView from '@in-sylva/json-view';
-import { updateArrayElement } from '../../Utils.js';
-
-const download = require('downloadjs');
-
-const getMuiTheme = () =>
-  createTheme({
-    overrides: {
-      MUIDataTable: {
-        root: {
-          backgroundColor: '#fafbfc',
-        },
-        paper: {
-          boxShadow: 'none',
-        },
-      },
-    },
-  });
-
-const changeFlyoutState = (array, index, value, defaultValue) => {
-  let newArray = new Array(array.length).fill(defaultValue);
-  newArray[index] = value;
-  return newArray;
-};
-
-const Results = (searchResults, search, basicSearch) => {
-  const [resultsCol, setResultsCol] = useState([]);
-  const [results, setResults] = useState([]);
-  const [isFlyoutOpen, setIsFlyoutOpen] = useState([false]);
-  const [searchQuery, setSearchQuery] = useState('');
-
-  useEffect(() => {
-    processData(searchResults);
-    search.length ? setSearchQuery(search) : setSearchQuery(basicSearch);
-  }, [searchResults, search, basicSearch]);
-
-  const updateTableCell = (tableContent, value, colIndex, rowIndex) => {
-    const updatedRow = updateArrayElement(tableContent[rowIndex], colIndex, value);
-    return updateArrayElement(tableContent, rowIndex, updatedRow);
-  };
-
-  const closeAllFlyouts = (tableContent) => {
-    const updatedResults = [];
-    tableContent.forEach((tableRow, index) => {
-      updatedResults.push(updateArrayElement(tableRow, 0));
-    });
-    return updatedResults;
-  };
-
-  const recordFlyout = (record, recordIndex, isOpen) => {
-    if (isOpen) {
-      return (
-        <>
-          <EuiFlyout
-            onClose={() => {
-              const updatedTable = updateTableCell(
-                closeAllFlyouts(results),
-                recordFlyout(record, recordIndex, false),
-                0,
-                recordIndex
-              );
-              const updatedArray = changeFlyoutState(
-                isFlyoutOpen,
-                recordIndex,
-                false,
-                false
-              );
-              setIsFlyoutOpen(updatedArray);
-              setResults(updatedTable);
-            }}
-            aria-labelledby={recordIndex}
-          >
-            <EuiFlyoutBody>
-              <EuiText size="s">
-                <Fragment>
-                  <JsonView
-                    name="In-Sylva metadata"
-                    collapsed={true}
-                    iconStyle={'triangle'}
-                    src={record}
-                    enableClipboard={false}
-                    displayDataTypes={false}
-                  />
-                </Fragment>
-              </EuiText>
-            </EuiFlyoutBody>
-          </EuiFlyout>
-          <EuiIcon type="eye" color="danger" />
-        </>
-      );
-    }
-  };
-
-  const resultsGridOptions = {
-    print: false,
-    download: false,
-    filter: true,
-    filterType: 'dropdown',
-    responsive: 'standard',
-    selectableRows: 'none',
-    selectableRowsOnClick: false,
-    onRowSelectionChange: (rowsSelected, allRows) => {},
-    onRowClick: (rowData, rowState) => {},
-    onCellClick: (val, colMeta) => {
-      // if (searchResults.hits.hits && colMeta.colIndex !== 0) {
-      if (searchResults && colMeta.colIndex !== 0) {
-        // const updatedTable = updateTableCell(closeAllFlyouts(results), recordFlyout(searchResults.hits.hits[colMeta.rowIndex]._source, colMeta.rowIndex, !isFlyoutOpen[colMeta.rowIndex]), 0, colMeta.rowIndex)
-        const updatedTable = updateTableCell(
-          closeAllFlyouts(results),
-          recordFlyout(
-            searchResults[colMeta.dataIndex],
-            colMeta.dataIndex,
-            !isFlyoutOpen[colMeta.dataIndex]
-          ),
-          0,
-          colMeta.dataIndex
-        );
-        const updatedArray = changeFlyoutState(
-          isFlyoutOpen,
-          colMeta.dataIndex,
-          !isFlyoutOpen[colMeta.dataIndex],
-          false
-        );
-        setIsFlyoutOpen(updatedArray);
-        setResults(updatedTable);
-      }
-    },
-  };
-
-  /*  const displayRecord = (record) => {
-         let recordDisplay = []
-         if (!!record) {
-             const fields = Object.keys(record)
-             fields.forEach(field => {
-                 if (typeof record[field] != 'string') {
-                     // const rndId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
-                     if (isNaN(field)) {
-                         // const buttonContent = `"${field}"`
-                         let isStrArray = false
-                         if (Array.isArray(record[field])) {
-                             isStrArray = true
-                             record[field].forEach(item => {
-                                 if (typeof item != 'string')
-                                     isStrArray = false
-                             })
-                         }
-                         if (isStrArray) {
-                             recordDisplay.push(
-                                 <>
-                                     <h3>
-                                         &emsp;{field}
-                                     </h3>
-                                     {displayRecord(record[field])}
-                                 </>
-                             )
-                         } else {
-                             recordDisplay.push(
-                                 <>
-                                     <EuiSpacer size="s" />
-                                     <EuiPanel paddingSize="s">
-                                         <EuiAccordion id={Math.random().toString()} buttonContent={field}>
-                                             <EuiText size="s">
-                                                 {displayRecord(record[field])}
-                                             </EuiText>
-                                         </EuiAccordion>
-                                     </EuiPanel>
-                                 </>
-                             )
-                         }
-                     } else {
-                         recordDisplay.push(
-                             <>
-                                 {displayRecord(record[field])}
-                             </>
-                         )
-                         if (fields[fields.indexOf(field) + 1])
-                             recordDisplay.push(
-                                 <>
-                                     <EuiSpacer size="m" />
-                                     <hr />
-                                 </>
-                             )
-                     }
-                 } else {
-                     if (isNaN(field)) {
-                         recordDisplay.push(
-                             <>
-                                 <h3>
-                                     &emsp;{field}
-                                 </h3>
-                                 <EuiTextColor color="secondary">&emsp;&emsp;{record[field]}</EuiTextColor>
-                             </>
-                         )
-                     } else {
-                         recordDisplay.push(
-                             <>
-                                 <EuiSpacer size="s" />
-                                 <EuiTextColor color="secondary">&emsp;&emsp;{record[field]}</EuiTextColor>
-                             </>
-                         )
-                     }
-                 }
-             })
-             return recordDisplay
-         }
-     }
-
-     const recordFlyout = (record, recordIndex, isFlyoutOpen, setIsFlyoutOpen) => {
-         let flyout
-         if (isFlyoutOpen[recordIndex]) {
-             // const flyOutContent = ReactHtmlParser(displayRecord(record, 1))
-             const flyOutStr = displayRecord(record)
-             // const flyOutContent = parse(flyOutStr, { htmlparser2: { lowerCaseTags: false } })
-             const flyout = (
-                 <>
-                     <EuiFlyout
-                         onClose={() => {
-                             // setIsFlyoutOpen(updateArrayElement(isFlyoutOpen, recordIndex, false))
-                             // updateResultsCell(false, 0, recordIndex)
-                             const updatedArray = changeFlyoutState(isFlyoutOpen, recordIndex, !isFlyoutOpen[recordIndex], false)
-                             setIsFlyoutOpen(updatedArray)
-                         }}
-                         aria-labelledby={recordIndex}>
-                         <EuiFlyoutBody>
-                             <EuiText size="s">
-                                 <Fragment>
-                                     {flyOutStr}
-                                 </Fragment>
-                             </EuiText>
-                         </EuiFlyoutBody>
-                     </EuiFlyout>
-                     <EuiIcon type='eye' color='danger' />
-                 </>
-             );
-             return (flyout)
-         }
-     } */
-
-  /* const viewButton = (record, recordIndex, isFlyoutOpenIndex, isFlyoutOpen, setIsFlyoutOpen) => {
-        return (
-            <>
-                <EuiButtonIcon
-                    size="m"
-                    color="success"
-                    onClick={() => {
-                        const flyOutArray = updateArrayElement(isFlyoutOpen, recordIndex, !isFlyoutOpen[recordIndex])
-                        setIsFlyoutOpen(flyOutArray)
-                        updateResultsCell(!isFlyoutOpen[recordIndex], isFlyoutOpenIndex, recordIndex)
-                    }}
-                    iconType="eye"
-                    title="View record"
-                />
-                {recordFlyout(record, recordIndex, isFlyoutOpen, setIsFlyoutOpen)}
-            </>
-        )
-    } */
-
-  const processData = (metadata) => {
-    // if (metadata && metadata.hits) {
-    if (metadata) {
-      const columns = [];
-      const rows = [];
-      // const metadataRecords = metadata.hits.hits
-      columns.push({
-        name: 'currently open',
-        options: {
-          display: true,
-          viewColumns: true,
-          filter: true,
-        },
-      });
-      /* for (let recordIndex = 0; recordIndex < metadataRecords.length; recordIndex++) {
-                const row = []
-                const displayedFields = metadataRecords[recordIndex]._source.resource
-                const flyoutCell = recordFlyout(metadataRecords[recordIndex]._source, recordIndex) */
-      for (let recordIndex = 0; recordIndex < metadata.length; recordIndex++) {
-        const row = [];
-        const displayedFields = metadata[recordIndex].resource;
-        const flyoutCell = recordFlyout(metadata[recordIndex], recordIndex);
-        if (recordIndex >= isFlyoutOpen.length) {
-          setIsFlyoutOpen([...isFlyoutOpen, false]);
-        }
-        row.push(flyoutCell);
-        for (const fieldName in displayedFields) {
-          if (typeof displayedFields[fieldName] === 'string') {
-            if (recordIndex === 0) {
-              const column = {
-                name: fieldName,
-                options: {
-                  display: true,
-                },
-              };
-              columns.push(column);
-            }
-            row.push(displayedFields[fieldName]);
-          }
-        }
-        rows.push(row);
-      }
-      setResultsCol(columns);
-      setResults(rows);
-    }
-  };
+import React, { useState } from 'react';
+import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
+import { useTranslation } from 'react-i18next';
+import ResultsTableMUI from './ResultsTableMUI';
+import ResourceFlyout from './ResourceFlyout';
+import ResultsDownload from './ResultsDownload';
+
+const Results = ({ searchResults, searchQuery, selectedRowsIds, setSelectedRowsIds }) => {
+  const { t } = useTranslation('results');
+  const [isResourceFlyoutOpen, setIsResourceFlyoutOpen] = useState(false);
+  const [resourceFlyoutData, setResourceFlyoutData] = useState({});
 
   return (
     <>
-      <EuiSpacer size="s" />
-      <EuiFlexGroup justifyContent="spaceAround">
-        <EuiSpacer size="s" />
-        <EuiFlexItem grow={false}>
-          <EuiTitle size="xs">
-            <h2>Your query : {searchQuery}</h2>
-          </EuiTitle>
-        </EuiFlexItem>
-        <EuiSpacer size="s" />
-      </EuiFlexGroup>
+      <ResourceFlyout
+        resourceFlyoutData={resourceFlyoutData}
+        setResourceFlyoutData={setResourceFlyoutData}
+        isResourceFlyoutOpen={isResourceFlyoutOpen}
+        setIsResourceFlyoutOpen={setIsResourceFlyoutOpen}
+      />
       <EuiFlexGroup>
         <EuiFlexItem>
-          <EuiCallOut
-            size="s"
-            title="Click on a line of the table to inspect resource metadata (except for the first column)."
-            iconType="search"
-          />
-        </EuiFlexItem>
-        <EuiFlexItem grow={false}>
-          <EuiButton
-            fill
-            onClick={() => {
-              if (searchResults) {
-                download(
-                  `{"metadataRecords": ${JSON.stringify(searchResults, null, '\t')}}`,
-                  'InSylvaSearchResults.json',
-                  'application/json'
-                );
-              }
-            }}
-          >
-            Download as JSON
-          </EuiButton>
+          <EuiCallOut size="s" title={t('results:clickOnRowTip')} iconType="search" />
         </EuiFlexItem>
+        <ResultsDownload searchResults={searchResults} />
       </EuiFlexGroup>
-      <MuiThemeProvider theme={getMuiTheme()}>
-        <MUIDataTable
-          title={'Search results'}
-          data={results}
-          columns={resultsCol}
-          options={resultsGridOptions}
-        />
-      </MuiThemeProvider>
+      <EuiSpacer size={'m'} />
+      <ResultsTableMUI
+        searchResults={searchResults}
+        searchQuery={searchQuery}
+        selectedRowsIds={selectedRowsIds}
+        setSelectedRowsIds={setSelectedRowsIds}
+        setResourceFlyoutData={setResourceFlyoutData}
+        setIsResourceFlyoutOpen={setIsResourceFlyoutOpen}
+      />
     </>
   );
 };
diff --git a/src/pages/results/ResultsDownload.js b/src/pages/results/ResultsDownload.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ed397818e778b6002540841f35743628c07c628
--- /dev/null
+++ b/src/pages/results/ResultsDownload.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { EuiButton, EuiFlexItem } from '@elastic/eui';
+import download from 'downloadjs';
+import { useTranslation } from 'react-i18next';
+
+const ResultsDownload = ({ searchResults }) => {
+  const { t } = useTranslation('results');
+
+  const downloadResults = () => {
+    if (!searchResults) {
+      return;
+    }
+    download(
+      `{"metadataRecords": ${JSON.stringify(searchResults, null, '\t')}}`,
+      'InSylvaSearchResults.json',
+      'application/json'
+    );
+  };
+
+  return (
+    <EuiFlexItem grow={false}>
+      <EuiButton fill onClick={() => downloadResults()}>
+        {t('results:downloadResultsButton.JSON')}
+      </EuiButton>
+    </EuiFlexItem>
+  );
+};
+
+export default ResultsDownload;
diff --git a/src/pages/results/ResultsTable.js b/src/pages/results/ResultsTable.js
new file mode 100644
index 0000000000000000000000000000000000000000..415a67298ac34c8f3f2606e1be931f61205e4c3e
--- /dev/null
+++ b/src/pages/results/ResultsTable.js
@@ -0,0 +1,112 @@
+import React, { useState } from 'react';
+import { EuiBasicTable } from '@elastic/eui';
+
+const buildColumnName = (name) => {
+  name = name.split('.').join(' ');
+  name = name.charAt(0).toUpperCase() + name.slice(1);
+  return name;
+};
+
+const ResultsTable = ({ searchResults }) => {
+  const [pageIndex, setPageIndex] = useState(0);
+  const [pageSize, setPageSize] = useState(10);
+
+  function getValueFromPath(obj, path) {
+    return path.split('.').reduce((acc, part, i, arr) => {
+      if (Array.isArray(acc)) {
+        // The next part should be a key to match within array objects
+        const key = arr[i + 1];
+        if (key) {
+          const found = acc.find((item) => item.type === key);
+          arr.splice(i + 1, 1); // Remove the key from the path array
+          return found ? found.value : undefined;
+        }
+      }
+      return acc && acc[part];
+    }, obj);
+  }
+
+  function getValues(obj, paths) {
+    return paths.reduce((acc, path) => {
+      acc[path] = getValueFromPath(obj, path);
+      return acc;
+    }, {});
+  }
+
+  const buildRows = (results, columns) => {
+    let dataRows = [];
+    results.forEach((result) => {
+      let row = getValues(result, columns);
+      dataRows.push(row);
+    });
+    return dataRows;
+  };
+
+  const buildColumns = (userColumns) => {
+    let dataColumns = [];
+    dataColumns.push({
+      field: 'isRowOpen',
+      name: 'Open',
+      sortable: false,
+      truncateText: true,
+    });
+    userColumns.forEach((userColumn) => {
+      dataColumns.push({
+        field: userColumn,
+        name: buildColumnName(userColumn),
+        sortable: true,
+        truncateText: true,
+      });
+    });
+    return dataColumns;
+  };
+
+  const buildSearchResultsTable = (results) => {
+    if (!results && results.length > 0) {
+      return;
+    }
+    // TODO: get columns settings from user to replace hard-coded array
+    const userColumns = [
+      'id',
+      'resource.title',
+      'resource.lineage',
+      'resource.identifier',
+      'resource.date.publication',
+      'resource.date.revision',
+      'resource.INSPIRE_type',
+    ];
+    const columns = buildColumns(userColumns);
+    const rows = buildRows(results, userColumns);
+    return {
+      rows,
+      columns,
+    };
+  };
+
+  const { rows, columns } = buildSearchResultsTable(searchResults);
+
+  const paginationOptions = {
+    pageSizeOptions: [5, 10, 20, 0],
+    pageIndex,
+    pageSize,
+    totalItemCount: rows?.length,
+  };
+
+  const onTableChange = ({ page }) => {
+    if (page) {
+      setPageIndex(page.index);
+      setPageSize(page.size);
+    }
+  };
+
+  return (
+    <EuiBasicTable
+      items={rows}
+      columns={columns}
+      pagination={paginationOptions}
+      onChange={onTableChange}
+    />
+  );
+};
+
+export default ResultsTable;
diff --git a/src/pages/results/ResultsTableMUI.js b/src/pages/results/ResultsTableMUI.js
new file mode 100644
index 0000000000000000000000000000000000000000..b28999146840743dd62dc1121d17a593a812b7cb
--- /dev/null
+++ b/src/pages/results/ResultsTableMUI.js
@@ -0,0 +1,228 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { Trans, useTranslation } from 'react-i18next';
+import MUIDataTable from 'mui-datatables';
+import { createTheme, ThemeProvider } from '@material-ui/core';
+import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+
+const getMuiTheme = () =>
+  createTheme({
+    overrides: {
+      MuiTableRow: {
+        root: {
+          '&:hover': {
+            cursor: 'pointer',
+          },
+        },
+      },
+    },
+  });
+
+const ResultsTableMUI = ({
+  searchResults,
+  searchQuery,
+  selectedRowsIds,
+  setSelectedRowsIds,
+  setIsResourceFlyoutOpen,
+  setResourceFlyoutData,
+}) => {
+  const { t } = useTranslation('results');
+  const [selectedRows, setSelectedRows] = useState([]);
+
+  useEffect(() => {
+    setSelectedRows(selectedRowsIds.map((id) => getRowIdFromResourceData(id)));
+  }, [selectedRowsIds]);
+
+  // Build each row in table from search results data
+  const buildRows = (results) => {
+    let dataRows = [];
+    if (results.length === 0) {
+      return dataRows;
+    }
+    results.forEach((result, index) => {
+      let row = {
+        id: result.id,
+      };
+      for (const fieldName in result.resource) {
+        if (typeof result.resource[fieldName] === 'string') {
+          row[fieldName] = result.resource[fieldName];
+        }
+      }
+      dataRows.push(row);
+    });
+    return dataRows;
+  };
+
+  const buildColumnName = (name) => {
+    name = name.split('_').join(' ');
+    name = name.charAt(0).toUpperCase() + name.slice(1);
+    return name;
+  };
+
+  const buildColumns = (results) => {
+    if (!results[0]?.resource) {
+      return [];
+    }
+    let dataColumns = [];
+    dataColumns.push({
+      name: 'id',
+      label: 'ID',
+      options: {
+        display: 'excluded',
+      },
+    });
+    // TODO: get columns settings from user to replace hard-coded array
+    for (const fieldName in results[0].resource) {
+      if (typeof results[0].resource[fieldName] === 'string') {
+        dataColumns.push({
+          name: fieldName,
+          label: buildColumnName(fieldName),
+          options: {
+            display: true,
+          },
+        });
+      }
+    }
+    return dataColumns;
+  };
+
+  const buildResultsTable = (results) => {
+    if (!results && results.length > 0) {
+      return;
+    }
+    return {
+      rows: buildRows(results),
+      columns: buildColumns(results),
+    };
+  };
+
+  const { rows, columns } = useMemo(
+    () => buildResultsTable(searchResults),
+    [searchResults]
+  );
+
+  const getResourceDataFromRowId = (id) => {
+    return searchResults.find((result) => result.id === id);
+  };
+
+  const getRowIdFromResourceData = (id) => {
+    for (let index = 0; index < rows.length; index++) {
+      if (rows[index].id === id) {
+        return index;
+      }
+    }
+  };
+
+  const onRowSelectionCallback = (selectedRow, allSelectedRows) => {
+    setSelectedRowsIds(
+      allSelectedRows.map((row) => {
+        return rows[row.dataIndex].id;
+      })
+    );
+  };
+
+  // Open resource flyout on row click (any cell)
+  const onCellClickCallback = (cellData, cellState) => {
+    if (!searchResults || searchResults.length === 0) {
+      return;
+    }
+    const resourceData = getResourceDataFromRowId(rows[cellState.dataIndex].id);
+    // Extract all values except for id to avoid displaying it to user
+    setResourceFlyoutData((({ id, ...rest }) => rest)(resourceData));
+    setIsResourceFlyoutOpen(true);
+  };
+
+  const sortBySelectedRows = () => {
+    // TODO add sorting by row selection
+    /*return data.sort((a, b) => {
+      const isSelectedA = selectedRowsIds.includes(a.data[0]);
+      const isSelectedB = selectedRowsIds.includes(b.data[0]);
+      if (isSelectedA && !isSelectedB) {
+        return -1;
+      } else if (!isSelectedA && isSelectedB) {
+        return 1;
+      } else {
+        // If both rows are either selected or not, maintain their order
+        return 0;
+      }
+    });*/
+  };
+
+  // Remove the delete rows button and display custom sort button
+  const CustomSelectToolbar = () => {
+    return (
+      <EuiFlexGroup style={{ marginLeft: '10px' }}>
+        <EuiFlexItem grow={false}>
+          <EuiButton onClick={() => sortBySelectedRows()}>
+            {t('results:table.displaySelectedRowsButton')}
+          </EuiButton>
+        </EuiFlexItem>
+      </EuiFlexGroup>
+    );
+  };
+
+  // Translations for mui-datatables component texts
+  const textLabels = {
+    body: {
+      noMatch: t('results:table.textLabels.body.noMatch'),
+      toolTip: t('results:table.textLabels.body.toolTip'),
+    },
+    pagination: {
+      next: t('results:table.textLabels.pagination.next'),
+      previous: t('results:table.textLabels.pagination.previous'),
+      rowsPerPage: t('results:table.textLabels.pagination.rowsPerPage'),
+      displayRows: t('results:table.textLabels.pagination.displayRows'),
+      jumpToPage: t('results:table.textLabels.pagination.jumpToPage'),
+    },
+    toolbar: {
+      search: t('results:table.textLabels.toolbar.search'),
+      viewColumns: t('results:table.textLabels.toolbar.viewColumns'),
+      filterTable: t('results:table.textLabels.toolbar.filterTable'),
+    },
+    filter: {
+      all: t('results:table.textLabels.filter.all'),
+      title: t('results:table.textLabels.filter.title'),
+      reset: t('results:table.textLabels.filter.reset'),
+    },
+    viewColumns: {
+      title: t('results:table.textLabels.viewColumns.title'),
+      titleAria: t('results:table.textLabels.viewColumns.titleAria'),
+    },
+    selectedRows: {
+      text: t('results:table.textLabels.selectedRows.text'),
+    },
+  };
+
+  const tableOptions = {
+    print: false,
+    download: false,
+    filter: true,
+    filterType: 'textField',
+    responsive: 'standard',
+    selectableRows: 'multiple',
+    selectableRowsOnClick: false,
+    rowsSelected: selectedRows,
+    rowsPerPage: 15,
+    rowsPerPageOptions: [15, 30, 50, 100],
+    jumpToPage: true,
+    searchPlaceholder: t('results:table.search'),
+    elevation: 0, // remove the boxShadow style
+    customToolbarSelect: () => <CustomSelectToolbar />,
+    selectToolbarPlacement: 'above',
+    onRowSelectionChange: onRowSelectionCallback,
+    onCellClick: onCellClickCallback,
+    textLabels,
+  };
+
+  return (
+    <ThemeProvider theme={getMuiTheme()}>
+      <MUIDataTable
+        title={<Trans i18nKey={'results:table.title'} components={{ searchQuery }} />}
+        data={rows}
+        columns={columns}
+        options={tableOptions}
+      />
+    </ThemeProvider>
+  );
+};
+
+export default ResultsTableMUI;
diff --git a/src/pages/search/AdvancedSearch/AdvancedSearch.js b/src/pages/search/AdvancedSearch/AdvancedSearch.js
new file mode 100644
index 0000000000000000000000000000000000000000..ce4b0156c34e546d3a337cfd54136e9967fe9841
--- /dev/null
+++ b/src/pages/search/AdvancedSearch/AdvancedSearch.js
@@ -0,0 +1,1522 @@
+import {
+  EuiButton,
+  EuiButtonEmpty,
+  EuiButtonIcon,
+  EuiComboBox,
+  EuiFieldText,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiForm,
+  EuiFormRow,
+  EuiGlobalToastList,
+  EuiHealth,
+  EuiIcon,
+  EuiModal,
+  EuiModalBody,
+  EuiModalFooter,
+  EuiModalHeader,
+  EuiModalHeaderTitle,
+  EuiOverlayMask,
+  EuiPanel,
+  EuiPopover,
+  EuiPopoverFooter,
+  EuiPopoverTitle,
+  EuiProgress,
+  EuiRadioGroup,
+  EuiSelect,
+  EuiSpacer,
+  EuiSwitch,
+  EuiTextArea,
+  EuiTextColor,
+  EuiTitle,
+} from '@elastic/eui';
+import React, { useEffect, useState } from 'react';
+import {
+  changeNameToLabel,
+  createAdvancedQueriesBySource,
+  getFieldsBySection,
+  getSections,
+  removeArrayElement,
+  SearchField,
+  updateArrayElement,
+  updateSearchFieldValues,
+} from '../../../Utils';
+import { getQueryCount, searchQuery } from '../../../actions/source';
+import { DateOptions, NumericOptions, Operators } from '../Data';
+import TextField from '@material-ui/core/TextField';
+import { addUserHistory, fetchUserHistory } from '../../../actions/user';
+import { useTranslation } from 'react-i18next';
+import styles from './styles';
+
+const updateSources = (
+  searchFields,
+  sources,
+  setSelectedSources,
+  setAvailableSources
+) => {
+  let updatedSources = [];
+  let availableSources = [];
+  let noPrivateField = true;
+  //search for policy fields to filter sources
+  searchFields.forEach((field) => {
+    if (field.isValidated) {
+      //if sources haven't already been filtered
+      if (noPrivateField && !updatedSources.length) {
+        availableSources = sources;
+      } else {
+        availableSources = updatedSources;
+      }
+      updatedSources = [];
+      field.sources.forEach((sourceId) => {
+        noPrivateField = false;
+        const source = availableSources.find((src) => src.id === sourceId);
+        if (source && !updatedSources.includes(source)) updatedSources.push(source);
+      });
+    }
+  });
+  setSelectedSources(updatedSources);
+  if (noPrivateField && !updatedSources.length) {
+    setAvailableSources(sources);
+  } else {
+    setAvailableSources(updatedSources);
+  }
+};
+
+const fieldValuesToString = (field) => {
+  let strValues = '';
+  switch (field.type) {
+    case 'Numeric':
+      field.values.forEach((element) => {
+        switch (element.option) {
+          case 'between':
+            strValues = `${strValues} ${element.value1} <= ${field.name} <= ${element.value2} or `;
+            break;
+          default:
+            strValues = `${strValues} ${field.name} ${element.option} ${element.value1} or `;
+        }
+      });
+      if (strValues.endsWith('or '))
+        strValues = strValues.substring(0, strValues.length - 4);
+      break;
+    case 'Date':
+      field.values.forEach((element) => {
+        switch (element.option) {
+          case 'between':
+            strValues = `${strValues} ${element.startDate} <= ${field.name} <= ${element.endDate} or `;
+            break;
+          default:
+            strValues = `${strValues} ${field.name} ${element.option} ${element.startDate} or `;
+        }
+      });
+      if (strValues.endsWith(' or '))
+        strValues = strValues.substring(0, strValues.length - 4);
+      break;
+    case 'List':
+      strValues = `${strValues} ${field.name} = `;
+      field.values.forEach((element) => {
+        strValues = `${strValues} ${element.label}, `;
+      });
+      if (strValues.endsWith(', '))
+        strValues = strValues.substring(0, strValues.length - 2);
+      break;
+    //type : text
+    default:
+      strValues = `${strValues} ${field.name} = ${field.values}`;
+  }
+  return strValues;
+};
+
+const addHistory = (
+  kcID,
+  search,
+  searchName,
+  searchFields,
+  searchDescription,
+  setUserHistory
+) => {
+  addUserHistory(
+    sessionStorage.getItem('user_id'),
+    search,
+    searchName,
+    searchFields,
+    searchDescription
+  ).then(() => {
+    fetchHistory(setUserHistory);
+  });
+};
+
+const fetchHistory = (setUserHistory) => {
+  fetchUserHistory(sessionStorage.getItem('user_id')).then((result) => {
+    if (result[0] && result[0].ui_structure) {
+      result.forEach((item) => {
+        item.ui_structure = JSON.parse(item.ui_structure);
+        item.label = `${item.name} - ${new Date(item.createdat).toLocaleString()}`;
+      });
+    }
+    setUserHistory(result);
+  });
+};
+
+const updateSearch = (setSearch, searchFields, selectedOperatorId, setSearchCount) => {
+  let searchText = '';
+  searchFields.forEach((field) => {
+    if (field.isValidated) {
+      searchText =
+        searchText +
+        `{${fieldValuesToString(field)} } ${Operators[selectedOperatorId].value.toUpperCase()} `;
+    }
+  });
+  if (searchText.endsWith(' AND ')) {
+    searchText = searchText.substring(0, searchText.length - 5);
+  } else if (searchText.endsWith(' OR ')) {
+    searchText = searchText.substring(0, searchText.length - 4);
+  }
+  setSearchCount();
+  setSearch(searchText);
+};
+
+const HistorySelect = ({
+  sources,
+  setAvailableSources,
+  setSelectedSources,
+  setSearch,
+  setSearchFields,
+  setSearchCount,
+  setFieldCount,
+  userHistory,
+  setUserHistory,
+}) => {
+  const { t } = useTranslation('search');
+  const [historySelectError, setHistorySelectError] = useState(undefined);
+  const [selectedSavedSearch, setSelectedSavedSearch] = useState(undefined);
+
+  useEffect(() => {
+    fetchHistory(setUserHistory);
+  }, [setUserHistory]);
+
+  const onHistoryChange = (selectedSavedSearch) => {
+    setHistorySelectError(undefined);
+    if (!!selectedSavedSearch[0].query) {
+      setSelectedSavedSearch(selectedSavedSearch);
+      setSearch(selectedSavedSearch[0].query);
+      setSearchCount();
+      setFieldCount([]);
+    }
+    if (!!selectedSavedSearch[0].ui_structure) {
+      updateSources(
+        selectedSavedSearch[0].ui_structure,
+        sources,
+        setSelectedSources,
+        setAvailableSources
+      );
+      setSearchFields(selectedSavedSearch[0].ui_structure);
+    }
+  };
+
+  const onHistorySearchChange = (value, hasMatchingOptions) => {
+    if (value.length === 0 || hasMatchingOptions) {
+      setHistorySelectError(undefined);
+    } else {
+      setHistorySelectError(t('search:advancedSearch.errorInvalidOption', { value }));
+    }
+  };
+
+  return (
+    <>
+      {userHistory && Object.keys(userHistory).length !== 0 && (
+        <EuiFormRow
+          error={historySelectError}
+          isInvalid={historySelectError !== undefined}
+        >
+          <EuiComboBox
+            placeholder={t('search:advancedSearch.searchHistory.placeholder')}
+            singleSelection={{ asPlainText: true }}
+            options={userHistory}
+            selectedOptions={selectedSavedSearch}
+            onChange={onHistoryChange}
+            onSearchChange={onHistorySearchChange}
+          />
+        </EuiFormRow>
+      )}
+    </>
+  );
+};
+
+const SearchBar = ({
+  search,
+  setSearch,
+  setSearchResults,
+  searchFields,
+  setSearchFields,
+  selectedSources,
+  setSelectedSources,
+  availableSources,
+  setAvailableSources,
+  standardFields,
+  sources,
+  setSelectedTabNumber,
+  searchCount,
+  setSearchCount,
+  setFieldCount,
+  createEditableQueryToast,
+}) => {
+  const { t } = useTranslation(['search', 'common']);
+  const [isLoading, setIsLoading] = useState(false);
+  const [userHistory, setUserHistory] = useState({});
+  const [isSaveSearchModalOpen, setIsSaveSearchModalOpen] = useState(false);
+  const [searchDescription, setSearchDescription] = useState('');
+  const [searchName, setSearchName] = useState('');
+  const [readOnlyQuery, setReadOnlyQuery] = useState(true);
+
+  const closeSaveSearchModal = () => {
+    setIsSaveSearchModalOpen(false);
+  };
+
+  const onClickAdvancedSearch = () => {
+    if (search.trim()) {
+      setIsLoading(true);
+      const queriesWithIndices = createAdvancedQueriesBySource(
+        standardFields,
+        search,
+        selectedSources,
+        availableSources
+      );
+      searchQuery(queriesWithIndices).then((result) => {
+        setSearchResults(result);
+        setSelectedTabNumber(1);
+        if (isLoading) {
+          setIsLoading(false);
+        }
+      });
+    }
+  };
+
+  const onClickCountResults = () => {
+    if (!!search) {
+      const queriesWithIndices = createAdvancedQueriesBySource(
+        standardFields,
+        search,
+        selectedSources,
+        availableSources
+      );
+      getQueryCount(queriesWithIndices).then((result) => {
+        if (result || result === 0) {
+          setSearchCount(result);
+        }
+      });
+    }
+  };
+
+  const onClickSaveSearch = () => {
+    if (!!searchName) {
+      addHistory(
+        sessionStorage.getItem('user_id'),
+        search,
+        searchName,
+        searchFields,
+        searchDescription,
+        setUserHistory
+      );
+      setSearchName('');
+      setSearchDescription('');
+      closeSaveSearchModal();
+    }
+  };
+
+  const SaveSearchModal = () => {
+    return (
+      <EuiOverlayMask>
+        <EuiModal onClose={closeSaveSearchModal} initialFocus="[name=searchName]">
+          <EuiModalHeader>
+            <EuiModalHeaderTitle>
+              {t('advancedSearch.searchHistory.saveSearch')}
+            </EuiModalHeaderTitle>
+          </EuiModalHeader>
+          <EuiModalBody>
+            <EuiForm>
+              <EuiFormRow label={t('advancedSearch.searchHistory.addSavedSearchName')}>
+                <EuiFieldText
+                  name="searchName"
+                  value={searchName}
+                  onChange={(e) => setSearchName(e.target.value)}
+                />
+              </EuiFormRow>
+              <EuiFormRow
+                label={t('advancedSearch.searchHistory.addSavedSearchDescription')}
+              >
+                <EuiTextArea
+                  value={searchDescription}
+                  onChange={(e) => setSearchDescription(e.target.value)}
+                  placeholder={t(
+                    'advancedSearch.searchHistory.addSavedSearchDescriptionPlaceholder'
+                  )}
+                  fullWidth
+                  compressed
+                />
+              </EuiFormRow>
+            </EuiForm>
+          </EuiModalBody>
+          <EuiModalFooter>
+            <EuiButtonEmpty
+              onClick={() => {
+                closeSaveSearchModal();
+              }}
+            >
+              {t('common:validationActions.cancel')}
+            </EuiButtonEmpty>
+            <EuiButton
+              onClick={() => {
+                onClickSaveSearch();
+              }}
+              fill
+            >
+              {t('common:validationActions.save')}
+            </EuiButton>
+          </EuiModalFooter>
+        </EuiModal>
+      </EuiOverlayMask>
+    );
+  };
+
+  return (
+    <>
+      {isSaveSearchModalOpen && <SaveSearchModal />}
+      <EuiFlexGroup>
+        <EuiFlexItem>
+          <EuiTextArea
+            readOnly={readOnlyQuery}
+            value={search}
+            onChange={(e) => setSearch(e.target.value)}
+            placeholder={t('search:advancedSearch.textQueryPlaceholder')}
+            fullWidth
+          />
+          {isLoading && (
+            <EuiFlexGroup>
+              <EuiFlexItem>
+                <EuiProgress postion="fixed" size="l" color="accent" />
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          )}
+        </EuiFlexItem>
+        <EuiFlexItem grow={false}>
+          <EuiButton
+            size="s"
+            fill
+            onClick={() => {
+              onClickAdvancedSearch();
+            }}
+          >
+            {t('search:sendSearchButton')}
+          </EuiButton>
+          <EuiSpacer size="s" />
+          {!isNaN(searchCount) && (
+            <>
+              <EuiTextColor
+                color="secondary"
+                style={{ display: 'flex', justifyContent: 'center' }}
+              >
+                {t('search:advancedSearch.resultsCount', { count: searchCount })}
+              </EuiTextColor>
+              <EuiSpacer size="s" />
+            </>
+          )}
+          <EuiButton
+            size="s"
+            onClick={() => {
+              onClickCountResults();
+            }}
+          >
+            {t('search:advancedSearch.countResultsButton')}
+          </EuiButton>
+          <EuiSpacer size="s" />
+          <EuiButton
+            size="s"
+            onClick={() => {
+              setIsSaveSearchModalOpen(true);
+            }}
+          >
+            {t('search:advancedSearch.searchHistory.saveSearch')}
+          </EuiButton>
+          <EuiSpacer size="s" />
+          <EuiSwitch
+            compressed
+            label={t('search:advancedSearch.editableSearchButton')}
+            checked={!readOnlyQuery}
+            onChange={() => {
+              setReadOnlyQuery(!readOnlyQuery);
+              if (readOnlyQuery) {
+                createEditableQueryToast();
+              }
+            }}
+          />
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiSpacer size="s" />
+      <EuiFlexGroup>
+        <EuiFlexItem>
+          <HistorySelect
+            sources={sources}
+            setAvailableSources={setAvailableSources}
+            setSelectedSources={setSelectedSources}
+            setSearch={setSearch}
+            setSearchFields={setSearchFields}
+            setSearchCount={setSearchCount}
+            setFieldCount={setFieldCount}
+            userHistory={userHistory}
+            setUserHistory={setUserHistory}
+          />
+        </EuiFlexItem>
+      </EuiFlexGroup>
+    </>
+  );
+};
+
+const PopoverSelect = ({ standardFields, searchFields, setSearchFields }) => {
+  const { t } = useTranslation('search');
+  const [isPopoverSelectOpen, setIsPopoverSelectOpen] = useState(false);
+  const [selectedField, setSelectedField] = useState([]);
+  const [selectedSection, setSelectedSection] = useState([]);
+
+  const handleAddField = () => {
+    if (!!selectedField[0]) {
+      const field = standardFields.find(
+        (item) =>
+          item.field_name.replace(/_|\./g, ' ') ===
+          selectedSection[0].label + ' ' + selectedField[0].label
+      );
+      switch (field.field_type) {
+        case 'Text':
+          setSearchFields([
+            ...searchFields,
+            new SearchField(field.field_name, field.field_type, '', false, field.sources),
+          ]);
+          break;
+        case 'List':
+          setSearchFields([
+            ...searchFields,
+            new SearchField(field.field_name, field.field_type, [], false, field.sources),
+          ]);
+          break;
+        default:
+          setSearchFields([
+            ...searchFields,
+            new SearchField(
+              field.field_name,
+              field.field_type,
+              [{}],
+              false,
+              field.sources
+            ),
+          ]);
+      }
+    }
+  };
+
+  const selectField = () => {
+    const renderOption = (option, searchValue, contentClassName) => {
+      const { label, color } = option;
+      return <EuiHealth color={color}>{label}</EuiHealth>;
+    };
+    if (selectedSection.length) {
+      return (
+        <>
+          <EuiComboBox
+            placeholder={t('search:advancedSearch.fields.addFieldPopover.title')}
+            singleSelection={{ asPlainText: true }}
+            options={getFieldsBySection(standardFields, selectedSection[0])}
+            selectedOptions={selectedField}
+            onChange={(selected) => setSelectedField(selected)}
+            isClearable={true}
+            renderOption={renderOption}
+          />
+          <EuiPopoverFooter>
+            <EuiButton
+              size="s"
+              onClick={() => {
+                handleAddField();
+                setIsPopoverSelectOpen(false);
+                setSelectedSection([]);
+                setSelectedField([]);
+              }}
+            >
+              {t('search:advancedSearch.fields.addFieldPopover.button')}
+            </EuiButton>
+          </EuiPopoverFooter>
+        </>
+      );
+    }
+  };
+
+  return (
+    <EuiPopover
+      panelPaddingSize="s"
+      button={
+        <EuiButton
+          iconType="listAdd"
+          iconSide="left"
+          onClick={() => setIsPopoverSelectOpen(!isPopoverSelectOpen)}
+        >
+          {t('search:advancedSearch.fields.addFieldPopover.openPopoverButton')}
+        </EuiButton>
+      }
+      isOpen={isPopoverSelectOpen}
+      closePopover={() => setIsPopoverSelectOpen(false)}
+    >
+      <div style={{ width: 'intrinsic', minWidth: 240 }}>
+        <EuiPopoverTitle>
+          {t('search:advancedSearch.fields.addFieldPopover.title')}
+        </EuiPopoverTitle>
+        <EuiComboBox
+          placeholder={t('search:advancedSearch.fields.addFieldPopover.selectSection')}
+          singleSelection={{ asPlainText: true }}
+          options={getSections(standardFields)}
+          selectedOptions={selectedSection}
+          onChange={(selected) => {
+            setSelectedSection(selected);
+            setSelectedField([]);
+          }}
+          isClearable={false}
+        />
+      </div>
+      {selectField()}
+    </EuiPopover>
+  );
+};
+
+const PopoverValueContent = ({
+  index,
+  standardFields,
+  searchFields,
+  setSearchFields,
+  setSearch,
+  setSearchCount,
+  fieldCount,
+  setFieldCount,
+  isPopoverValueOpen,
+  setIsPopoverValueOpen,
+  selectedOperatorId,
+  createPolicyToast,
+  selectedSources,
+  setSelectedSources,
+  availableSources,
+  setAvailableSources,
+}) => {
+  const { t } = useTranslation(['search', 'common']);
+  const datePickerStyles = styles();
+  const [valueError, setValueError] = useState(undefined);
+
+  const onValueSearchChange = (value, hasMatchingOptions) => {
+    if (value.length === 0 || hasMatchingOptions) {
+      setValueError(undefined);
+    } else {
+      setValueError(t('search:advancedSearch.errorInvalidOption', { value }));
+    }
+  };
+
+  const validateFieldValues = () => {
+    let fieldValues;
+    if (Array.isArray(searchFields[index].values)) {
+      fieldValues = [];
+      searchFields[index].values.forEach((value) => {
+        if (!!value) {
+          fieldValues.push(value);
+        }
+      });
+    } else {
+      fieldValues = searchFields[index].values;
+    }
+
+    const updatedSearchFields = updateArrayElement(
+      searchFields,
+      index,
+      new SearchField(
+        searchFields[index].name,
+        searchFields[index].type,
+        fieldValues,
+        true,
+        searchFields[index].sources
+      )
+    );
+    setSearchFields(updatedSearchFields);
+    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
+    setFieldCount(updateArrayElement(fieldCount, index));
+    if (searchFields[index].sources.length) {
+      const filteredSources = [];
+      searchFields[index].sources.forEach((sourceId) => {
+        let source;
+        if (selectedSources.length) {
+          source = selectedSources.find((src) => src.id === sourceId);
+        } else {
+          source = availableSources.find((src) => src.id === sourceId);
+        }
+        if (source) {
+          filteredSources.push(source);
+        }
+      });
+      setAvailableSources(filteredSources);
+      setSelectedSources(filteredSources);
+      createPolicyToast();
+    }
+  };
+
+  const invalidateFieldValues = () => {
+    const updatedSearchFields = updateArrayElement(
+      searchFields,
+      index,
+      new SearchField(
+        searchFields[index].name,
+        searchFields[index].type,
+        searchFields[index].values,
+        false,
+        searchFields[index].sources
+      )
+    );
+    setSearchFields(updatedSearchFields);
+    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
+  };
+
+  const ValuePopoverFooter = (i) => {
+    if (i === searchFields[index].values.length - 1) {
+      return (
+        <EuiPopoverFooter>
+          <EuiButton
+            size="s"
+            onClick={() => {
+              setSearchFields(
+                updateArrayElement(
+                  searchFields,
+                  index,
+                  new SearchField(
+                    searchFields[index].name,
+                    searchFields[index].type,
+                    [...searchFields[index].values, {}],
+                    false,
+                    searchFields[index].sources
+                  )
+                )
+              );
+            }}
+          >
+            {t('search:advancedSearch.fields.fieldContentPopover.addValue')}
+          </EuiButton>
+          <EuiButton
+            size="s"
+            style={{ float: 'right' }}
+            onClick={() => {
+              validateFieldValues();
+              setIsPopoverValueOpen(updateArrayElement(isPopoverValueOpen, index, false));
+            }}
+          >
+            {t('common:validationActions.validate')}
+          </EuiButton>
+        </EuiPopoverFooter>
+      );
+    }
+  };
+
+  const addFieldValue = (i, selectedOption) => {
+    setSearchFields(
+      updateSearchFieldValues(
+        searchFields,
+        index,
+        updateArrayElement(searchFields[index].values, i, { option: selectedOption })
+      )
+    );
+  };
+
+  const getListFieldValues = () => {
+    const listFieldValues = [];
+    standardFields
+      .find((item) => item.field_name === searchFields[index].name)
+      .values.split(', ')
+      .sort()
+      .forEach((element) => {
+        listFieldValues.push({ label: element });
+      });
+    return listFieldValues;
+  };
+
+  switch (searchFields[index].type) {
+    case 'Text':
+      return (
+        <>
+          <EuiFlexItem>
+            <EuiFieldText
+              placeholder={t(
+                'search:advancedSearch.fields.fieldContentPopover.inputTextValue'
+              )}
+              value={searchFields[index].values}
+              onChange={(e) =>
+                setSearchFields(
+                  updateSearchFieldValues(searchFields, index, e.target.value)
+                )
+              }
+            />
+          </EuiFlexItem>
+          <EuiPopoverFooter>
+            <EuiButton
+              size="s"
+              style={{ float: 'right' }}
+              onClick={() => {
+                validateFieldValues();
+                setIsPopoverValueOpen(
+                  updateArrayElement(isPopoverValueOpen, index, false)
+                );
+              }}
+            >
+              {t('common:validationActions.validate')}
+            </EuiButton>
+          </EuiPopoverFooter>
+        </>
+      );
+    case 'List':
+      return (
+        <>
+          <EuiFormRow error={valueError} isInvalid={valueError !== undefined}>
+            <EuiComboBox
+              placeholder={t(
+                'search:advancedSearch.fields.fieldContentPopover.selectValues'
+              )}
+              options={getListFieldValues()}
+              selectedOptions={searchFields[index].values}
+              onChange={(selectedOptions) => {
+                setValueError(undefined);
+                setSearchFields(
+                  updateSearchFieldValues(searchFields, index, selectedOptions)
+                );
+              }}
+              onSearchChange={onValueSearchChange}
+            />
+          </EuiFormRow>
+          <EuiPopoverFooter>
+            <EuiButton
+              size="s"
+              style={{ float: 'right' }}
+              onClick={() => {
+                validateFieldValues();
+                setIsPopoverValueOpen(
+                  updateArrayElement(isPopoverValueOpen, index, false)
+                );
+              }}
+            >
+              {t('common:validationActions.validate')}
+            </EuiButton>
+          </EuiPopoverFooter>
+        </>
+      );
+    case 'Numeric':
+      const NumericValues = (i) => {
+        if (!!searchFields[index].values[i].option) {
+          switch (searchFields[index].values[i].option) {
+            case 'between':
+              return (
+                <>
+                  <EuiFlexItem>
+                    <EuiFieldText
+                      placeholder={t(
+                        'search:advancedSearch.fields.fieldContentPopover.firstValue'
+                      )}
+                      value={searchFields[index].values[i].value1}
+                      onChange={(e) => {
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              value1: e.target.value,
+                              value2: searchFields[index].values[i].value2,
+                            })
+                          )
+                        );
+                      }}
+                    />
+                  </EuiFlexItem>
+                  <EuiFlexItem>
+                    <EuiFieldText
+                      placeholder={t(
+                        'search:advancedSearch.fields.fieldContentPopover.secondValue'
+                      )}
+                      value={searchFields[index].values[i].value2}
+                      onChange={(e) =>
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              value1: searchFields[index].values[i].value1,
+                              value2: e.target.value,
+                            })
+                          )
+                        )
+                      }
+                    />
+                  </EuiFlexItem>
+                  {ValuePopoverFooter(i)}
+                </>
+              );
+
+            default:
+              return (
+                <>
+                  <EuiFlexItem>
+                    <EuiFieldText
+                      placeholder={t(
+                        'search:advancedSearch.fields.fieldContentPopover.inputTextValue'
+                      )}
+                      value={searchFields[index].values[i].value1}
+                      onChange={(e) => {
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              value1: e.target.value,
+                              value2: searchFields[index].values[i].value2,
+                            })
+                          )
+                        );
+                      }}
+                    />
+                  </EuiFlexItem>
+                  {ValuePopoverFooter(i)}
+                </>
+              );
+          }
+        }
+      };
+
+      return (
+        <>
+          {searchFields[index].values.map((value, i) => (
+            <div key={i}>
+              <EuiSelect
+                hasNoInitialSelection
+                id="Select an option"
+                options={NumericOptions}
+                value={searchFields[index].values[i].option}
+                onChange={(e) => {
+                  addFieldValue(i, e.target.value);
+                  invalidateFieldValues();
+                }}
+              />
+              {NumericValues(i)}
+            </div>
+          ))}
+        </>
+      );
+    case 'Date':
+      const SelectDates = (i) => {
+        if (!!searchFields[index].values[i].option) {
+          switch (searchFields[index].values[i].option) {
+            case 'between':
+              return (
+                <>
+                  <form className={datePickerStyles.container} noValidate>
+                    <TextField
+                      label={t(
+                        'search:advancedSearch.fields.fieldContentPopover.betweenDate'
+                      )}
+                      type="date"
+                      defaultValue={
+                        !!searchFields[index].values[i].startDate
+                          ? searchFields[index].values[i].startDate
+                          : Date.now()
+                      }
+                      className={datePickerStyles.textField}
+                      InputLabelProps={{
+                        shrink: true,
+                      }}
+                      onChange={(e) =>
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              startDate: e.target.value,
+                              endDate: searchFields[index].values[i].endDate,
+                            })
+                          )
+                        )
+                      }
+                    />
+                  </form>
+                  <form className={datePickerStyles.container} noValidate>
+                    <TextField
+                      label={t(
+                        'search:advancedSearch.fields.fieldContentPopover.andDate'
+                      )}
+                      type="date"
+                      defaultValue={
+                        !!searchFields[index].values[i].endDate
+                          ? searchFields[index].values[i].endDate
+                          : Date.now()
+                      }
+                      className={datePickerStyles.textField}
+                      InputLabelProps={{
+                        shrink: true,
+                      }}
+                      onChange={(e) =>
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              startDate: searchFields[index].values[i].startDate,
+                              endDate: e.target.value,
+                            })
+                          )
+                        )
+                      }
+                    />
+                  </form>
+                  {ValuePopoverFooter(i)}
+                </>
+              );
+
+            default:
+              return (
+                <>
+                  <form className={datePickerStyles.container} noValidate>
+                    <TextField
+                      type="date"
+                      defaultValue={
+                        !!searchFields[index].values[i].startDate
+                          ? searchFields[index].values[i].startDate
+                          : Date.now()
+                      }
+                      className={datePickerStyles.textField}
+                      InputLabelProps={{
+                        shrink: true,
+                      }}
+                      onChange={(e) =>
+                        setSearchFields(
+                          updateSearchFieldValues(
+                            searchFields,
+                            index,
+                            updateArrayElement(searchFields[index].values, i, {
+                              option: searchFields[index].values[i].option,
+                              startDate: e.target.value,
+                              endDate: Date.now(),
+                            })
+                          )
+                        )
+                      }
+                    />
+                  </form>
+                  {ValuePopoverFooter(i)}
+                </>
+              );
+          }
+        }
+      };
+
+      return (
+        <>
+          {searchFields[index].values.map((value, i) => (
+            <div key={i}>
+              <EuiSelect
+                hasNoInitialSelection
+                id="Select an option"
+                options={DateOptions}
+                value={searchFields[index].values[i].option}
+                onChange={(e) => {
+                  addFieldValue(i, e.target.value);
+                  invalidateFieldValues();
+                }}
+              />
+              {SelectDates(i)}
+            </div>
+          ))}
+        </>
+      );
+    default:
+  }
+};
+
+const PopoverValueButton = ({
+  index,
+  standardFields,
+  searchFields,
+  setSearchFields,
+  setSearch,
+  setSearchCount,
+  fieldCount,
+  setFieldCount,
+  selectedOperatorId,
+  createPolicyToast,
+  selectedSources,
+  setSelectedSources,
+  availableSources,
+  setAvailableSources,
+}) => {
+  const { t } = useTranslation('search');
+  const [isPopoverValueOpen, setIsPopoverValueOpen] = useState([false]);
+
+  return (
+    <EuiPopover
+      panelPaddingSize="s"
+      button={
+        <EuiButtonIcon
+          size="s"
+          color="primary"
+          onClick={() =>
+            setIsPopoverValueOpen(
+              updateArrayElement(isPopoverValueOpen, index, !isPopoverValueOpen[index])
+            )
+          }
+          iconType="documentEdit"
+          title={t('search:advancedSearch.fields.fieldContentPopover.addFieldValues')}
+          aria-label={t(
+            'search:advancedSearch.fields.fieldContentPopover.addFieldValues'
+          )}
+        />
+      }
+      isOpen={isPopoverValueOpen[index]}
+      closePopover={() =>
+        setIsPopoverValueOpen(updateArrayElement(isPopoverValueOpen, index, false))
+      }
+    >
+      <div style={{ width: 240 }}>
+        <PopoverValueContent
+          index={index}
+          standardFields={standardFields}
+          searchFields={searchFields}
+          setSearchFields={setSearchFields}
+          setSearch={setSearch}
+          setSearchCount={setSearchCount}
+          fieldCount={fieldCount}
+          setFieldCount={setFieldCount}
+          isPopoverValueOpen={isPopoverValueOpen}
+          setIsPopoverValueOpen={setIsPopoverValueOpen}
+          selectedOperatorId={selectedOperatorId}
+          createPolicyToast={createPolicyToast}
+          selectedSources={selectedSources}
+          setSelectedSources={setSelectedSources}
+          availableSources={availableSources}
+          setAvailableSources={setAvailableSources}
+        />
+      </div>
+    </EuiPopover>
+  );
+};
+
+const FieldsPanel = ({
+  standardFields,
+  searchFields,
+  setSearchFields,
+  setSearch,
+  setSearchCount,
+  selectedOperatorId,
+  setSelectedOperatorId,
+  fieldCount,
+  setFieldCount,
+  availableSources,
+  setAvailableSources,
+  selectedSources,
+  setSelectedSources,
+  sources,
+  createPolicyToast,
+}) => {
+  const { t } = useTranslation('search');
+
+  const countFieldValues = (field, index) => {
+    const fieldStr = `{${fieldValuesToString(field)}}`;
+    const queriesWithIndices = createAdvancedQueriesBySource(
+      standardFields,
+      fieldStr,
+      selectedSources,
+      availableSources
+    );
+    getQueryCount(queriesWithIndices).then((result) => {
+      if (result || result === 0)
+        setFieldCount(updateArrayElement(fieldCount, index, result));
+    });
+  };
+
+  const handleRemoveField = (index) => {
+    const updatedSearchFields = removeArrayElement(searchFields, index);
+    setSearchFields(updatedSearchFields);
+    updateSources(updatedSearchFields, sources, setSelectedSources, setAvailableSources);
+    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
+  };
+
+  const handleClearValues = (index) => {
+    let updatedSearchFields;
+    switch (searchFields[index].type) {
+      case 'Text':
+        updatedSearchFields = updateArrayElement(
+          searchFields,
+          index,
+          new SearchField(
+            searchFields[index].name,
+            searchFields[index].type,
+            '',
+            false,
+            searchFields[index].sources
+          )
+        );
+        break;
+      case 'List':
+        updatedSearchFields = updateArrayElement(
+          searchFields,
+          index,
+          new SearchField(
+            searchFields[index].name,
+            searchFields[index].type,
+            [],
+            false,
+            searchFields[index].sources
+          )
+        );
+        break;
+      default:
+        updatedSearchFields = updateArrayElement(
+          searchFields,
+          index,
+          new SearchField(
+            searchFields[index].name,
+            searchFields[index].type,
+            [{}],
+            false,
+            searchFields[index].sources
+          )
+        );
+    }
+    setSearchFields(updatedSearchFields);
+    updateSources(updatedSearchFields, sources, setSelectedSources, setAvailableSources);
+    setFieldCount(updateArrayElement(fieldCount, index));
+    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
+  };
+
+  if (standardFields === []) {
+    return <h2>{t('search:advancedSearch.fields.loadingFields')}</h2>;
+  }
+
+  return (
+    <>
+      <EuiTitle size="xs">
+        <h2>{t('search:advancedSearch.fields.title')}</h2>
+      </EuiTitle>
+      <EuiPanel paddingSize="m">
+        <EuiFlexGroup direction="column">
+          {searchFields.map((field, index) => (
+            <EuiPanel key={'field' + index} paddingSize="s">
+              <EuiFlexItem grow={false}>
+                <EuiFlexGroup direction="row" alignItems="center">
+                  <EuiFlexItem grow={false}>
+                    <EuiButtonIcon
+                      size="s"
+                      color="danger"
+                      onClick={() => handleRemoveField(index)}
+                      iconType="indexClose"
+                      title={t('search:advancedSearch.fields.removeFieldButton')}
+                      aria-label={t('search:advancedSearch.fields.removeFieldButton')}
+                    />
+                  </EuiFlexItem>
+                  <EuiFlexItem>
+                    {field.isValidated ? (
+                      <>
+                        {field.sources.length ? (
+                          <EuiHealth color="danger">
+                            {fieldValuesToString(field).replace(/_|\./g, ' ')}
+                          </EuiHealth>
+                        ) : (
+                          <EuiHealth color="primary">
+                            {fieldValuesToString(field).replace(/_|\./g, ' ')}
+                          </EuiHealth>
+                        )}
+                      </>
+                    ) : (
+                      <>
+                        {field.sources.length ? (
+                          <EuiHealth color="danger">
+                            {field.name.replace(/_|\./g, ' ')}
+                          </EuiHealth>
+                        ) : (
+                          <EuiHealth color="primary">
+                            {field.name.replace(/_|\./g, ' ')}
+                          </EuiHealth>
+                        )}
+                      </>
+                    )}
+                  </EuiFlexItem>
+                  <EuiFlexItem grow={false}>
+                    {!isNaN(fieldCount[index]) && (
+                      <EuiTextColor color="secondary">
+                        {t('search:advancedSearch.resultsCount', {
+                          count: fieldCount[index],
+                        })}
+                      </EuiTextColor>
+                    )}
+                  </EuiFlexItem>
+                  <EuiFlexItem grow={false}>
+                    {field.isValidated && (
+                      <EuiButtonIcon
+                        size="s"
+                        onClick={() => countFieldValues(field, index)}
+                        iconType="number"
+                        title={t('search:advancedSearch.countResultsButton')}
+                        aria-label={t('search:advancedSearch.countResultsButton')}
+                      />
+                    )}
+                  </EuiFlexItem>
+                  <EuiFlexItem grow={false}>
+                    {field.isValidated && (
+                      <EuiButtonIcon
+                        size="s"
+                        color="danger"
+                        onClick={() => handleClearValues(index)}
+                        iconType="trash"
+                        title={t('search:advancedSearch.fields.clearValues')}
+                        aria-label={t('search:advancedSearch.fields.clearValues')}
+                      />
+                    )}
+                  </EuiFlexItem>
+                  <EuiFlexItem grow={false}>
+                    <PopoverValueButton
+                      index={index}
+                      standardFields={standardFields}
+                      searchFields={searchFields}
+                      setSearchFields={setSearchFields}
+                      setSearch={setSearch}
+                      setSearchCount={setSearchCount}
+                      fieldCount={fieldCount}
+                      setFieldCount={setFieldCount}
+                      selectedOperatorId={selectedOperatorId}
+                      createPolicyToast={createPolicyToast}
+                      selectedSources={selectedSources}
+                      setSelectedSources={setSelectedSources}
+                      availableSources={availableSources}
+                      setAvailableSources={setAvailableSources}
+                    />
+                  </EuiFlexItem>
+                </EuiFlexGroup>
+              </EuiFlexItem>
+            </EuiPanel>
+          ))}
+        </EuiFlexGroup>
+        <EuiSpacer size="l" />
+        <PopoverSelect
+          standardFields={standardFields}
+          searchFields={searchFields}
+          setSearchFields={setSearchFields}
+        />
+      </EuiPanel>
+      <EuiSpacer size="s" />
+      <EuiRadioGroup
+        options={Operators.map((operator) => {
+          return { ...operator, label: t(operator.label) };
+        })}
+        idSelected={selectedOperatorId}
+        onChange={(id) => {
+          setSelectedOperatorId(id);
+          updateSearch(setSearch, searchFields, id, setSearchCount);
+        }}
+        name="operators group"
+        legend={{
+          children: <span>{t('search:advancedSearch.searchOptions.title')}</span>,
+        }}
+      />
+    </>
+  );
+};
+
+const SourceSelect = ({ availableSources, selectedSources, setSelectedSources }) => {
+  const { t } = useTranslation('search');
+  const [sourceSelectError, setSourceSelectError] = useState(undefined);
+
+  if (Object.keys(availableSources).length === 0) {
+    return (
+      <p>
+        <EuiIcon type="alert" color="danger" />
+      </p>
+    );
+  }
+  availableSources.forEach((source) => {
+    if (source.name) {
+      source = changeNameToLabel(source);
+    }
+  });
+
+  const onSourceChange = (selectedOptions) => {
+    setSourceSelectError(undefined);
+    setSelectedSources(selectedOptions);
+  };
+
+  const onSourceSearchChange = (value, hasMatchingOptions) => {
+    if (value.length === 0 || hasMatchingOptions) {
+      setSourceSelectError(undefined);
+    } else {
+      setSourceSelectError(
+        t('search:advancedSearch.errorInvalidOption', { value: value })
+      );
+    }
+  };
+
+  return (
+    <>
+      <EuiTitle size="xs">
+        <h2>{t('search:advancedSearch.partnerSources.title')}</h2>
+      </EuiTitle>
+      <EuiSpacer size="s" />
+      <EuiFlexItem>
+        <EuiFormRow error={sourceSelectError} isInvalid={sourceSelectError !== undefined}>
+          <EuiComboBox
+            placeholder={t('search:advancedSearch.partnerSources.allSourcesSelected')}
+            options={availableSources}
+            selectedOptions={selectedSources}
+            onChange={onSourceChange}
+            onSearchChange={onSourceSearchChange}
+          />
+        </EuiFormRow>
+      </EuiFlexItem>
+    </>
+  );
+};
+
+const AdvancedSearch = ({
+  search,
+  setSearch,
+  setSearchResults,
+  selectedSources,
+  setSelectedSources,
+  availableSources,
+  setAvailableSources,
+  standardFields,
+  setStandardFields,
+  sources,
+  setSelectedTabNumber,
+  setIsAdvancedSearch,
+  isAdvancedSearch,
+}) => {
+  const { t } = useTranslation('search');
+  const [notificationToasts, setNotificationToasts] = useState([]);
+  const [selectedOperatorId, setSelectedOperatorId] = useState('0');
+  const [searchFields, setSearchFields] = useState([]);
+  const [fieldCount, setFieldCount] = useState([]);
+  const [searchCount, setSearchCount] = useState();
+
+  const createPolicyToast = () => {
+    const toast = {
+      title: t('search:advancedSearch.policyToast.title'),
+      color: 'warning',
+      iconType: 'alert',
+      toastLifeTimeMs: 15000,
+      text: (
+        <>
+          <p>{t('search:advancedSearch.policyToast.content.0')}</p>
+          <p>{t('search:advancedSearch.policyToast.content.1')}</p>
+          <p>{t('search:advancedSearch.policyToast.content.2')}</p>
+        </>
+      ),
+    };
+    setNotificationToasts(notificationToasts.concat(toast));
+  };
+
+  const createEditableQueryToast = () => {
+    const toast = {
+      title: t('search:advancedSearch.policyToast.title'),
+      color: 'warning',
+      iconType: 'alert',
+      toastLifeTimeMs: 15000,
+      text: (
+        <>
+          <p>{t('search:advancedSearch.editableQueryToast.content.part1')}</p>
+          <ul>
+            <li>{t('search:advancedSearch.editableQueryToast.content.part2')}</li>
+            <li>{t('search:advancedSearch.editableQueryToast.content.part3')}</li>
+            <li>{t('search:advancedSearch.editableQueryToast.content.part4')}</li>
+          </ul>
+        </>
+      ),
+    };
+    setNotificationToasts(notificationToasts.concat(toast));
+  };
+
+  const removeToast = (removedToast) => {
+    setNotificationToasts(
+      notificationToasts.filter((toast) => toast.id !== removedToast.id)
+    );
+  };
+
+  return (
+    <>
+      <EuiFlexGroup>
+        <EuiFlexItem grow={false}>
+          <EuiButtonEmpty
+            onClick={() => {
+              setIsAdvancedSearch(!isAdvancedSearch);
+            }}
+          >
+            {t('search:advancedSearch.switchSearchMode')}
+          </EuiButtonEmpty>
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiFlexGroup>
+        <EuiFlexItem>
+          <EuiSpacer size="s" />
+          <SearchBar
+            search={search}
+            setSearch={setSearch}
+            setSearchResults={setSearchResults}
+            searchFields={searchFields}
+            setSearchFields={setSearchFields}
+            selectedSources={selectedSources}
+            setSelectedSources={setSelectedSources}
+            availableSources={availableSources}
+            setAvailableSources={setAvailableSources}
+            standardFields={standardFields}
+            sources={sources}
+            setSelectedTabNumber={setSelectedTabNumber}
+            searchCount={searchCount}
+            setSearchCount={setSearchCount}
+            setFieldCount={setFieldCount}
+            createEditableQueryToast={createEditableQueryToast}
+          />
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiFlexGroup>
+        <EuiFlexItem>
+          <EuiSpacer size="s" />
+          <FieldsPanel
+            standardFields={standardFields}
+            setStandardFields={setStandardFields}
+            searchFields={searchFields}
+            setSearchFields={setSearchFields}
+            search={search}
+            setSearch={setSearch}
+            setSearchCount={setSearchCount}
+            selectedOperatorId={selectedOperatorId}
+            setSelectedOperatorId={setSelectedOperatorId}
+            fieldCount={fieldCount}
+            setFieldCount={setFieldCount}
+            availableSources={availableSources}
+            setAvailableSources={setAvailableSources}
+            selectedSources={selectedSources}
+            setSelectedSources={setSelectedSources}
+            sources={sources}
+            createPolicyToast={createPolicyToast}
+          />
+          <EuiSpacer size="s" />
+          <SourceSelect
+            availableSources={availableSources}
+            selectedSources={selectedSources}
+            setSelectedSources={setSelectedSources}
+          />
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiGlobalToastList
+        toasts={notificationToasts}
+        dismissToast={removeToast}
+        toastLifeTimeMs={2500}
+      />
+    </>
+  );
+};
+
+export default AdvancedSearch;
diff --git a/src/pages/search/AdvancedSearch/styles.js b/src/pages/search/AdvancedSearch/styles.js
new file mode 100644
index 0000000000000000000000000000000000000000..66022dc748fea12084c48d6a7c6fc471b22dce14
--- /dev/null
+++ b/src/pages/search/AdvancedSearch/styles.js
@@ -0,0 +1,15 @@
+import { makeStyles } from '@material-ui/core/styles';
+
+const style = makeStyles((theme) => ({
+  container: {
+    display: 'flex',
+    flexWrap: 'wrap',
+  },
+  textField: {
+    marginLeft: theme.spacing(1),
+    marginRight: theme.spacing(1),
+    width: 240,
+  },
+}));
+
+export default style;
diff --git a/src/pages/search/BasicSearch/BasicSearch.js b/src/pages/search/BasicSearch/BasicSearch.js
new file mode 100644
index 0000000000000000000000000000000000000000..397091ade583db73a62cd91f5e1353964949b301
--- /dev/null
+++ b/src/pages/search/BasicSearch/BasicSearch.js
@@ -0,0 +1,93 @@
+import React, { useState } from 'react';
+import {
+  EuiButton,
+  EuiButtonEmpty,
+  EuiFieldSearch,
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiProgress,
+  EuiSpacer,
+} from '@elastic/eui';
+import { createBasicQueriesBySource } from '../../../Utils';
+import { searchQuery } from '../../../actions/source';
+import { useTranslation } from 'react-i18next';
+
+const BasicSearch = ({
+  standardFields,
+  availableSources,
+  selectedSources,
+  basicSearch,
+  setBasicSearch,
+  setIsAdvancedSearch,
+  isAdvancedSearch,
+  setSearchResults,
+  setSelectedTabNumber,
+}) => {
+  const { t } = useTranslation('search');
+  const [isLoading, setIsLoading] = useState(false);
+
+  const onFormSubmit = () => {
+    setIsLoading(true);
+    const queriesWithIndices = createBasicQueriesBySource(
+      standardFields,
+      basicSearch,
+      selectedSources,
+      availableSources
+    );
+    searchQuery(queriesWithIndices).then((result) => {
+      setSearchResults(result);
+      if (isLoading) {
+        setIsLoading(false);
+      }
+      setSelectedTabNumber(1);
+    });
+  };
+
+  return (
+    <>
+      <EuiFlexGroup>
+        <EuiFlexItem grow={false}>
+          <EuiButtonEmpty
+            onClick={() => {
+              setIsAdvancedSearch(!isAdvancedSearch);
+            }}
+          >
+            {t('basicSearch.switchSearchMode')}
+          </EuiButtonEmpty>
+        </EuiFlexItem>
+      </EuiFlexGroup>
+      <EuiFlexGroup>
+        <EuiFlexItem>
+          <EuiSpacer size="s" />
+          <form onSubmit={() => onFormSubmit()}>
+            <EuiFlexGroup>
+              <EuiFlexItem>
+                <EuiFieldSearch
+                  value={basicSearch}
+                  onChange={(e) => setBasicSearch(e.target.value)}
+                  placeholder={t('basicSearch.searchInputPlaceholder')}
+                  autoFocus={true}
+                  fullWidth
+                />
+                {isLoading && (
+                  <EuiFlexGroup>
+                    <EuiFlexItem>
+                      <EuiProgress postion="fixed" size="l" color="accent" />
+                    </EuiFlexItem>
+                  </EuiFlexGroup>
+                )}
+              </EuiFlexItem>
+              <EuiFlexItem grow={false}>
+                <EuiButton type="submit" fill isDisabled={isAdvancedSearch}>
+                  {t('sendSearchButton')}
+                </EuiButton>
+              </EuiFlexItem>
+            </EuiFlexGroup>
+          </form>
+        </EuiFlexItem>
+      </EuiFlexGroup>
+    </>
+  );
+};
+
+export default BasicSearch;
diff --git a/src/pages/search/Data.js b/src/pages/search/Data.js
index c6577648ea4029f5243b834d71fac2563982fbbb..d0a399a60e2e9dbe10a10c075a207501b35c6130 100644
--- a/src/pages/search/Data.js
+++ b/src/pages/search/Data.js
@@ -2,12 +2,12 @@ export const Operators = [
   {
     id: '0',
     value: 'And',
-    label: 'Match all criterias',
+    label: 'search:advancedSearch.searchOptions.matchAll',
   },
   {
     id: '1',
     value: 'Or',
-    label: 'Match at least one criteria',
+    label: 'search:advancedSearch.searchOptions.matchAtLeastOne',
   },
 ];
 
diff --git a/src/pages/search/Search.js b/src/pages/search/Search.js
index 4587f18b482ccf511ed4a59d83caf2bcf3a13cb9..5f92324661616fc050f13403cf4942cc00f3febb 100644
--- a/src/pages/search/Search.js
+++ b/src/pages/search/Search.js
@@ -1,1551 +1,35 @@
 import React, { useState, useEffect } from 'react';
 import {
-  EuiProgress,
-  EuiRadioGroup,
-  EuiFieldText,
-  EuiPanel,
-  EuiPopover,
-  EuiPopoverTitle,
-  EuiPopoverFooter,
   EuiTabbedContent,
-  EuiFormRow,
-  EuiComboBox,
   EuiPageContentBody,
-  EuiForm,
-  EuiTextArea,
   EuiFlexGroup,
   EuiFlexItem,
-  EuiFieldSearch,
-  EuiButton,
-  EuiButtonEmpty,
-  EuiSwitch,
-  EuiButtonIcon,
-  EuiIcon,
   EuiSpacer,
-  EuiPageContent,
-  EuiPageContentHeader,
-  EuiTitle,
-  EuiPageContentHeaderSection,
-  EuiTextColor,
-  EuiOverlayMask,
-  EuiModal,
-  EuiModalHeader,
-  EuiModalHeaderTitle,
-  EuiModalBody,
-  EuiModalFooter,
-  EuiSelect,
-  EuiGlobalToastList,
-  EuiHealth,
 } from '@elastic/eui';
-import { makeStyles } from '@material-ui/core/styles';
-import TextField from '@material-ui/core/TextField';
-import { Operators, NumericOptions, DateOptions } from './Data';
 import Results from '../results/Results';
 import SearchMap from '../maps/SearchMap';
-import {
-  createBasicQueriesBySource,
-  changeNameToLabel,
-  SearchField,
-  removeNullFields,
-  getSections,
-  getFieldsBySection,
-  updateArrayElement,
-  removeArrayElement,
-  updateSearchFieldValues,
-  createAdvancedQueriesBySource,
-} from '../../Utils.js';
+import { removeNullFields } from '../../Utils.js';
 import {
   fetchPublicFields,
   fetchUserPolicyFields,
   fetchSources,
-  searchQuery,
-  getQueryCount,
 } from '../../actions/source';
-import { addUserHistory, fetchUserHistory } from '../../actions/user';
-
-const useStyles = makeStyles((theme) => ({
-  container: {
-    display: 'flex',
-    flexWrap: 'wrap',
-  },
-  textField: {
-    marginLeft: theme.spacing(1),
-    marginRight: theme.spacing(1),
-    width: 240,
-  },
-}));
-
-const fieldValuesToString = (field) => {
-  let strValues = '';
-  switch (field.type) {
-    case 'Numeric':
-      field.values.forEach((element) => {
-        switch (element.option) {
-          case 'between':
-            strValues = `${strValues} ${element.value1} <= ${field.name} <= ${element.value2} or `;
-            break;
-          default:
-            strValues = `${strValues} ${field.name} ${element.option} ${element.value1} or `;
-        }
-      });
-      if (strValues.endsWith('or '))
-        strValues = strValues.substring(0, strValues.length - 4);
-      break;
-    case 'Date':
-      field.values.forEach((element) => {
-        switch (element.option) {
-          case 'between':
-            strValues = `${strValues} ${element.startDate} <= ${field.name} <= ${element.endDate} or `;
-            break;
-          default:
-            strValues = `${strValues} ${field.name} ${element.option} ${element.startDate} or `;
-        }
-      });
-      if (strValues.endsWith(' or '))
-        strValues = strValues.substring(0, strValues.length - 4);
-      break;
-    case 'List':
-      strValues = `${strValues} ${field.name} = `;
-      field.values.forEach((element) => {
-        strValues = `${strValues} ${element.label}, `;
-      });
-      if (strValues.endsWith(', '))
-        strValues = strValues.substring(0, strValues.length - 2);
-      break;
-
-    //type : text
-    default:
-      strValues = `${strValues} ${field.name} = ${field.values}`;
-  }
-  return strValues;
-};
-
-const updateSources = (
-  searchFields,
-  sources,
-  setSelectedSources,
-  setAvailableSources
-) => {
-  let updatedSources = [];
-  let availableSources = [];
-  let noPrivateField = true;
-  //search for policy fields to filter sources
-  searchFields.forEach((field) => {
-    if (field.isValidated) {
-      //if sources haven't already been filtered
-      if (noPrivateField && !updatedSources.length) {
-        availableSources = sources;
-      } else {
-        availableSources = updatedSources;
-      }
-      updatedSources = [];
-      field.sources.forEach((sourceId) => {
-        noPrivateField = false;
-        const source = availableSources.find((src) => src.id === sourceId);
-        if (source && !updatedSources.includes(source)) updatedSources.push(source);
-      });
-    }
-  });
-  setSelectedSources(updatedSources);
-  if (noPrivateField && !updatedSources.length) {
-    setAvailableSources(sources);
-  } else {
-    setAvailableSources(updatedSources);
-  }
-};
-
-const fetchHistory = (setUserHistory) => {
-  fetchUserHistory(sessionStorage.getItem('user_id')).then((result) => {
-    if (result[0] && result[0].ui_structure) {
-      result.forEach((item) => {
-        item.ui_structure = JSON.parse(item.ui_structure);
-        item.label = `${item.name} - ${new Date(item.createdat).toLocaleString()}`;
-      });
-    }
-    setUserHistory(result);
-  });
-};
-
-const addHistory = (
-  kcID,
-  search,
-  searchName,
-  searchFields,
-  searchDescription,
-  setUserHistory
-) => {
-  addUserHistory(
-    sessionStorage.getItem('user_id'),
-    search,
-    searchName,
-    searchFields,
-    searchDescription
-  ).then(() => {
-    fetchHistory(setUserHistory);
-  });
-};
-
-const updateSearch = (setSearch, searchFields, selectedOperatorId, setSearchCount) => {
-  let searchText = '';
-  searchFields.forEach((field) => {
-    if (field.isValidated) {
-      searchText =
-        searchText +
-        `{${fieldValuesToString(field)} } ${Operators[selectedOperatorId].value.toUpperCase()} `;
-    }
-  });
-  if (searchText.endsWith(' AND ')) {
-    searchText = searchText.substring(0, searchText.length - 5);
-  } else if (searchText.endsWith(' OR ')) {
-    searchText = searchText.substring(0, searchText.length - 4);
-  }
-  setSearchCount();
-  setSearch(searchText);
-};
-
-const HistorySelect = (
-  sources,
-  setAvailableSources,
-  setSelectedSources,
-  setSearch,
-  searchFields,
-  selectedOperatorId,
-  userHistory,
-  setUserHistory,
-  setSearchFields,
-  setSearchCount,
-  setFieldCount,
-  selectedSavedSearch,
-  setSelectedSavedSearch,
-  historySelectError,
-  setHistorySelectError
-) => {
-  if (Object.keys(userHistory).length !== 0) {
-    const onHistoryChange = (selectedSavedSearch) => {
-      setHistorySelectError(undefined);
-      if (!!selectedSavedSearch[0].query) {
-        setSelectedSavedSearch(selectedSavedSearch);
-        setSearch(selectedSavedSearch[0].query);
-        setSearchCount();
-        setFieldCount([]);
-      }
-      if (!!selectedSavedSearch[0].ui_structure) {
-        updateSources(
-          selectedSavedSearch[0].ui_structure,
-          sources,
-          setSelectedSources,
-          setAvailableSources
-        );
-        setSearchFields(selectedSavedSearch[0].ui_structure);
-      }
-    };
-
-    const onHistorySearchChange = (value, hasMatchingOptions) => {
-      setHistorySelectError(
-        value.length === 0 || hasMatchingOptions
-          ? undefined
-          : `"${value}" is not a valid option`
-      );
-    };
-
-    return (
-      <>
-        <EuiFormRow
-          error={historySelectError}
-          isInvalid={historySelectError !== undefined}
-        >
-          <EuiComboBox
-            placeholder="Load a previous search"
-            singleSelection={{ asPlainText: true }}
-            options={userHistory}
-            selectedOptions={selectedSavedSearch}
-            onChange={onHistoryChange}
-            onSearchChange={onHistorySearchChange}
-          />
-        </EuiFormRow>
-      </>
-    );
-  }
-};
-
-const SearchBar = (
-  isLoading,
-  setIsLoading,
-  search,
-  setSearch,
-  searchResults,
-  setSearchResults,
-  searchFields,
-  setSearchFields,
-  searchName,
-  setSearchName,
-  searchDescription,
-  setSearchDescription,
-  readOnlyQuery,
-  setReadOnlyQuery,
-  selectedSources,
-  setSelectedSources,
-  availableSources,
-  setAvailableSources,
-  standardFields,
-  sources,
-  setSelectedTabNumber,
-  searchCount,
-  setSearchCount,
-  setFieldCount,
-  isReadOnlyModalOpen,
-  setIsReadOnlyModalOpen,
-  isSaveSearchModalOpen,
-  setIsSaveSearchModalOpen,
-  userHistory,
-  setUserHistory,
-  selectedSavedSearch,
-  setSelectedSavedSearch,
-  historySelectError,
-  setHistorySelectError,
-  selectedOperatorId,
-  createEditableQueryToast
-) => {
-  // const closeReadOnlyModal = () => setIsReadOnlyModalOpen(false)
-
-  /* const switchReadOnly = (readOnlyQuery, isReadOnlyModalOpen) => {
-        if (readOnlyQuery) {
-            setIsReadOnlyModalOpen(true)
-        } else {
-            setReadOnlyQuery(true)
-        } */
-  /* if (!localStorage.getItem("InSylvaReadOnlySearch") && readOnlyQuery) {
-        setIsReadOnlyModalOpen(!isReadOnlyModalOpen)
-    } */
-  // }
-
-  /* let readOnlyModal;
-
-    if (isReadOnlyModalOpen) {
-        readOnlyModal = (
-            <EuiOverlayMask>
-                <EuiConfirmModal
-                    title="Allow query editing"
-                    onCancel={() => closeReadOnlyModal()}
-                    onConfirm={() => {
-                        setReadOnlyQuery(!readOnlyQuery)
-                        closeReadOnlyModal()
-                    }}
-                    cancelButtonText="No"
-                    confirmButtonText="Yes"
-                    buttonColor="danger"
-                    defaultFocusedButton="confirm">
-                    <p>Be aware that manually editing the query can spoil search results.</p>
-                    <p>The syntax needs to be respected :</p>
-                    <ul>Fields and their values must be given between brackets : &#123; &#125;</ul>
-                    <ul>Check eventual typing mistakes</ul>
-                    <ul>Make sure every opened bracket is properly closed</ul>
-                    <p>Are you sure you want to do this?</p>
-                </EuiConfirmModal>
-            </EuiOverlayMask>
-        )
-    }*/
-
-  const closeSaveSearchModal = () => setIsSaveSearchModalOpen(false);
-
-  let saveSearchModal;
-
-  if (isSaveSearchModalOpen) {
-    saveSearchModal = (
-      <EuiOverlayMask>
-        <EuiModal onClose={closeSaveSearchModal} initialFocus="[name=searchName]">
-          <EuiModalHeader>
-            <EuiModalHeaderTitle>Save search</EuiModalHeaderTitle>
-          </EuiModalHeader>
-
-          <EuiModalBody>
-            <EuiForm>
-              <EuiFormRow label="Search name">
-                <EuiFieldText
-                  name="searchName"
-                  value={searchName}
-                  onChange={(e) => {
-                    setSearchName(e.target.value);
-                  }}
-                />
-              </EuiFormRow>
-              <EuiFormRow label="Description (optional)">
-                <EuiTextArea
-                  value={searchDescription}
-                  onChange={(e) => setSearchDescription(e.target.value)}
-                  placeholder="Search description..."
-                  fullWidth
-                  compressed
-                />
-              </EuiFormRow>
-            </EuiForm>
-          </EuiModalBody>
-
-          <EuiModalFooter>
-            <EuiButtonEmpty
-              onClick={() => {
-                closeSaveSearchModal();
-              }}
-            >
-              Cancel
-            </EuiButtonEmpty>
-            <EuiButton
-              onClick={() => {
-                if (!!searchName) {
-                  addHistory(
-                    sessionStorage.getItem('user_id'),
-                    search,
-                    searchName,
-                    searchFields,
-                    searchDescription,
-                    setUserHistory
-                  );
-                  setSearchName('');
-                  setSearchDescription('');
-                  closeSaveSearchModal();
-                }
-              }}
-              fill
-            >
-              Save
-            </EuiButton>
-          </EuiModalFooter>
-        </EuiModal>
-      </EuiOverlayMask>
-    );
-  }
-
-  return (
-    <>
-      {/*!readOnlyQuery ?
-                <>
-                    <EuiCallOut title="Proceed with caution!" color="warning" iconType="alert">
-                        <p>Be aware that manually editing the query can spoil search results. The syntax must be respected :</p>
-                        <ul>Fields and their values should be put between brackets : &#123; &#125;  -  Make sure every opened bracket is properly closed</ul>
-                        <ul>"AND" and "OR" should be capitalized between different fields conditions and lowercased within a field expression</ul>
-                        <ul>Make sure to check eventual typing mistakes</ul>
-
-                    </EuiCallOut>
-                    <EuiSpacer size="s" />
-                </>
-                : <></>
-            */}
-      <EuiFlexGroup>
-        <EuiFlexItem>
-          <EuiTextArea
-            readOnly={readOnlyQuery}
-            value={search}
-            onChange={(e) => setSearch(e.target.value)}
-            placeholder="Add fields..."
-            fullWidth
-          />
-        </EuiFlexItem>
-        <EuiFlexItem grow={false}>
-          <EuiButton
-            size="s"
-            fill
-            onClick={() => {
-              if (search.trim()) {
-                setIsLoading(true);
-                const queriesWithIndices = createAdvancedQueriesBySource(
-                  standardFields,
-                  search,
-                  selectedSources,
-                  availableSources
-                );
-                searchQuery(queriesWithIndices).then((result) => {
-                  // sessionStorage.setItem("searchResults", JSON.stringify(result))
-                  setSearchResults(result);
-                  setSelectedTabNumber(1);
-                  setIsLoading(false);
-                });
-              }
-            }}
-          >
-            Search
-          </EuiButton>
-          <EuiSpacer size="s" />
-          {isNaN(searchCount) ? (
-            <></>
-          ) : (
-            <>
-              <EuiTextColor
-                color="secondary"
-                style={{ display: 'flex', justifyContent: 'center' }}
-              >
-                {searchCount} {searchCount === 1 ? 'result' : 'results'}
-              </EuiTextColor>
-              <EuiSpacer size="s" />
-            </>
-          )}
-          <EuiButton
-            size="s"
-            onClick={() => {
-              if (!!search) {
-                const queriesWithIndices = createAdvancedQueriesBySource(
-                  standardFields,
-                  search,
-                  selectedSources,
-                  availableSources
-                );
-                getQueryCount(queriesWithIndices).then((result) => {
-                  if (result || result === 0) setSearchCount(result);
-                });
-              }
-            }}
-          >
-            Count results
-          </EuiButton>
-          <EuiSpacer size="s" />
-          <EuiButton
-            size="s"
-            onClick={() => {
-              setIsSaveSearchModalOpen(true);
-            }}
-          >
-            Save search
-          </EuiButton>
-          {saveSearchModal}
-          <EuiSpacer size="s" />
-          <EuiSwitch
-            compressed
-            label={'Editable'}
-            checked={!readOnlyQuery}
-            onChange={() => {
-              // switchReadOnly(readOnlyQuery, isReadOnlyModalOpen)
-              setReadOnlyQuery(!readOnlyQuery);
-              if (readOnlyQuery) {
-                createEditableQueryToast();
-              }
-            }}
-          />
-          {/* readOnlyModal */}
-        </EuiFlexItem>
-      </EuiFlexGroup>
-      {isLoading && (
-        <EuiFlexGroup>
-          <EuiFlexItem>
-            <EuiProgress postion="fixed" size="l" color="accent" />
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      )}
-      <EuiSpacer size="s" />
-      <EuiFlexGroup>
-        <EuiFlexItem>
-          {HistorySelect(
-            sources,
-            setAvailableSources,
-            setSelectedSources,
-            setSearch,
-            searchFields,
-            selectedOperatorId,
-            userHistory,
-            setUserHistory,
-            setSearchFields,
-            setSearchCount,
-            setFieldCount,
-            selectedSavedSearch,
-            setSelectedSavedSearch,
-            historySelectError,
-            setHistorySelectError
-          )}
-        </EuiFlexItem>
-      </EuiFlexGroup>
-    </>
-  );
-};
-
-const PopoverSelect = (
-  standardFields,
-  setStandardFields,
-  searchFields,
-  setSearchFields,
-  selectedField,
-  setSelectedField,
-  selectedSection,
-  setSelectedSection,
-  isPopoverSelectOpen,
-  setIsPopoverSelectOpen,
-  fieldCount,
-  setFieldCount,
-  selectedSources,
-  setSelectedSources
-) => {
-  const handleAddfield = () => {
-    if (!!selectedField[0]) {
-      const field = standardFields.find(
-        (item) =>
-          item.field_name.replace(/_|\./g, ' ') ===
-          selectedSection[0].label + ' ' + selectedField[0].label
-      );
-      switch (field.field_type) {
-        case 'Text':
-          setSearchFields([
-            ...searchFields,
-            new SearchField(field.field_name, field.field_type, '', false, field.sources),
-          ]);
-          break;
-        case 'List':
-          setSearchFields([
-            ...searchFields,
-            new SearchField(field.field_name, field.field_type, [], false, field.sources),
-          ]);
-          break;
-        default:
-          setSearchFields([
-            ...searchFields,
-            new SearchField(
-              field.field_name,
-              field.field_type,
-              [{}],
-              false,
-              field.sources
-            ),
-          ]);
-      }
-    }
-  };
-
-  const selectField = () => {
-    const renderOption = (option, searchValue, contentClassName) => {
-      const { label, color } = option;
-      return <EuiHealth color={color}>{label}</EuiHealth>;
-    };
-    if (selectedSection.length) {
-      return (
-        <>
-          <EuiComboBox
-            placeholder="Select a field"
-            singleSelection={{ asPlainText: true }}
-            options={getFieldsBySection(standardFields, selectedSection[0])}
-            selectedOptions={selectedField}
-            onChange={(selected) => setSelectedField(selected)}
-            isClearable={true}
-            renderOption={renderOption}
-          />
-          <EuiPopoverFooter>
-            <EuiButton
-              size="s"
-              onClick={() => {
-                handleAddfield();
-                setIsPopoverSelectOpen(false);
-                setSelectedSection([]);
-                setSelectedField([]);
-              }}
-            >
-              Add this field
-            </EuiButton>
-          </EuiPopoverFooter>
-        </>
-      );
-    }
-  };
-
-  return (
-    <EuiPopover
-      panelPaddingSize="s"
-      button={
-        <EuiButton
-          iconType="listAdd"
-          iconSide="left"
-          onClick={() => setIsPopoverSelectOpen(!isPopoverSelectOpen)}
-        >
-          Add field
-        </EuiButton>
-      }
-      isOpen={isPopoverSelectOpen}
-      closePopover={() => setIsPopoverSelectOpen(false)}
-    >
-      <div style={{ width: 'intrinsic', minWidth: 240 }}>
-        <EuiPopoverTitle>Select a field</EuiPopoverTitle>
-        <EuiComboBox
-          placeholder="Select a section"
-          singleSelection={{ asPlainText: true }}
-          options={getSections(standardFields)}
-          selectedOptions={selectedSection}
-          onChange={(selected) => {
-            setSelectedSection(selected);
-            setSelectedField([]);
-          }}
-          isClearable={false}
-        />
-      </div>
-      {selectField()}
-    </EuiPopover>
-  );
-};
-
-const PopoverValueContent = (
-  index,
-  standardFields,
-  setStandardFields,
-  searchFields,
-  setSearchFields,
-  valueError,
-  setValueError,
-  search,
-  setSearch,
-  setSearchCount,
-  fieldCount,
-  setFieldCount,
-  isPopoverValueOpen,
-  setIsPopoverValueOpen,
-  selectedOperatorId,
-  datePickerStyles,
-  createPolicyToast,
-  selectedSources,
-  setSelectedSources,
-  availableSources,
-  setAvailableSources
-) => {
-  const onValueSearchChange = (value, hasMatchingOptions) => {
-    setValueError(
-      value.length === 0 || hasMatchingOptions
-        ? undefined
-        : `"${value}" is not a valid option`
-    );
-  };
-
-  const validateFieldValues = () => {
-    let fieldValues;
-    if (Array.isArray(searchFields[index].values)) {
-      fieldValues = [];
-      searchFields[index].values.forEach((value) => {
-        if (!!value) {
-          fieldValues.push(value);
-        }
-      });
-    } else {
-      fieldValues = searchFields[index].values;
-    }
-
-    const updatedSearchFields = updateArrayElement(
-      searchFields,
-      index,
-      new SearchField(
-        searchFields[index].name,
-        searchFields[index].type,
-        fieldValues,
-        true,
-        searchFields[index].sources
-      )
-    );
-    setSearchFields(updatedSearchFields);
-    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
-    setFieldCount(updateArrayElement(fieldCount, index));
-    if (searchFields[index].sources.length) {
-      const filteredSources = [];
-      searchFields[index].sources.forEach((sourceId) => {
-        let source;
-        if (selectedSources.length) {
-          source = selectedSources.find((src) => src.id === sourceId);
-        } else {
-          source = availableSources.find((src) => src.id === sourceId);
-        }
-        if (source) {
-          filteredSources.push(source);
-        }
-      });
-      setAvailableSources(filteredSources);
-      setSelectedSources(filteredSources);
-      createPolicyToast();
-    }
-  };
-
-  const invalidateFieldValues = () => {
-    const updatedSearchFields = updateArrayElement(
-      searchFields,
-      index,
-      new SearchField(
-        searchFields[index].name,
-        searchFields[index].type,
-        searchFields[index].values,
-        false,
-        searchFields[index].sources
-      )
-    );
-    setSearchFields(updatedSearchFields);
-    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
-  };
-
-  const ValuePopoverFooter = (i) => {
-    if (i === searchFields[index].values.length - 1) {
-      return (
-        <EuiPopoverFooter>
-          <EuiButton
-            size="s"
-            onClick={() => {
-              setSearchFields(
-                updateArrayElement(
-                  searchFields,
-                  index,
-                  new SearchField(
-                    searchFields[index].name,
-                    searchFields[index].type,
-                    [...searchFields[index].values, {}],
-                    false,
-                    searchFields[index].sources
-                  )
-                )
-              );
-            }}
-          >
-            Add value
-          </EuiButton>
-          <EuiButton
-            size="s"
-            style={{ float: 'right' }}
-            onClick={() => {
-              validateFieldValues();
-              setIsPopoverValueOpen(updateArrayElement(isPopoverValueOpen, index, false));
-            }}
-          >
-            Validate
-          </EuiButton>
-        </EuiPopoverFooter>
-      );
-    }
-  };
-
-  const addFieldValue = (i, selectedOption) => {
-    setSearchFields(
-      updateSearchFieldValues(
-        searchFields,
-        index,
-        updateArrayElement(searchFields[index].values, i, { option: selectedOption })
-      )
-    );
-  };
-
-  const getListFieldValues = () => {
-    const listFieldValues = [];
-    standardFields
-      .find((item) => item.field_name === searchFields[index].name)
-      .values.split(', ')
-      .sort()
-      .forEach((element) => {
-        listFieldValues.push({ label: element });
-      });
-    return listFieldValues;
-  };
-
-  switch (searchFields[index].type) {
-    case 'Text':
-      return (
-        <>
-          <EuiFlexItem>
-            <EuiFieldText
-              placeholder={'Type values'}
-              value={searchFields[index].values}
-              onChange={(e) =>
-                setSearchFields(
-                  updateSearchFieldValues(searchFields, index, e.target.value)
-                )
-              }
-            />
-          </EuiFlexItem>
-          <EuiPopoverFooter>
-            <EuiButton
-              size="s"
-              style={{ float: 'right' }}
-              onClick={() => {
-                validateFieldValues();
-                setIsPopoverValueOpen(
-                  updateArrayElement(isPopoverValueOpen, index, false)
-                );
-              }}
-            >
-              Validate
-            </EuiButton>
-          </EuiPopoverFooter>
-        </>
-      );
-    case 'List':
-      return (
-        <>
-          <EuiFormRow error={valueError} isInvalid={valueError !== undefined}>
-            <EuiComboBox
-              placeholder={'Select values'}
-              options={getListFieldValues()}
-              selectedOptions={searchFields[index].values}
-              onChange={(selectedOptions) => {
-                setValueError(undefined);
-                setSearchFields(
-                  updateSearchFieldValues(searchFields, index, selectedOptions)
-                );
-              }}
-              onSearchChange={onValueSearchChange}
-            />
-          </EuiFormRow>
-          <EuiPopoverFooter>
-            <EuiButton
-              size="s"
-              style={{ float: 'right' }}
-              onClick={() => {
-                validateFieldValues();
-                setIsPopoverValueOpen(
-                  updateArrayElement(isPopoverValueOpen, index, false)
-                );
-              }}
-            >
-              Validate
-            </EuiButton>
-          </EuiPopoverFooter>
-        </>
-      );
-
-    case 'Numeric':
-      const NumericValues = (i) => {
-        if (!!searchFields[index].values[i].option) {
-          switch (searchFields[index].values[i].option) {
-            case 'between':
-              return (
-                <>
-                  <EuiFlexItem>
-                    <EuiFieldText
-                      placeholder={'1st value'}
-                      value={searchFields[index].values[i].value1}
-                      onChange={(e) => {
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              value1: e.target.value,
-                              value2: searchFields[index].values[i].value2,
-                            })
-                          )
-                        );
-                      }}
-                    />
-                  </EuiFlexItem>
-                  <EuiFlexItem>
-                    <EuiFieldText
-                      placeholder={'2nd value'}
-                      value={searchFields[index].values[i].value2}
-                      onChange={(e) =>
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              value1: searchFields[index].values[i].value1,
-                              value2: e.target.value,
-                            })
-                          )
-                        )
-                      }
-                    />
-                  </EuiFlexItem>
-                  {ValuePopoverFooter(i)}
-                </>
-              );
-
-            default:
-              return (
-                <>
-                  <EuiFlexItem>
-                    <EuiFieldText
-                      placeholder={'Type value'}
-                      value={searchFields[index].values[i].value1}
-                      onChange={(e) => {
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              value1: e.target.value,
-                              value2: searchFields[index].values[i].value2,
-                            })
-                          )
-                        );
-                      }}
-                    />
-                  </EuiFlexItem>
-                  {ValuePopoverFooter(i)}
-                </>
-              );
-          }
-        }
-      };
-
-      return (
-        <>
-          {searchFields[index].values.map((value, i) => (
-            <div key={i}>
-              <EuiSelect
-                hasNoInitialSelection
-                id="Select an option"
-                options={NumericOptions}
-                value={searchFields[index].values[i].option}
-                onChange={(e) => {
-                  addFieldValue(i, e.target.value);
-                  invalidateFieldValues();
-                }}
-              />
-              {NumericValues(i)}
-            </div>
-          ))}
-        </>
-      );
-
-    case 'Date':
-      const SelectDates = (i) => {
-        if (!!searchFields[index].values[i].option) {
-          switch (searchFields[index].values[i].option) {
-            case 'between':
-              return (
-                <>
-                  <form className={datePickerStyles.container} noValidate>
-                    <TextField
-                      label="between"
-                      type="date"
-                      defaultValue={
-                        !!searchFields[index].values[i].startDate
-                          ? searchFields[index].values[i].startDate
-                          : Date.now()
-                      }
-                      className={datePickerStyles.textField}
-                      InputLabelProps={{
-                        shrink: true,
-                      }}
-                      onChange={(e) =>
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              startDate: e.target.value,
-                              endDate: searchFields[index].values[i].endDate,
-                            })
-                          )
-                        )
-                      }
-                    />
-                  </form>
-                  <form className={datePickerStyles.container} noValidate>
-                    <TextField
-                      label="and"
-                      type="date"
-                      defaultValue={
-                        !!searchFields[index].values[i].endDate
-                          ? searchFields[index].values[i].endDate
-                          : Date.now()
-                      }
-                      className={datePickerStyles.textField}
-                      InputLabelProps={{
-                        shrink: true,
-                      }}
-                      onChange={(e) =>
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              startDate: searchFields[index].values[i].startDate,
-                              endDate: e.target.value,
-                            })
-                          )
-                        )
-                      }
-                    />
-                  </form>
-                  {ValuePopoverFooter(i)}
-                </>
-              );
-
-            default:
-              return (
-                <>
-                  <form className={datePickerStyles.container} noValidate>
-                    <TextField
-                      type="date"
-                      defaultValue={
-                        !!searchFields[index].values[i].startDate
-                          ? searchFields[index].values[i].startDate
-                          : Date.now()
-                      }
-                      className={datePickerStyles.textField}
-                      InputLabelProps={{
-                        shrink: true,
-                      }}
-                      onChange={(e) =>
-                        setSearchFields(
-                          updateSearchFieldValues(
-                            searchFields,
-                            index,
-                            updateArrayElement(searchFields[index].values, i, {
-                              option: searchFields[index].values[i].option,
-                              startDate: e.target.value,
-                              endDate: Date.now(),
-                            })
-                          )
-                        )
-                      }
-                    />
-                  </form>
-                  {ValuePopoverFooter(i)}
-                </>
-              );
-          }
-        }
-      };
-
-      return (
-        <>
-          {searchFields[index].values.map((value, i) => (
-            <div key={i}>
-              <EuiSelect
-                hasNoInitialSelection
-                id="Select an option"
-                options={DateOptions}
-                value={searchFields[index].values[i].option}
-                onChange={(e) => {
-                  addFieldValue(i, e.target.value);
-                  invalidateFieldValues();
-                }}
-              />
-              {SelectDates(i)}
-            </div>
-          ))}
-        </>
-      );
-    default:
-  }
-};
-
-const PopoverValueButton = (
-  index,
-  standardFields,
-  setStandardFields,
-  searchFields,
-  setSearchFields,
-  isPopoverValueOpen,
-  setIsPopoverValueOpen,
-  valueError,
-  setValueError,
-  search,
-  setSearch,
-  setSearchCount,
-  fieldCount,
-  setFieldCount,
-  selectedOperatorId,
-  datePickerStyles,
-  createPolicyToast,
-  selectedSources,
-  setSelectedSources,
-  availableSources,
-  setAvailableSources
-) => {
-  return (
-    <EuiPopover
-      panelPaddingSize="s"
-      button={
-        <EuiButtonIcon
-          size="s"
-          color="primary"
-          onClick={() =>
-            setIsPopoverValueOpen(
-              updateArrayElement(isPopoverValueOpen, index, !isPopoverValueOpen[index])
-            )
-          }
-          iconType="documentEdit"
-          title="Give field values"
-        />
-      }
-      isOpen={isPopoverValueOpen[index]}
-      closePopover={() =>
-        setIsPopoverValueOpen(updateArrayElement(isPopoverValueOpen, index, false))
-      }
-    >
-      {/*<div style={{ width: 240 }}>
-                <EuiButtonIcon
-                    size="s"
-                    style={{ float: 'right' }}
-                    color="danger"
-                    onClick={() => setIsPopoverValueOpen(updateArrayElement(isPopoverValueOpen, index, false))}
-                    iconType="crossInACircleFilled"
-                    title="Close popover"
-                />
-            </div>*/}
-      <div style={{ width: 240 }}>
-        {PopoverValueContent(
-          index,
-          standardFields,
-          setStandardFields,
-          searchFields,
-          setSearchFields,
-          valueError,
-          setValueError,
-          search,
-          setSearch,
-          setSearchCount,
-          fieldCount,
-          setFieldCount,
-          isPopoverValueOpen,
-          setIsPopoverValueOpen,
-          selectedOperatorId,
-          datePickerStyles,
-          createPolicyToast,
-          selectedSources,
-          setSelectedSources,
-          availableSources,
-          setAvailableSources
-        )}
-      </div>
-    </EuiPopover>
-  );
-};
-
-const FieldsPanel = (
-  standardFields,
-  setStandardFields,
-  searchFields,
-  setSearchFields,
-  selectedField,
-  setSelectedField,
-  selectedSection,
-  setSelectedSection,
-  isPopoverSelectOpen,
-  setIsPopoverSelectOpen,
-  isPopoverValueOpen,
-  setIsPopoverValueOpen,
-  valueError,
-  setValueError,
-  search,
-  setSearch,
-  setSearchCount,
-  selectedOperatorId,
-  setSelectedOperatorId,
-  fieldCount,
-  setFieldCount,
-  availableSources,
-  setAvailableSources,
-  selectedSources,
-  setSelectedSources,
-  sources,
-  datePickerStyles,
-  createPolicyToast
-) => {
-  const countFieldValues = (field, index) => {
-    const fieldStr = `{${fieldValuesToString(field)}}`;
-    const queriesWithIndices = createAdvancedQueriesBySource(
-      standardFields,
-      fieldStr,
-      selectedSources,
-      availableSources
-    );
-    getQueryCount(queriesWithIndices).then((result) => {
-      if (result || result === 0)
-        setFieldCount(updateArrayElement(fieldCount, index, result));
-    });
-  };
-
-  const handleRemoveField = (index) => {
-    const updatedSearchFields = removeArrayElement(searchFields, index);
-    setSearchFields(updatedSearchFields);
-    updateSources(updatedSearchFields, sources, setSelectedSources, setAvailableSources);
-    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
-  };
-
-  const handleClearValues = (index) => {
-    let updatedSearchFields = [];
-    switch (searchFields[index].type) {
-      case 'Text':
-        updatedSearchFields = updateArrayElement(
-          searchFields,
-          index,
-          new SearchField(
-            searchFields[index].name,
-            searchFields[index].type,
-            '',
-            false,
-            searchFields[index].sources
-          )
-        );
-        break;
-      case 'List':
-        updatedSearchFields = updateArrayElement(
-          searchFields,
-          index,
-          new SearchField(
-            searchFields[index].name,
-            searchFields[index].type,
-            [],
-            false,
-            searchFields[index].sources
-          )
-        );
-        break;
-      default:
-        updatedSearchFields = updateArrayElement(
-          searchFields,
-          index,
-          new SearchField(
-            searchFields[index].name,
-            searchFields[index].type,
-            [{}],
-            false,
-            searchFields[index].sources
-          )
-        );
-    }
-    setSearchFields(updatedSearchFields);
-    updateSources(updatedSearchFields, sources, setSelectedSources, setAvailableSources);
-    setFieldCount(updateArrayElement(fieldCount, index));
-    updateSearch(setSearch, updatedSearchFields, selectedOperatorId, setSearchCount);
-  };
-
-  if (standardFields === []) {
-    return <h2>Loading user fields...</h2>;
-  }
-
-  return (
-    <>
-      <EuiTitle size="xs">
-        <h2>Field search</h2>
-      </EuiTitle>
-      <EuiPanel paddingSize="m">
-        <EuiFlexGroup direction="column">
-          {searchFields.map((field, index) => (
-            <EuiPanel key={'field' + index} paddingSize="s">
-              <EuiFlexItem grow={false}>
-                <EuiFlexGroup direction="row" alignItems="center">
-                  <EuiFlexItem grow={false}>
-                    <EuiButtonIcon
-                      size="s"
-                      color="danger"
-                      onClick={() => handleRemoveField(index)}
-                      iconType="indexClose"
-                      title="Remove field"
-                    />
-                  </EuiFlexItem>
-                  <EuiFlexItem>
-                    {field.isValidated ? (
-                      <>
-                        {field.sources.length ? (
-                          <EuiHealth color="danger">
-                            {fieldValuesToString(field).replace(/_|\./g, ' ')}
-                          </EuiHealth>
-                        ) : (
-                          <EuiHealth color="primary">
-                            {fieldValuesToString(field).replace(/_|\./g, ' ')}
-                          </EuiHealth>
-                        )}
-                      </>
-                    ) : (
-                      <>
-                        {field.sources.length ? (
-                          <EuiHealth color="danger">
-                            {field.name.replace(/_|\./g, ' ')}
-                          </EuiHealth>
-                        ) : (
-                          <EuiHealth color="primary">
-                            {field.name.replace(/_|\./g, ' ')}
-                          </EuiHealth>
-                        )}
-                      </>
-                    )}
-                  </EuiFlexItem>
-                  <EuiFlexItem grow={false}>
-                    {isNaN(fieldCount[index]) ? (
-                      <></>
-                    ) : (
-                      <>
-                        <EuiTextColor color="secondary">
-                          {fieldCount[index]}{' '}
-                          {fieldCount[index] === 1 ? 'result' : 'results'}
-                        </EuiTextColor>
-                      </>
-                    )}
-                  </EuiFlexItem>
-                  <EuiFlexItem grow={false}>
-                    {field.isValidated ? (
-                      <>
-                        <EuiButtonIcon
-                          size="s"
-                          onClick={() => countFieldValues(field, index)}
-                          iconType="number"
-                          title="Count results"
-                        />
-                      </>
-                    ) : (
-                      <></>
-                    )}
-                  </EuiFlexItem>
-                  <EuiFlexItem grow={false}>
-                    {field.isValidated ? (
-                      <>
-                        <EuiButtonIcon
-                          size="s"
-                          color="danger"
-                          onClick={() => handleClearValues(index)}
-                          iconType="trash"
-                          title="Clear values"
-                        />
-                      </>
-                    ) : (
-                      <></>
-                    )}
-                  </EuiFlexItem>
-                  <EuiFlexItem grow={false}>
-                    {PopoverValueButton(
-                      index,
-                      standardFields,
-                      setStandardFields,
-                      searchFields,
-                      setSearchFields,
-                      isPopoverValueOpen,
-                      setIsPopoverValueOpen,
-                      valueError,
-                      setValueError,
-                      search,
-                      setSearch,
-                      setSearchCount,
-                      fieldCount,
-                      setFieldCount,
-                      selectedOperatorId,
-                      datePickerStyles,
-                      createPolicyToast,
-                      selectedSources,
-                      setSelectedSources,
-                      availableSources,
-                      setAvailableSources
-                    )}
-                  </EuiFlexItem>
-                </EuiFlexGroup>
-              </EuiFlexItem>
-            </EuiPanel>
-          ))}
-        </EuiFlexGroup>
-        <EuiSpacer size="l" />
-        {PopoverSelect(
-          standardFields,
-          setStandardFields,
-          searchFields,
-          setSearchFields,
-          selectedField,
-          setSelectedField,
-          selectedSection,
-          setSelectedSection,
-          isPopoverSelectOpen,
-          setIsPopoverSelectOpen,
-          fieldCount,
-          setFieldCount,
-          selectedSources,
-          setSelectedSources
-        )}
-      </EuiPanel>
-      <EuiSpacer size="s" />
-      <EuiRadioGroup
-        options={Operators}
-        idSelected={selectedOperatorId}
-        onChange={(id) => {
-          setSelectedOperatorId(id);
-          updateSearch(setSearch, searchFields, id, setSearchCount);
-        }}
-        name="operators group"
-        legend={{
-          children: <span>Search option</span>,
-        }}
-      />
-    </>
-  );
-};
-
-const SourceSelect = (
-  availableSources,
-  selectedSources,
-  setSelectedSources,
-  sourceSelectError,
-  setSourceSelectError
-) => {
-  if (Object.keys(availableSources).length !== 0) {
-    availableSources.forEach((source) => {
-      if (source.name) {
-        source = changeNameToLabel(source);
-      }
-    });
-
-    const onSourceChange = (selectedOptions) => {
-      setSourceSelectError(undefined);
-      setSelectedSources(selectedOptions);
-    };
-
-    const onSourceSearchChange = (value, hasMatchingOptions) => {
-      setSourceSelectError(
-        value.length === 0 || hasMatchingOptions
-          ? undefined
-          : `"${value}" is not a valid option`
-      );
-    };
-    return (
-      <>
-        <EuiTitle size="xs">
-          <h2>Partner sources</h2>
-        </EuiTitle>
-        <EuiSpacer size="s" />
-        <EuiFlexItem>
-          <EuiFormRow
-            error={sourceSelectError}
-            isInvalid={sourceSelectError !== undefined}
-          >
-            <EuiComboBox
-              placeholder="By default, all sources are selected"
-              options={availableSources}
-              selectedOptions={selectedSources}
-              onChange={onSourceChange}
-              onSearchChange={onSourceSearchChange}
-            />
-          </EuiFormRow>
-        </EuiFlexItem>
-      </>
-    );
-  } else {
-    return (
-      <p>
-        <EuiIcon type="alert" color="danger" /> No source available !
-      </p>
-    );
-  }
-};
+import { useTranslation } from 'react-i18next';
+import AdvancedSearch from './AdvancedSearch/AdvancedSearch';
+import BasicSearch from './BasicSearch/BasicSearch';
 
 const Search = () => {
-  const [isLoading, setIsLoading] = useState(false);
+  const { t } = useTranslation('search');
   const [selectedTabNumber, setSelectedTabNumber] = useState(0);
-  const [userHistory, setUserHistory] = useState({});
-  const [advancedSearch, setAdvancedSearch] = useState(false);
-  const [readOnlyQuery, setReadOnlyQuery] = useState(true);
-  const [selectedField, setSelectedField] = useState([]);
-  const [selectedSection, setSelectedSection] = useState([]);
-  const [isPopoverSelectOpen, setIsPopoverSelectOpen] = useState(false);
-  const [isPopoverValueOpen, setIsPopoverValueOpen] = useState([false]);
+  const [isAdvancedSearch, setIsAdvancedSearch] = useState(false);
   const [selectedSources, setSelectedSources] = useState([]);
+  const [sources, setSources] = useState([]);
   const [availableSources, setAvailableSources] = useState([]);
-  const [sourceSelectError, setSourceSelectError] = useState(undefined);
-  const [valueError, setValueError] = useState(undefined);
   const [search, setSearch] = useState('');
-  const [searchName, setSearchName] = useState('');
-  const [searchDescription, setSearchDescription] = useState('');
   const [basicSearch, setBasicSearch] = useState('');
-  const [selectedOperatorId, setSelectedOperatorId] = useState('0');
-  const [searchFields, setSearchFields] = useState([]);
   const [standardFields, setStandardFields] = useState([]);
-  const [sources, setSources] = useState([]);
-  const [searchResults, setSearchResults] = useState();
-  const [searchCount, setSearchCount] = useState();
-  const [fieldCount, setFieldCount] = useState([]);
-  const [isReadOnlyModalOpen, setIsReadOnlyModalOpen] = useState(false);
-  const [isSaveSearchModalOpen, setIsSaveSearchModalOpen] = useState(false);
-  const [selectedSavedSearch, setSelectedSavedSearch] = useState();
-  const [historySelectError, setHistorySelectError] = useState(undefined);
-  const [notificationToasts, setNotificationToasts] = useState([]);
-  const datePickerStyles = useStyles();
+  const [searchResults, setSearchResults] = useState([]);
+  const [selectedResultsRowsIds, setSelectedResultsRowsIds] = useState([]);
 
   useEffect(() => {
     fetchPublicFields().then((resultStdFields) => {
@@ -1576,264 +60,83 @@ const Search = () => {
           setStandardFields(removeNullFields(userFields));
         }
       );
-
-      // policyField => {
-      //     policyField.forEach(
     });
     fetchSources(sessionStorage.getItem('user_id')).then((result) => {
       setSources(result);
       setAvailableSources(result);
     });
-    fetchHistory(setUserHistory);
   }, []);
 
-  const createPolicyToast = () => {
-    const toast = {
-      title: 'Policy field selected',
-      color: 'warning',
-      iconType: 'alert',
-      toastLifeTimeMs: 15000,
-      text: (
-        <>
-          <p>You selected a private field.</p>
-          <p>
-            Access to this field was granted for specific sources, which means that your
-            search will be restricted to those.
-          </p>
-          <p>Please check the sources list before searching.</p>
-        </>
-      ),
-    };
-    setNotificationToasts(notificationToasts.concat(toast));
-  };
-
-  const createEditableQueryToast = () => {
-    const toast = {
-      title: 'Proceed with caution',
-      color: 'warning',
-      iconType: 'alert',
-      toastLifeTimeMs: 15000,
-      text: (
-        <>
-          <p>
-            Be aware that manually editing the query can spoil search results. The syntax
-            must be respected :
-          </p>
-          <ul>
-            Fields and their values should be put between brackets : &#123; &#125; - Make
-            sure every opened bracket is properly closed
-          </ul>
-          <ul>
-            "AND" and "OR" should be capitalized between different fields conditions and
-            lowercased within a field expression
-          </ul>
-          <ul>Make sure to check eventual typing mistakes</ul>
-        </>
-      ),
-    };
-    setNotificationToasts(notificationToasts.concat(toast));
-  };
-
-  const removeToast = (removedToast) => {
-    setNotificationToasts(
-      notificationToasts.filter((toast) => toast.id !== removedToast.id)
-    );
-  };
-
   const tabsContent = [
     {
       id: 'tab1',
-      name: 'Compose search',
+      name: t('tabs.composeSearch'),
       content: (
-        <>
-          {advancedSearch ? (
-            <>
-              <EuiFlexGroup>
-                <EuiFlexItem grow={false}>
-                  <EuiSpacer size="s" />
-                  <EuiButtonEmpty
-                    onClick={() => {
-                      setAdvancedSearch(!advancedSearch);
-                    }}
-                  >
-                    Switch to basic search
-                  </EuiButtonEmpty>
-                </EuiFlexItem>
-              </EuiFlexGroup>
-              <EuiFlexGroup>
-                <EuiFlexItem>
-                  <EuiSpacer size="s" />
-                  {SearchBar(
-                    isLoading,
-                    setIsLoading,
-                    search,
-                    setSearch,
-                    searchResults,
-                    setSearchResults,
-                    searchFields,
-                    setSearchFields,
-                    searchName,
-                    setSearchName,
-                    searchDescription,
-                    setSearchDescription,
-                    readOnlyQuery,
-                    setReadOnlyQuery,
-                    selectedSources,
-                    setSelectedSources,
-                    availableSources,
-                    setAvailableSources,
-                    standardFields,
-                    sources,
-                    setSelectedTabNumber,
-                    searchCount,
-                    setSearchCount,
-                    setFieldCount,
-                    isReadOnlyModalOpen,
-                    setIsReadOnlyModalOpen,
-                    isSaveSearchModalOpen,
-                    setIsSaveSearchModalOpen,
-                    userHistory,
-                    setUserHistory,
-                    selectedSavedSearch,
-                    setSelectedSavedSearch,
-                    historySelectError,
-                    setHistorySelectError,
-                    selectedOperatorId,
-                    createEditableQueryToast
-                  )}
-                </EuiFlexItem>
-              </EuiFlexGroup>
-              <EuiFlexGroup>
-                <EuiFlexItem>
-                  <EuiSpacer size="s" />
-                  {FieldsPanel(
-                    standardFields,
-                    setStandardFields,
-                    searchFields,
-                    setSearchFields,
-                    selectedField,
-                    setSelectedField,
-                    selectedSection,
-                    setSelectedSection,
-                    isPopoverSelectOpen,
-                    setIsPopoverSelectOpen,
-                    isPopoverValueOpen,
-                    setIsPopoverValueOpen,
-                    valueError,
-                    setValueError,
-                    search,
-                    setSearch,
-                    setSearchCount,
-                    selectedOperatorId,
-                    setSelectedOperatorId,
-                    fieldCount,
-                    setFieldCount,
-                    availableSources,
-                    setAvailableSources,
-                    selectedSources,
-                    setSelectedSources,
-                    sources,
-                    datePickerStyles,
-                    createPolicyToast
-                  )}
-                  <EuiSpacer size="s" />
-                  {SourceSelect(
-                    availableSources,
-                    selectedSources,
-                    setSelectedSources,
-                    sourceSelectError,
-                    setSourceSelectError
-                  )}
-                </EuiFlexItem>
-              </EuiFlexGroup>
-              <EuiGlobalToastList
-                toasts={notificationToasts}
-                dismissToast={removeToast}
-                toastLifeTimeMs={2500}
+        <EuiFlexGroup>
+          <EuiFlexItem>
+            <EuiSpacer size={'l'} />
+            {isAdvancedSearch ? (
+              <AdvancedSearch
+                search={search}
+                setSearch={setSearch}
+                setSearchResults={setSearchResults}
+                selectedSources={selectedSources}
+                setSelectedSources={setSelectedSources}
+                availableSources={availableSources}
+                setAvailableSources={setAvailableSources}
+                standardFields={standardFields}
+                setStandardFields={setStandardFields}
+                sources={sources}
+                setSelectedTabNumber={setSelectedTabNumber}
+                isAdvancedSearch={isAdvancedSearch}
+                setIsAdvancedSearch={setIsAdvancedSearch}
+              />
+            ) : (
+              <BasicSearch
+                isAdvancedSearch={isAdvancedSearch}
+                setIsAdvancedSearch={setIsAdvancedSearch}
+                standardFields={standardFields}
+                availableSources={availableSources}
+                selectedSources={selectedSources}
+                basicSearch={basicSearch}
+                setBasicSearch={setBasicSearch}
+                setSearchResults={setSearchResults}
+                setSelectedTabNumber={setSelectedTabNumber}
               />
-            </>
-          ) : (
-            <>
-              <EuiFlexGroup>
-                <EuiFlexItem grow={false}>
-                  <EuiSpacer size="s" />
-                  <EuiButtonEmpty
-                    onClick={() => {
-                      setAdvancedSearch(!advancedSearch);
-                    }}
-                  >
-                    Switch to advanced search
-                  </EuiButtonEmpty>
-                </EuiFlexItem>
-              </EuiFlexGroup>
-              <EuiFlexGroup>
-                <EuiFlexItem>
-                  <EuiSpacer size="s" />
-                  <EuiFlexGroup>
-                    <EuiFlexItem>
-                      <EuiFieldSearch
-                        value={basicSearch}
-                        onChange={(e) => setBasicSearch(e.target.value)}
-                        placeholder="Search..."
-                        fullWidth
-                      />
-                    </EuiFlexItem>
-                    <EuiFlexItem grow={false}>
-                      <EuiButton
-                        fill
-                        isDisabled={advancedSearch}
-                        onClick={() => {
-                          setIsLoading(true);
-                          const queriesWithIndices = createBasicQueriesBySource(
-                            standardFields,
-                            basicSearch,
-                            selectedSources,
-                            availableSources
-                          );
-                          searchQuery(queriesWithIndices).then((result) => {
-                            // sessionStorage.setItem("searchResults", JSON.stringify(result))
-                            setSearchResults(result);
-                            setSelectedTabNumber(1);
-                            setIsLoading(false);
-                          });
-                        }}
-                      >
-                        Search
-                      </EuiButton>
-                    </EuiFlexItem>
-                  </EuiFlexGroup>
-                  {isLoading && (
-                    <EuiFlexGroup>
-                      <EuiFlexItem>
-                        <EuiProgress postion="fixed" size="l" color="accent" />
-                      </EuiFlexItem>
-                    </EuiFlexGroup>
-                  )}
-                </EuiFlexItem>
-              </EuiFlexGroup>
-            </>
-          )}
-        </>
+            )}
+          </EuiFlexItem>
+        </EuiFlexGroup>
       ),
     },
     {
-      id: 'tab3',
-      name: 'Results',
+      id: 'tab2',
+      name: t('tabs.results'),
       content: (
         <EuiFlexGroup>
-          <EuiFlexItem>{Results(searchResults, search, basicSearch)}</EuiFlexItem>
+          <EuiFlexItem>
+            <EuiSpacer size="l" />
+            <Results
+              searchResults={searchResults}
+              searchQuery={isAdvancedSearch ? search : basicSearch}
+              selectedRowsIds={selectedResultsRowsIds}
+              setSelectedRowsIds={setSelectedResultsRowsIds}
+            />
+          </EuiFlexItem>
         </EuiFlexGroup>
       ),
     },
     {
-      id: 'tab2',
-      name: 'Map',
+      id: 'tab3',
+      name: t('tabs.map'),
       content: (
         <EuiFlexGroup>
           <EuiFlexItem>
             <EuiSpacer size="l" />
-            {/*<a href="https://agroenvgeo.data.inra.fr/mapfishapp/"><img src={map} width="460" height="400" alt='Map' /></a>*/}
-            <SearchMap searchResults={searchResults} />
+            <SearchMap
+              searchResults={searchResults}
+              selectedPointsIds={selectedResultsRowsIds}
+              setSelectedPointsIds={setSelectedResultsRowsIds}
+            />
           </EuiFlexItem>
         </EuiFlexGroup>
       ),
@@ -1841,30 +144,15 @@ const Search = () => {
   ];
 
   return (
-    <>
-      <EuiPageContent>
-        {' '}
-        {/*style={{ backgroundColor: "#fafafa" }}*/}
-        <EuiPageContentHeader>
-          <EuiPageContentHeaderSection>
-            <EuiTitle>
-              <h2>In-Sylva Metadata Search Platform</h2>
-            </EuiTitle>
-          </EuiPageContentHeaderSection>
-        </EuiPageContentHeader>
-        <EuiPageContentBody>
-          <EuiForm>
-            <EuiTabbedContent
-              tabs={tabsContent}
-              selectedTab={tabsContent[selectedTabNumber]}
-              onTabClick={(tab) => {
-                setSelectedTabNumber(tabsContent.indexOf(tab));
-              }}
-            />
-          </EuiForm>
-        </EuiPageContentBody>
-      </EuiPageContent>
-    </>
+    <EuiPageContentBody>
+      <EuiTabbedContent
+        tabs={tabsContent}
+        selectedTab={tabsContent[selectedTabNumber]}
+        onTabClick={(tab) => {
+          setSelectedTabNumber(tabsContent.indexOf(tab));
+        }}
+      />
+    </EuiPageContentBody>
   );
 };