userpage: show expiry

This commit is contained in:
Harvey Tindall 2023-06-18 12:27:18 +01:00
parent a22f032924
commit 5beeeb958b
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
42 changed files with 258 additions and 62 deletions

View File

@ -33,7 +33,7 @@ func (app *appContext) MyDetails(gc *gin.Context) {
if emailEnabled {
resp.Email = &MyDetailsContactMethodsDTO{}
if email, ok := app.storage.emails[user.ID]; ok {
if email, ok := app.storage.emails[user.ID]; ok && email.Addr != "" {
resp.Email.Value = email.Addr
resp.Email.Enabled = email.Contact
}

View File

@ -44,13 +44,16 @@
{{ template "login-modal.html" . }}
<div class="page-container">
<div class="card @low dark:~d_neutral mb-4" id="card-user">
<span class="heading"></span>
<span class="heading mb-2"></span>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="card @low dark:~d_neutral" id="card-times">
<div class="card @low dark:~d_neutral unfocused" id="card-status">
<span class="heading mb-2">{{ .strings.expiry }}</span>
<aside class="aside ~warning user-expiry my-4"></aside>
<div class="user-expiry-countdown"></div>
</div>
<div class="card @low dark:~d_neutral" id="card-contact">
<span class="heading">{{ .strings.contactMethods }}</span>
<span class="heading mb-2">{{ .strings.contactMethods }}</span>
<div class="content"></div>
</div>
</div>

View File

@ -26,9 +26,10 @@ func (ls *adminLangs) getOptions() [][2]string {
type commonLangs map[string]commonLang
type commonLang struct {
Meta langMeta `json:"meta"`
Strings langSection `json:"strings"`
Notifications langSection `json:"notifications"`
Meta langMeta `json:"meta"`
Strings langSection `json:"strings"`
Notifications langSection `json:"notifications"`
QuantityStrings map[string]quantityString `json:"quantityStrings"`
}
type adminLang struct {
@ -58,6 +59,7 @@ type userLang struct {
notificationsJSON string
ValidationStrings map[string]quantityString `json:"validationStrings"`
validationStringsJSON string
QuantityStrings map[string]quantityString `json:"quantityStrings"`
JSON string
}

View File

@ -30,7 +30,6 @@
"lastActiveTime": "Sidst Aktiv",
"from": "Fra",
"user": "Bruger",
"expiry": "Udløb",
"userExpiry": "Brugerens Udløb",
"userExpiryDescription": "En specificeret tid efter hver tilmelding, sletter/deaktiverer jfa-go kontoen. Du kan ændre denne adfærd i indstillingerne.",
"aboutProgram": "Om",

View File

@ -81,7 +81,6 @@
"download": "Herunterladen",
"update": "Aktualisieren",
"updates": "Aktualisierungen",
"expiry": "Ablaufdatum",
"extendExpiry": "Ablaufdatum verlängern",
"donate": "Spenden",
"conditionals": "Bedingungen",

View File

@ -75,7 +75,6 @@
"download": "Λήψη",
"search": "Αναζήτηση",
"inviteDuration": "Διάρκεια Πρόσκλησης",
"expiry": "Λήξη",
"userExpiry": "Λήξη Χρήστη",
"userExpiryDescription": "Μετά απο ένα καθορισμένο χρόνο μετά απο κάθε εγγραφή, το jfa-go θα διαγράφει/απενεργοποιεί τον λογαριασμό. Μπορείτε να αλλάξετε αυτή την συμπεριφορά στις ρυθμίσεις.",
"announce": "Ανακοίνωση",

View File

@ -71,7 +71,6 @@
"apply": "Apply",
"delete": "Delete",
"updates": "Updates",
"expiry": "Expiry",
"variables": "Variables",
"preview": "Preview",
"markdownSupported": "Markdown is supported.",

View File

@ -33,7 +33,6 @@
"after": "After",
"before": "Before",
"user": "User",
"expiry": "Expiry",
"userExpiry": "User Expiry",
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
"aboutProgram": "About",

View File

@ -28,7 +28,6 @@
"lastActiveTime": "Último activo",
"from": "De",
"user": "Usuario",
"expiry": "Expiración",
"userExpiry": "Caducidad del usuario",
"userExpiryDescription": "Una cantidad de tiempo específica después de cada registro, jfa-go eliminará / deshabilitará la cuenta. Puede cambiar este comportamiento en la configuración.",
"aboutProgram": "Acerca de",

View File

@ -76,7 +76,6 @@
"edit": "Éditer",
"customizeMessages": "Personnaliser les e-mails",
"inviteDuration": "Durée de l'invitation",
"expiry": "Expiration",
"advancedSettings": "Paramètres avancés",
"userExpiry": "Expiration de l'utilisateur",
"updates": "Mises à jour",

View File

@ -31,7 +31,6 @@
"lastActiveTime": "Utoljára aktív",
"from": "Feladó",
"user": "Felhasználó",
"expiry": "Lejárat",
"userExpiry": "Felhasználói lejárat",
"userExpiryDescription": "Egy meghatározott idő után minden regisztrációt töröl, vagy felfüggeszt a jfa-go. Ezt a működést megváltoztathatod a beállításokban.",
"aboutProgram": "Névjegy",

View File

@ -75,7 +75,6 @@
"customizeMessages": "E-mails aanpassen",
"inviteDuration": "Geldigheidsduur uitnodiging",
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
"expiry": "Verloop",
"userExpiry": "Gebruikersverloop",
"extendExpiry": "Verleng verloop",
"updates": "Updates",

View File

@ -31,7 +31,6 @@
"lastActiveTime": "Ostatnia aktywność",
"from": "Od",
"user": "Użytkownik",
"expiry": "Wygasa",
"userExpiry": "Użytkownik wygasa",
"userExpiryDescription": "",
"aboutProgram": "O",

View File

@ -75,7 +75,6 @@
"customizeMessages": "Customizar Emails",
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
"inviteDuration": "Duração do Convite",
"expiry": "Expira",
"userExpiry": "Vencimento do Usuário",
"extendExpiry": "Extender o vencimento",
"updates": "Atualizações",

View File

@ -74,7 +74,6 @@
"notifyInviteExpiry": "Vid utgång",
"notifyUserCreation": "Vid användarskapande",
"inviteDuration": "Varaktighet för inbjudan",
"expiry": "Löper ut",
"userExpiry": "Användarutgång",
"userExpiryDescription": "Efter en angiven tid efter varje registrering så tar jfa-go bort/inaktiverar kontot. Du kan ändra detta beteende i inställningarna.",
"extendExpiry": "Förläng utgång"

View File

@ -31,7 +31,6 @@
"lastActiveTime": "Lần cuối Hoạt động",
"from": "Từ",
"user": "Người dùng",
"expiry": "Hết hạn",
"userExpiry": "Hết hạn Người dùng",
"userExpiryDescription": "Sau một khoảng thời gian nhất định sau khi mỗi đăng ký, jfa-go sẽ xóa/vô hiệu hóa tài khoản. Bạn có thể chỉnh sửa chế độ này trong cài đặt.",
"aboutProgram": "Thông tin",

View File

@ -30,7 +30,6 @@
"lastActiveTime": "上次活动",
"from": "从",
"user": "用户",
"expiry": "到期",
"userExpiry": "用户到期",
"userExpiryDescription": "每次注册后的指定时间jfa-go 将删除/禁用该帐户。您可以在设置中更改此行为。",
"aboutProgram": "关于",

View File

@ -31,7 +31,6 @@
"lastActiveTime": "上次啟用時間",
"from": "從",
"user": "帳戶",
"expiry": "到期",
"userExpiry": "帳戶到期",
"userExpiryDescription": "每次註冊后指定的時間jfa-go 將刪除/禁用該帳戶。您可以在設定中更改此行為。",
"aboutProgram": "關於",

View File

@ -3,5 +3,6 @@
"name": "العربية (AR)"
},
"strings": {},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Aktiveret",
"disabled": "Deaktiveret",
"reEnable": "Genaktiver",
"disable": "Deaktiver"
"disable": "Deaktiver",
"expiry": "Udløb"
},
"notifications": {
"errorLoginBlank": "Brugernavnet og/eller adgangskoden blev efterladt tomme.",
@ -39,5 +40,6 @@
"errorUnknown": "Ukendt fejl.",
"error401Unauthorized": "Adgang nægtet. Prøv at genindlæse siden.",
"errorSaveSettings": "Kunne ikke gemme indstillingerne."
}
},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Aktiviert",
"disabled": "Deaktiviert",
"reEnable": "Wieder aktivieren",
"disable": "Deaktivieren"
"disable": "Deaktivieren",
"expiry": "Ablaufdatum"
},
"notifications": {
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
@ -39,5 +40,6 @@
"errorUnknown": "Unbekannter Fehler.",
"error401Unauthorized": "Unberechtigt. Versuch, die Seite zu aktualisieren.",
"errorSaveSettings": "Einstellungen konnten nicht gespeichert werden."
}
},
"quantityStrings": {}
}

View File

@ -22,7 +22,8 @@
"enabled": "Ενεργοποιημένο",
"disabled": "Απενεργοποιημένο",
"reEnable": "Επανα-ενεργοποίηση",
"disable": "Απενεργοποίηση"
"disable": "Απενεργοποίηση",
"expiry": "Λήξη"
},
"notifications": {
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
@ -30,5 +31,6 @@
"errorUnknown": "Άγνωστο σφάλμα.",
"error401Unauthorized": "Ανεξουσιοδότητος. Προσπαθήστε να κάνετε επαναφόρτωση την σελίδα.",
"errorSaveSettings": "Αποτυχία αποθήκευσης ρυθμίσεων."
}
},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Enabled",
"disabled": "Disabled",
"reEnable": "Re-enable",
"disable": "Disable"
"disable": "Disable",
"expiry": "Expiry"
},
"notifications": {
"errorLoginBlank": "The username and/or password was left blank.",
@ -39,5 +40,6 @@
"errorUnknown": "Unknown error.",
"error401Unauthorized": "Unauthorised. Try refreshing the page.",
"errorSaveSettings": "Couldn't save settings."
}
},
"quantityStrings": {}
}

View File

@ -32,7 +32,10 @@
"disabled": "Disabled",
"reEnable": "Re-enable",
"disable": "Disable",
"contactMethods": "Contact Methods"
"contactMethods": "Contact Methods",
"accountStatus": "Account Status",
"notSet": "Not set",
"expiry": "Expiry"
},
"notifications": {
"errorLoginBlank": "The username and/or password were left blank.",
@ -40,5 +43,19 @@
"errorUnknown": "Unknown error.",
"error401Unauthorized": "Unauthorized. Try refreshing the page.",
"errorSaveSettings": "Couldn't save settings."
},
"quantityStrings": {
"year": {
"singular": "{n} Year",
"plural": "{n} Years"
},
"month": {
"singular": "{n} Month",
"plural": "{n} Months"
},
"day": {
"singular": "{n} Day",
"plural": "{n} Days"
}
}
}
}

View File

@ -31,7 +31,8 @@
"enabled": "Activado",
"disabled": "Desactivado",
"reEnable": "Reactivar",
"disable": "Desactivar"
"disable": "Desactivar",
"expiry": "Expiración"
},
"notifications": {
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
@ -39,5 +40,6 @@
"errorUnknown": "Error desconocido.",
"error401Unauthorized": "No autorizado. Intente actualizar la página.",
"errorSaveSettings": "No se pudo guardar la configuración."
}
},
"quantityStrings": {}
}

View File

@ -24,5 +24,6 @@
"contactDiscord": "از طریق دیسکورد تماس بگیرید",
"theme": "موضوع"
},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Activé",
"disabled": "Désactivé",
"reEnable": "Ré-activé",
"disable": "Désactivé"
"disable": "Désactivé",
"expiry": "Expiration"
},
"notifications": {
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
@ -39,5 +40,6 @@
"errorUnknown": "Erreur inconnue.",
"error401Unauthorized": "Non autorisé. Essayez d'actualiser la page.",
"errorSaveSettings": "Impossible d'enregistrer les paramètres."
}
},
"quantityStrings": {}
}

View File

@ -9,7 +9,9 @@
"enabled": "Engedélyezve",
"disabled": "Tiltva",
"reEnable": "Újra engedélyezés",
"disable": "Letiltás"
"disable": "Letiltás",
"expiry": "Lejárat"
},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -25,5 +25,6 @@
"errorUnknown": "Kesalahan yang tidak diketahui.",
"error401Unauthorized": "Tidak ter-otorisasi. Coba segarkan halaman.",
"errorSaveSettings": "Tidak dapat menyimpan pengaturan."
}
},
"quantityStrings": {}
}

View File

@ -26,5 +26,6 @@
"refresh": "Aggiorna",
"required": "Richiesto"
},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Ingeschakeld",
"disabled": "Uitgeschakeld",
"reEnable": "Opnieuw inschakelen",
"disable": "Uitschakelen"
"disable": "Uitschakelen",
"expiry": "Verloop"
},
"notifications": {
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
@ -39,5 +40,6 @@
"errorUnknown": "Onbekende fout.",
"error401Unauthorized": "Geen toegang. Probeer de pagina te vernieuwen.",
"errorSaveSettings": "Opslaan van instellingen mislukt."
}
},
"quantityStrings": {}
}

View File

@ -28,11 +28,13 @@
"admin": "Admin",
"enabled": "Włączone",
"disabled": "Wyłączone",
"disable": "Wyłączone"
"disable": "Wyłączone",
"expiry": "Wygasa"
},
"notifications": {
"errorConnection": "Nie udało się połączyć z jfa-go.",
"errorUnknown": "Nieznany błąd.",
"error401Unauthorized": "Nieautoryzowany. Spróbuj odświeżyć stronę."
}
},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "Habilitado",
"disabled": "Desativado",
"reEnable": "Reativar",
"disable": "Desativar"
"disable": "Desativar",
"expiry": "Expira"
},
"notifications": {
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
@ -39,5 +40,6 @@
"errorUnknown": "Erro desconhecido.",
"error401Unauthorized": "Não autorizado. Tente atualizar a página.",
"errorSaveSettings": "Não foi possível salvar as configurações."
}
},
"quantityStrings": {}
}

View File

@ -3,5 +3,6 @@
"name": "Română (ROU)"
},
"strings": {},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -26,5 +26,6 @@
"refresh": "Osveži",
"required": "Obvezno"
},
"notifications": {}
"notifications": {},
"quantityStrings": {}
}

View File

@ -19,7 +19,8 @@
"logout": "Logga ut",
"admin": "Admin",
"enabled": "Aktiverad",
"disabled": "Inaktiverad"
"disabled": "Inaktiverad",
"expiry": "Löper ut"
},
"notifications": {
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
@ -27,5 +28,6 @@
"errorUnknown": "Okänt fel.",
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan.",
"errorSaveSettings": "Det gick inte att spara inställningarna."
}
},
"quantityStrings": {}
}

View File

@ -9,10 +9,12 @@
"enabled": "Mở",
"disabled": "Tắt",
"reEnable": "Mở lại",
"disable": "Tắt"
"disable": "Tắt",
"expiry": "Hết hạn"
},
"notifications": {
"errorConnection": "Không thể kết nối với jfa-go.",
"error401Unauthorized": "Không được phép. Hãy thử làm mới trang."
}
},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "已启用",
"disabled": "已禁用",
"reEnable": "重新启用",
"disable": "禁用"
"disable": "禁用",
"expiry": "到期"
},
"notifications": {
"errorLoginBlank": "用户名/密码留空。",
@ -39,5 +40,6 @@
"errorUnknown": "未知错误。",
"error401Unauthorized": "无授权。尝试刷新页面。",
"errorSaveSettings": "无法保存设置。"
}
},
"quantityStrings": {}
}

View File

@ -31,7 +31,8 @@
"enabled": "已啟用",
"disabled": "已禁用",
"reEnable": "重新啟用",
"disable": "禁用"
"disable": "禁用",
"expiry": "到期"
},
"notifications": {
"errorLoginBlank": "帳戶名稱和/或密碼留空。",
@ -39,5 +40,6 @@
"errorUnknown": "未知的錯誤。",
"error401Unauthorized": "未經授權。嘗試重新整理頁面。",
"errorSaveSettings": "無法儲存設置。"
}
},
"quantityStrings": {}
}

View File

@ -0,0 +1,52 @@
{
"meta": {
"name": "English (US)"
},
"strings": {
"username": "common",
"password": "common",
"emailAddress": "common",
"name": "common",
"submit": "common",
"send": "common",
"success": "common",
"continue": "common",
"error": "common",
"copy": "common",
"copied": "common",
"time24h": "common",
"time12h": "common",
"linkTelegram": "common",
"contactEmail": "common",
"contactTelegram": "common",
"linkDiscord": "common",
"linkMatrix": "common",
"contactDiscord": "common",
"theme": "common",
"refresh": "common",
"required": "common",
"login": "common",
"logout": "common",
"admin": "common",
"enabled": "common",
"disabled": "common",
"reEnable": "common",
"disable": "common",
"contactMethods": "common",
"accountStatus": "common",
"notSet": "common",
"expiry": "admin"
},
"notifications": {
"errorLoginBlank": "common",
"errorConnection": "common",
"errorUnknown": "common",
"error401Unauthorized": "common",
"errorSaveSettings": "common"
},
"quantityStrings": {
"year": "common",
"month": "common",
"day": "common"
}
}

View File

@ -202,6 +202,25 @@ func (common *commonLangs) patchCommonNotifications(to *langSection, from ...str
}
}
func (common *commonLangs) patchCommonQuantityStrings(to *map[string]quantityString, from ...string) {
if *to == nil {
*to = map[string]quantityString{}
}
for n, ev := range (*common)[from[len(from)-1]].QuantityStrings {
if v, ok := (*to)[n]; !ok || (v.Singular == "" && v.Plural == "") {
i := 0
for i < len(from)-1 {
ev, ok = (*common)[from[i]].QuantityStrings[n]
if ok && ev.Singular != "" && ev.Plural != "" {
break
}
i++
}
(*to)[n] = ev
}
}
}
func patchLang(to *langSection, from ...*langSection) {
if *to == nil {
*to = langSection{}
@ -283,10 +302,14 @@ func (st *Storage) loadLangCommon(filesystems ...fs.FS) error {
if err == nil {
loadedLangs[fsIndex][lang.Meta.Fallback+".json"] = true
patchLang(&lang.Strings, &fallback.Strings, &english.Strings)
patchLang(&lang.Notifications, &fallback.Notifications, &english.Notifications)
patchQuantityStrings(&lang.QuantityStrings, &fallback.QuantityStrings, &english.QuantityStrings)
}
}
if (lang.Meta.Fallback != "" && err != nil) || lang.Meta.Fallback == "" {
patchLang(&lang.Strings, &english.Strings)
patchLang(&lang.Notifications, &english.Notifications)
patchQuantityStrings(&lang.QuantityStrings, &english.QuantityStrings)
}
}
st.lang.Common[index] = lang
@ -437,6 +460,7 @@ func (st *Storage) loadLangUser(filesystems ...fs.FS) error {
}
st.lang.Common.patchCommonStrings(&lang.Strings, index)
st.lang.Common.patchCommonNotifications(&lang.Notifications, index)
st.lang.Common.patchCommonQuantityStrings(&lang.QuantityStrings, index)
// turns out, a lot of email strings are useful on the user page.
emailLang := []langSection{st.lang.Email[index].WelcomeEmail, st.lang.Email[index].UserDisabled, st.lang.Email[index].UserExpired}
for _, v := range emailLang {

View File

@ -1,7 +1,7 @@
import { ThemeManager } from "./modules/theme.js";
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
import { Modal } from "./modules/modal.js";
import { _get, _post, notificationBox, whichAnimationEvent } from "./modules/common.js";
import { _get, _post, notificationBox, whichAnimationEvent, toDateString } from "./modules/common.js";
import { Login } from "./modules/login.js";
interface userWindow extends Window {
@ -31,6 +31,7 @@ window.notifications = new notificationBox(document.getElementById('notification
var rootCard = document.getElementById("card-user");
var contactCard = document.getElementById("card-contact");
var statusCard = document.getElementById("card-status");
interface MyDetailsContactMethod {
value: string;
@ -58,15 +59,17 @@ interface ContactDTO {
class ContactMethods {
private _card: HTMLElement;
private _content: HTMLElement;
private _buttons: { [name: string]: { element: HTMLElement, details: MyDetailsContactMethod } };
constructor (card: HTMLElement) {
this._card = card;
this._content = this._card.querySelector(".content");
this._buttons = {};
}
clear = () => {
this._card.textContent = "";
this._content.textContent = "";
this._buttons = {};
}
@ -80,7 +83,7 @@ class ContactMethods {
${icon}
</span>
</span>
<span class="ml-2 font-bold">${details.value}</span>
<span class="ml-2 font-bold">${(details.value == "") ? window.lang.strings("notSet") : details.value}</span>
</div>
<div class="flex items-center">
<button class="user-contact-enabled-disabled button ~neutral">
@ -121,7 +124,7 @@ class ContactMethods {
checkbox.checked = details.enabled;
setButtonAppearance();
this._card.appendChild(row);
this._content.appendChild(row);
};
private _save = () => {
@ -141,6 +144,80 @@ class ContactMethods {
};
}
class ExpiryCard {
private _card: HTMLElement;
private _expiry: Date;
private _aside: HTMLElement;
private _countdown: HTMLElement;
private _interval: number = null;
constructor(card: HTMLElement) {
this._card = card;
this._aside = this._card.querySelector(".user-expiry") as HTMLElement;
this._countdown = this._card.querySelector(".user-expiry-countdown") as HTMLElement;
}
private _drawCountdown = () => {
let now = new Date();
// Years, Months, Days
let ymd = [0, 0, 0];
while (now.getFullYear() != this._expiry.getFullYear()) {
ymd[0] += 1;
now.setFullYear(now.getFullYear()+1);
}
if (now.getMonth() > this._expiry.getMonth()) {
ymd[0] -=1;
now.setFullYear(now.getFullYear()-1);
}
while (now.getMonth() != this._expiry.getMonth()) {
ymd[1] += 1;
now.setMonth(now.getMonth() + 1);
}
if (now.getDate() > this._expiry.getDate()) {
ymd[1] -=1;
now.setMonth(now.getMonth()-1);
}
while (now.getDate() != this._expiry.getDate()) {
ymd[2] += 1;
now.setDate(now.getDate() + 1);
}
const langKeys = ["year", "month", "day"];
let innerHTML = ``;
for (let i = 0; i < langKeys.length; i++) {
if (ymd[i] == 0) continue;
const words = window.lang.quantity(langKeys[i], ymd[i]).split(" ");
innerHTML += `
<div class="row my-3">
<div class="inline baseline">
<span class="text-2xl">${words[0]}</span> <span class="text-gray-400 text-lg">${words[1]}</span>
</div>
</div>
`;
}
this._countdown.innerHTML = innerHTML;
};
get expiry(): Date { return this._expiry; };
set expiry(expiryUnix: number) {
if (this._interval !== null) {
window.clearInterval(this._interval);
this._interval = null;
}
if (expiryUnix == 0) return;
this._expiry = new Date(expiryUnix * 1000);
this._aside.textContent = window.lang.strings("yourAccountIsValidUntil").replace("{date}", toDateString(this._expiry));
this._card.classList.remove("unfocused");
this._interval = window.setInterval(this._drawCountdown, 60*1000);
this._drawCountdown();
}
}
var expiryCard = new ExpiryCard(statusCard);
var contactMethodList = new ContactMethods(contactCard);
document.addEventListener("details-reload", () => {
@ -179,6 +256,8 @@ document.addEventListener("details-reload", () => {
contactMethodList.append(method[0], details[method[0]], method[1]);
}
}
expiryCard.expiry = details.expiry;
}
});
});