Skip to content

Commit

Permalink
feat(4ps): update assign user role
Browse files Browse the repository at this point in the history
  • Loading branch information
develite98 committed Jan 8, 2024
1 parent 75172fe commit 035b70f
Show file tree
Hide file tree
Showing 22 changed files with 281 additions and 33 deletions.
1 change: 1 addition & 0 deletions libs/mix-lib/src/model/core/roles.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface MixRole {
id: string;
name: string;
normalizedName: string;
roleId?: string;
}

export enum MixRoleConst {
Expand Down
3 changes: 3 additions & 0 deletions libs/mix-lib/src/model/core/user-vm.model.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MixRole } from './roles.model';

export interface UserDetail {
id: string;
userName: string;
Expand Down Expand Up @@ -52,6 +54,7 @@ export class UserListVm {
public lockoutEnabled?: boolean;
public accessFailedCount?: number;
public data?: UserDetail;
public roles: MixRole[] = [];

constructor(data: Partial<UserListVm>) {
Object.keys(data).forEach((key) => {
Expand Down
1 change: 1 addition & 0 deletions libs/mix-lib/src/swagger/mix.swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const MixSwagger = {
role: '/api/v2/rest/auth/role',
permission: '/api/v2/rest/mix-services/permission',
delete: '/api/v2/rest/auth/user/remove-user',
toggleRole: '/api/v2/rest/auth/user/user-in-role',
},
events: {
scheduler: '/api/v2/scheduler/trigger',
Expand Down
14 changes: 14 additions & 0 deletions libs/mix-share/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ export class AuthService extends BaseApiService {
return this.get<GlobalSettings>(MixSwagger.global.globalSetting);
}

public toggleUserInRoles(
active: boolean,
roleId: string,
roleName: string,
userId: string
) {
return this.post(MixSwagger.user.toggleRole, {
isUserInRole: active,
roleId,
roleName,
userId,
});
}

public gelCultures(): Observable<PaginationResultModel<Culture>> {
return this.get<PaginationResultModel<Culture>>(MixSwagger.auth.culture, {
pageSize: 100,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@
</div>

<div class="mix-dialog__footer">
<mix-button class="mr-auto"
type="outline"
(click)="ref.close()"
size="m">
Cancel
</mix-button>

<div *ngIf="mode === 'create'"
class="mr-auto">
class="mr-2">
<mix-checkbox [formControl]="continueCreate"
label="Continues to create"></mix-checkbox>
</div>

<mix-button type="outline"
(click)="ref.close()"
size="m">
Cancel
</mix-button>

<mix-button [loading]="(loadingState$ | async) === 'Loading'"
(click)="onSaveData()"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="p-3 border-b w-full border-slate-200 flex gap-3 items-center">
<div>
<mix-toggle [formControl]="activeForm"></mix-toggle>
</div>
<div>
{{ role.name }}
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MixRole } from '@mixcore/lib/model';
import { MixToggleComponent } from '@mixcore/ui/toggle';

@Component({
selector: 'role-active',
standalone: true,
imports: [CommonModule, MixToggleComponent, ReactiveFormsModule],
templateUrl: './role-active.component.html',
styleUrl: './role-active.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RoleActiveComponent {
@Output() public activeChange = new EventEmitter<boolean>();
@Input() public role!: MixRole;
@Input() public set active(value: boolean) {
this._active = value;
this.activeForm.patchValue(value, { emitEvent: false });
}
public get active() {
return this._active;
}
private _active: boolean = false;

public activeForm = new FormControl(this.active);

constructor() {
this.activeForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((v) => {
this.activeChange.emit(Boolean(v));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<div class="mix-dialog --default-padding h-full flex flex-col">
<div class="mix-dialog__header">Update user info</div>
<div class="mix-dialog__content grow grid grid-cols-4 divide-x">
<div class="col-span-1">
<div class="flex flex-col items-center text-center p-3 py-5">
<img class="rounded-circle"
src="https://st3.depositphotos.com/15648834/17930/v/600/depositphotos_179308454-stock-illustration-unknown-person-silhouette-glasses-profile.jpg"
width="150px"
height="150px">
<span class="font-weight-bold text-l">
<mix-inline-input placeHolder="Type the name"></mix-inline-input>
</span>
</div>

<div class="mt-3 pr-4">
<mix-text-area placeHolder="Note something..."></mix-text-area>
</div>

</div>

<div class="col-span-2 px-4"
[formGroup]="userForm">
<div class="text-xl font-medium"> Information </div>

<label class="content-label mt-4">Email</label>
<mix-input [mixAutoFocus]="true"
formControlName="email"
placeHolder="Type email"></mix-input>
<mix-form-error formControlName="email"></mix-form-error>

<label class="content-label mt-2">Username - Login ID</label>
<mix-input formControlName="username"
placeHolder="Type username for login"></mix-input>
<mix-form-error formControlName="username"></mix-form-error>

<label class="content-label mt-2">First name</label>
<mix-input formControlName="firstName"
placeHolder="Type first name"></mix-input>
<mix-form-error formControlName="firstName"></mix-form-error>

<label class="content-label mt-2">Last name</label>
<mix-input formControlName="lastName"
placeHolder="Type last name"></mix-input>
<mix-form-error formControlName="lastName"></mix-form-error>

<div class="w-full bg-slate-100 p-4 rounded-md mt-4">
<label class="content-label">New Password:</label>
<mix-input type="password"
formControlName="password"
placeHolder="Type password"></mix-input>
<mix-form-error formControlName="password"></mix-form-error>

<label class="content-label mt-2">Confirm Password:</label>
<mix-input type="password"
formControlName="confirmPassword"
placeHolder="Confirm password"></mix-input>
<mix-form-error formControlName="confirmPassword"></mix-form-error>
</div>

</div>

<div *ngIf="roleStore.vm$ | async as vm"
class="col-span-1 px-4">
<div class="text-xl font-medium mb-4"> Roles </div>

@for (role of vm.data; track role.id) {
<role-active [active]="roleDict[role.id] === true"
[role]="role"
(activeChange)="userRoleChange(role , $event)"></role-active>
}

</div>
</div>

<div class="mix-dialog__footer mt-auto">
<mix-button class="mr-auto"
type="outline"
[loading]="loadingState() === 'Loading'"
(click)="dialogRef.close()">Cancel</mix-button>
<mix-button [loading]="loadingState() === 'Loading'"
(click)="dialogRef.close()">Update</mix-button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:host {
height: 100%;
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import {
FormControl,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import { MixRole, UserListVm } from '@mixcore/lib/model';
import { MixApiFacadeService } from '@mixcore/share/api';
import { AuthService } from '@mixcore/share/auth';
import { BaseComponent } from '@mixcore/share/base';
import { MixAutoFocus } from '@mixcore/share/directives';
import { MixFormErrorComponent } from '@mixcore/share/form';
import { toastObserverProcessing } from '@mixcore/share/helper';
import { UserInfoStore } from '@mixcore/share/stores';
import { MixButtonComponent } from '@mixcore/ui/button';
import { MixInlineInputComponent } from '@mixcore/ui/inline-input';
import { MixInputComponent } from '@mixcore/ui/input';
import { MixTextAreaComponent } from '@mixcore/ui/textarea';
import { DialogRef, DialogService } from '@ngneat/dialog';
import { HotToastService } from '@ngneat/hot-toast';
import { RolesStore } from '../../stores/roles.store';
import { UserStore } from '../../stores/user.store';
import { RoleActiveComponent } from '../role-active/role-active.component';

@Component({
selector: 'update-user-dialog',
standalone: true,
imports: [
CommonModule,
MixButtonComponent,
MixInputComponent,
MixInlineInputComponent,
MixFormErrorComponent,
MixTextAreaComponent,
MixAutoFocus,
ReactiveFormsModule,
RoleActiveComponent,
],
templateUrl: './update-user-dialog.component.html',
styleUrl: './update-user-dialog.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UpdateUserDialogComponent extends BaseComponent {
public store = inject(UserStore);
public infoStore = inject(UserInfoStore);
public roleStore = inject(RolesStore);

public mixApi = inject(MixApiFacadeService);
public dialog = inject(DialogService);
public toast = inject(HotToastService);
public dialogRef = inject(DialogRef);
public authService = inject(AuthService);

public roleDict: Record<string, boolean> = {};
public userData!: UserListVm;
public userForm = new FormGroup({
avatar: new FormControl('', { validators: [], nonNullable: true }),
username: new FormControl('', {
validators: [Validators.required],
nonNullable: true,
}),
password: new FormControl('', {
validators: [Validators.required],
nonNullable: true,
}),
confirmPassword: new FormControl('', {
validators: [Validators.required],
nonNullable: true,
}),
firstName: new FormControl('', { validators: [], nonNullable: true }),
lastName: new FormControl('', { validators: [], nonNullable: true }),
email: new FormControl('', {
validators: [Validators.email],
nonNullable: true,
}),
});

ngOnInit() {
this.userData = this.dialogRef.data;
this.userForm.patchValue(this.userData);
(this.userData.roles || []).forEach((role) => {
this.roleDict[role.roleId!] = true;
});
}

public userRoleChange(role: MixRole, active: boolean) {
this.authService
.toggleUserInRoles(active, role.id, role.name, this.userData.id)
.pipe(toastObserverProcessing(this.toast))
.subscribe({
next: () => {
this.roleDict[role.id] = active;
},
});
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
mixTableColumn>
<ng-template let-data
mixColumnCell>
<div class="text-600">
<div class="text-600 cursor-pointer"
(click)="editUser(data)">
<div class="flex items-center">
<div class="user-avatar">
<img [src]="
Expand Down
10 changes: 8 additions & 2 deletions libs/mix-share/src/modules/account/users/users.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { MixDataTableModule, TableContextMenu } from '@mixcore/ui/table';
import { DialogService } from '@ngneat/dialog';
import { tuiPure } from '@taiga-ui/cdk';
import { CreateUserDialogComponent } from '../components/create-user-dialog/create-user-dialog.component';
import { UserDetailDialogComponent } from '../components/user-detail-dialog/user-detail-dialog.component';
import { UpdateUserDialogComponent } from '../components/update-user-dialog/update-user-dialog.component';
import { UserStore } from '../stores/user.store';
import { UserService } from './services/user.service';

Expand Down Expand Up @@ -70,7 +70,13 @@ export class UserComponent extends BasePageComponent {
}

public editUser(item: UserListVm): void {
this.dialog.open(UserDetailDialogComponent);
this.dialog.open(UpdateUserDialogComponent, {
width: '80vw',
height: '90vh',
maxWidth: 1440,
maxHeight: 840,
data: item,
});
}

@tuiPure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MixButtonComponent } from '@mixcore/ui/button';
imports: [CommonModule, MixButtonComponent],
template: `
<mix-button
style="width: fit-content; display: block"
[loading]="loadingState() === 'Loading'"
(click)="backupSingleTable()"
>Backup table</mix-button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MixButtonComponent } from '@mixcore/ui/button';
imports: [CommonModule, MixButtonComponent],
template: `
<mix-button
style="width: fit-content; display: block"
[loading]="loadingState() === 'Loading'"
(click)="migrateSingleTable()"
>Migrate to single table</mix-button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MixButtonComponent } from '@mixcore/ui/button';
imports: [CommonModule, MixButtonComponent],
template: `
<mix-button
style="width: fit-content; display: block"
[type]="'danger'"
[loading]="loadingState() === 'Loading'"
(click)="restoreSingleTable()"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MixButtonComponent } from '@mixcore/ui/button';
imports: [CommonModule, MixButtonComponent],
template: `
<mix-button
style="width: fit-content; display: block"
[loading]="loadingState() === 'Loading'"
(click)="updateSingleTable()"
>Update data table</mix-button
Expand Down
Loading

1 comment on commit 035b70f

@vercel
Copy link

@vercel vercel bot commented on 035b70f Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.