From 98f489a910cf21cd86e41ae6d1219ae6ddb5cece Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Mon, 15 Jun 2026 18:40:23 -0400 Subject: [PATCH 01/13] Improve UI/UX for Terms and Conditions Review (CFM-501) --- .../AgreementCollectors/dispatch.inc | 220 +++--------------- .../templates/element/agreeDialog.php | 4 +- .../TermsAndConditionsController.php | 69 +++++- .../Model/Table/TermsAndConditionsTable.php | 20 +- app/templates/TermsAndConditions/review.php | 132 ++++------- app/templates/element/javascript.php | 4 +- app/webroot/css/co-base.css | 12 + 7 files changed, 155 insertions(+), 306 deletions(-) diff --git a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc index 11026edd3..12c5412d4 100644 --- a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc +++ b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc @@ -1,193 +1,29 @@ element('flash', []); - -// Make the Form fields editable -$this->Field->enableFormEditMode(); -?> - -

- -Form->create(null, [ - 'id' => 'agreement-form', - 'type' => 'post' -]); - - -?> - - - - - - - - - - - - - - - - -
- - - - url)): // We have a URL based T&C ?> - - - element('TermsAgreer.agreeDialog', ['vv_tc' => $tc]); ?> - - -
- Form->checkbox( - 'tc'.$tc['id'], - ['id' => 'tc'.$tc['id'], 'class' => 'form-check-input tc-agree-checkbox'] - ) . - $this->Form->label( - 'tc'.$tc['id'], - __d('operation','agree'), - ['class' => 'form-check-label'] - ) - ?> -
-
- - - \ No newline at end of file + /** + * COmanage Registry T&C Agreement Collectors Petition Fields + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.2.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + +// This dispatch uses the same user interface as the core TermsAndConditions/tandcs.inc template. + include ROOT . DS . 'templates' . DS . 'TermsAndConditions' . DS . 'tandcs.inc'; \ No newline at end of file diff --git a/app/plugins/TermsAgreer/templates/element/agreeDialog.php b/app/plugins/TermsAgreer/templates/element/agreeDialog.php index 0d710126d..49b25c244 100644 --- a/app/plugins/TermsAgreer/templates/element/agreeDialog.php +++ b/app/plugins/TermsAgreer/templates/element/agreeDialog.php @@ -57,9 +57,9 @@ -element('flash') // Flash messages ?> - - +element('flash') // Flash messages ?> + +Form->create(null); // We don't need an object for this form ?>
- - - - - - - - - - - - - - - - - - - - -
getName()]); ?>
-
-
- id; - $action_args['vv_actions'] = []; - - if($t['status'] != TAndCStatusEnum::Agreed) { - // T&C that are not current can be agreed to - - $action_args['vv_actions'][] = [ - 'order' => $this->Menu->getMenuOrder('Default'), - 'icon' => 'signature', - 'url' => [ - 'controller' => 'terms_and_conditions', - 'action' => 'agree', - $t['tandc']->id - ], - 'label' => __d('operation', 'agree'), - 'confirm' => [ - 'dg_body_txt' => __d('operation', 'TermsAndConditions.agree.confirm'), - 'dg_confirm_btn' => __d('operation', 'confirm') - ] - ]; - } + +
- if(!empty($action_args['vv_actions'])) { - print $this->element('menuAction', $action_args); - } - ?> -
- description; ?> - -
identifier ?? "" ?>created) - ? $this->Time->nice($t['agreement']->created, $vv_tz) - : ""; - ?>
+
+
+Form->end(); ?> \ No newline at end of file diff --git a/app/templates/element/javascript.php b/app/templates/element/javascript.php index f37219223..abb256c72 100644 --- a/app/templates/element/javascript.php +++ b/app/templates/element/javascript.php @@ -339,8 +339,8 @@ } }); - // Add a .nospin class to all on-page cake error and warning links - $(".cake-error a").addClass('nospin'); + // Add a .nospin class to all on-page cake error and warning links (and debugging accordions) + $(".cake-error a, a.cake-debug-collapse").addClass('nospin'); // Add loading animation when a form is submitted, when any item with a "spin" class is clicked, // or on any anchor tag lacking the .nospin class. We do not automatically add this to buttons diff --git a/app/webroot/css/co-base.css b/app/webroot/css/co-base.css index 3b59ef4ad..7e5ca1bb7 100644 --- a/app/webroot/css/co-base.css +++ b/app/webroot/css/co-base.css @@ -2555,6 +2555,18 @@ body.termsandconditions ul.form-list li.fields-url { .tc-agree-dialog .modal-body h6 { margin-bottom: 0.5em; } +/* Terms and Conditions Review hides most interface elements. + XXX If we find there is a general need to hide navigation elements outside of + enrollment flows and T&Cs, we'll do this more generically */ +body.termsandconditions.review #top-bar, +body.termsandconditions.review #breadcrumbs, +body.termsandconditions.review #navigation-drawer { + display: none; +} +body.termsandconditions.review #tandc-review-submit { + text-align: right; + margin: 1.5em 0 0; +} /* MOSTLY STATIC PAGES */ body.pages.logged-out #top-bar, body.pages.logged-out #breadcrumbs { From b8d117d2584951c3603218419dde66ca9f460f08 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Thu, 18 Jun 2026 17:58:02 -0400 Subject: [PATCH 02/13] Move common code and language strings from TermsAgreer plugin to core (CFM-501) --- .../resources/locales/en_US/terms_agreer.po | 9 - .../AgreementCollectors/dispatch.inc | 52 ++--- app/resources/locales/en_US/information.po | 9 + app/templates/TermsAndConditions/review.php | 5 +- app/templates/TermsAndConditions/tandcs.inc | 210 ++++++++++++++++++ .../element/tandcAgreeDialog.php} | 2 +- 6 files changed, 249 insertions(+), 38 deletions(-) create mode 100644 app/templates/TermsAndConditions/tandcs.inc rename app/{plugins/TermsAgreer/templates/element/agreeDialog.php => templates/element/tandcAgreeDialog.php} (97%) diff --git a/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po b/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po index b2c8b8cda..35da383df 100644 --- a/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po +++ b/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po @@ -43,15 +43,6 @@ msgstr "Did not receive agreement for \"{0}\" (T&C {1})" msgid "field.AgreementCollectors.t_and_c_mode" msgstr "Terms and Conditions Mode" -msgid "information.AgreementCollectors.external" -msgstr "These Terms and Conditions will be loaded in an external browser window. After review, you must return to this window and click \"Agree\" to continue." - -msgid "information.AgreementCollectors.review" -msgstr "You must review and agree to these Terms and Conditions before continuing." - -msgid "information.AgreementCollectors.review.tc" -msgstr "Review Terms & Conditions" - msgid "result.AgreementCollectors.ignored" msgstr "Terms and Conditions collection disabled" diff --git a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc index 12c5412d4..1e8cf7b2d 100644 --- a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc +++ b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc @@ -1,29 +1,29 @@ Form->create(null); // We don't need an object for this form ?>
diff --git a/app/templates/TermsAndConditions/tandcs.inc b/app/templates/TermsAndConditions/tandcs.inc new file mode 100644 index 000000000..ed9bc8dfc --- /dev/null +++ b/app/templates/TermsAndConditions/tandcs.inc @@ -0,0 +1,210 @@ +element('flash', []); + + // Make the Form fields editable + $this->Field->enableFormEditMode(); +?> + +

+ +Form->create(null, [ + 'id' => 'agreement-form', + 'type' => 'post' + ]); + + +?> + + + + + + + + + + + + + + $tc): ?> + + + + + + + + + + + + +
getName()]); ?>
+ + identifier ?? "" ?>created) + ? $this->Time->nice($vv_tandc_statuses[$i]['agreement']->created, $vv_tz) + : ""; + ?> + + url)): // We have a URL based T&C ?> + + + element('tandcAgreeDialog', ['vv_tc' => $tc]); ?> + + +
+ Form->checkbox( + 'tc'.$tc['id'], + [ + 'id' => 'tc'.$tc['id'], + 'class' => 'form-check-input tc-agree-checkbox', + 'checked' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] == 'Y' ? true : false, + ] + ) . + $this->Form->label( + 'tc'.$tc['id'], + __d('operation','agree'), + [ + 'class' => 'form-check-label' + ] + ) + ?> +
+
+ + \ No newline at end of file diff --git a/app/plugins/TermsAgreer/templates/element/agreeDialog.php b/app/templates/element/tandcAgreeDialog.php similarity index 97% rename from app/plugins/TermsAgreer/templates/element/agreeDialog.php rename to app/templates/element/tandcAgreeDialog.php index 49b25c244..63e384a90 100644 --- a/app/plugins/TermsAgreer/templates/element/agreeDialog.php +++ b/app/templates/element/tandcAgreeDialog.php @@ -52,7 +52,7 @@ + + +
+
- '; - print $this->Html->link( - // There might be a more elegant way to render this than appending - // it to the URL label... - $t['oldtandc']->description, - [ - 'controller' => 'terms_and_conditions', - // We can only view archive records, not edit - 'action' => 'view', - $t['oldtandc']->id - ] - ); - print $this->element('notify/alert', [ - 'message' => __d('information', 'TermsAndConditions.desc.old') - ]); - print '
'; - } else { - print $this->Html->link( - $t['tandc']->description, - [ - 'controller' => 'terms_and_conditions', - 'action' => 'edit', - $t['tandc']->id - ] - ); - } +
+ +
+ + +
+ +
+
+ identifier ?? "" ?> +
+ + +
+ getName()]); ?> +
+
+ created) + ? $this->Time->nice($t['agreement']->created, $vv_tz) + : ""; ?> -
+ - - identifier ?? "" ?> - created) - ? $this->Time->nice($t['agreement']->created, $vv_tz) - : ""; - ?> diff --git a/app/templates/TermsAndConditions/tandcs.inc b/app/templates/TermsAndConditions/tandcs.inc index 19468cbac..00cf2f585 100644 --- a/app/templates/TermsAndConditions/tandcs.inc +++ b/app/templates/TermsAndConditions/tandcs.inc @@ -45,81 +45,107 @@ ?> - - - - - - - - - - - - - - $tc): ?> - - - - - - - - + + + + +
getName()]); ?>
- - identifier ?? "" ?>created) - ? $this->Time->nice($vv_tandc_statuses[$i]['agreement']->created, $vv_tz) - : ""; - ?> - - url)): // We have a URL based T&C ?> - - - element('tandcAgreeDialog', ['vv_tc' => $tc]); ?> +
+ + + + + + + + + + + + + + + $tc): ?> + + + + + + - - - - - -
getName()]); ?>
+
+ +
+
+
+
+ +
+
+
+
+ identifier ?? "" ?> +
+
+
getName()]); ?>
+
+ created) + ? $this->Time->nice($vv_tandc_statuses[$i]['agreement']->created, $vv_tz) + : ""; + ?> +
+
-
- Form->checkbox( - 'tc'.$tc['id'], - [ - 'id' => 'tc'.$tc['id'], - 'class' => 'form-check-input tc-agree-checkbox', - 'checked' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] === 'Y' ? true : false, - 'data-id' => $tc['id'], - 'data-status' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] === 'Y' ? 'Y' : 'N', - 'data-coid' => !empty($vv_cur_co) ? $vv_cur_co?->id : -1 - ] - ) . - $this->Form->label( - 'tc'.$tc['id'], - __d('operation','agree'), - [ - 'class' => 'form-check-label' - ] - ) - ?> -
-
+
+
+
+ + url)): // We have a URL based T&C ?> + + + element('tandcAgreeDialog', ['vv_tc' => $tc]); ?> + +
+
+
+
+
+ Form->checkbox( + 'tc'.$tc['id'], + [ + 'id' => 'tc'.$tc['id'], + 'class' => 'form-check-input tc-agree-checkbox', + 'checked' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] === 'Y' ? true : false, + 'data-id' => $tc['id'], + 'data-status' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] === 'Y' ? 'Y' : 'N', + 'data-coid' => !empty($vv_cur_co) ? $vv_cur_co?->id : -1 + ] + ) . + $this->Form->label( + 'tc'.$tc['id'], + __d('operation','agree'), + [ + 'class' => 'form-check-label' + ] + ) + ?> +
+
+
+