From 9bfbef6f64000e03eedb1bbdba05e1bca0a9c6b9 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Wed, 11 Mar 2026 20:42:15 +0330 Subject: [PATCH] update breadcrumb and create account module --- src/app/core/constants/accountTypes.const.ts | 10 ++ src/app/core/models/namedRoutes.model.ts | 2 +- src/app/core/services/breadcrumb.service.ts | 30 +++-- .../guilds/components/layout.component.html | 5 + .../guilds/components/layout.component.ts | 50 +++++++ .../guilds/constants/routes/index.ts | 2 + .../guilds/views/single.component.ts | 4 - .../components/accounts/form.component.html | 42 ++++++ .../components/accounts/form.component.ts | 81 ++++++++++++ .../components/accounts/list.component.html | 15 +++ .../components/accounts/list.component.ts | 38 ++++++ .../users/components/form.component.html | 11 +- .../users/components/form.component.ts | 124 ++++++++---------- .../users/constants/apiRoutes/accounts.ts | 6 + .../users/constants/apiRoutes/index.ts | 2 + .../users/constants/routes/index.ts | 2 +- .../superAdmin/users/models/accounts_io.d.ts | 13 ++ .../domains/superAdmin/users/models/index.ts | 1 + .../domains/superAdmin/users/models/io.d.ts | 21 +-- .../users/services/accounts.service.ts | 28 ++++ .../superAdmin/users/store/user.store.ts | 53 ++++++++ .../superAdmin/users/views/accounts/index.ts | 1 + .../users/views/accounts/list.component.html | 1 + .../users/views/accounts/list.component.ts | 15 +++ .../domains/superAdmin/users/views/index.ts | 1 + .../users/views/list.component.html | 17 ++- .../superAdmin/users/views/list.component.ts | 13 +- .../users/views/single.component.html | 21 ++- .../users/views/single.component.ts | 51 ++++++- .../layout/component/app.layout.component.ts | 2 +- src/app/modules/auth/pages/auth.component.ts | 4 +- .../components/breadcrumb.component.html | 2 +- .../shared/components/breadcrumb.component.ts | 17 +-- .../components/page-loading.component.html | 3 + .../components/page-loading.component.ts | 9 ++ .../pageDataList/page-data-list.component.ts | 3 - 36 files changed, 570 insertions(+), 130 deletions(-) create mode 100644 src/app/core/constants/accountTypes.const.ts create mode 100644 src/app/domains/superAdmin/guilds/components/layout.component.html create mode 100644 src/app/domains/superAdmin/guilds/components/layout.component.ts create mode 100644 src/app/domains/superAdmin/users/components/accounts/form.component.html create mode 100644 src/app/domains/superAdmin/users/components/accounts/form.component.ts create mode 100644 src/app/domains/superAdmin/users/components/accounts/list.component.html create mode 100644 src/app/domains/superAdmin/users/components/accounts/list.component.ts create mode 100644 src/app/domains/superAdmin/users/constants/apiRoutes/accounts.ts create mode 100644 src/app/domains/superAdmin/users/models/accounts_io.d.ts create mode 100644 src/app/domains/superAdmin/users/services/accounts.service.ts create mode 100644 src/app/domains/superAdmin/users/store/user.store.ts create mode 100644 src/app/domains/superAdmin/users/views/accounts/index.ts create mode 100644 src/app/domains/superAdmin/users/views/accounts/list.component.html create mode 100644 src/app/domains/superAdmin/users/views/accounts/list.component.ts create mode 100644 src/app/shared/components/page-loading.component.html create mode 100644 src/app/shared/components/page-loading.component.ts diff --git a/src/app/core/constants/accountTypes.const.ts b/src/app/core/constants/accountTypes.const.ts new file mode 100644 index 0000000..b83d047 --- /dev/null +++ b/src/app/core/constants/accountTypes.const.ts @@ -0,0 +1,10 @@ +export enum ACCOUNT_TYPES { + 'PARTNER', + 'BUSINESS', + 'SUPER_ADMIN', + 'ADMIN', + 'PROVIDER', + 'POS', +} + +export type TAccountType = keyof typeof ACCOUNT_TYPES; diff --git a/src/app/core/models/namedRoutes.model.ts b/src/app/core/models/namedRoutes.model.ts index dfc0e7e..2c7b941 100644 --- a/src/app/core/models/namedRoutes.model.ts +++ b/src/app/core/models/namedRoutes.model.ts @@ -19,7 +19,7 @@ export interface RouteInfo { meta: { title: string; icon?: string; - pagePath?: (params: any) => string; + pagePath?: (params?: any) => string; }; } diff --git a/src/app/core/services/breadcrumb.service.ts b/src/app/core/services/breadcrumb.service.ts index ca7b057..a5c7af6 100644 --- a/src/app/core/services/breadcrumb.service.ts +++ b/src/app/core/services/breadcrumb.service.ts @@ -5,24 +5,36 @@ import { filter } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class BreadcrumbService { - private readonly _items = signal([]); + readonly _items = signal([]); private router = inject(Router); constructor() { - // Clear breadcrumb items on navigation start so previous page items don't persist. - // Components for the new route can set their own items in their lifecycle (e.g. ngOnInit). - this.router.events.pipe(filter((e) => e instanceof NavigationStart)).subscribe(() => { - this.clear(); + // Clear breadcrumb items only when the path changes (not on query string changes) + let lastPath = ''; + this.router.events.pipe(filter((e) => e instanceof NavigationStart)).subscribe((e) => { + const nav = e as NavigationStart; + const urlPath = nav.url.split('?')[0]; + + if (!lastPath || (lastPath && urlPath !== lastPath)) { + this.clear(); + } + lastPath = urlPath; }); } - get items() { - return this._items(); + setItems(items: MenuItem[]) { + this._items.set(this.mapItems(items)); } - setItems(items: MenuItem[]) { - this._items.set(items); + private readonly mapItems = (items: MenuItem[]) => + items.map((item) => ({ + ...item, + label: item.title || '', + })); + + addItems(items: MenuItem[]) { + this._items.update((value) => ({ ...value, ...this.mapItems(items) })); } clear() { diff --git a/src/app/domains/superAdmin/guilds/components/layout.component.html b/src/app/domains/superAdmin/guilds/components/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/superAdmin/guilds/components/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/superAdmin/guilds/components/layout.component.ts b/src/app/domains/superAdmin/guilds/components/layout.component.ts new file mode 100644 index 0000000..1962292 --- /dev/null +++ b/src/app/domains/superAdmin/guilds/components/layout.component.ts @@ -0,0 +1,50 @@ +import { BreadcrumbService } from '@/core/services'; +import { PageLoadingComponent } from '@/shared/components/page-loading.component'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute, RouterOutlet } from '@angular/router'; +import { guildsNamedRoutes } from '../constants'; +import { GuildStore } from '../store/guild.store'; + +@Component({ + selector: 'superAdmin-guild-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class GuildLayoutComponent { + private readonly store = inject(GuildStore); + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + + readonly guildId = signal(this.route.snapshot.paramMap.get('guildId')!); + + readonly loading = computed(() => this.store.loading()); + readonly guild = computed(() => this.store.entity()); + + constructor() { + effect(() => { + if (this.guild()?.id) { + this.setBreadcrumb(); + } + }); + } + + getData() { + this.store.getData(this.guildId()); + } + + ngOnInit() { + this.getData(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + { + ...guildsNamedRoutes.guilds.meta, + routerLink: guildsNamedRoutes.guilds.meta.pagePath!(), + }, + { + title: this.guild()?.name, + }, + ]); + } +} diff --git a/src/app/domains/superAdmin/guilds/constants/routes/index.ts b/src/app/domains/superAdmin/guilds/constants/routes/index.ts index 80d8027..781b814 100644 --- a/src/app/domains/superAdmin/guilds/constants/routes/index.ts +++ b/src/app/domains/superAdmin/guilds/constants/routes/index.ts @@ -29,6 +29,8 @@ export const GUILDS_ROUTES: Routes = [ guildsNamedRoutes.guilds, { path: 'guilds/:guildId', + loadComponent: () => + import('../../components/layout.component').then((m) => m.GuildLayoutComponent), children: [ { diff --git a/src/app/domains/superAdmin/guilds/views/single.component.ts b/src/app/domains/superAdmin/guilds/views/single.component.ts index b03a447..00a2aaf 100644 --- a/src/app/domains/superAdmin/guilds/views/single.component.ts +++ b/src/app/domains/superAdmin/guilds/views/single.component.ts @@ -30,8 +30,4 @@ export class GuildComponent { getData() { this.store.getData(this.guildId()); } - - ngOnInit() { - this.getData(); - } } diff --git a/src/app/domains/superAdmin/users/components/accounts/form.component.html b/src/app/domains/superAdmin/users/components/accounts/form.component.html new file mode 100644 index 0000000..babb102 --- /dev/null +++ b/src/app/domains/superAdmin/users/components/accounts/form.component.html @@ -0,0 +1,42 @@ + +
+ + + + + + رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد. + + + + + + + + +
diff --git a/src/app/domains/superAdmin/users/components/accounts/form.component.ts b/src/app/domains/superAdmin/users/components/accounts/form.component.ts new file mode 100644 index 0000000..37684d0 --- /dev/null +++ b/src/app/domains/superAdmin/users/components/accounts/form.component.ts @@ -0,0 +1,81 @@ +import { MustMatch, password } from '@/core/validators'; +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; +import { InputComponent } from '@/shared/components'; +import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; +import { UikitFieldComponent } from '@/uikit'; +import { Component, inject, Input } from '@angular/core'; +import { ReactiveFormsModule, Validators } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { Password } from 'primeng/password'; +import { IAccountRequest, IAccountResponse } from '../../models'; +import { AdminUserAccountsService } from '../../services/accounts.service'; + +@Component({ + selector: 'superAdmin-user-account-form', + templateUrl: './form.component.html', + imports: [ + ReactiveFormsModule, + Dialog, + InputComponent, + FormFooterActionsComponent, + UikitFieldComponent, + Password, + EnumSelectComponent, + ], +}) +export class UserAccountFormComponent extends AbstractFormDialog< + IAccountRequest, + IAccountResponse +> { + private readonly service = inject(AdminUserAccountsService); + + @Input() userId!: string; + @Input() accountId!: string; + + initForm = () => { + if (this.editMode) { + return this.fb.group( + { + username: [this.initialValues?.username || '', [Validators.required]], + // @ts-ignore + type: [this.initialValues?.type, [Validators.required]], + + password: ['', [password()]], + confirmPassword: [''], + }, + { + validators: [MustMatch('password', 'confirmPassword')], + }, + ); + } + return this.fb.group( + { + username: [this.initialValues?.username || '', [Validators.required]], + // @ts-ignore + type: [this.initialValues?.type, [Validators.required]], + + password: ['', [Validators.required, password()]], + confirmPassword: ['', [Validators.required]], + }, + { + validators: [MustMatch('password', 'confirmPassword')], + }, + ); + }; + + form = this.initForm(); + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IAccountRequest; + if (this.editMode) { + return this.service.update(this.userId, this.accountId, formValue); + } + return this.service.create(this.userId, formValue); + } +} diff --git a/src/app/domains/superAdmin/users/components/accounts/list.component.html b/src/app/domains/superAdmin/users/components/accounts/list.component.html new file mode 100644 index 0000000..d594c53 --- /dev/null +++ b/src/app/domains/superAdmin/users/components/accounts/list.component.html @@ -0,0 +1,15 @@ + + + diff --git a/src/app/domains/superAdmin/users/components/accounts/list.component.ts b/src/app/domains/superAdmin/users/components/accounts/list.component.ts new file mode 100644 index 0000000..d35ae4b --- /dev/null +++ b/src/app/domains/superAdmin/users/components/accounts/list.component.ts @@ -0,0 +1,38 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { IAccountResponse } from '../../models'; +import { AdminUserAccountsService } from '../../services/accounts.service'; +import { UserAccountFormComponent } from './form.component'; + +@Component({ + selector: 'superAdmin-user-account-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, UserAccountFormComponent], +}) +export class UsersComponent extends AbstractList { + @Input() userId!: string; + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = [ + { field: 'id', header: 'شناسه' }, + { field: 'username', header: 'نام کاربری' }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + private readonly service = inject(AdminUserAccountsService); + + override setColumns(): void { + this.columns = this.header; + } + + override getDataRequest() { + return this.service.getAll(this.userId); + } +} diff --git a/src/app/domains/superAdmin/users/components/form.component.html b/src/app/domains/superAdmin/users/components/form.component.html index 067eb25..3452a54 100644 --- a/src/app/domains/superAdmin/users/components/form.component.html +++ b/src/app/domains/superAdmin/users/components/form.component.html @@ -7,11 +7,12 @@ (onHide)="close()" >
- - - + + + + - + diff --git a/src/app/domains/superAdmin/users/components/form.component.ts b/src/app/domains/superAdmin/users/components/form.component.ts index d010b8e..8d60654 100644 --- a/src/app/domains/superAdmin/users/components/form.component.ts +++ b/src/app/domains/superAdmin/users/components/form.component.ts @@ -1,101 +1,81 @@ -import { ToastService } from '@/core/services/toast.service'; -import { mobileValidator, MustMatch, password } from '@/core/validators'; +import { MustMatch, password } from '@/core/validators'; // import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; import { InputComponent } from '@/shared/components'; import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; import { UikitFieldComponent } from '@/uikit'; -import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core'; -import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Component, inject, Input } from '@angular/core'; +import { ReactiveFormsModule, Validators } from '@angular/forms'; import { Dialog } from 'primeng/dialog'; import { Password } from 'primeng/password'; import { IUserRequest, IUserResponse } from '../models'; import { UsersService } from '../services/main.service'; @Component({ - selector: 'user-form', + selector: 'superAdmin-user-form', templateUrl: './form.component.html', imports: [ ReactiveFormsModule, Dialog, InputComponent, FormFooterActionsComponent, - // CatalogRolesComponent, UikitFieldComponent, Password, + EnumSelectComponent, ], }) -export class UserFormComponent { - @Input() initialValues?: IUserResponse; +export class UserAccountFormComponent extends AbstractFormDialog { + private readonly service = inject(UsersService); - @Input() - set visible(v: boolean) { - this.visibleSignal.set(!!v); - } - get visible() { - return this.visibleSignal(); - } - private visibleSignal = signal(false); + @Input() userId!: string; + @Input() accountId!: string; - @Output() visibleChange = new EventEmitter(); - @Output() onSubmit = new EventEmitter(); + initForm = () => { + if (this.editMode) { + return this.fb.group( + { + first_name: [this.initialValues?.first_name || '', [Validators.required]], + last_name: [this.initialValues?.last_name || '', [Validators.required]], + mobile_number: [this.initialValues?.mobile_number || '', [Validators.required]], + // @ts-ignore + // role: [this.initialValues?.role || '', [Validators.required]], - private fb = inject(FormBuilder); - constructor( - private service: UsersService, - private toastService: ToastService, - ) { - // effect(() => { - // const v = this.visibleSignal(); - // // this.visibleChange.emit(v); - // if (!v) this.form.reset(); - // }); - } - - form = this.fb.group( - { - firstName: [this.initialValues?.firstName || '', [Validators.required]], - lastName: [this.initialValues?.lastName || '', [Validators.required]], - mobileNumber: [ - this.initialValues?.mobileNumber || '', - [Validators.required, mobileValidator()], - ], - roleId: [this.initialValues?.role.id || null, [Validators.required]], - password: ['', [Validators.required, password()]], - confirmPassword: ['', [Validators.required]], - }, - { - validators: [MustMatch('password', 'confirmPassword')], - }, - ); - - submitLoading = signal(false); - - submit() { - this.form.markAllAsTouched(); - if (this.form.valid) { - this.form.disable(); - this.submitLoading.set(true); - const { confirmPassword, ...rest } = this.form.value; - this.service.create(rest as IUserRequest).subscribe({ - next: (res) => { - this.toastService.success({ - text: `کاربر ${this.form.value.firstName} با موفقیت ایجاد شد`, - }); - this.close(); - this.submitLoading.set(false); - this.form.enable(); - this.form.reset(); - this.onSubmit.emit(res); + // password: ['', [password()]], + // confirmPassword: [''], }, - error: () => { - this.submitLoading.set(false); - this.form.enable(); - }, - }); + // { + // validators: [MustMatch('password', 'confirmPassword')], + // }, + ); } + return this.fb.group( + { + first_name: [this.initialValues?.first_name || '', [Validators.required]], + last_name: [this.initialValues?.last_name || '', [Validators.required]], + mobile_number: [this.initialValues?.mobile_number || '', [Validators.required]], + // @ts-ignore + // role: [this.initialValues?.role || '', [Validators.required]], + password: ['', [Validators.required, password()]], + confirmPassword: ['', [Validators.required]], + }, + { + validators: [MustMatch('password', 'confirmPassword')], + }, + ); + }; + + form = this.initForm(); + + override ngOnChanges(): void { + this.form = this.initForm(); } - close() { - this.visibleChange.emit(false); + submitForm() { + const formValue = this.form.value as IUserRequest; + if (this.editMode) { + return this.service.update(this.userId, formValue); + } + return this.service.create(formValue); } } diff --git a/src/app/domains/superAdmin/users/constants/apiRoutes/accounts.ts b/src/app/domains/superAdmin/users/constants/apiRoutes/accounts.ts new file mode 100644 index 0000000..dfe39ff --- /dev/null +++ b/src/app/domains/superAdmin/users/constants/apiRoutes/accounts.ts @@ -0,0 +1,6 @@ +const baseUrl = (userId: string) => `/api/v1/admin/users/${userId}/accounts`; + +export const ACCOUNTS_API_ROUTES = { + list: (userId: string) => `${baseUrl(userId)}`, + single: (userId: string, accountId: string) => `${baseUrl(userId)}/${accountId}`, +}; diff --git a/src/app/domains/superAdmin/users/constants/apiRoutes/index.ts b/src/app/domains/superAdmin/users/constants/apiRoutes/index.ts index de7428d..46d5de5 100644 --- a/src/app/domains/superAdmin/users/constants/apiRoutes/index.ts +++ b/src/app/domains/superAdmin/users/constants/apiRoutes/index.ts @@ -1,3 +1,5 @@ +export * from './accounts'; + const baseUrl = '/api/v1/admin/users'; export const USERS_API_ROUTES = { diff --git a/src/app/domains/superAdmin/users/constants/routes/index.ts b/src/app/domains/superAdmin/users/constants/routes/index.ts index 450b429..9be8bed 100644 --- a/src/app/domains/superAdmin/users/constants/routes/index.ts +++ b/src/app/domains/superAdmin/users/constants/routes/index.ts @@ -17,7 +17,7 @@ export const usersNamedRoutes: NamedRoutes = { loadComponent: () => import('../../views/single.component').then((m) => m.UserComponent), meta: { title: 'کاربر', - pagePath: () => '/super_admin/users/:userId', + pagePath: (userId: string) => `/super_admin/users/${userId}`, }, }, }; diff --git a/src/app/domains/superAdmin/users/models/accounts_io.d.ts b/src/app/domains/superAdmin/users/models/accounts_io.d.ts new file mode 100644 index 0000000..f8aad6f --- /dev/null +++ b/src/app/domains/superAdmin/users/models/accounts_io.d.ts @@ -0,0 +1,13 @@ +import { TAccountType } from '@/core/constants/accountTypes.const'; + +export interface IAccountRawResponse { + username: string; + id: number; +} +export interface IAccountResponse extends IAccountRawResponse {} + +export interface IAccountRequest { + username: string; + password?: string; + type: TAccountType; +} diff --git a/src/app/domains/superAdmin/users/models/index.ts b/src/app/domains/superAdmin/users/models/index.ts index 61a518a..388437e 100644 --- a/src/app/domains/superAdmin/users/models/index.ts +++ b/src/app/domains/superAdmin/users/models/index.ts @@ -1 +1,2 @@ +export * from './accounts_io'; export * from './io'; diff --git a/src/app/domains/superAdmin/users/models/io.d.ts b/src/app/domains/superAdmin/users/models/io.d.ts index 4d4677a..32d0943 100644 --- a/src/app/domains/superAdmin/users/models/io.d.ts +++ b/src/app/domains/superAdmin/users/models/io.d.ts @@ -1,17 +1,18 @@ -import { IRoleResponse } from '@/shared/catalog/roles'; +import { TRoles } from '@/core'; export interface IUserRawResponse { - mobileNumber: string; - firstName: string; - lastName: string; - id: number; - role: IRoleResponse; + mobile_number: string; + first_name: string; + last_name: string; + fullname: string; + id: string; + role: TRoles; } export interface IUserResponse extends IUserRawResponse {} export interface IUserRequest { - firstName: string; - lastName: string; - mobileNumber: string; - roleId: number; + first_name: string; + last_name: string; + mobile_number: string; + role: TRoles; } diff --git a/src/app/domains/superAdmin/users/services/accounts.service.ts b/src/app/domains/superAdmin/users/services/accounts.service.ts new file mode 100644 index 0000000..70caefc --- /dev/null +++ b/src/app/domains/superAdmin/users/services/accounts.service.ts @@ -0,0 +1,28 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ACCOUNTS_API_ROUTES } from '../constants'; +import { IAccountRawResponse, IAccountRequest, IAccountResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class AdminUserAccountsService { + constructor(private http: HttpClient) {} + + private apiRoutes = ACCOUNTS_API_ROUTES; + + getAll(userId: string): Observable> { + return this.http.get>(this.apiRoutes.list(userId)); + } + getSingle(userId: string, accountId: string): Observable { + return this.http.get(this.apiRoutes.single(userId, accountId)); + } + + create(userId: string, data: IAccountRequest): Observable { + return this.http.post(this.apiRoutes.list(userId), data); + } + + update(userId: string, accountId: string, data: IAccountRequest): Observable { + return this.http.patch(this.apiRoutes.single(userId, accountId), data); + } +} diff --git a/src/app/domains/superAdmin/users/store/user.store.ts b/src/app/domains/superAdmin/users/store/user.store.ts new file mode 100644 index 0000000..da12bf5 --- /dev/null +++ b/src/app/domains/superAdmin/users/store/user.store.ts @@ -0,0 +1,53 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { inject, Injectable } from '@angular/core'; +import { catchError, finalize, throwError } from 'rxjs'; +import { IUserResponse } from '../models'; +import { UsersService } from '../services/main.service'; + +interface UserState extends EntityState {} + +@Injectable({ + providedIn: 'root', +}) +export class UserStore extends EntityStore { + private readonly service = inject(UsersService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + }); + } + + getData(userId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(userId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError(() => { + this.patchState({ + error: '', + }); + return throwError(''); + }), + ) + .subscribe((entity) => { + this.patchState({ entity }); + }); + } + + override reset(): void { + this.setState({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + }); + } +} diff --git a/src/app/domains/superAdmin/users/views/accounts/index.ts b/src/app/domains/superAdmin/users/views/accounts/index.ts new file mode 100644 index 0000000..576a89e --- /dev/null +++ b/src/app/domains/superAdmin/users/views/accounts/index.ts @@ -0,0 +1 @@ +export * from './list.component'; diff --git a/src/app/domains/superAdmin/users/views/accounts/list.component.html b/src/app/domains/superAdmin/users/views/accounts/list.component.html new file mode 100644 index 0000000..30c9888 --- /dev/null +++ b/src/app/domains/superAdmin/users/views/accounts/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/superAdmin/users/views/accounts/list.component.ts b/src/app/domains/superAdmin/users/views/accounts/list.component.ts new file mode 100644 index 0000000..936b719 --- /dev/null +++ b/src/app/domains/superAdmin/users/views/accounts/list.component.ts @@ -0,0 +1,15 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { Component, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { UsersComponent } from '../../components/accounts/list.component'; + +@Component({ + selector: 'superAdmin-user-accounts', + templateUrl: './list.component.html', + imports: [UsersComponent], +}) +export class UserAccountsComponent { + private readonly route = inject(ActivatedRoute); + + userId = signal(this.route.snapshot.params['userId']); +} diff --git a/src/app/domains/superAdmin/users/views/index.ts b/src/app/domains/superAdmin/users/views/index.ts index bc9dfc9..95918ec 100644 --- a/src/app/domains/superAdmin/users/views/index.ts +++ b/src/app/domains/superAdmin/users/views/index.ts @@ -1,2 +1,3 @@ +export * from './accounts'; export * from './list.component'; export * from './single.component'; diff --git a/src/app/domains/superAdmin/users/views/list.component.html b/src/app/domains/superAdmin/users/views/list.component.html index 0597bfb..3e85d06 100644 --- a/src/app/domains/superAdmin/users/views/list.component.html +++ b/src/app/domains/superAdmin/users/views/list.component.html @@ -9,10 +9,15 @@ [loading]="loading()" [showDetails]="true" [showAdd]="true" + [showEdit]="true" (onAdd)="openAddForm()" -> - - - + (onEdit)="onEditClick($event)" + (onDetails)="toSinglePage($event)" +/> + diff --git a/src/app/domains/superAdmin/users/views/list.component.ts b/src/app/domains/superAdmin/users/views/list.component.ts index 7d96f73..31e908a 100644 --- a/src/app/domains/superAdmin/users/views/list.component.ts +++ b/src/app/domains/superAdmin/users/views/list.component.ts @@ -2,17 +2,20 @@ import { AbstractList } from '@/shared/abstractClasses/abstract-list'; import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component'; import { Component, inject } from '@angular/core'; -import { UserFormComponent } from '../components/form.component'; +import { Router } from '@angular/router'; +import { UserAccountFormComponent } from '../components/form.component'; +import { usersNamedRoutes } from '../constants'; import { IUserResponse } from '../models'; import { UsersService } from '../services/main.service'; @Component({ - selector: 'app-users', + selector: 'superAdmin-users', templateUrl: './list.component.html', - imports: [PageDataListComponent, UserFormComponent], + imports: [PageDataListComponent, UserAccountFormComponent], }) export class UsersComponent extends AbstractList { private readonly service = inject(UsersService); + private readonly router = inject(Router); override setColumns(): void { this.columns = [ @@ -31,4 +34,8 @@ export class UsersComponent extends AbstractList { override getDataRequest() { return this.service.getAll(); } + + toSinglePage(item: IUserResponse) { + this.router.navigateByUrl(usersNamedRoutes.user.meta.pagePath!(item.id)); + } } diff --git a/src/app/domains/superAdmin/users/views/single.component.html b/src/app/domains/superAdmin/users/views/single.component.html index 7144e26..44706c9 100644 --- a/src/app/domains/superAdmin/users/views/single.component.html +++ b/src/app/domains/superAdmin/users/views/single.component.html @@ -1 +1,20 @@ -
+
+ +
+
+ + +
+
+
+ + + + +
diff --git a/src/app/domains/superAdmin/users/views/single.component.ts b/src/app/domains/superAdmin/users/views/single.component.ts index e9f64f3..cf87f83 100644 --- a/src/app/domains/superAdmin/users/views/single.component.ts +++ b/src/app/domains/superAdmin/users/views/single.component.ts @@ -1,9 +1,54 @@ -import { Component } from '@angular/core'; +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { UsersComponent } from '../components/accounts/list.component'; +import { UserAccountFormComponent } from '../components/form.component'; +import { usersNamedRoutes } from '../constants'; +import { UserStore } from '../store/user.store'; @Component({ - selector: 'app-user', + selector: 'superAdmin-user', templateUrl: './single.component.html', + imports: [AppCardComponent, KeyValueComponent, UserAccountFormComponent, UsersComponent], }) export class UserComponent { - constructor() {} + private readonly store = inject(UserStore); + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + + readonly userId = signal(this.route.snapshot.paramMap.get('userId')!); + editMode = signal(false); + + readonly loading = computed(() => this.store.loading()); + readonly user = computed(() => this.store.entity()); + + constructor() { + effect(() => { + if (this.user()?.id) { + this.setBreadcrumb(); + } + }); + } + + async getData() { + await this.store.getData(this.userId()); + this.setBreadcrumb(); + } + + ngOnInit() { + this.getData(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + { + ...usersNamedRoutes.users.meta, + routerLink: usersNamedRoutes.users.meta.pagePath!(), + }, + { + title: this.user()?.fullname, + }, + ]); + } } diff --git a/src/app/layout/component/app.layout.component.ts b/src/app/layout/component/app.layout.component.ts index 567e98f..7444c3e 100644 --- a/src/app/layout/component/app.layout.component.ts +++ b/src/app/layout/component/app.layout.component.ts @@ -130,7 +130,7 @@ export class AppLayout { } get showBreadcrumb(): boolean { - return this.breadcrumbService.items.length > 0; + return this.breadcrumbService._items().length > 0; } get isFixedContentSize(): boolean { diff --git a/src/app/modules/auth/pages/auth.component.ts b/src/app/modules/auth/pages/auth.component.ts index 96c1fb9..3f0067c 100644 --- a/src/app/modules/auth/pages/auth.component.ts +++ b/src/app/modules/auth/pages/auth.component.ts @@ -64,10 +64,10 @@ export class AuthComponent { redirectUrl = '/super_admin'; break; case 'ADMIN': - redirectUrl = '/admin'; + redirectUrl = '/super_admin'; break; case 'POS': - redirectUrl = '/poss'; + redirectUrl = '/pos'; break; case 'PARTNER': redirectUrl = '/partner'; diff --git a/src/app/shared/components/breadcrumb.component.html b/src/app/shared/components/breadcrumb.component.html index 147717f..90f88a6 100644 --- a/src/app/shared/components/breadcrumb.component.html +++ b/src/app/shared/components/breadcrumb.component.html @@ -1,4 +1,4 @@ - +
diff --git a/src/app/shared/components/breadcrumb.component.ts b/src/app/shared/components/breadcrumb.component.ts index 06f1995..68bff56 100644 --- a/src/app/shared/components/breadcrumb.component.ts +++ b/src/app/shared/components/breadcrumb.component.ts @@ -1,6 +1,5 @@ import { BreadcrumbService } from '@/core/services/breadcrumb.service'; -import { Component, inject } from '@angular/core'; -import { MenuItem } from 'primeng/api'; +import { Component, computed, inject } from '@angular/core'; import { BreadcrumbModule } from 'primeng/breadcrumb'; import { TooltipModule } from 'primeng/tooltip'; @@ -13,11 +12,13 @@ import { TooltipModule } from 'primeng/tooltip'; }) export class BreadcrumbComponent { private breadcrumbService = inject(BreadcrumbService); + items = computed(() => { + return this.breadcrumbService._items(); + }); - get items(): MenuItem[] { - return this.breadcrumbService.items.map((item) => ({ - ...item, - label: item.title || '', - })); - } + // get items() { + // console.log('asd'); + + // return this.breadcrumbService._items(); + // } } diff --git a/src/app/shared/components/page-loading.component.html b/src/app/shared/components/page-loading.component.html new file mode 100644 index 0000000..88a192a --- /dev/null +++ b/src/app/shared/components/page-loading.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/shared/components/page-loading.component.ts b/src/app/shared/components/page-loading.component.ts new file mode 100644 index 0000000..3838fba --- /dev/null +++ b/src/app/shared/components/page-loading.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; +import { ProgressSpinner } from 'primeng/progressspinner'; + +@Component({ + selector: 'shared-page-loading', + templateUrl: './page-loading.component.html', + imports: [ProgressSpinner], +}) +export class PageLoadingComponent {} diff --git a/src/app/shared/components/pageDataList/page-data-list.component.ts b/src/app/shared/components/pageDataList/page-data-list.component.ts index a9720d1..8fab474 100644 --- a/src/app/shared/components/pageDataList/page-data-list.component.ts +++ b/src/app/shared/components/pageDataList/page-data-list.component.ts @@ -87,9 +87,6 @@ export class PageDataListComponent { filterDrawerVisible = signal(false); ngOnInit() { - console.log(this.fullHeight); - console.log(this.height); - this.renderer.setStyle( this.host.nativeElement, 'height',