Commit 161369a1 authored by Emiliano Balbuena's avatar Emiliano Balbuena

(feat): Allow admins to edit Pro settings; custom <head> support

Closes #1894
Closes #1896
1 merge request!528WIP: (feat): Minds Pro
Pipeline #81678765 failed with stages
in 5 minutes and 11 seconds
......@@ -8,6 +8,7 @@
@media screen and (max-width: $min-tablet) {
padding-left: 0;
flex-wrap: wrap;
}
&:not(.m-topbar--navigation--text-only) .m-topbar--navigation--item span {
......
<ng-container *ngIf="channel; else loader">
<ng-container *ngIf="!channel.pro || isOwner; else isProChannel">
<ng-container *ngIf="!channel.pro || isOwner || isAdmin; else isProChannel">
<m-channel #channelComponent></m-channel>
</ng-container>
<ng-template #isProChannel>
......
......@@ -84,7 +84,12 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
this.channel = response.channel;
// NOTE: Temporary workaround until channel component supports children routes
if (!this.site.isProDomain && this.channel.pro && !this.isOwner) {
if (
!this.site.isProDomain &&
this.channel.pro &&
!this.isOwner &&
!this.isAdmin
) {
this.router.navigate(['/pro', this.channel.username], {
replaceUrl: true,
});
......@@ -100,4 +105,8 @@ export class ChannelContainerComponent implements OnInit, OnDestroy {
const currentUser = this.session.getLoggedInUser();
return this.channel && currentUser && this.channel.guid == currentUser.guid;
}
get isAdmin() {
return this.site.isAdmin;
}
}
......@@ -262,25 +262,24 @@
<span [hidden]="!editing" i18n="@@M__ACTION__SAVE">Save</span>
</button>
</div>
<ng-container *ngIf="session.getLoggedInUser()?.guid == user.guid">
<a
*ngIf="!user.pro"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim m-btn--action"
routerLink="/pro"
>
<i class="material-icons">business_center</i>
<span i18n>Become Pro</span>
</a>
<a
*ngIf="user.pro"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim"
routerLink="/pro/settings"
>
<i class="material-icons">business_center</i>
<span i18n>Pro</span>
</a>
</ng-container>
<a
*ngIf="showBecomeProButton"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim m-btn--action"
routerLink="/pro"
>
<i class="material-icons">business_center</i>
<span i18n>Become Pro</span>
</a>
<a
*ngIf="showProSettings"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim"
[routerLink]="proSettingsRouterLink"
>
<i class="material-icons">business_center</i>
<span i18n>Pro</span>
</a>
<minds-button-boost
*ngIf="session.getLoggedInUser().guid == user.guid"
......
......@@ -159,4 +159,31 @@ export class ChannelSidebar {
)
.present();
}
get showBecomeProButton() {
const isOwner =
this.session.isLoggedIn() &&
this.session.getLoggedInUser().guid == this.user.guid;
return isOwner && !this.user.pro;
}
get showProSettings() {
const isOwner =
this.session.isLoggedIn() &&
this.session.getLoggedInUser().guid == this.user.guid;
const isAdmin = window.Minds.Admin;
return (isOwner || isAdmin) && this.user.pro;
}
get proSettingsRouterLink() {
const isAdmin = window.Minds.Admin;
const route: any[] = ['/pro/settings'];
if (isAdmin) {
route.push({ user: this.user.username });
}
return route;
}
}
......@@ -28,9 +28,15 @@ export class ProService {
return true;
}
async get(): Promise<{ isActive; settings }> {
async get(remoteUser: string | null = null): Promise<{ isActive; settings }> {
const endpoint = ['api/v2/pro/settings'];
if (remoteUser) {
endpoint.push(remoteUser);
}
const { isActive, settings } = (await this.client.get(
'api/v2/pro/settings',
endpoint.join('/'),
{},
{ cache: false }
)) as any;
......@@ -56,8 +62,14 @@ export class ProService {
return { isActive, settings };
}
async set(settings): Promise<boolean> {
await this.client.post('api/v2/pro/settings', settings);
async set(settings, remoteUser: string | null = null): Promise<boolean> {
const endpoint = ['api/v2/pro/settings'];
if (remoteUser) {
endpoint.push(remoteUser);
}
await this.client.post(endpoint.join('/'), settings);
return true;
}
}
......@@ -9,7 +9,7 @@
>
<span i18n>General</span>
<m-tooltip icon="help" i18n>
TBD
Customize your title and headline.
</m-tooltip>
</a>
......@@ -20,7 +20,7 @@
>
<span i18n>Theme</span>
<m-tooltip icon="help" i18n>
TBD
Set up your color scheme.
</m-tooltip>
</a>
......@@ -31,7 +31,7 @@
>
<span i18n>Hashtags</span>
<m-tooltip icon="help" i18n>
TBD
Set up category filters using hashtags.
</m-tooltip>
</a>
......@@ -42,7 +42,7 @@
>
<span i18n>Footer</span>
<m-tooltip icon="help" i18n>
TBD
Set up site footer items.
</m-tooltip>
</a>
......@@ -53,18 +53,19 @@
>
<span i18n>Domain</span>
<m-tooltip icon="help" i18n>
TBD
Configure your custom domain.
</m-tooltip>
</a>
<a
*ngIf="!isRemote"
class="m-topbar--navigation--item"
[class.m-topbar--navigation--item-active]="currentTab === 'cancel'"
(click)="currentTab = 'cancel'"
>
<span i18n>Cancel</span>
<m-tooltip icon="help" i18n>
TBD
Cancel your Pro subscription.
</m-tooltip>
</a>
</div>
......@@ -316,7 +317,7 @@
</div>
</ng-template>
<!-- Cancel -->
<!-- Domain -->
<ng-template ngSwitchCase="domain">
<p class="m-pro--settings--note" i18n>
......@@ -332,6 +333,22 @@
[(ngModel)]="settings.domain"
/>
</div>
<div class="m-pro--settings--field">
<label for="custom_head" i18n>Custom &lt;head&gt; Code</label>
<textarea
class="m-pro--settings--code-textarea"
id="custom_head"
name="custom_head"
[(ngModel)]="settings.custom_head"
[readOnly]="!isAdmin"
></textarea>
<p *ngIf="!isAdmin" class="m-pro--settings--note" i18n>
In order to customize this field, please contact a Minds admin
or email info@minds.com.
</p>
</div>
</ng-template>
<!-- Cancel -->
......
......@@ -71,6 +71,17 @@
textarea {
height: 6em;
resize: none;
&.m-pro--settings--code-textarea {
font-family: monospace;
font-size: 13px;
max-width: 49em;
height: 12em;
@media screen and (max-width: 768px) {
max-width: 100%;
}
}
}
&.m-pro--settings--field-actions {
......
......@@ -2,19 +2,22 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import { ProService } from '../pro.service';
import { Session } from '../../../services/session';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { MindsTitle } from '../../../services/ux/title';
import { Subscription } from 'rxjs';
import { SiteService } from '../../../services/site.service';
@Component({
selector: 'm-pro--settings',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'settings.component.html',
})
export class ProSettingsComponent implements OnInit {
export class ProSettingsComponent implements OnInit, OnDestroy {
settings: any;
inProgress: boolean;
......@@ -29,25 +32,41 @@ export class ProSettingsComponent implements OnInit {
| 'domain'
| 'cancel' = 'general';
user: string | null = null;
protected param$: Subscription;
constructor(
protected service: ProService,
protected session: Session,
protected router: Router,
protected route: ActivatedRoute,
protected cd: ChangeDetectorRef,
protected title: MindsTitle
protected title: MindsTitle,
protected site: SiteService
) {}
ngOnInit() {
this.load();
this.param$ = this.route.params.subscribe(params => {
if (this.site.isAdmin) {
this.user = params['user'] || null;
}
this.load();
});
}
ngOnDestroy() {
this.param$.unsubscribe();
}
async load() {
this.inProgress = true;
this.detectChanges();
const { isActive, settings } = await this.service.get();
const { isActive, settings } = await this.service.get(this.user);
if (!isActive) {
if (!isActive && !this.user) {
this.router.navigate(['/pro'], { replaceUrl: true });
return;
}
......@@ -64,7 +83,7 @@ export class ProSettingsComponent implements OnInit {
this.inProgress = true;
this.detectChanges();
await this.service.set(this.settings);
await this.service.set(this.settings, this.user);
this.saved = true;
this.inProgress = false;
......@@ -101,10 +120,18 @@ export class ProSettingsComponent implements OnInit {
}
get previewRoute() {
return ['/pro', this.session.getLoggedInUser().username];
return ['/pro', this.user || this.session.getLoggedInUser().username];
}
get ratios() {
return this.service.ratios;
}
get isRemote() {
return Boolean(this.user);
}
get isAdmin() {
return this.site.isAdmin;
}
}
......@@ -6,11 +6,15 @@ export class SiteService {
return window.Minds.pro;
}
get isProDomain() {
get isProDomain(): boolean {
return Boolean(this.pro);
}
get title() {
get title(): string {
return this.isProDomain ? this.pro.title || '' : 'Minds';
}
get isAdmin(): boolean {
return window.Minds.Admin;
}
}
......@@ -57,6 +57,13 @@
}
</script>
<?php if ($pro && $pro->getCustomHead()): /* Blank line below IS IMPORTANT! Do not remove. */ ?>
<!-- Minds Pro: <?php echo $pro->getUserGuid(); ?> --><?php echo "\n" . $pro->getCustomHead() . "\n"; ?>
<!-- End -->
<?php endif; ?>
</head>
<body>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment