diff --git a/src/app/api/utils/create-api/create-api.ts b/src/app/api/utils/create-api/create-api.ts index a3433a04..9a3a49c7 100644 --- a/src/app/api/utils/create-api/create-api.ts +++ b/src/app/api/utils/create-api/create-api.ts @@ -61,7 +61,9 @@ export function createApi< private call(name: keyof T, params: Record) { return this.createExtendedParams().pipe( - switchMap((p) => this.api[name](Object.assign({}, params, ...p))), + switchMap((extendParams) => + this.api[name](Object.assign({}, ...extendParams, params)), + ), ); } diff --git a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.html b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.html index 5c7e966c..816a63db 100644 --- a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.html +++ b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.html @@ -7,7 +7,9 @@ *ngFor="let roleId of roleIds" class="dsh-body-2" fxLayoutAlign="center center" - >{{ (roleIdDict$ | async)?.[roleId] }} diff --git a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.ts b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.ts index 703616ff..69ee45a5 100644 --- a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.ts +++ b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.component.ts @@ -6,18 +6,20 @@ import { Input, OnInit, Output, + OnChanges, } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { MemberRole, ResourceScopeId, RoleId } from '@vality/swag-organizations'; +import { ComponentChanges } from '@vality/ng-core'; +import { MemberRole, ResourceScopeId, RoleId, Organization } from '@vality/swag-organizations'; import { coerceBoolean } from 'coerce-property'; import isNil from 'lodash-es/isNil'; -import { BehaviorSubject, combineLatest, EMPTY, Observable, of } from 'rxjs'; -import { first, map, switchMap, tap } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, EMPTY, Observable, of, ReplaySubject } from 'rxjs'; +import { first, map, switchMap, tap, shareReplay } from 'rxjs/operators'; import { OrganizationsDictionaryService } from '@dsh/app/api/organizations'; +import { ShopsService } from '@dsh/app/api/payments'; import { DialogConfig, DIALOG_CONFIG } from '@dsh/app/sections/tokens'; -import { ShopsDataService } from '@dsh/app/shared'; import { sortRoleIds } from '@dsh/app/shared/components/organization-roles/utils/sort-role-ids'; import { PartialReadonly } from '@dsh/type-utils'; @@ -34,7 +36,7 @@ import { SelectRoleDialogData } from './components/select-role-dialog/types/sele templateUrl: 'change-roles-table.component.html', styleUrls: ['change-roles-table.component.scss'], }) -export class ChangeRolesTableComponent implements OnInit { +export class ChangeRolesTableComponent implements OnInit, OnChanges { @Input() set roles(roles: PartialReadonly[]) { if (!isNil(roles)) { this.roles$.next(roles); @@ -44,6 +46,7 @@ export class ChangeRolesTableComponent implements OnInit { get roles(): PartialReadonly[] { return this.roles$.value; } + @Input() organization: Organization; /** * Edit mode: @@ -57,8 +60,14 @@ export class ChangeRolesTableComponent implements OnInit { @Output() addedRoles = new EventEmitter[]>(); @Output() removedRoles = new EventEmitter[]>(); + organization$ = new ReplaySubject(1); roleIds: RoleId[] = []; - shops$ = this.shopsDataService.shops$; + shops$ = this.organization$.pipe( + switchMap((organization) => + this.shopsService.getShopsForParty({ partyID: organization.party }), + ), + shareReplay({ bufferSize: 1, refCount: true }), + ); roleIdDict$ = this.organizationsDictionaryService.roleId$; get availableRoles(): RoleId[] { @@ -71,20 +80,31 @@ export class ChangeRolesTableComponent implements OnInit { roles$ = new BehaviorSubject[]>([]); - isAllowRemoves$ = this.roles$.pipe(map((r) => r.length > 1)); + isAllowRemoves$ = this.roles$.pipe( + map( + (roles) => + !this.editMode || roles.some((r) => roles.some((b) => b.roleId !== r.roleId)), + ), + ); private get hasAdminRole() { return !!this.roles.find((r) => r.id === RoleId.Administrator); } constructor( - private shopsDataService: ShopsDataService, + private shopsService: ShopsService, private dialog: MatDialog, @Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig, private cdr: ChangeDetectorRef, private organizationsDictionaryService: OrganizationsDictionaryService, ) {} + ngOnChanges({ organization }: ComponentChanges) { + if (organization) { + this.organization$.next(organization.currentValue); + } + } + ngOnInit(): void { this.roles$.pipe(untilDestroyed(this)).subscribe((roles) => this.selectedRoles.emit(roles)); } @@ -116,6 +136,25 @@ export class ChangeRolesTableComponent implements OnInit { }); } + show(roleId: RoleId) { + const removeDialogsClass = addDialogsClass(this.dialog.openDialogs, 'dsh-hidden'); + this.dialog + .open( + SelectRoleDialogComponent, + { + ...this.dialogConfig.large, + data: { availableRoles: [roleId], isShow: true }, + }, + ) + .afterClosed() + .pipe(untilDestroyed(this)) + .subscribe({ + complete: () => { + removeDialogsClass(); + }, + }); + } + remove(roleId: RoleId): void { this.removeRoleIds([roleId]); this.removeRoles(this.roles.filter((r) => r.roleId === roleId)); diff --git a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.module.ts b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.module.ts index c52fa26c..9fce0c53 100644 --- a/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.module.ts +++ b/src/app/sections/organization-section/organization-details/change-roles-table/change-roles-table.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FlexModule } from '@angular/flex-layout'; import { ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatRadioModule } from '@angular/material/radio'; import { TranslocoModule } from '@ngneat/transloco'; @@ -26,6 +27,7 @@ import { SelectRoleDialogComponent } from './components/select-role-dialog/selec MatRadioModule, ReactiveFormsModule, SelectionModule, + MatButtonModule, ], declarations: [ChangeRolesTableComponent, SelectRoleDialogComponent], exports: [ChangeRolesTableComponent], diff --git a/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/select-role-dialog.component.html b/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/select-role-dialog.component.html index 3d032389..f350fd82 100644 --- a/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/select-role-dialog.component.html +++ b/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/select-role-dialog.component.html @@ -5,13 +5,13 @@ > - + {{ (roleIdDict$ | async)?.[role] }} - + @@ -33,7 +33,7 @@ - + diff --git a/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/types/selected-role-dialog-data.ts b/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/types/selected-role-dialog-data.ts index 56777714..0176607c 100644 --- a/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/types/selected-role-dialog-data.ts +++ b/src/app/sections/organization-section/organization-details/change-roles-table/components/select-role-dialog/types/selected-role-dialog-data.ts @@ -2,4 +2,5 @@ import { RoleId } from '@vality/swag-organizations'; export interface SelectRoleDialogData { availableRoles: RoleId[]; + isShow?: boolean; } diff --git a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.html b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.html index b0dc0a9a..5f2ce24d 100644 --- a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.html +++ b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.html @@ -17,7 +17,10 @@

{{ t('roles') }}

- +
diff --git a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.ts b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.ts index b5df5459..832a0d07 100644 --- a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.ts +++ b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/create-invitation-dialog.component.ts @@ -37,7 +37,7 @@ export class CreateInvitationDialogComponent { create() { return this.invitationsService .createInvitation({ - orgId: this.data.orgId, + orgId: this.data.organization.id, invitationRequest: { invitee: { contact: { diff --git a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/types/create-invitation-dialog-data.ts b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/types/create-invitation-dialog-data.ts index 2e222528..94270807 100644 --- a/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/types/create-invitation-dialog-data.ts +++ b/src/app/sections/organization-section/organization-details/invitations/components/create-invitation-dialog/types/create-invitation-dialog-data.ts @@ -1,5 +1,5 @@ import { Organization } from '@vality/swag-organizations'; export type CreateInvitationDialogData = { - orgId: Organization['id']; + organization: Organization; }; diff --git a/src/app/sections/organization-section/organization-details/invitations/invitations.component.ts b/src/app/sections/organization-section/organization-details/invitations/invitations.component.ts index 9834a71b..9ed71568 100644 --- a/src/app/sections/organization-section/organization-details/invitations/invitations.component.ts +++ b/src/app/sections/organization-section/organization-details/invitations/invitations.component.ts @@ -43,7 +43,7 @@ export class InvitationsComponent { return this.organization$ .pipe( first(), - switchMap(({ id: orgId }) => + switchMap((organization) => this.dialog .open< CreateInvitationDialogComponent, @@ -51,7 +51,7 @@ export class InvitationsComponent { BaseDialogResponseStatus >(CreateInvitationDialogComponent, { ...this.dialogConfig.large, - data: { orgId }, + data: { organization }, }) .afterClosed(), ), diff --git a/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/edit-roles-dialog.component.html b/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/edit-roles-dialog.component.html index 92ae8888..38450632 100644 --- a/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/edit-roles-dialog.component.html +++ b/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/edit-roles-dialog.component.html @@ -5,6 +5,7 @@ (cancel)="cancel()" > this.updateRoles$).pipe( switchMap(() => this.membersService - .getOrgMember({ orgId: this.data.orgId, userId: this.data.userId }) + .getOrgMember({ orgId: this.data.organization.id, userId: this.data.userId }) .pipe(map((r) => r.roles)), ), untilDestroyed(this), @@ -45,7 +45,7 @@ export class EditRolesDialogComponent { return forkJoin( roles.map((memberRole) => this.membersService.assignMemberRole({ - orgId: this.data.orgId, + orgId: this.data.organization.id, userId: this.data.userId, memberRole, }), @@ -65,7 +65,7 @@ export class EditRolesDialogComponent { roles.map((role) => this.membersService .removeMemberRole({ - orgId: this.data.orgId, + orgId: this.data.organization.id, userId: this.data.userId, memberRoleId: role.id, }) diff --git a/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/types/edit-roles-dialog-data.ts b/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/types/edit-roles-dialog-data.ts index f2ce6ee0..4fefd22e 100644 --- a/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/types/edit-roles-dialog-data.ts +++ b/src/app/sections/organization-section/organization-details/members/components/edit-roles-dialog/types/edit-roles-dialog-data.ts @@ -1,4 +1,6 @@ +import { Organization } from '@vality/swag-organizations'; + export interface EditRolesDialogData { - orgId: string; + organization: Organization; userId: string; } diff --git a/src/app/sections/organization-section/organization-details/members/components/member/member.component.ts b/src/app/sections/organization-section/organization-details/members/components/member/member.component.ts index ed7b1d1d..bd2caed2 100644 --- a/src/app/sections/organization-section/organization-details/members/components/member/member.component.ts +++ b/src/app/sections/organization-section/organization-details/members/components/member/member.component.ts @@ -82,7 +82,7 @@ export class MemberComponent implements OnChanges { .open(EditRolesDialogComponent, { ...this.dialogConfig.large, data: { - orgId: this.organization.id, + organization: this.organization, userId: this.member.id, }, }) diff --git a/src/app/sections/payment-section/integrations/integrations.component.html b/src/app/sections/payment-section/integrations/integrations.component.html index 839c8f5c..fcbf3da3 100644 --- a/src/app/sections/payment-section/integrations/integrations.component.html +++ b/src/app/sections/payment-section/integrations/integrations.component.html @@ -4,16 +4,18 @@ fxLayoutGap="32px" > diff --git a/src/app/sections/payment-section/integrations/integrations.component.ts b/src/app/sections/payment-section/integrations/integrations.component.ts index 8a80fb92..6a06e84a 100644 --- a/src/app/sections/payment-section/integrations/integrations.component.ts +++ b/src/app/sections/payment-section/integrations/integrations.component.ts @@ -1,6 +1,8 @@ import { Component } from '@angular/core'; import { TranslocoService } from '@ngneat/transloco'; +import { RoleAccessName } from '@dsh/app/auth'; + @Component({ templateUrl: 'integrations.component.html', }) @@ -13,6 +15,7 @@ export class IntegrationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.PaymentLinks], }, { path: 'api-keys', @@ -21,6 +24,7 @@ export class IntegrationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.ApiKeys], }, { path: 'webhooks', @@ -29,6 +33,7 @@ export class IntegrationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.Webhooks], }, ]; diff --git a/src/app/sections/payment-section/integrations/integrations.module.ts b/src/app/sections/payment-section/integrations/integrations.module.ts index 8ee976ee..e322f629 100644 --- a/src/app/sections/payment-section/integrations/integrations.module.ts +++ b/src/app/sections/payment-section/integrations/integrations.module.ts @@ -4,6 +4,7 @@ import { FlexModule } from '@angular/flex-layout'; import { MatTabsModule } from '@angular/material/tabs'; import { TranslocoModule } from '@ngneat/transloco'; +import { AuthModule } from '@dsh/app/auth'; import { LayoutModule } from '@dsh/components/layout'; import { ScrollUpModule } from '@dsh/components/navigation'; @@ -19,6 +20,7 @@ import { IntegrationsComponent } from './integrations.component'; TranslocoModule, ScrollUpModule, MatTabsModule, + AuthModule, ], declarations: [IntegrationsComponent], }) diff --git a/src/app/sections/payment-section/operations/operations.component.html b/src/app/sections/payment-section/operations/operations.component.html index f704bc8d..7a705b4f 100644 --- a/src/app/sections/payment-section/operations/operations.component.html +++ b/src/app/sections/payment-section/operations/operations.component.html @@ -5,16 +5,18 @@ fxLayoutGap="32px" >
diff --git a/src/app/sections/payment-section/operations/operations.component.ts b/src/app/sections/payment-section/operations/operations.component.ts index 38af422d..c773b728 100644 --- a/src/app/sections/payment-section/operations/operations.component.ts +++ b/src/app/sections/payment-section/operations/operations.component.ts @@ -1,6 +1,8 @@ import { Component } from '@angular/core'; import { TranslocoService } from '@ngneat/transloco'; +import { RoleAccessName } from '@dsh/app/auth'; + @Component({ templateUrl: 'operations.component.html', }) @@ -13,6 +15,7 @@ export class OperationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.ViewPayments], }, { path: 'invoices', @@ -21,6 +24,7 @@ export class OperationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.ViewInvoices], }, { path: 'refunds', @@ -29,6 +33,7 @@ export class OperationsComponent { null, 'payment-section', ), + roles: [RoleAccessName.ViewRefunds], }, ]; diff --git a/src/app/sections/payment-section/operations/operations.module.ts b/src/app/sections/payment-section/operations/operations.module.ts index f2ea3312..02450d48 100644 --- a/src/app/sections/payment-section/operations/operations.module.ts +++ b/src/app/sections/payment-section/operations/operations.module.ts @@ -4,6 +4,7 @@ import { FlexLayoutModule } from '@angular/flex-layout'; import { MatTabsModule } from '@angular/material/tabs'; import { TranslocoModule } from '@ngneat/transloco'; +import { AuthModule } from '@dsh/app/auth'; import { LayoutModule } from '@dsh/components/layout'; import { ScrollUpModule } from '@dsh/components/navigation'; @@ -19,6 +20,7 @@ import { OperationsComponent } from './operations.component'; TranslocoModule, ScrollUpModule, MatTabsModule, + AuthModule, ], declarations: [OperationsComponent], }) diff --git a/src/app/sections/payment-section/payment-section-routing.module.ts b/src/app/sections/payment-section/payment-section-routing.module.ts index ee1c1399..e540e8d7 100644 --- a/src/app/sections/payment-section/payment-section-routing.module.ts +++ b/src/app/sections/payment-section/payment-section-routing.module.ts @@ -31,11 +31,18 @@ const PAYMENT_SECTION_ROUTES: Routes = [ }, [RoleAccessName.ViewAnalytics], ), - { - path: 'operations', - loadChildren: () => - import('./operations/operations.module').then((m) => m.OperationsModule), - }, + createPrivateRoute( + { + path: 'operations', + loadChildren: () => + import('./operations/operations.module').then((m) => m.OperationsModule), + }, + [ + RoleAccessName.ViewPayments, + RoleAccessName.ViewInvoices, + RoleAccessName.ViewRefunds, + ], + ), createPrivateRoute( { path: 'reports', @@ -51,11 +58,16 @@ const PAYMENT_SECTION_ROUTES: Routes = [ // }, // [RoleAccessName.ViewPayouts] // ), - { - path: 'integrations', - loadChildren: () => - import('./integrations/integrations.module').then((m) => m.IntegrationsModule), - }, + createPrivateRoute( + { + path: 'integrations', + loadChildren: () => + import('./integrations/integrations.module').then( + (m) => m.IntegrationsModule, + ), + }, + [RoleAccessName.PaymentLinks, RoleAccessName.ApiKeys, RoleAccessName.Webhooks], + ), ], }, ]; diff --git a/src/app/sections/payment-section/shops/shops.component.html b/src/app/sections/payment-section/shops/shops.component.html index 20d982ba..a8a3640b 100644 --- a/src/app/sections/payment-section/shops/shops.component.html +++ b/src/app/sections/payment-section/shops/shops.component.html @@ -3,7 +3,13 @@ fxLayout="column" fxLayoutGap="32px" > -
+
= defer(() => - combineLatest([ - this.organization$, - this.contextOrganizationService.organization$.pipe(pluck('party')), - ]), + combineLatest([this.organization$, this.keycloakTokenInfoService.userID$]), ).pipe( map(([{ owner }, id]) => owner === id), shareReplay(SHARE_REPLAY_CONF), ); - isOrganizationAdmin$: Observable = this.contextOrganizationService.member$.pipe( - map((member) => member.roles.findIndex((r) => r.roleId === RoleId.Administrator) !== -1), + isOrganizationAdmin$: Observable = combineLatest([ + this.members$, + this.keycloakTokenInfoService.userID$, + ]).pipe( + map(([members, userId]) => members.find((m) => m.id === userId)), + map( + (member) => member?.roles?.findIndex?.((r) => r.roleId === RoleId.Administrator) !== -1, + ), shareReplay(SHARE_REPLAY_CONF), ); hasAdminAccess$: Observable = defer(() => @@ -39,7 +42,7 @@ export class OrganizationManagementService implements Initializable { constructor( private membersService: MembersService, - private contextOrganizationService: ContextOrganizationService, + private keycloakTokenInfoService: KeycloakTokenInfoService, ) {} init(organization: Organization) { diff --git a/src/assets/i18n/organization-section/en.json b/src/assets/i18n/organization-section/en.json index 30a277ec..d26ab69d 100644 --- a/src/assets/i18n/organization-section/en.json +++ b/src/assets/i18n/organization-section/en.json @@ -115,7 +115,7 @@ "manageWebhooks": "Manage webhooks", "payments": "Payments", "viewAnalytics": "View analytics", - "viewApiKey": "View the API key", + "viewApiKey": "View API keys", "viewInvoices": "View invoices", "viewPayments": "View payments", "viewPayouts": "View payouts", diff --git a/src/assets/i18n/organization-section/ru.json b/src/assets/i18n/organization-section/ru.json index 113081e1..f4e63e0d 100644 --- a/src/assets/i18n/organization-section/ru.json +++ b/src/assets/i18n/organization-section/ru.json @@ -115,7 +115,7 @@ "manageWebhooks": "Управление Webhooks", "payments": "Платежи", "viewAnalytics": "Просмотр аналитики", - "viewApiKey": "Просмотр API ключа", + "viewApiKey": "Просмотр API ключей", "viewInvoices": "Просмотр инвойсов", "viewPayments": "Просмотр платежей", "viewPayouts": "Просмотр возмещений",