create license management
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<p-dialog
|
||||
header="اطلاعات لایسنس"
|
||||
[(visible)]="visible"
|
||||
[modal]="true"
|
||||
[style]="{ width: '400px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
@if (!licenseStatus()) {
|
||||
<p-message severity="warn" [closable]="false" variant="text" icon="pi pi-info-circle" class="mb-5">
|
||||
برای کاربر شما لایسنسی در نظر گرفته نشده است. برای پیگیری با پشتیبانی تماس بگیرید.
|
||||
</p-message>
|
||||
} @else {
|
||||
@if (licenseStatus() === "EXPIRED") {
|
||||
<p-message severity="error" [closable]="false" variant="text" icon="pi pi-info-circle" class="mb-5">
|
||||
لایسنس شما منقضی شده است. برای تمدید با پشتیبانی تماس بگیرید.
|
||||
</p-message>
|
||||
}
|
||||
<div class="flex flex-col gap-4">
|
||||
<app-key-value label="شروع لایسنس از" [value]="license()?.starts_at!" type="date" />
|
||||
<app-key-value label="انقضای لایسنس" [value]="license()?.expires_at!" type="date" />
|
||||
<app-key-value label="ارایه شده توسط" [value]="license()?.partner?.name || 'برند نرمافزار'" />
|
||||
</div>
|
||||
}
|
||||
</p-dialog>
|
||||
@@ -0,0 +1,31 @@
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { KeyValueComponent } from '@/shared/components';
|
||||
import { licenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import { Dialog } from 'primeng/dialog';
|
||||
import { Message } from 'primeng/message';
|
||||
import { ConsumerStore } from '../store/main.store';
|
||||
|
||||
@Component({
|
||||
selector: 'consumer-license-info-dialog',
|
||||
templateUrl: './license-info-dialog.component.html',
|
||||
imports: [Dialog, KeyValueComponent, Message],
|
||||
})
|
||||
export class ConsumerLicenseInfoDialogComponent extends AbstractDialog {
|
||||
private readonly store = inject(ConsumerStore);
|
||||
|
||||
license = computed(() => this.store.entity()?.license);
|
||||
|
||||
licenseStatus = computed(() => {
|
||||
if (!this.store.entity()?.license?.expires_at) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
new Date().toDateString() >
|
||||
new Date(this.store.entity()?.license?.expires_at || '').toDateString()
|
||||
) {
|
||||
return licenseStatus.EXPIRED;
|
||||
}
|
||||
return licenseStatus.ACTIVE;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const baseUrl = '/api/v1/consumer';
|
||||
|
||||
export const CONSUMERS_API_ROUTES = {
|
||||
info: () => `${baseUrl}`,
|
||||
};
|
||||
@@ -1 +1,2 @@
|
||||
export * from './apiRoutes';
|
||||
export * from './menuItems.const';
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
<ng-template #topBarMoreAction>
|
||||
@if (licenseStatus() === "ACTIVE") {
|
||||
<p-button outlined severity="success" size="small" (click)="showLicenseInfo()">لایسنس فعال</p-button>
|
||||
} @else if (licenseStatus() === "EXPIRED") {
|
||||
<p-button severity="warn" size="small" (onClick)="showLicenseInfo()">
|
||||
لایسنس غیرفعال
|
||||
<i class="pi pi-question-circle" pButtonIcon></i>
|
||||
</p-button>
|
||||
} @else if (licenseStatus() === null) {
|
||||
<p-button severity="warn" size="small" (click)="showLicenseInfo()">
|
||||
لایسنس غیرفعال
|
||||
<i class="pi pi-question-circle" pButtonIcon></i>
|
||||
</p-button>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<consumer-license-info-dialog [(visible)]="visibleLicenseInfo" />
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,17 +1,52 @@
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { licenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
import { Component, computed, inject, signal, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { Button, ButtonIcon } from 'primeng/button';
|
||||
import { ConsumerLicenseInfoDialogComponent } from '../components/license-info-dialog.component';
|
||||
import { CONSUMER_MENU_ITEMS } from '../constants';
|
||||
import { ConsumerStore } from '../store/main.store';
|
||||
|
||||
@Component({
|
||||
selector: 'consumer-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
imports: [RouterOutlet],
|
||||
imports: [RouterOutlet, Button, ButtonIcon, ConsumerLicenseInfoDialogComponent],
|
||||
})
|
||||
export class LayoutComponent {
|
||||
@ViewChild('topBarMoreAction') topBarMoreAction!: TemplateRef<any>;
|
||||
|
||||
private readonly layoutService = inject(LayoutService);
|
||||
private readonly store = inject(ConsumerStore);
|
||||
|
||||
visibleLicenseInfo = signal(false);
|
||||
|
||||
licenseStatus = computed(() => {
|
||||
if (!this.store.entity()?.license?.expires_at) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
new Date().toDateString() >
|
||||
new Date(this.store.entity()?.license?.expires_at || '').toDateString()
|
||||
) {
|
||||
return licenseStatus.EXPIRED;
|
||||
}
|
||||
return licenseStatus.ACTIVE;
|
||||
});
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.setMenuItems(CONSUMER_MENU_ITEMS);
|
||||
this.store.getData();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.layoutService.setHeaderSlot(this.topBarMoreAction);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.layoutService.setHeaderSlot(null);
|
||||
}
|
||||
|
||||
showLicenseInfo() {
|
||||
this.visibleLicenseInfo.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './io';
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { TLicenseStatus } from '@/shared/localEnum/constants/licenseStatus';
|
||||
|
||||
export interface IConsumerInfoRawResponse {
|
||||
id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
full_name: string;
|
||||
mobile_number: string;
|
||||
license: {
|
||||
starts_at: string;
|
||||
expires_at: string;
|
||||
status: TLicenseStatus;
|
||||
partner?: ISummary;
|
||||
};
|
||||
}
|
||||
export interface IConsumerInfoResponse extends IConsumerInfoRawResponse {}
|
||||
@@ -1,6 +1,6 @@
|
||||
const baseUrl = '/api/v1/consumer/accounts';
|
||||
|
||||
export const CONSUMERS_API_ROUTES = {
|
||||
export const CONSUMER_Accounts_API_ROUTES = {
|
||||
list: () => `${baseUrl}`,
|
||||
single: (id: string) => `${baseUrl}/${id}`,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IPaginatedResponse } from '@/core/models/service.model';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { CONSUMERS_API_ROUTES as CONSUMER_ACCOUNTS_API_ROUTES } from '../constants';
|
||||
import { CONSUMER_Accounts_API_ROUTES as CONSUMER_ACCOUNTS_API_ROUTES } from '../constants';
|
||||
import { IAccountRawResponse, IAccountRequest, IAccountResponse } from '../models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { CONSUMERS_API_ROUTES } from '../constants';
|
||||
import { IConsumerInfoRawResponse, IConsumerInfoResponse } from '../models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ConsumerService {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
private apiRoutes = CONSUMERS_API_ROUTES;
|
||||
|
||||
getInfo(): Observable<IConsumerInfoResponse> {
|
||||
return this.http.get<IConsumerInfoRawResponse>(this.apiRoutes.info());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { EntityState, EntityStore } from '@/core/state';
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { catchError, finalize, throwError } from 'rxjs';
|
||||
import { IConsumerInfoResponse } from '../models';
|
||||
import { ConsumerService } from '../services/main.service';
|
||||
|
||||
interface ConsumerState extends EntityState<IConsumerInfoResponse> {}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ConsumerStore extends EntityStore<IConsumerInfoResponse, ConsumerState> {
|
||||
private readonly service = inject(ConsumerService);
|
||||
private readonly layoutService = inject(LayoutService);
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
loading: false,
|
||||
error: null,
|
||||
entity: null,
|
||||
initialized: false,
|
||||
isRefreshing: false,
|
||||
});
|
||||
}
|
||||
|
||||
getData() {
|
||||
this.patchState({ loading: true });
|
||||
this.service
|
||||
.getInfo()
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.patchState({ loading: false });
|
||||
}),
|
||||
catchError(() => {
|
||||
this.patchState({
|
||||
error: '',
|
||||
});
|
||||
return throwError('');
|
||||
}),
|
||||
)
|
||||
.subscribe((entity) => {
|
||||
this.layoutService.setPanelInfo({
|
||||
title: 'پنل مدیریت کسب و کار',
|
||||
});
|
||||
this.patchState({ entity });
|
||||
});
|
||||
}
|
||||
|
||||
override reset(): void {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: null,
|
||||
entity: null,
|
||||
initialized: false,
|
||||
isRefreshing: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user