Improve the visuals and the content of the expiring licenses box
authorAlexander Ebert <ebert@woltlab.com>
Wed, 14 Feb 2024 14:30:11 +0000 (15:30 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 14 Feb 2024 14:30:11 +0000 (15:30 +0100)
wcfsetup/install/files/acp/style/layout.scss
wcfsetup/install/files/acp/templates/expiringLicensesAcpDashboardBox.tpl
wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php
wcfsetup/install/files/lib/system/acp/dashboard/box/AbstractAcpDashboardBox.class.php
wcfsetup/install/files/lib/system/acp/dashboard/box/CreditsAcpDashboardBox.class.php
wcfsetup/install/files/lib/system/acp/dashboard/box/ExpiringLicensesAcpDashboardBox.class.php
wcfsetup/install/files/lib/system/acp/dashboard/box/NewsAcpDashboardBox.class.php
wcfsetup/install/files/lib/system/acp/dashboard/box/SystemInfoAcpDashboardBox.class.php
wcfsetup/install/files/lib/system/acp/dashboard/box/UsersAwaitingApprovalAcpDashboardBox.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 4aac5df7d43b7a20673124f81acdc4c55f0e3054..2836b9d45e29ed26abf00e706a4d11709a49be6a 100644 (file)
@@ -877,6 +877,16 @@ html[data-color-scheme="dark"] {
        padding: 0;
 }
 
+.acpDashboardBox[data-name="com.woltlab.wcf.expiringLicenses"] {
+       border-color: var(--wcfStatusErrorBorder);
+
+       .acpDashboardBox__title {
+               background-color: var(--wcfStatusErrorBackground);
+               border-color: var(--wcfStatusErrorBorder);
+               color: var(--wcfStatusErrorText);
+       }
+}
+
 .woltlabNewsfeed {
        border-radius: 0 0 var(--wcfBorderRadius) var(--wcfBorderRadius);
        height: 400px;
@@ -1012,3 +1022,17 @@ html[data-color-scheme="dark"] {
        display: flex;
        flex-direction: column;
 }
+
+.acpDashboardBox__explanation {
+       @include wcfFontSmall;
+
+       &.acpDashboardBox__explanation--cta {
+               font-weight: 600;
+               text-align: center;
+       }
+}
+
+.acpDashboardBox__cta {
+       margin-top: 20px;
+       text-align: center;
+}
index b23d608d511c04303a20f9aaa11594c0f740f000..fc66c28c94c6ebecf0266c214a6467e7009ad37d 100644 (file)
@@ -1,11 +1,16 @@
 {hascontent}
        <div class="acpDashboardBox__keyValueGroup">
-               <h2 class="acpDashboardBox__keyValueGroup_title">{lang}wcf.acp.dashboard.box.expiringLicenses{/lang}</h2>
+               <p class="acpDashboardBox__explanation">
+                       {lang}wcf.acp.dashboard.box.expiringLicenses.expiringSoon{/lang}
+               </p>
+               <p class="acpDashboardBox__explanation acpDashboardBox__explanation--cta">
+                       {lang}wcf.acp.dashboard.box.expiringLicenses.expiringSoon.cta{/lang}
+               </p>
                {content}
                        {foreach from=$expiringLicenses item=date key=packageName}
                                <dl class="plain acpDashboardBox__keyValue">
                                        <dd class="acpDashboardBox__keyValue__key">{$packages[$packageName]}</dd>
-                                       <dt class="acpDashboardBox__keyValue__value">{dateInterval end=$date}</dt>
+                                       <dt class="acpDashboardBox__keyValue__value" title="{$date|plainTime}">{dateInterval end=$date}</dt>
                                </dl>
                        {/foreach}
                {/content}
@@ -13,7 +18,9 @@
 {/hascontent}
 {hascontent}
        <div class="acpDashboardBox__keyValueGroup">
-               <h2 class="acpDashboardBox__keyValueGroup_title">{lang}wcf.acp.dashboard.box.expiredLicenses{/lang}</h2>
+               <p class="acpDashboardBox__explanation">
+                       {lang}wcf.acp.dashboard.box.expiringLicenses.expired{/lang}
+               </p>
                {content}
                        {foreach from=$expiredLicenses item=date key=packageName}
                                <dl class="plain acpDashboardBox__keyValue">
@@ -24,3 +31,7 @@
                {/content}
        </div>
 {/hascontent}
+
+<div class="acpDashboardBox__cta">
+       <a href="{$ctaLink}" class="button buttonPrimary" rel="nofollow noopener">{lang}wcf.acp.dashboard.box.expiringLicenses.cta{/lang}</a>
+</div>
index 743bffaf90d14d8dba22c2c6ed4995c30131dadb..c34690f0975fe0ad3a33a15c53100091b8830c65 100644 (file)
@@ -77,10 +77,10 @@ return static function (): void {
     $eventHandler->register(AcpDashboardCollecting::class, static function (AcpDashboardCollecting $event) {
         $event->register(new \wcf\system\acp\dashboard\box\NewsAcpDashboardBox());
         $event->register(new \wcf\system\acp\dashboard\box\StatusMessageAcpDashboardBox());
+        $event->register(new \wcf\system\acp\dashboard\box\ExpiringLicensesAcpDashboardBox());
         $event->register(new \wcf\system\acp\dashboard\box\UsersAwaitingApprovalAcpDashboardBox());
         $event->register(new \wcf\system\acp\dashboard\box\SystemInfoAcpDashboardBox());
         $event->register(new \wcf\system\acp\dashboard\box\CreditsAcpDashboardBox());
-        $event->register(new \wcf\system\acp\dashboard\box\ExpiringLicensesAcpDashboardBox());
     });
 
     try {
index 7aab45bb76d06756474949a50eb7520778141e60..34076be10ab9ba217b610903d69f70e3f425217f 100644 (file)
@@ -12,11 +12,13 @@ namespace wcf\system\acp\dashboard\box;
  */
 abstract class AbstractAcpDashboardBox implements IAcpDashboardBox
 {
+    #[\Override]
     public function isAccessible(): bool
     {
         return true;
     }
 
+    #[\Override]
     public function hasContent(): bool
     {
         return true;
index de24bafc5795778592b9c18f12e76edda89758c0..cd998ae8729fd89bbd9bcf0505c34f43fe2fb4d4 100644 (file)
@@ -14,16 +14,19 @@ use wcf\system\WCF;
  */
 final class CreditsAcpDashboardBox extends AbstractAcpDashboardBox
 {
+    #[\Override]
     public function getTitle(): string
     {
         return WCF::getLanguage()->get('wcf.acp.dashboard.box.credits');
     }
 
+    #[\Override]
     public function getContent(): string
     {
         return WCF::getTPL()->fetch('creditsAcpDashboardBox');
     }
 
+    #[\Override]
     public function getName(): string
     {
         return 'com.woltlab.wcf.credits';
index 7bbfa56f8c88509975b37f7b50c3de502a60a9a3..0f69f5c7e7df186f9f1a1cb24dcbac858c794c24 100644 (file)
@@ -11,7 +11,7 @@ use wcf\system\WCF;
  * ACP dashboard box listing expired and expiring licenses.
  *
  * @author      Olaf Braun
- * @copyright   2001-2023 WoltLab GmbH
+ * @copyright   2001-2024 WoltLab GmbH
  * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @since       6.1
  */
@@ -67,24 +67,39 @@ final class ExpiringLicensesAcpDashboardBox extends AbstractAcpDashboardBox
         return $this->licenseData;
     }
 
+    #[\Override]
     public function getTitle(): string
     {
-        return WCF::getLanguage()->get('wcf.acp.dashboard.box.expiredLicenses.title');
+        return WCF::getLanguage()->get('wcf.acp.dashboard.box.expiringLicenses');
     }
 
+    #[\Override]
     public function getContent(): string
     {
         $packages = [];
         foreach (\array_keys($this->getExpiredLicenses()) as $packageName) {
             $packages[$packageName] = PackageCache::getInstance()->getPackageByIdentifier($packageName);
         }
+
+        $licenseNo = $this->getLicenseData()->getLicenseNumber();
+        if ($licenseNo === null) {
+            $ctaLink = 'https://www.woltlab.com/license-list/';
+        } else {
+            $ctaLink = \sprintf(
+                'https://www.woltlab.com/license-extend/%s/',
+                $licenseNo,
+            );
+        }
+
         return WCF::getTPL()->fetch('expiringLicensesAcpDashboardBox', 'wcf', [
             'packages' => $packages,
             'expiredLicenses' => \array_filter($this->getExpiredLicenses(), fn($date) => $date < \TIME_NOW),
             'expiringLicenses' => \array_filter($this->getExpiredLicenses(), fn($date) => $date >= \TIME_NOW),
-        ]);
+            'ctaLink' => $ctaLink,
+        ], true);
     }
 
+    #[\Override]
     public function getName(): string
     {
         return 'com.woltlab.wcf.expiringLicenses';
index 491e3d02ea34cbe8cdf652a1eb6cf0b3ad5bbefd..0bb6875273c9151dc5aad8bb44523245245f6ab2 100644 (file)
@@ -14,16 +14,19 @@ use wcf\system\WCF;
  */
 final class NewsAcpDashboardBox extends AbstractAcpDashboardBox
 {
+    #[\Override]
     public function getTitle(): string
     {
         return WCF::getLanguage()->get('wcf.acp.dashboard.box.news');
     }
 
+    #[\Override]
     public function getContent(): string
     {
         return WCF::getTPL()->fetch('newsAcpDashboardBox');
     }
 
+    #[\Override]
     public function getName(): string
     {
         return 'com.woltlab.wcf.news';
index 02db27395d720effefe8ddc009f8281ffe3c1174..8d21cf48aa44b634dc8d4c6e563c269c454cd93b 100644 (file)
@@ -14,16 +14,19 @@ use wcf\system\WCF;
  */
 final class SystemInfoAcpDashboardBox extends AbstractAcpDashboardBox
 {
+    #[\Override]
     public function getTitle(): string
     {
         return WCF::getLanguage()->get('wcf.acp.dashboard.box.systemInfo');
     }
 
+    #[\Override]
     public function getContent(): string
     {
-        return WCF::getTPL()->fetch('systemInfoAcpDashboardBox', 'wcf', $this->getVariables());
+        return WCF::getTPL()->fetch('systemInfoAcpDashboardBox', 'wcf', $this->getVariables(), true);
     }
 
+    #[\Override]
     public function getName(): string
     {
         return 'com.woltlab.wcf.systemInfo';
index 8f16b188f634e06554350b7884969a4c7c9c4029..b82ab73882b294343e5d4712fa0c726dc74ac437 100644 (file)
@@ -32,6 +32,7 @@ final class UsersAwaitingApprovalAcpDashboardBox extends AbstractAcpDashboardBox
         return $this->getUsersAwaitingApproval() !== 0;
     }
 
+    #[\Override]
     public function getTitle(): string
     {
         return WCF::getLanguage()->getDynamicVariable('wcf.acp.dashboard.box.usersAwaitingApproval', [
@@ -39,6 +40,7 @@ final class UsersAwaitingApprovalAcpDashboardBox extends AbstractAcpDashboardBox
         ]);
     }
 
+    #[\Override]
     public function getContent(): string
     {
         $userList = $this->getUserList();
@@ -50,6 +52,7 @@ final class UsersAwaitingApprovalAcpDashboardBox extends AbstractAcpDashboardBox
         ]);
     }
 
+    #[\Override]
     public function getName(): string
     {
         return 'com.woltlab.wcf.usersAwaitingApproval';
index 7e18e59d3b443d7e1ea2cd27bbd587639b09ae4d..815d0b0b68b2882c34fbe44ec8f77f839a6f2946 100644 (file)
@@ -959,9 +959,11 @@ Sie erreichen das Fehlerprotokoll unter: {link controller='ExceptionLogView' isE
                <item name="wcf.acp.dashboard.box.statusMessage"><![CDATA[Status]]></item>
                <item name="wcf.acp.dashboard.box.missing.extensions"><![CDATA[Die {plural value=$missingExtensions|count one='PHP-Erweiterung' other='PHP-Erweiterungen'} {implode from=$missingExtensions item=extension}<strong>{$extension}</strong>{/implode} {plural value=$missingExtensions|count one='fehlt' other='fehlen'}.]]></item>
                <item name="wcf.acp.dashboard.configure"><![CDATA[Dashboard konfigurieren]]></item>
-               <item name="wcf.acp.dashboard.box.expiredLicenses.title"><![CDATA[Zugang zu Updates und Support]]></item>
-               <item name="wcf.acp.dashboard.box.expiredLicenses"><![CDATA[Nicht mehr berechtigt]]></item>
-               <item name="wcf.acp.dashboard.box.expiringLicenses"><![CDATA[Endet demnächst]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses"><![CDATA[Zugang zu Updates und Support]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expiringSoon"><![CDATA[Die Lizenzen für die folgenden Produkte laufen demnächst aus, damit {if LANGUAGE_USE_INFORMAL_VARIANT}verlierst du{else}verlieren Sie{/if} den Anspruch auf Updates und den Zugang zum Ticket-Support.]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expiringSoon.cta"><![CDATA[Jetzt verlängern und 10% Rabatt sichern!]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expired"><![CDATA[Die Lizenzen für die folgenden Produkte sind ausgelaufen und berechtigen nicht länger zum Zugriff auf neue Versionen sowie den Ticket-Support.]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.cta"><![CDATA[Jetzt Lizenzen verlängern ↗]]></item>
        </category>
        <category name="wcf.acp.index">
                <item name="wcf.acp.index.inRescueMode"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du rufst{else}Sie rufen{/if} diese Installation über eine abweichende Domain auf, etwa aufgrund eines Umzuges. Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}korrigiere{else}korrigieren Sie{/if} die Einstellungen unter <a href="{link controller='ApplicationManagement'}{/link}">Apps verwalten</a>.]]></item>
index af87208917f0b902f48d486418ca65e5c96906a3..2e5ef4cf5f87db83423229cea0a3ebd5db50c22c 100644 (file)
@@ -937,9 +937,11 @@ You can access the error log at: {link controller='ExceptionLogView' isEmail=tru
                <item name="wcf.acp.dashboard.box.statusMessage"><![CDATA[Status]]></item>
                <item name="wcf.acp.dashboard.box.missing.extensions"><![CDATA[The PHP {plural value=$missingExtensions|count one='extension' other='extensions'} {implode from=$missingExtensions item=extension}<strong>{$extension}</strong>{/implode} {plural value=$missingExtensions|count one='is' other='are'} missing.]]></item>
                <item name="wcf.acp.dashboard.configure"><![CDATA[Configure Dashboard]]></item>
-               <item name="wcf.acp.dashboard.box.expiredLicenses.title"><![CDATA[Access to updates and support]]></item>
-               <item name="wcf.acp.dashboard.box.expiredLicenses"><![CDATA[No longer authorised]]></item>
-               <item name="wcf.acp.dashboard.box.expiringLicenses"><![CDATA[Ends soon]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses"><![CDATA[Access to Updates and Support]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expiringSoon"><![CDATA[The licenses for the following products are about to expire and you will lose your entitlement to updates and access to ticket support.]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expiringSoon.cta"><![CDATA[Renew now and get a 10% discount!]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.expired"><![CDATA[The licenses for the following products have expired and no longer entitle you to access new versions and ticket support.]]></item>
+               <item name="wcf.acp.dashboard.box.expiringLicenses.cta"><![CDATA[Renew Licenses Now ↗]]></item>
        </category>
        <category name="wcf.acp.index">
                <item name="wcf.acp.index.inRescueMode"><![CDATA[You are accessing this installation from an unknown domain, possibly caused by moving to a new host. Please update the settings on <a href="{link controller='ApplicationManagement'}{/link}">Manage Apps</a>.]]></item>