From 78a329cefae7121f58b88d37dc98e9c3f3bb4257 Mon Sep 17 00:00:00 2001 From: colemanw Date: Wed, 11 Oct 2023 19:23:44 -0400 Subject: [PATCH] Add user_dashboard core extension (alpha) Includes search displays to replace the user dashboard, minus the action links --- .gitignore | 1 + distmaker/core-ext.txt | 1 + .../ang/afsearchUserDashboard.aff.php | 32 +++ ext/user_dashboard/info.xml | 36 ++++ .../managed/Dashboard_Tag.mgd.php | 27 +++ ...vedSearch_UserDashboard_Activities.mgd.php | 175 +++++++++++++++ .../SavedSearch_UserDashboard_Groups.mgd.php | 149 +++++++++++++ .../SavedSearch_UserDashboard_Pledges.mgd.php | 146 +++++++++++++ .../UserDashboard_Contributions.mgd.php | 114 ++++++++++ .../managed/UserDashboard_Events.mgd.php | 106 ++++++++++ .../managed/UserDashboard_Memberships.mgd.php | 114 ++++++++++ .../managed/UserDashboard_PCPs.mgd.php | 98 +++++++++ .../UserDashboard_Relationships.mgd.php | 143 +++++++++++++ ext/user_dashboard/user_dashboard.civix.php | 200 ++++++++++++++++++ ext/user_dashboard/user_dashboard.php | 80 +++++++ 15 files changed, 1422 insertions(+) create mode 100644 ext/user_dashboard/ang/afsearchUserDashboard.aff.php create mode 100644 ext/user_dashboard/info.xml create mode 100644 ext/user_dashboard/managed/Dashboard_Tag.mgd.php create mode 100644 ext/user_dashboard/managed/SavedSearch_UserDashboard_Activities.mgd.php create mode 100644 ext/user_dashboard/managed/SavedSearch_UserDashboard_Groups.mgd.php create mode 100644 ext/user_dashboard/managed/SavedSearch_UserDashboard_Pledges.mgd.php create mode 100644 ext/user_dashboard/managed/UserDashboard_Contributions.mgd.php create mode 100644 ext/user_dashboard/managed/UserDashboard_Events.mgd.php create mode 100644 ext/user_dashboard/managed/UserDashboard_Memberships.mgd.php create mode 100644 ext/user_dashboard/managed/UserDashboard_PCPs.mgd.php create mode 100644 ext/user_dashboard/managed/UserDashboard_Relationships.mgd.php create mode 100644 ext/user_dashboard/user_dashboard.civix.php create mode 100644 ext/user_dashboard/user_dashboard.php diff --git a/.gitignore b/.gitignore index 20ab4f93a8..231ab14697 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ !/ext/civi_pledge !/ext/civi_report !/ext/scheduled_communications +!/ext/user_dashboard backdrop/ bower_components CRM/Case/xml/configuration diff --git a/distmaker/core-ext.txt b/distmaker/core-ext.txt index 9e2a64087f..1021333ca7 100644 --- a/distmaker/core-ext.txt +++ b/distmaker/core-ext.txt @@ -35,3 +35,4 @@ civi_member civi_pledge civi_report scheduled_communications +user_dashboard diff --git a/ext/user_dashboard/ang/afsearchUserDashboard.aff.php b/ext/user_dashboard/ang/afsearchUserDashboard.aff.php new file mode 100644 index 0000000000..acb8944bc9 --- /dev/null +++ b/ext/user_dashboard/ang/afsearchUserDashboard.aff.php @@ -0,0 +1,32 @@ + 'search', + 'title' => E::ts('User Dashboard'), + 'server_route' => 'civicrm/user', + 'permission' => ['access Contact Dashboard'], + 'layout' => '', + // temporary, remove after merging https://github.com/civicrm/civicrm-core/pull/27783 + 'requires' => ['af', 'afCore', 'crmSearchDisplayTable'], +]; + +// Add displays for every SavedSearch tagged "UserDashboard" +$searchDisplays = civicrm_api4('SearchDisplay', 'get', [ + 'checkPermissions' => FALSE, + 'select' => ['name', 'label', 'type:name', 'saved_search_id.name'], + 'where' => [ + ['saved_search_id.is_current', '=', TRUE], + ['saved_search_id.tags:name', 'IN', ['UserDashboard']], + ], + 'orderBy' => ['name' => 'ASC'], +]); +foreach ($searchDisplays as $display) { + $afform['layout'] .= << + <{$display['type:name']} search-name="{$display['saved_search_id.name']}" display-name="$display[name]"> + + HTML; +} + +return $afform; diff --git a/ext/user_dashboard/info.xml b/ext/user_dashboard/info.xml new file mode 100644 index 0000000000..4e87e481b1 --- /dev/null +++ b/ext/user_dashboard/info.xml @@ -0,0 +1,36 @@ + + + user_dashboard + User Dashboard + Adds a page for users to see their contributions, memberships, etc. + AGPL-3.0 + + CiviCRM + info@civicrm.org + + + http://FIXME + http://FIXME + http://FIXME + http://www.gnu.org/licenses/agpl-3.0.html + + 2023-10-07 + 1.0 + alpha + + 5.68.alpha1 + + This extension is still experimental + + + + + + CRM/UserDashboard + 23.02.1 + crmUserDashboard + + + mgd-php@1.0.0 + + diff --git a/ext/user_dashboard/managed/Dashboard_Tag.mgd.php b/ext/user_dashboard/managed/Dashboard_Tag.mgd.php new file mode 100644 index 0000000000..753a40b9e9 --- /dev/null +++ b/ext/user_dashboard/managed/Dashboard_Tag.mgd.php @@ -0,0 +1,27 @@ + 'Dashboard_Tag', + 'entity' => 'Tag', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'label' => E::ts('User Dashboard'), + 'name' => 'UserDashboard', + 'description' => E::ts('Search will appear on the User Dashboard page'), + 'is_reserved' => TRUE, + 'used_for' => [ + 'civicrm_saved_search', + ], + 'color' => '#5d677b', + ], + 'match' => [ + 'name', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/SavedSearch_UserDashboard_Activities.mgd.php b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Activities.mgd.php new file mode 100644 index 0000000000..65538659cc --- /dev/null +++ b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Activities.mgd.php @@ -0,0 +1,175 @@ + 'SavedSearch_UserDashboard_Activities', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Activities', + 'label' => E::ts('User Dashboard - Activities'), + 'api_entity' => 'Activity', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'subject', + 'activity_type_id:label', + 'GROUP_CONCAT(DISTINCT Activity_ActivityContact_Contact_01.sort_name) AS GROUP_CONCAT_Activity_ActivityContact_Contact_01_sort_name', + 'GROUP_CONCAT(DISTINCT Activity_ActivityContact_Contact_02.sort_name) AS GROUP_CONCAT_Activity_ActivityContact_Contact_02_sort_name', + 'activity_date_time', + 'status_id:label', + ], + 'orderBy' => [], + 'where' => [ + [ + 'status_id:name', + '!=', + 'Completed', + ], + ], + 'groupBy' => [ + 'id', + ], + 'join' => [ + [ + 'Contact AS Activity_ActivityContact_Contact_01', + 'LEFT', + 'ActivityContact', + [ + 'id', + '=', + 'Activity_ActivityContact_Contact_01.activity_id', + ], + [ + 'Activity_ActivityContact_Contact_01.record_type_id:name', + '=', + '"Activity Source"', + ], + ], + [ + 'Contact AS Activity_ActivityContact_Contact_02', + 'LEFT', + 'ActivityContact', + [ + 'id', + '=', + 'Activity_ActivityContact_Contact_02.activity_id', + ], + [ + 'Activity_ActivityContact_Contact_02.record_type_id:name', + '=', + '"Activity Targets"', + ], + ], + [ + 'Contact AS Activity_ActivityContact_Contact_03', + 'INNER', + 'ActivityContact', + [ + 'id', + '=', + 'Activity_ActivityContact_Contact_03.activity_id', + ], + [ + 'Activity_ActivityContact_Contact_03.record_type_id:name', + '=', + '"Activity Assignees"', + ], + [ + 'Activity_ActivityContact_Contact_03.id', + '=', + '"user_contact_id"', + ], + ], + ], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Activities_SearchDisplay_UserDashboard_Activities', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Activities', + 'label' => E::ts('Your Assigned Activities'), + 'saved_search_id.name' => 'UserDashboard_Activities', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'expose_limit' => TRUE, + 'hide_single' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'activity_type_id:label', + 'dataType' => 'Integer', + 'label' => E::ts('Type'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'subject', + 'dataType' => 'String', + 'label' => E::ts('Subject'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'GROUP_CONCAT_Activity_ActivityContact_Contact_01_sort_name', + 'dataType' => 'String', + 'label' => E::ts('Added by'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'GROUP_CONCAT_Activity_ActivityContact_Contact_02_sort_name', + 'dataType' => 'String', + 'label' => E::ts('With'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'activity_date_time', + 'dataType' => 'Timestamp', + 'label' => E::ts('Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'dataType' => 'Integer', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/SavedSearch_UserDashboard_Groups.mgd.php b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Groups.mgd.php new file mode 100644 index 0000000000..34c4d43b31 --- /dev/null +++ b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Groups.mgd.php @@ -0,0 +1,149 @@ + 'SavedSearch_UserDashboard_Groups', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Groups', + 'label' => E::ts('User Dashboard - Groups'), + 'api_entity' => 'Group', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'frontend_title', + 'Group_GroupContact_Contact_01.status:label', + 'MAX(Group_SubscriptionHistory_group_id_01.date) AS MAX_Group_SubscriptionHistory_group_id_01_date', + ], + 'orderBy' => [], + 'where' => [ + [ + 'Group_GroupContact_Contact_01.id', + '=', + 'user_contact_id', + ], + [ + 'visibility:name', + '=', + 'Public Pages', + ], + [ + 'is_active', + '=', + TRUE, + ], + ], + 'groupBy' => [ + 'id', + 'Group_GroupContact_Contact_01.id', + ], + 'join' => [ + [ + 'Contact AS Group_GroupContact_Contact_01', + 'LEFT', + 'GroupContact', + [ + 'id', + '=', + 'Group_GroupContact_Contact_01.group_id', + ], + ], + [ + 'SubscriptionHistory AS Group_SubscriptionHistory_group_id_01', + 'LEFT', + [ + 'id', + '=', + 'Group_SubscriptionHistory_group_id_01.group_id', + ], + [ + 'Group_SubscriptionHistory_group_id_01.contact_id', + '=', + '"user_contact_id"', + ], + ], + ], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Groups_SearchDisplay_UserDashboard_Groups', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Groups', + 'label' => E::ts('Your Group(s)'), + 'saved_search_id.name' => 'UserDashboard_Groups', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [ + [ + 'Group_GroupContact_Contact_01.status', + 'ASC', + ], + ], + 'limit' => 20, + 'pager' => [ + 'expose_limit' => TRUE, + 'hide_single' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'frontend_title', + 'dataType' => 'String', + 'label' => E::ts('Group'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'Group_GroupContact_Contact_01.status:label', + 'dataType' => 'String', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'MAX_Group_SubscriptionHistory_group_id_01_date', + 'dataType' => 'Timestamp', + 'label' => E::ts('Since'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + 'cssRules' => [ + [ + 'disabled', + 'Group_GroupContact_Contact_01.status', + '=', + 'Removed', + ], + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/SavedSearch_UserDashboard_Pledges.mgd.php b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Pledges.mgd.php new file mode 100644 index 0000000000..9b9f696c7b --- /dev/null +++ b/ext/user_dashboard/managed/SavedSearch_UserDashboard_Pledges.mgd.php @@ -0,0 +1,146 @@ + 'SavedSearch_UserDashboard_Pledges', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Pledges', + 'label' => E::ts('User Dashboard - Pledges'), + 'api_entity' => 'Pledge', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'amount', + 'SUM(Pledge_PledgePayment_pledge_id_01.actual_amount) AS SUM_Pledge_PledgePayment_pledge_id_01_actual_amount', + 'financial_type_id:label', + 'create_date', + 'MIN(Pledge_PledgePayment_pledge_id_02.scheduled_date) AS MIN_Pledge_PledgePayment_pledge_id_02_scheduled_date', + 'MAX(Pledge_PledgePayment_pledge_id_02.scheduled_amount) AS MAX_Pledge_PledgePayment_pledge_id_02_scheduled_amount', + 'status_id:label', + ], + 'orderBy' => [], + 'where' => [ + ['contact_id', '=', 'user_contact_id'], + ], + 'groupBy' => [ + 'id', + ], + 'join' => [ + [ + 'PledgePayment AS Pledge_PledgePayment_pledge_id_01', + 'LEFT', + ['id', '=', 'Pledge_PledgePayment_pledge_id_01.pledge_id'], + ['Pledge_PledgePayment_pledge_id_01.status_id:name', '=', '"Completed"'], + ], + [ + 'PledgePayment AS Pledge_PledgePayment_pledge_id_02', + 'LEFT', + ['id', '=', 'Pledge_PledgePayment_pledge_id_02.pledge_id'], + ['Pledge_PledgePayment_pledge_id_02.status_id:name', '!=', '"Completed"'], + ], + ], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Pledges_SearchDisplay_UserDashboard_Pledges', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Pledges', + 'label' => E::ts('Your Pledges'), + 'saved_search_id.name' => 'UserDashboard_Pledges', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'amount', + 'dataType' => 'Money', + 'label' => E::ts('Pledged'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'SUM_Pledge_PledgePayment_pledge_id_01_actual_amount', + 'dataType' => 'Money', + 'label' => E::ts('Total Paid'), + 'sortable' => TRUE, + 'empty_value' => '0', + ], + [ + 'type' => 'field', + 'key' => 'financial_type_id:label', + 'dataType' => 'Integer', + 'label' => E::ts('Pledged For'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'create_date', + 'dataType' => 'Timestamp', + 'label' => E::ts('Pledge Made'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'MIN_Pledge_PledgePayment_pledge_id_02_scheduled_date', + 'dataType' => 'Timestamp', + 'label' => E::ts('Next Pay Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'MAX_Pledge_PledgePayment_pledge_id_02_scheduled_amount', + 'dataType' => 'Money', + 'label' => E::ts('Next Amount'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'dataType' => 'Integer', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/UserDashboard_Contributions.mgd.php b/ext/user_dashboard/managed/UserDashboard_Contributions.mgd.php new file mode 100644 index 0000000000..d5b5638feb --- /dev/null +++ b/ext/user_dashboard/managed/UserDashboard_Contributions.mgd.php @@ -0,0 +1,114 @@ + 'SavedSearch_UserDashboard_Contributions', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Contributions', + 'label' => E::ts('User Dashboard - Contributions'), + 'api_entity' => 'Contribution', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'total_amount', + 'financial_type_id:label', + 'contribution_status_id:label', + 'receive_date', + 'receipt_date', + ], + 'orderBy' => [], + 'where' => [ + ['contact_id', '=', 'user_contact_id'], + ], + 'groupBy' => [], + 'join' => [], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Contributions_SearchDisplay_UserDashboard_Contributions', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Contributions', + 'label' => E::ts('Your Contribution(s)'), + 'saved_search_id.name' => 'UserDashboard_Contributions', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'total_amount', + 'dataType' => 'String', + 'label' => E::ts('Total Amount'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'financial_type_id:label', + 'dataType' => 'String', + 'label' => E::ts('Type'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'receive_date', + 'dataType' => 'Date', + 'label' => E::ts('Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'receipt_date', + 'dataType' => 'Date', + 'label' => E::ts('Receipt Sent'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'contribution_status_id:label', + 'dataType' => 'String', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/UserDashboard_Events.mgd.php b/ext/user_dashboard/managed/UserDashboard_Events.mgd.php new file mode 100644 index 0000000000..c1cb1087cd --- /dev/null +++ b/ext/user_dashboard/managed/UserDashboard_Events.mgd.php @@ -0,0 +1,106 @@ + 'SavedSearch_UserDashboard_Events', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Events', + 'label' => E::ts('User Dashboard - Events'), + 'api_entity' => 'Participant', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'event_id.title', + 'role_id:label', + 'status_id:label', + 'event_id.start_date', + ], + 'orderBy' => [], + 'where' => [ + ['contact_id', '=', 'user_contact_id'], + ], + 'groupBy' => [], + 'join' => [], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Events_SearchDisplay_UserDashboard_Events', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Events', + 'label' => E::ts('Your Event(s)'), + 'saved_search_id.name' => 'UserDashboard_Events', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'event_id.title', + 'dataType' => 'String', + 'label' => E::ts('Event'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'event_id.start_date', + 'dataType' => 'Date', + 'label' => E::ts('Event Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'role_id:label', + 'dataType' => 'String', + 'label' => E::ts('Role'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'dataType' => 'String', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/UserDashboard_Memberships.mgd.php b/ext/user_dashboard/managed/UserDashboard_Memberships.mgd.php new file mode 100644 index 0000000000..3604070c83 --- /dev/null +++ b/ext/user_dashboard/managed/UserDashboard_Memberships.mgd.php @@ -0,0 +1,114 @@ + 'SavedSearch_UserDashboard_Memberships', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Memberships', + 'label' => E::ts('User Dashboard - Memberships'), + 'api_entity' => 'Membership', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'membership_type_id:label', + 'status_id:label', + 'start_date', + 'end_date', + 'join_date', + ], + 'orderBy' => [], + 'where' => [ + ['contact_id', '=', 'user_contact_id'], + ], + 'groupBy' => [], + 'join' => [], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Memberships_SearchDisplay_UserDashboard_Memberships', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Memberships', + 'label' => E::ts('Your Membership(s)'), + 'saved_search_id.name' => 'UserDashboard_Memberships', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'membership_type_id:label', + 'dataType' => 'String', + 'label' => E::ts('Type'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'join_date', + 'dataType' => 'Date', + 'label' => E::ts('Member Since'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'start_date', + 'dataType' => 'Date', + 'label' => E::ts('Start Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'end_date', + 'dataType' => 'Date', + 'label' => E::ts('End Date'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'dataType' => 'String', + 'label' => E::ts('Status'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/UserDashboard_PCPs.mgd.php b/ext/user_dashboard/managed/UserDashboard_PCPs.mgd.php new file mode 100644 index 0000000000..4098795f14 --- /dev/null +++ b/ext/user_dashboard/managed/UserDashboard_PCPs.mgd.php @@ -0,0 +1,98 @@ + 'SavedSearch_UserDashboard_PCPs', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_PCPs', + 'label' => E::ts('User Dashboard - PCPs'), + 'api_entity' => 'PCP', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'title', + 'status_id:label', + 'page_id.frontend_title', + ], + 'orderBy' => [], + 'where' => [ + ['contact_id', '=', 'user_contact_id'], + ], + 'groupBy' => [], + 'join' => [], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_PCPs_SearchDisplay_UserDashboard_PCPs', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_PCPs', + 'label' => E::ts('Personal Campaign Pages'), + 'saved_search_id.name' => 'UserDashboard_PCPs', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'title', + 'dataType' => 'String', + 'label' => E::ts('Title'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'status_id:label', + 'dataType' => 'String', + 'label' => E::ts('Type'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'page_id.frontend_title', + 'dataType' => 'String', + 'label' => E::ts('Campaign'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/managed/UserDashboard_Relationships.mgd.php b/ext/user_dashboard/managed/UserDashboard_Relationships.mgd.php new file mode 100644 index 0000000000..85c7a653dc --- /dev/null +++ b/ext/user_dashboard/managed/UserDashboard_Relationships.mgd.php @@ -0,0 +1,143 @@ + 'SavedSearch_UserDashboard_Relationships', + 'entity' => 'SavedSearch', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Relationships', + 'label' => E::ts('User Dashboard - Relationships'), + 'api_entity' => 'RelationshipCache', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'near_relation:label', + 'RelationshipCache_Contact_far_contact_id_01.display_name', + 'start_date', + 'RelationshipCache_Contact_far_contact_id_01.address_primary.city', + 'RelationshipCache_Contact_far_contact_id_01.address_primary.state_province_id:label', + 'RelationshipCache_Contact_far_contact_id_01.email_primary.email', + 'RelationshipCache_Contact_far_contact_id_01.phone_primary.phone', + ], + 'orderBy' => [], + 'where' => [ + ['near_contact_id', '=', 'user_contact_id'], + ['is_current', '=', TRUE], + ], + 'groupBy' => [], + 'join' => [ + [ + 'Contact AS RelationshipCache_Contact_far_contact_id_01', + 'LEFT', + ['far_contact_id', '=', 'RelationshipCache_Contact_far_contact_id_01.id'], + ], + ], + 'having' => [], + ], + ], + 'match' => [ + 'name', + ], + ], + ], + [ + 'name' => 'SavedSearch_UserDashboard_Relationships_SearchDisplay_UserDashboard_Relationships', + 'entity' => 'SearchDisplay', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'UserDashboard_Relationships', + 'label' => E::ts('Your Contacts / Organizations'), + 'saved_search_id.name' => 'UserDashboard_Relationships', + 'type' => 'table', + 'settings' => [ + 'description' => NULL, + 'sort' => [], + 'limit' => 20, + 'pager' => [ + 'hide_single' => TRUE, + 'expose_limit' => TRUE, + ], + 'placeholder' => 1, + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'near_relation:label', + 'dataType' => 'String', + 'label' => E::ts('Relationship'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'RelationshipCache_Contact_far_contact_id_01.display_name', + 'dataType' => 'String', + 'label' => E::ts('With'), + 'sortable' => TRUE, + 'icons' => [ + [ + 'field' => 'RelationshipCache_Contact_far_contact_id_01.contact_sub_type:icon', + 'side' => 'left', + ], + [ + 'field' => 'RelationshipCache_Contact_far_contact_id_01.contact_type:icon', + 'side' => 'left', + ], + ], + ], + [ + 'type' => 'field', + 'key' => 'start_date', + 'dataType' => 'Date', + 'label' => E::ts('Since'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'RelationshipCache_Contact_far_contact_id_01.address_primary.city', + 'dataType' => 'String', + 'label' => E::ts('City'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'RelationshipCache_Contact_far_contact_id_01.address_primary.state_province_id:label', + 'dataType' => 'Integer', + 'label' => E::ts('State/Prov'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'RelationshipCache_Contact_far_contact_id_01.email_primary.email', + 'dataType' => 'String', + 'label' => E::ts('Email'), + 'sortable' => TRUE, + ], + [ + 'type' => 'field', + 'key' => 'RelationshipCache_Contact_far_contact_id_01.phone_primary.phone', + 'dataType' => 'String', + 'label' => E::ts('Phone'), + 'sortable' => TRUE, + ], + ], + 'actions' => FALSE, + 'classes' => [ + 'table', + 'table-striped', + ], + ], + ], + 'match' => [ + 'name', + 'saved_search_id', + ], + ], + ], +]; diff --git a/ext/user_dashboard/user_dashboard.civix.php b/ext/user_dashboard/user_dashboard.civix.php new file mode 100644 index 0000000000..3f00bdefde --- /dev/null +++ b/ext/user_dashboard/user_dashboard.civix.php @@ -0,0 +1,200 @@ +getUrl(self::LONG_NAME), '/'); + } + return CRM_Core_Resources::singleton()->getUrl(self::LONG_NAME, $file); + } + + /** + * Get the path of a resource file (in this extension). + * + * @param string|NULL $file + * Ex: NULL. + * Ex: 'css/foo.css'. + * @return string + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo'. + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo/css/foo.css'. + */ + public static function path($file = NULL) { + // return CRM_Core_Resources::singleton()->getPath(self::LONG_NAME, $file); + return __DIR__ . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file)); + } + + /** + * Get the name of a class within this extension. + * + * @param string $suffix + * Ex: 'Page_HelloWorld' or 'Page\\HelloWorld'. + * @return string + * Ex: 'CRM_Foo_Page_HelloWorld'. + */ + public static function findClass($suffix) { + return self::CLASS_PREFIX . '_' . str_replace('\\', '_', $suffix); + } + +} + +use CRM_UserDashboard_ExtensionUtil as E; + +/** + * (Delegated) Implements hook_civicrm_config(). + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config + */ +function _user_dashboard_civix_civicrm_config($config = NULL) { + static $configured = FALSE; + if ($configured) { + return; + } + $configured = TRUE; + + $extRoot = __DIR__ . DIRECTORY_SEPARATOR; + $include_path = $extRoot . PATH_SEPARATOR . get_include_path(); + set_include_path($include_path); + // Based on , this does not currently require mixin/polyfill.php. +} + +/** + * Implements hook_civicrm_install(). + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install + */ +function _user_dashboard_civix_civicrm_install() { + _user_dashboard_civix_civicrm_config(); + // Based on , this does not currently require mixin/polyfill.php. +} + +/** + * (Delegated) Implements hook_civicrm_enable(). + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable + */ +function _user_dashboard_civix_civicrm_enable(): void { + _user_dashboard_civix_civicrm_config(); + // Based on , this does not currently require mixin/polyfill.php. +} + +/** + * Inserts a navigation menu item at a given place in the hierarchy. + * + * @param array $menu - menu hierarchy + * @param string $path - path to parent of this item, e.g. 'my_extension/submenu' + * 'Mailing', or 'Administer/System Settings' + * @param array $item - the item to insert (parent/child attributes will be + * filled for you) + * + * @return bool + */ +function _user_dashboard_civix_insert_navigation_menu(&$menu, $path, $item) { + // If we are done going down the path, insert menu + if (empty($path)) { + $menu[] = [ + 'attributes' => array_merge([ + 'label' => $item['name'] ?? NULL, + 'active' => 1, + ], $item), + ]; + return TRUE; + } + else { + // Find an recurse into the next level down + $found = FALSE; + $path = explode('/', $path); + $first = array_shift($path); + foreach ($menu as $key => &$entry) { + if ($entry['attributes']['name'] == $first) { + if (!isset($entry['child'])) { + $entry['child'] = []; + } + $found = _user_dashboard_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item); + } + } + return $found; + } +} + +/** + * (Delegated) Implements hook_civicrm_navigationMenu(). + */ +function _user_dashboard_civix_navigationMenu(&$nodes) { + if (!is_callable(['CRM_Core_BAO_Navigation', 'fixNavigationMenu'])) { + _user_dashboard_civix_fixNavigationMenu($nodes); + } +} + +/** + * Given a navigation menu, generate navIDs for any items which are + * missing them. + */ +function _user_dashboard_civix_fixNavigationMenu(&$nodes) { + $maxNavID = 1; + array_walk_recursive($nodes, function($item, $key) use (&$maxNavID) { + if ($key === 'navID') { + $maxNavID = max($maxNavID, $item); + } + }); + _user_dashboard_civix_fixNavigationMenuItems($nodes, $maxNavID, NULL); +} + +function _user_dashboard_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID) { + $origKeys = array_keys($nodes); + foreach ($origKeys as $origKey) { + if (!isset($nodes[$origKey]['attributes']['parentID']) && $parentID !== NULL) { + $nodes[$origKey]['attributes']['parentID'] = $parentID; + } + // If no navID, then assign navID and fix key. + if (!isset($nodes[$origKey]['attributes']['navID'])) { + $newKey = ++$maxNavID; + $nodes[$origKey]['attributes']['navID'] = $newKey; + $nodes[$newKey] = $nodes[$origKey]; + unset($nodes[$origKey]); + $origKey = $newKey; + } + if (isset($nodes[$origKey]['child']) && is_array($nodes[$origKey]['child'])) { + _user_dashboard_civix_fixNavigationMenuItems($nodes[$origKey]['child'], $maxNavID, $nodes[$origKey]['attributes']['navID']); + } + } +} diff --git a/ext/user_dashboard/user_dashboard.php b/ext/user_dashboard/user_dashboard.php new file mode 100644 index 0000000000..5cd4495aa7 --- /dev/null +++ b/ext/user_dashboard/user_dashboard.php @@ -0,0 +1,80 @@ +name, 'UserDashboard_')) { + return; + } + + // Transition note: the legacy dashboard used a setting ('user_dashboard_options') + // to control which panes are enabled. + // This new extension uses a tag. + // For the next year or so, we'll conditionally tag the searches in this extension based on that setting. + // When the transition is complete, the setting can be deleted and this class can be simplified to unconditionally + // tag all SavedSearches in this extension. + $legacySetting = Civi\Api4\Setting::get(FALSE) + ->addSelect('user_dashboard_options:name') + ->execute() + ->first(); + + // If the legacy setting corresponding to this pane is enabled, tag it + $settingNames = [ + 'UserDashboard_Activities' => 'Assigned Activities', + 'UserDashboard_Groups' => 'Groups', + 'UserDashboard_Pledges' => 'CiviPledge', + 'UserDashboard_Contributions' => 'CiviContribute', + 'UserDashboard_Events' => 'CiviEvent', + 'UserDashboard_Memberships' => 'CiviMember', + 'UserDashboard_PCPs' => 'PCP', + 'UserDashboard_Relationships' => 'Permissioned Orgs', + ]; + + $settingName = $settingNames[$savedSearch->name] ?? NULL; + + if (!$settingName || in_array($settingName, $legacySetting['value'], TRUE)) { + Civi\Api4\EntityTag::save(FALSE) + ->addRecord(['entity_table' => 'civicrm_saved_search', 'entity_id' => $id, 'tag_id:name' => 'UserDashboard']) + ->execute(); + } +} -- 2.25.1