From b1def48eac05e1f214f60e5382a06ee34a8f5b70 Mon Sep 17 00:00:00 2001 From: Priyavrat Sharma <52522330+priyavrat7@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:54:28 -0400 Subject: [PATCH 1/7] [user_accounts] to add SweetAlert2 reject user (#10475) **Situation:** In the LORIS `user_accounts` module (`edit_user` interface), clicking the "Reject User" button triggers an immediate AJAX call to reject the account. There is no confirmation dialog, making it extremely easy for an administrator to accidentally reject a user with a misclick. **Task:** My objective was to introduce a confirmation step before executing the rejection AJAX call, ensuring a better and safer user experience. The implementation needed to adhere strictly to modern LORIS framework standards, specifically utilizing the SweetAlert2 library. **Action:** - **Refactored Legacy Code:** Converted the plain jQuery script `modules/user_accounts/js/rejectUser.js` into a modern proper source file at `modules/user_accounts/jsx/rejectUser.js`. - **Integrated SweetAlert2:** Used modern Webpack imports (`import swal from 'sweetalert2';`) to implement a `swal.fire()` confirmation modal with a 'warning' type, standardizing the UI with other LORIS modules. - **Updated Webpack Entry Point:** Registered the new `rejectUser` file in `webpack.config.ts` under the `user_accounts` entry. - **Compiled Bundle:** Built the new asset via `npm run compile`, resulting in a self-contained Webpack JS bundle that replaces the old jQuery file. **Result:** Administrators can now see SweetAlert2 warning dialog when attempting to reject a user. The AJAX call is correctly blocked until the user explicitly clicks "Yes, reject user!", completely preventing accidental rejections and fixes #10474. image --- modules/user_accounts/.gitignore | 2 +- modules/user_accounts/js/rejectUser.js | 29 --------- modules/user_accounts/jsx/rejectUser.js | 64 +++++++++++++++++++ .../locale/fr/LC_MESSAGES/user_accounts.po | 9 +++ .../locale/hi/LC_MESSAGES/user_accounts.po | 9 +++ .../locale/ja/LC_MESSAGES/user_accounts.po | 8 +++ .../locale/zh/LC_MESSAGES/user_accounts.po | 9 +++ webpack.config.ts | 2 +- 8 files changed, 101 insertions(+), 31 deletions(-) delete mode 100644 modules/user_accounts/js/rejectUser.js create mode 100644 modules/user_accounts/jsx/rejectUser.js diff --git a/modules/user_accounts/.gitignore b/modules/user_accounts/.gitignore index 0683785912..1034f44c2f 100644 --- a/modules/user_accounts/.gitignore +++ b/modules/user_accounts/.gitignore @@ -1,2 +1,2 @@ js/* -!js/edit_user_helper.js +!js/edit_user_helper.js \ No newline at end of file diff --git a/modules/user_accounts/js/rejectUser.js b/modules/user_accounts/js/rejectUser.js deleted file mode 100644 index 1c0d63b633..0000000000 --- a/modules/user_accounts/js/rejectUser.js +++ /dev/null @@ -1,29 +0,0 @@ -$(document).ready(function() { - $("#btn_reject").click(function() { - const userID = document.getElementById("UserID").value; - const baseurl = loris.BaseURL; - const lorisFetch = window.lorisFetch || fetch; - - lorisFetch(baseurl + '/user_accounts/ajax/rejectUser.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', - }, - body: new URLSearchParams({identifier: userID}), - credentials: 'same-origin', - }) - .then((response) => { - if (!response.ok) { - return response.text().then((text) => { - let error = new Error('request_failed'); - error.lorisMessage = text; - throw error; - }); - } - location.href = baseurl + '/user_accounts/'; - }) - .catch((error) => { - alert(error.lorisMessage || ''); - }); - }); -}); diff --git a/modules/user_accounts/jsx/rejectUser.js b/modules/user_accounts/jsx/rejectUser.js new file mode 100644 index 0000000000..a051860275 --- /dev/null +++ b/modules/user_accounts/jsx/rejectUser.js @@ -0,0 +1,64 @@ +import swal from 'sweetalert2'; +import i18n from 'I18nSetup'; +import hiStrings from '../locale/hi/LC_MESSAGES/user_accounts.json'; +import jaStrings from '../locale/ja/LC_MESSAGES/user_accounts.json'; +import frStrings from '../locale/fr/LC_MESSAGES/user_accounts.json'; +import zhStrings from '../locale/zh/LC_MESSAGES/user_accounts.json'; + +window.addEventListener('load', () => { + i18n.addResourceBundle('ja', 'user_accounts', jaStrings); + i18n.addResourceBundle('hi', 'user_accounts', hiStrings); + i18n.addResourceBundle('fr', 'user_accounts', frStrings); + i18n.addResourceBundle('zh', 'user_accounts', zhStrings); + const btn = document.getElementById('btn_reject'); + + if (!btn) return; + + btn.addEventListener('click', () => { + const pathParts = window.location.pathname.split('/'); + const userID = pathParts[pathParts.length - 1]; + const baseurl = loris.BaseURL; + + swal.fire({ + title: i18n.t('Are you sure?', {ns: 'loris'}), + html: i18n.t( + 'Do you really want to reject this user?', + {ns: 'user_accounts'} + ) + '
' + i18n.t( + 'This action cannot be undone.', + {ns: 'user_accounts'} + ), + type: 'warning', + showCancelButton: true, + confirmButtonText: i18n.t( + 'Yes, reject user!', + {ns: 'user_accounts'} + ), + cancelButtonText: i18n.t('Cancel', {ns: 'loris'}), + }).then((result) => { + if (result.value) { + fetch(`${baseurl}/user_accounts/ajax/rejectUser.php`, { + method: 'POST', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + identifier: userID, + }), + }) + .then((resp) => { + if (!resp.ok) { + return resp.text().then((text) => { + throw new Error(text); + }); + } + window.location.href = `${baseurl}/user_accounts/`; + }) + .catch((error) => { + swal.fire(i18n.t('Error', {ns: 'loris'}), error.message, 'error'); + }); + } + }); + }); +}); diff --git a/modules/user_accounts/locale/fr/LC_MESSAGES/user_accounts.po b/modules/user_accounts/locale/fr/LC_MESSAGES/user_accounts.po index 494aeca361..a87f123561 100644 --- a/modules/user_accounts/locale/fr/LC_MESSAGES/user_accounts.po +++ b/modules/user_accounts/locale/fr/LC_MESSAGES/user_accounts.po @@ -232,3 +232,12 @@ msgstr "Les nouveaux et anciens mots de passe sont identiques." msgid "This email address is already in use" msgstr "Cette adresse email est déjà utilisée" + +msgid "Do you really want to reject this user?" +msgstr "Voulez-vous vraiment rejeter cet utilisateur ?" + +msgid "This action cannot be undone." +msgstr "Cette action ne peut pas être annulée." + +msgid "Yes, reject user!" +msgstr "Oui, rejeter l’utilisateur !" diff --git a/modules/user_accounts/locale/hi/LC_MESSAGES/user_accounts.po b/modules/user_accounts/locale/hi/LC_MESSAGES/user_accounts.po index d9f8aaaa6a..65a7f3cbe6 100644 --- a/modules/user_accounts/locale/hi/LC_MESSAGES/user_accounts.po +++ b/modules/user_accounts/locale/hi/LC_MESSAGES/user_accounts.po @@ -191,3 +191,12 @@ msgstr "नया और पुराना पासवर्ड समान msgid "This email address is already in use" msgstr "यह ईमेल पता पहले से उपयोग में है।" + +msgid "Do you really want to reject this user?" +msgstr "क्या आप वाकई इस उपयोगकर्ता को अस्वीकार करना चाहते हैं?" + +msgid "This action cannot be undone." +msgstr "यह क्रिया पूर्ववत नहीं की जा सकती।" + +msgid "Yes, reject user!" +msgstr "हाँ, उपयोगकर्ता को अस्वीकार करें!" diff --git a/modules/user_accounts/locale/ja/LC_MESSAGES/user_accounts.po b/modules/user_accounts/locale/ja/LC_MESSAGES/user_accounts.po index d8e0a60d40..27b8af1951 100644 --- a/modules/user_accounts/locale/ja/LC_MESSAGES/user_accounts.po +++ b/modules/user_accounts/locale/ja/LC_MESSAGES/user_accounts.po @@ -198,3 +198,11 @@ msgstr "新しいパスワードと古いパスワードは同一です。" msgid "This email address is already in use" msgstr "このメールアドレスはすでに使用されています。" +msgid "Do you really want to reject this user?" +msgstr "本当にこのユーザーを拒否しますか?" + +msgid "This action cannot be undone." +msgstr "この操作は取り消せません。" + +msgid "Yes, reject user!" +msgstr "はい、ユーザーを拒否します!" diff --git a/modules/user_accounts/locale/zh/LC_MESSAGES/user_accounts.po b/modules/user_accounts/locale/zh/LC_MESSAGES/user_accounts.po index 83a0eaa27e..86e90fa0fb 100644 --- a/modules/user_accounts/locale/zh/LC_MESSAGES/user_accounts.po +++ b/modules/user_accounts/locale/zh/LC_MESSAGES/user_accounts.po @@ -211,3 +211,12 @@ msgstr "新旧密码相同" msgid "This email address is already in use" msgstr "该电子邮件地址已被使用" + +msgid "Do you really want to reject this user?" +msgstr "您确定要拒绝该用户吗?" + +msgid "This action cannot be undone." +msgstr "此操作无法撤销。" + +msgid "Yes, reject user!" +msgstr "是的,拒绝用户!" diff --git a/webpack.config.ts b/webpack.config.ts index 871d56839c..21cdbb0e93 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -65,7 +65,7 @@ const lorisModules: Record = { instrument_manager: ['instrumentManagerIndex'], survey_accounts: ['surveyAccountsIndex'], mri_violations: ['mriViolationsIndex'], - user_accounts: ['userAccountsIndex'], + user_accounts: ['userAccountsIndex', 'rejectUser'], examiner: ['examinerIndex'], help_editor: ['help_editor', 'helpEditorForm'], brainbrowser: ['Brainbrowser'], From 291d827d26e057d5b3fe40e47aba11f3bb25fbc0 Mon Sep 17 00:00:00 2001 From: Michael Lapadula Date: Thu, 25 Jun 2026 13:46:14 -0400 Subject: [PATCH 2/7] [dataquery] Updating TestPlan.md to specify admin pinned queries (#10685) ## Brief summary of changes The dataquery TestPlan specifies that queries should only be able to be pinned by users with "Data Query Tool: Admin dataquery queries" permission. - [x] Have you updated related documentation? #### Testing instructions (if applicable) 1. Verify the TestPlan #### Link(s) to related issue(s) * Resolves [10602](https://github.com/aces/Loris/issues/10602). Co-authored-by: Michael Lapadula --- modules/dataquery/test/TestPlan.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/dataquery/test/TestPlan.md b/modules/dataquery/test/TestPlan.md index e0d59f88e2..8162eac0cd 100644 --- a/modules/dataquery/test/TestPlan.md +++ b/modules/dataquery/test/TestPlan.md @@ -5,7 +5,8 @@ 1. Ensure the module loads only for a user that has the `dataquery_view` permission. They must also have access to the dictionary module. 2. Assert that: `Instructions` panel, `Recent Queries` panel, and `Next Steps` panel (bottom-right corner) collapse as expected. 3. Assert that: `Continue to Define Fields` button in the main panel, and `Choose Fields` button in the `Next Steps` panel are redirecting to the same page. -4. `Recent Queries` panel +4. Ensure the pinning icon only appears for users that have the `dataquery_admin` (Data Query Tool: Admin dataquery queries) permission. Users without it should not be able to pin queries. +5. `Recent Queries` panel 1. If not queries are available, make some so they will be added to this section. 2. Assert that: queries you made have their parameters correctly displayed (i.e. fields and filters). 3. Assert that: `text filter` immediately filter the queries. From 533a0bbf28a8994f63c26891d4f3834a64a9e616 Mon Sep 17 00:00:00 2001 From: Camille Beaudoin <51176779+CamilleBeau@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:56:01 -0400 Subject: [PATCH 3/7] [NDB_Notifier] Fix 'active_to' query (#10686) ## Brief summary of changes No notifications were being sent out because the "Active_to" condition in the query for users to be notified had the opposite logic than it should (it was checking users who have already had their access expired instead of users who are still active). - [ ] Have you updated related documentation? #### Testing instructions (if applicable) 1. Create a user and grant the user each permission from the my_preferences page. Make sure the user is active and does not have an active_to date set 2. Test each operation that sends notifications to make sure the notifications are properly sent 3. Edit the user to have an active_to date set before now 4. Make sure the notifications are not sent 5. Edit the user to have an active_to date set after now 6. Make sure the notifications are sent 7. Remove all of the notification settings from my_preferences page 8. Make sure that the notifications are not sent #### Link(s) to related issue(s) * Resolves #10588 --- php/libraries/NDB_Notifier_Abstract.class.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/libraries/NDB_Notifier_Abstract.class.inc b/php/libraries/NDB_Notifier_Abstract.class.inc index 7592c3027c..209c649868 100644 --- a/php/libraries/NDB_Notifier_Abstract.class.inc +++ b/php/libraries/NDB_Notifier_Abstract.class.inc @@ -244,7 +244,7 @@ abstract class NDB_Notifier_Abstract AND nm.operation_type=:ot AND u.Pending_approval = 'N' AND u.Active = 'Y' - AND u.active_to < NOW() + AND (u.active_to > NOW() OR u.active_to IS NULL) "; $params = [ "nm" => $this->module, From 30b999b8cdca8ccb315365a59ca0945db214227b Mon Sep 17 00:00:00 2001 From: George Murad Date: Fri, 26 Jun 2026 09:57:56 -0400 Subject: [PATCH 4/7] [survey_accounts]Add French Language To Survey Accounts --- .../ajax/ValidateEmailSubmitInput.php | 13 +- .../js/survey_accounts_helper.js | 6 +- .../jsx/surveyAccountsIndex.js | 21 ++- .../fr_CA/LC_MESSAGES/survey_accounts.po | 129 ++++++++++++++++++ .../locale/survey_accounts.pot | 33 ++++- .../survey_accounts/php/addsurvey.class.inc | 34 +++-- .../php/survey_accounts.class.inc | 8 +- .../templates/form_addSurvey.tpl | 6 +- 8 files changed, 217 insertions(+), 33 deletions(-) create mode 100644 modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.po diff --git a/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php b/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php index fd16cbe134..4d9ac8b390 100644 --- a/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php +++ b/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php @@ -69,7 +69,7 @@ if ($numSessions != 1) { echo json_encode( [ - 'error_msg' => dgettext('loris', 'Visit').' '. $_REQUEST['VL'].' '. + 'error_msg' => dgettext('survey_accounts', 'Visit').' '. $_REQUEST['VL'].' '. dgettext('survey_accounts', 'does not exist for given candidate'), ] ); @@ -78,7 +78,7 @@ if (empty($_REQUEST['TN'])) { echo json_encode( - ['error_msg' => dgettext('survey_accounts', 'Please choose an instrument')] + ['error_msg' => dgettext('survey_accounts', 'Please choose an instrument.')] ); exit(0); } @@ -100,8 +100,13 @@ if ($_REQUEST['TN'] == $instrument['Test_name']) { echo json_encode( [ - 'error_msg' => dgettext('loris', 'Instrument').' '. $_REQUEST['TN'] - .' ' .dgettext( + 'error_msg' => dcngettext( + 'survey_accounts', + 'Instrument', + 'Instruments', + 1, + LC_MESSAGES + ).' '. $_REQUEST['TN'].' ' .dgettext( 'survey_accounts', 'already exists for given candidate for visit' ).' '. $_REQUEST['VL'], diff --git a/modules/survey_accounts/js/survey_accounts_helper.js b/modules/survey_accounts/js/survey_accounts_helper.js index e458048385..69d4834d23 100644 --- a/modules/survey_accounts/js/survey_accounts_helper.js +++ b/modules/survey_accounts/js/survey_accounts_helper.js @@ -41,7 +41,9 @@ $(document).ready(function () { } if (email.length > 0 && email2.length > 0 && email !== email2) { - $("#email-error").show().html("Emails do not match"); + $("#email-error") + .show() + .html($("#email-error").data("email-mismatch")); } } ); $("#emailData").click(function(){ @@ -60,7 +62,7 @@ $(document).ready(function () { }).appendTo("#participant_accounts_form"); $("#participant_accounts_form").submit(); }); - $("input[type=submit]").click(function (e) { + $("input[type=submit], button[type=submit]").click(function (e) { if(e.currentTarget.classList.contains('email')) { $.get(loris.BaseURL + "/survey_accounts/ajax/ValidateEmailSubmitInput.php", { dccid: $("input[name=CandID]").val(), diff --git a/modules/survey_accounts/jsx/surveyAccountsIndex.js b/modules/survey_accounts/jsx/surveyAccountsIndex.js index 96c40f9fe5..01cc2f4acb 100644 --- a/modules/survey_accounts/jsx/surveyAccountsIndex.js +++ b/modules/survey_accounts/jsx/surveyAccountsIndex.js @@ -9,6 +9,9 @@ import Loader from 'Loader'; import FilterableDataTable from 'FilterableDataTable'; import hiStrings from '../locale/hi/LC_MESSAGES/survey_accounts.json'; +import jaStrings from '../locale/ja/LC_MESSAGES/survey_accounts.json'; +import frCAStrings from '../locale/fr_CA/LC_MESSAGES/survey_accounts.json'; +import zhStrings from '../locale/zh/LC_MESSAGES/survey_accounts.json'; /** * Survey Account React Component */ @@ -73,7 +76,7 @@ class SurveyAccountsIndex extends Component { const url = loris.BaseURL + '/survey.php?key=' + row.URL; result = {cell}; break; - case t('Instrument', {ns: 'loris', count: 1}): + case t('Instrument', {ns: 'survey_accounts', count: 1}): result = {this.state.data.fieldOptions.instruments[cell]}; break; } @@ -110,20 +113,20 @@ class SurveyAccountsIndex extends Component { const options = this.state.data.fieldOptions; const fields = [ { - label: t('PSCID', {ns: 'loris'}), show: true, filter: { + label: t('PSCID', {ns: 'survey_accounts'}), show: true, filter: { name: 'pscid', type: 'text', }, }, { - label: t('Visit', {ns: 'loris'}), show: true, filter: { + label: t('Visit', {ns: 'survey_accounts'}), show: true, filter: { name: 'visit', type: 'select', options: options.visits, }, }, { - label: t('Instrument', {ns: 'loris', count: 1}), show: true, filter: { + label: t('Instrument', {ns: 'survey_accounts', count: 1}), show: true, filter: { name: 'instrument', type: 'select', options: options.instruments, @@ -139,7 +142,10 @@ class SurveyAccountsIndex extends Component { }, ]; const addSurvey = () => { - location.href = '/survey_accounts/addSurvey/'; + const params = new URLSearchParams(window.location.search); + const lang = params.get('lang'); + const query = lang ? `?lang=${encodeURIComponent(lang)}` : ''; + location.href = `${loris.BaseURL}/survey_accounts/addSurvey/${query}`; }; const actions = [ {label: t('Add Survey', {ns: 'survey_accounts'}), action: addSurvey}, @@ -167,8 +173,9 @@ SurveyAccountsIndex.propTypes = { window.addEventListener( 'load', () => { i18n.addResourceBundle('hi', 'survey_accounts', hiStrings); - i18n.addResourceBundle('ja', 'survey_accounts', {}); - i18n.addResourceBundle('zh', 'survey_accounts', {}); + i18n.addResourceBundle('ja', 'survey_accounts', jaStrings); + i18n.addResourceBundle('fr_CA', 'survey_accounts', frCAStrings); + i18n.addResourceBundle('zh', 'survey_accounts', zhStrings); const Index = withTranslation( ['survey_accounts'] )(SurveyAccountsIndex); diff --git a/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.po b/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.po new file mode 100644 index 0000000000..97b151dca6 --- /dev/null +++ b/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.po @@ -0,0 +1,129 @@ +# Default LORIS strings to be translated (French Canadian). +# Copy this to a language specific file and add translations to the +# new file. +# Copyright (C) 2025 +# This file is distributed under the same license as the LORIS package. +# Dave MacFarlane , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: LORIS 27\n" +"Report-Msgid-Bugs-To: https://github.com/aces/Loris/issues\n" +"POT-Creation-Date: 2025-04-08 14:37-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: French Canadian \n" +"Language: fr_CA\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Survey Accounts" +msgstr "Comptes de sondage" + +msgid "Survey was added successfully." +msgstr "Le sondage a été ajouté avec succès." + +msgid "Click here to go back to view the list of survey's created" +msgstr "Cliquez ici pour revenir à la liste des sondages créés" + +msgid "Survey List" +msgstr "Liste des sondages" + +msgid "Usage" +msgstr "Utilisation" + +msgid "Use this form to create a link for a study participant to use in order to directly enter a form/data into Loris." +msgstr "Utilisez ce formulaire pour créer un lien permettant à un participant à l'étude de saisir directement un formulaire/des données dans LORIS." + +msgid "Add Survey" +msgstr "Ajouter un sondage" + +msgid "Create survey" +msgstr "Créer un sondage" + +msgid "Email survey" +msgstr "Envoyer le sondage par courriel" + +msgid "Close" +msgstr "Fermer" + +msgid "Email to Study Participant" +msgstr "Courriel au participant à l'étude" + +msgid "Optionally enter a customized message here. A default email will be sent if left blank." +msgstr "Saisissez éventuellement un message personnalisé ici. Un courriel par défaut sera envoyé si ce champ est laissé vide." + +msgid "This is where your message goes." +msgstr "Votre message s'inscrit ici." + +msgid "Email" +msgstr "Adresse courriel" + +msgid "DCCID" +msgstr "DCCID" + +msgid "PSCID" +msgstr "PSCID" + +msgid "Visit" +msgstr "Visite" + +msgid "Visit Label" +msgstr "Libellé de visite" + +msgid "Email address" +msgstr "Adresse courriel" + +msgid "Instrument" +msgid_plural "Instruments" +msgstr[0] "Instrument" +msgstr[1] "Instruments" + +msgid "URL" +msgstr "URL" + +msgid "Status" +msgstr "Statut" + +msgid "Created" +msgstr "Créé" + +msgid "Sent" +msgstr "Envoyé" + +msgid "In Progress" +msgstr "En cours" + +msgid "Complete" +msgstr "Complété" + +msgid "PSCID and DCCID do not match or candidate does not exist." +msgstr "Le PSCID et le DCCID ne correspondent pas ou le candidat n'existe pas." + +msgid "does not exist for given candidate" +msgstr "n'existe pas pour le candidat donné" + +msgid "Please choose an instrument." +msgstr "Veuillez choisir un instrument." + +msgid "already exists for given candidate for visit" +msgstr "existe déjà pour le candidat donné pour la visite" + +msgid "The email address is not valid." +msgstr "L'adresse courriel n'est pas valide." + +msgid "Please confirm the email address." +msgstr "Veuillez confirmer l'adresse courriel." + +msgid "The email addresses do not match." +msgstr "Les adresses courriel ne correspondent pas." + +msgid "You must specify a valid Visit Label." +msgstr "Vous devez préciser un libellé de visite valide." + +msgid "You are not affiliated with this session's project" +msgstr "Vous n'êtes pas affilié au projet de cette session" + +msgid "Confirm Email address" +msgstr "Confirmer l'adresse courriel" diff --git a/modules/survey_accounts/locale/survey_accounts.pot b/modules/survey_accounts/locale/survey_accounts.pot index 9bd3b188f9..31ae876ad1 100644 --- a/modules/survey_accounts/locale/survey_accounts.pot +++ b/modules/survey_accounts/locale/survey_accounts.pot @@ -60,15 +60,43 @@ msgstr "" msgid "Email" msgstr "" -msgid "Instrument" +msgid "DCCID" +msgstr "" + +msgid "PSCID" msgstr "" +msgid "Visit" +msgstr "" + +msgid "Visit Label" +msgstr "" + +msgid "Email address" +msgstr "" + +msgid "Instrument" +msgid_plural "Instruments" +msgstr[0] "" + msgid "URL" msgstr "" msgid "Status" msgstr "" +msgid "Created" +msgstr "" + +msgid "Sent" +msgstr "" + +msgid "In Progress" +msgstr "" + +msgid "Complete" +msgstr "" + msgid "PSCID and DCCID do not match or candidate does not exist." msgstr "" @@ -96,8 +124,5 @@ msgstr "" msgid "You are not affiliated with this session's project" msgstr "" -msgid "Email is not valid." -msgstr "" - msgid "Confirm Email address" msgstr "" diff --git a/modules/survey_accounts/php/addsurvey.class.inc b/modules/survey_accounts/php/addsurvey.class.inc index 6635d4ed0e..d8271899f0 100644 --- a/modules/survey_accounts/php/addsurvey.class.inc +++ b/modules/survey_accounts/php/addsurvey.class.inc @@ -139,7 +139,7 @@ class AddSurvey extends \NDB_Form if ($numSessions != 1) { return [ - 'VL' => dgettext('loris', "Visit")." ". + 'VL' => dgettext('survey_accounts', "Visit")." ". $values['VL']." ". dgettext( 'survey_accounts', @@ -193,14 +193,20 @@ class AddSurvey extends \NDB_Form $instrument['Test_name'] ); return [ - 'Test_name' => "Instrument ". + 'Test_name' => dcngettext( + 'survey_accounts', + 'Instrument', + 'Instruments', + 1, + LC_MESSAGES + )." ". $instrument_instance->getFullName(). $reminder. $values['VL'], ]; } } if (!isset($_REQUEST['fire_away']) - || ($_REQUEST['fire_away'] !== 'Create survey') + || ($_REQUEST['fire_away'] !== 'create_survey') ) { if (!filter_var( $values['Email'], @@ -209,7 +215,7 @@ class AddSurvey extends \NDB_Form ) { return ['Email' => dgettext( 'survey_accounts', - 'Email is not valid.' + 'The email address is not valid.' ) ]; @@ -326,18 +332,28 @@ class AddSurvey extends \NDB_Form parent::setup(); $this->redirect = "test_name=$this->name"; - $this->addBasicText("CandID", "DCCID"); - $this->addBasicText("PSCID", "PSCID"); - $this->addSelect("VL", "Visit Label", \Utility::getVisitList()); + $this->addBasicText("CandID", dgettext('survey_accounts', 'DCCID')); + $this->addBasicText("PSCID", dgettext('survey_accounts', 'PSCID')); + $this->addSelect( + "VL", + dgettext('survey_accounts', 'Visit Label'), + \Utility::getVisitList() + ); $this->addSelect( "Test_name", - "Instrument", + dcngettext( + 'survey_accounts', + 'Instrument', + 'Instruments', + 1, + LC_MESSAGES + ), array_merge( ['' => ''], \NDB_BVL_Instrument::getDirectEntryInstrumentNamesList($this->loris) ) ); - $this->addBasicText("Email", "Email address"); + $this->addBasicText("Email", dgettext('survey_accounts', 'Email address')); $this->addBasicText( "Email2", dgettext('survey_accounts', 'Confirm Email address') diff --git a/modules/survey_accounts/php/survey_accounts.class.inc b/modules/survey_accounts/php/survey_accounts.class.inc index 42423878b6..d16bde3538 100644 --- a/modules/survey_accounts/php/survey_accounts.class.inc +++ b/modules/survey_accounts/php/survey_accounts.class.inc @@ -77,10 +77,10 @@ class Survey_Accounts extends \DataFrameworkMenu public function getFieldOptions() : array { $statusOptions = [ - 'Created' => dgettext("loris", "Created"), - 'Sent' => dgettext("loris", "Sent"), - 'In Progress' => dgettext("loris", "In Progress"), - 'Complete' => dgettext("loris", "Complete"), + 'Created' => dgettext("survey_accounts", "Created"), + 'Sent' => dgettext("survey_accounts", "Sent"), + 'In Progress' => dgettext("survey_accounts", "In Progress"), + 'Complete' => dgettext("survey_accounts", "Complete"), ]; $instruments diff --git a/modules/survey_accounts/templates/form_addSurvey.tpl b/modules/survey_accounts/templates/form_addSurvey.tpl index d24e0ff5e8..214783e656 100644 --- a/modules/survey_accounts/templates/form_addSurvey.tpl +++ b/modules/survey_accounts/templates/form_addSurvey.tpl @@ -31,7 +31,7 @@ {/foreach} - + @@ -60,8 +60,8 @@ - - + + {/if} From 3182174e1721da671e657d00414336f248945fa1 Mon Sep 17 00:00:00 2001 From: George Murad Date: Fri, 26 Jun 2026 10:08:06 -0400 Subject: [PATCH 5/7] add the json file --- .../fr_CA/LC_MESSAGES/survey_accounts.json | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.json diff --git a/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.json b/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.json new file mode 100644 index 0000000000..7155095871 --- /dev/null +++ b/modules/survey_accounts/locale/fr_CA/LC_MESSAGES/survey_accounts.json @@ -0,0 +1,39 @@ +{ + "Survey Accounts": "Comptes de sondage", + "Survey was added successfully.": "Le sondage a été ajouté avec succès.", + "Click here to go back to view the list of survey's created": "Cliquez ici pour revenir à la liste des sondages créés", + "Survey List": "Liste des sondages", + "Usage": "Utilisation", + "Use this form to create a link for a study participant to use in order to directly enter a form/data into Loris.": "Utilisez ce formulaire pour créer un lien permettant à un participant à l'étude de saisir directement un formulaire/des données dans LORIS.", + "Add Survey": "Ajouter un sondage", + "Create survey": "Créer un sondage", + "Email survey": "Envoyer le sondage par courriel", + "Close": "Fermer", + "Email to Study Participant": "Courriel au participant à l'étude", + "Optionally enter a customized message here. A default email will be sent if left blank.": "Saisissez éventuellement un message personnalisé ici. Un courriel par défaut sera envoyé si ce champ est laissé vide.", + "This is where your message goes.": "Votre message s'inscrit ici.", + "Email": "Adresse courriel", + "DCCID": "DCCID", + "PSCID": "PSCID", + "Visit": "Visite", + "Visit Label": "Libellé de visite", + "Email address": "Adresse courriel", + "Instrument": "Instrument", + "Instrument_plural": "Instruments", + "URL": "URL", + "Status": "Statut", + "Created": "Créé", + "Sent": "Envoyé", + "In Progress": "En cours", + "Complete": "Complété", + "PSCID and DCCID do not match or candidate does not exist.": "Le PSCID et le DCCID ne correspondent pas ou le candidat n'existe pas.", + "does not exist for given candidate": "n'existe pas pour le candidat donné", + "Please choose an instrument.": "Veuillez choisir un instrument.", + "already exists for given candidate for visit": "existe déjà pour le candidat donné pour la visite", + "The email address is not valid.": "L'adresse courriel n'est pas valide.", + "Please confirm the email address.": "Veuillez confirmer l'adresse courriel.", + "The email addresses do not match.": "Les adresses courriel ne correspondent pas.", + "You must specify a valid Visit Label.": "Vous devez préciser un libellé de visite valide.", + "You are not affiliated with this session's project": "Vous n'êtes pas affilié au projet de cette session", + "Confirm Email address": "Confirmer l'adresse courriel" +} \ No newline at end of file From f313af362ce5614a0c73f884143ad03178e55b99 Mon Sep 17 00:00:00 2001 From: George Murad Date: Fri, 26 Jun 2026 10:22:57 -0400 Subject: [PATCH 6/7] lint error --- modules/survey_accounts/ajax/ValidateEmailSubmitInput.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php b/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php index 4d9ac8b390..1ca9fe79d8 100644 --- a/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php +++ b/modules/survey_accounts/ajax/ValidateEmailSubmitInput.php @@ -69,7 +69,8 @@ if ($numSessions != 1) { echo json_encode( [ - 'error_msg' => dgettext('survey_accounts', 'Visit').' '. $_REQUEST['VL'].' '. + 'error_msg' => dgettext('survey_accounts', 'Visit').' '. + $_REQUEST['VL'].' '. dgettext('survey_accounts', 'does not exist for given candidate'), ] ); From fe6eedbed5c7f76fcc316c0495522fb080a4fda4 Mon Sep 17 00:00:00 2001 From: George Murad Date: Fri, 26 Jun 2026 10:34:58 -0400 Subject: [PATCH 7/7] eslint error --- modules/survey_accounts/jsx/surveyAccountsIndex.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/survey_accounts/jsx/surveyAccountsIndex.js b/modules/survey_accounts/jsx/surveyAccountsIndex.js index 01cc2f4acb..f776b2efa9 100644 --- a/modules/survey_accounts/jsx/surveyAccountsIndex.js +++ b/modules/survey_accounts/jsx/surveyAccountsIndex.js @@ -126,7 +126,9 @@ class SurveyAccountsIndex extends Component { }, }, { - label: t('Instrument', {ns: 'survey_accounts', count: 1}), show: true, filter: { + label: t('Instrument', {ns: 'survey_accounts', count: 1}), + show: true, + filter: { name: 'instrument', type: 'select', options: options.instruments,