Skip to content

Commit

Permalink
Kavita now has a much nicer Unlocked message and will now generate sc…
Browse files Browse the repository at this point in the history
…robble events after 24 hours.

Added an info variant to the confirm service.
  • Loading branch information
majora2007 committed Jan 10, 2025
1 parent a7fb333 commit 03e9aa1
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 22 deletions.
3 changes: 2 additions & 1 deletion API/Controllers/LicenseController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using API.Extensions;
using API.Services;
using API.Services.Plus;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -107,7 +108,7 @@ public async Task<ActionResult> UpdateLicense(UpdateLicenseDto dto)
try
{
await licenseService.AddLicense(dto.License.Trim(), dto.Email.Trim(), dto.DiscordId);
await taskScheduler.ScheduleKavitaPlusTasks();
BackgroundJob.Schedule(() => taskScheduler.ScheduleKavitaPlusTasks(), TimeSpan.FromHours(24));
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {LoadingComponent} from "../../shared/loading/loading.component";
TranslocoDirective,
VirtualScrollerModule,
UtcToLocalTimePipe,
DefaultValuePipe,
LoadingComponent
],
templateUrl: './email-history.component.html',
Expand Down
11 changes: 7 additions & 4 deletions UI/Web/src/app/admin/license/license.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {WikiLink} from "../../_models/wiki";
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
import {DecimalPipe} from "@angular/common";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {of, startWith, switchMap} from "rxjs";
import {switchMap} from "rxjs";
import {LicenseInfo} from "../../_models/kavitaplus/license-info";
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
import {filter, tap} from "rxjs/operators";
Expand Down Expand Up @@ -62,7 +62,10 @@ export class LicenseComponent implements OnInit {
this.formGroup.addControl('email', new FormControl('', [Validators.required]));
this.formGroup.addControl('discordId', new FormControl('', [Validators.pattern(/\d+/)]));

this.loadLicenseInfo().subscribe();
this.loadLicenseInfo().subscribe(async () => {
await this.confirmService.info(translate('license.k+-unlocked-description'), translate('license.k+-unlocked'))
});

}

loadLicenseInfo(forceCheck = false) {
Expand Down Expand Up @@ -109,9 +112,9 @@ export class LicenseComponent implements OnInit {
this.isViewMode = true;
this.isSaving = false;
this.cdRef.markForCheck();
this.loadLicenseInfo().subscribe(info => {
this.loadLicenseInfo().subscribe(async (info) => {
if (info?.isActive && !hadActiveLicenseBefore) {
this.toastr.success(translate('toasts.k+-unlocked'));
await this.confirmService.info(translate('license.k+-unlocked-description'), translate('license.k+-unlocked'));
} else {
this.toastr.info(translate('toasts.k+-license-saved'));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ConfirmButton } from './confirm-button';

export class ConfirmConfig {
_type: 'confirm' | 'alert' = 'confirm';
_type: 'confirm' | 'alert' | 'info' = 'confirm';
header: string = 'Confirm';
content: string = '';
buttons: Array<ConfirmButton> = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<ng-container *transloco="let t">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{config.header}}</h4>
<button type="button" class="btn-close" [attr.aria-label]="t('common.close')" (click)="close()" *ngIf="!config.disableEscape"></button>
@if (!config.disableEscape) {
<button type="button" class="btn-close" [attr.aria-label]="t('common.close')" (click)="close()"></button>
}
</div>
<div class="modal-body" style="overflow-x: auto" [innerHtml]="config.content | safeHtml">
</div>
<div class="modal-footer">
<div *ngFor="let btn of config.buttons">
<button type="button" class="btn btn-{{btn.type}}" (click)="clickButton(btn)">{{btn.text}}</button>
</div>
@for(btn of config.buttons; track btn) {
<div>
<button type="button" class="btn btn-{{btn.type}}" (click)="clickButton(btn)">{{btn.text}}</button>
</div>
}
</div>

</ng-container>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, inject, OnInit} from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmButton } from './_models/confirm-button';
import { ConfirmConfig } from './_models/confirm-config';
Expand All @@ -9,15 +9,15 @@ import {TranslocoDirective} from "@jsverse/transloco";
@Component({
selector: 'app-confirm-dialog',
standalone: true,
imports: [CommonModule, SafeHtmlPipe, TranslocoDirective],
imports: [SafeHtmlPipe, TranslocoDirective],
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss']
})
export class ConfirmDialogComponent implements OnInit {

config!: ConfirmConfig;
protected readonly modal = inject(NgbActiveModal);

constructor(public modal: NgbActiveModal) {}
config!: ConfirmConfig;

ngOnInit(): void {
if (this.config) {
Expand Down
49 changes: 44 additions & 5 deletions UI/Web/src/app/shared/confirm.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { take } from 'rxjs/operators';
import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component';
import { ConfirmConfig } from './confirm-dialog/_models/confirm-config';
import {translate} from "@jsverse/transloco";
import {ConfirmButton} from "./confirm-dialog/_models/confirm-button";


@Injectable({
providedIn: 'root'
Expand All @@ -12,15 +14,25 @@ export class ConfirmService {

defaultConfirm = new ConfirmConfig();
defaultAlert = new ConfirmConfig();
defaultInfo = new ConfirmConfig();

constructor(private modalService: NgbModal) {
this.defaultConfirm.buttons.push({text: 'Cancel', type: 'secondary'});
this.defaultConfirm.buttons.push({text: 'Confirm', type: 'primary'});
this.defaultConfirm.buttons = [
{text: translate('confirm.cancel'), type: 'secondary'},
{text: translate('confirm.confirm'), type: 'primary'},
];

this.defaultAlert._type = 'alert';
this.defaultAlert.header = 'Alert';
this.defaultAlert.buttons.push({text: 'Ok', type: 'primary'});
this.defaultAlert.header = translate('confirm.alert');
this.defaultAlert.buttons = [
{text: translate('confirm.ok'), type: 'primary'}
];

this.defaultInfo.buttons = [
{text: translate('confirm.ok'), type: 'primary'}
];
this.defaultInfo.header = translate('confirm.info');
this.defaultInfo._type = 'info';
}

public async confirm(content?: string, config?: ConfirmConfig): Promise<boolean> {
Expand Down Expand Up @@ -52,6 +64,33 @@ export class ConfirmService {

}

public async info(content: string, header?: string, config?: ConfirmConfig): Promise<boolean> {
return new Promise((resolve, reject) => {
if (content === undefined && config === undefined) {
console.error('Alert must have either text or a config object passed');
return reject(false);
}

if (content !== undefined && config === undefined) {
config = this.defaultInfo;
config.content = content;

if (header != undefined) {
config.header = header;
}
}

const modalRef = this.modalService.open(ConfirmDialogComponent, {size: "lg", fullscreen: "md"});
modalRef.componentInstance.config = config;
modalRef.closed.pipe(take(1)).subscribe(result => {
return resolve(result);
});
modalRef.dismissed.pipe(take(1)).subscribe(() => {
return resolve(false);
});
});
}

public async alert(content?: string, config?: ConfirmConfig): Promise<boolean> {
return new Promise((resolve, reject) => {
if (content === undefined && config === undefined) {
Expand All @@ -73,6 +112,6 @@ export class ConfirmService {
modalRef.dismissed.pipe(take(1)).subscribe(() => {
return resolve(false);
});
})
});
}
}
9 changes: 7 additions & 2 deletions UI/Web/src/assets/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,9 @@
"k+-already-registered-header": "License already registered",
"overwrite": "Overwrite",

"k+-unlocked": "Kavita+ unlocked!",
"k+-unlocked-description": "Welcome to Kavita+! Kavita will generate scrobble events from your progress, ratings and want to read in 24 hours. Take this time to ensure any series you don't want synced have a hold on them.",

"activate-description": "Enter the License Key and Email used to register with Stripe",
"activate-license-label": "License Key",
"activate-email-label": "{{common.email}}",
Expand Down Expand Up @@ -2418,7 +2421,10 @@

"confirm": {
"alert": "Alert",
"confirm": "Confirm"
"confirm": "Confirm",
"info": "Info",
"cancel": "{{common.cancel}}",
"ok": "Ok"
},

"toasts": {
Expand Down Expand Up @@ -2471,7 +2477,6 @@
"email-sent": "Email sent to {{email}}",
"email-not-sent": "Email on file is not a valid email and can not be sent. A link has been dumped in logs. The admin can provide this link to complete flow.",
"k+-license-saved": "License Key saved, but it is not valid. Click check to revalidate the subscription. First time registration may take a min to propagate.",
"k+-unlocked": "Kavita+ unlocked!",
"k+-error": "There was an error when activating your license. Please try again.",
"k+-delete-key": "This will only delete Kavita's license key and allow a buy link to show. <b>This will not cancel your subscription!</b> Use Manage to cancel your subscription first.",
"k+-reset-key": "This will invalidate a previous registration using your license and allow you to re-register a Kavita instance.",
Expand Down

0 comments on commit 03e9aa1

Please sign in to comment.