diff --git a/asset-bundles.json b/asset-bundles.json index 9cc6dd3..fb9306a 100644 --- a/asset-bundles.json +++ b/asset-bundles.json @@ -10,6 +10,17 @@ } } }, + "js/pages/dashboard": { + "scripts": [ + "organisations/js/widgets/organisations.js", + "organisations/js/pages/dashboard.js" + ], + "options": { + "sprinkle": { + "onCollision": "merge" + } + } + }, "js/pages/organisation": { "scripts": [ "userfrosting/js/widgets/users.js", diff --git a/assets/organisations/css/organisations.css b/assets/organisations/css/organisations.css index 9c58d62..13d73bf 100644 --- a/assets/organisations/css/organisations.css +++ b/assets/organisations/css/organisations.css @@ -6,4 +6,16 @@ } .membership-pending { color: #ffd24a !important; +} + +.widget-organisations .widget-user-username, .widget-organisations .widget-user-desc { + margin-left: 0px; +} + +.widget-organisations .widget-user-desc { + text-overflow: ellipsis; + overflow: hidden; + width: 100%; + displaY: inline-block; + white-space: nowrap; } \ No newline at end of file diff --git a/assets/organisations/js/pages/dashboard.js b/assets/organisations/js/pages/dashboard.js new file mode 100644 index 0000000..ac27d51 --- /dev/null +++ b/assets/organisations/js/pages/dashboard.js @@ -0,0 +1,17 @@ +/** + * Page-specific Javascript file. Should generally be included as a separate asset bundle in your page template. + * example: {{ assets.js('js/pages/sign-in-or-register') | raw }} + * + * Target page: /dashboard + */ + +$(document).ready(function() { + // Table of organisations + var organisations = $("#widget-organisations"); + if (organisations.length) { + organisations.ufTable({ + dataUrl: site.uri.public + "/api/organisations", + useLoadingTransition: site.uf_table.use_loading_transition + }); + } +}); diff --git a/locale/en_US/messages.php b/locale/en_US/messages.php index 2ca65c8..2192da0 100644 --- a/locale/en_US/messages.php +++ b/locale/en_US/messages.php @@ -17,6 +17,9 @@ return [ 1 => 'Organisation', 2 => 'Organisations', + 'LATEST' => 'Latest Organisations', + 'VIEW_ALL' => 'View all organisations', + 'PAGE_DESCRIPTION' => 'A listing of the organisations for your site. Provides management tools for editing and deleting organisations.', 'DELETED_PAGE_DESCRIPTION' => 'A listing of the deleted organisations for your site. Provides management tools for restoring and permenently deleting organisations.', 'INFO_PAGE' => 'Organisation information page for {{name}}', @@ -164,6 +167,8 @@ return [ 2 => 'Administrators', ], + 'CREATED_ON' => 'Created on', + 'MERGE' => 'Merge', 'MERGE_INTO' => 'Merge into', 'MERGE_CANNOT_UNDONE' => 'This action cannot be undone.', diff --git a/routes/dashboard.php b/routes/dashboard.php new file mode 100644 index 0000000..ef0535e --- /dev/null +++ b/routes/dashboard.php @@ -0,0 +1,18 @@ +group('/dashboard', function () { + $this->get('', 'UserFrosting\Sprinkle\Organisations\Controller\DashboardController:pageDashboard') + ->setName('dashboard'); +})->add('authGuard')->add(new NoCache()); \ No newline at end of file diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php new file mode 100644 index 0000000..72e1f2b --- /dev/null +++ b/src/Controller/DashboardController.php @@ -0,0 +1,109 @@ +ci->authorizer; + + /** @var \Illuminate\Cache\Repository $cache */ + $cache = $this->ci->cache; + + /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = $this->ci->classMapper; + + /** @var \UserFrosting\Support\Repository\Repository $config */ + $config = $this->ci->config; + + /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ + $currentUser = $this->ci->currentUser; + + + // Access-controlled page + if (!$authorizer->checkAccess($currentUser, 'uri_dashboard')) { + throw new ForbiddenException(); + } + + // Probably a better way to do this + $users = $classMapper->getClassMapping('user')::orderBy('created_at', 'desc') + ->take(8) + ->get(); + + // Transform the `create_at` date in "x days ago" type of string + $users->transform(function ($item, $key) { + $item->registered = Carbon::parse($item->created_at)->diffForHumans(); + + return $item; + }); + + // Probably a better way to do this + $organisations = $classMapper->getClassMapping('organisation')::orderBy('created_at', 'desc') + ->take(4) + ->get(); + + // Transform the `create_at` date in "x days ago" type of string + $organisations->transform(function ($item, $key) { + $item->registered = Carbon::parse($item->created_at)->diffForHumans(); + + return $item; + }); + + // Get each sprinkle db version + $sprinkles = $this->ci->sprinkleManager->getSprinkleNames(); + + return $this->ci->view->render($response, 'pages/dashboard.html.twig', [ + 'counter' => [ + 'users' => $classMapper->getClassMapping('user')::count(), + 'roles' => $classMapper->getClassMapping('role')::count(), + 'groups' => $classMapper->getClassMapping('group')::count(), + 'organisations' => $classMapper->getClassMapping('organisation')::count(), + ], + 'info' => [ + 'version' => [ + 'UF' => \UserFrosting\VERSION, + 'php' => phpversion(), + 'database' => EnvironmentInfo::database(), + ], + 'database' => [ + 'name' => $config['db.default.database'], + ], + 'environment' => $this->ci->environment, + 'path' => [ + 'project' => \UserFrosting\ROOT_DIR, + ], + ], + 'sprinkles' => $sprinkles, + 'users' => $users, + 'organisations' => $organisations, + ]); + } +} \ No newline at end of file diff --git a/src/Database/Models/Organisation.php b/src/Database/Models/Organisation.php index ab6c345..a33682e 100644 --- a/src/Database/Models/Organisation.php +++ b/src/Database/Models/Organisation.php @@ -135,6 +135,19 @@ class Organisation extends Model implements OrganisationInterface, TokenOwnerInt ->where('flag_admin', true); } + /** + * Get a list of pending members within this organisation. + */ + public function pendingMembers() + { + /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this + ->belongsToMany($classMapper->getClassMapping('user'), 'organisation_members', 'organisation_id', 'user_id') + ->where('flag_approved', false); + } + /** * Delete this organisation from the database, along with any linked objects. * diff --git a/src/Sprunje/OrganisationSprunje.php b/src/Sprunje/OrganisationSprunje.php index e009c0c..7f44f9a 100644 --- a/src/Sprunje/OrganisationSprunje.php +++ b/src/Sprunje/OrganisationSprunje.php @@ -33,6 +33,7 @@ class OrganisationSprunje extends Sprunje 'member_count', 'admin_count', 'status', + 'created_at', ]; protected $filterable = [ @@ -42,6 +43,7 @@ class OrganisationSprunje extends Sprunje 'admin_count', 'status', 'info', + 'created_at', ]; protected $excludeForAll = [ @@ -136,4 +138,20 @@ class OrganisationSprunje extends Sprunje return $this; } + + /** + * Sort based on created date. + * + * @param Builder $query + * @param string $direction + * + * @return self + */ + protected function sortCreatedAt($query, $direction) + { + $query->orderBy('organisations.created_at', $direction) + ->orderby('organisations.id', $direction); + + return $this; + } } diff --git a/templates/pages/dashboard.html.twig b/templates/pages/dashboard.html.twig new file mode 100644 index 0000000..0f480da --- /dev/null +++ b/templates/pages/dashboard.html.twig @@ -0,0 +1,345 @@ +{% extends "@admin/pages/dashboard.html.twig" %} + +{% block body_matter %} + {% block info_boxes %} + + {% if hasRole('site-admin') or hasRole('organisations-admin') %} +