Skip to content
Snippets Groups Projects
Commit 039beb2c authored by Kawtar Laariche's avatar Kawtar Laariche
Browse files

#19: implement share with team logic

parent 85efbb27
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,6 @@ import { Component, ElementRef, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service';
import { BrowserStorageService } from 'src/app/core/services/storage/browser-storage.service';
import { MatDividerModule } from '@angular/material/divider';
import { MatTabsModule } from '@angular/material/tabs';
import { MatProgressBarModule } from '@angular/material/progress-bar';
......@@ -47,7 +46,6 @@ export class ModelDetailsDescriptionComponent {
constructor(
private activatedRoute: ActivatedRoute,
private publicSolutionsService: PublicSolutionsService,
private browserStorageService: BrowserStorageService,
private sharedDataService: SharedDataService,
) {}
......
<div class="workflow-right-header workflow-header">Share With Team</div>
<div style="display: flex; flex-direction: column; gap: 20px; margin: 24px">
<div>
<p class="manage-models">
Sharing a model gives co-authorship to that person. They will be able to
edit, share and publish, just as a model owner can.
</p>
</div>
<mat-divider style="color: #dbcbe8"></mat-divider>
<div style="display: flex; flex-direction: column">
<div style="display: flex; flex-direction: row" class="manage-models">
<span>This Model shared with below team members</span>|<span
class="green"
>
({{ sharedWith.length }} members)</span
>
</div>
<div>
<mat-chip-set style="justify-content: space-evenly !important">
@for (sharedUser of sharedWith; track sharedUser) {
<mat-chip (removed)="removeUser(sharedUser)" style="width: 80px">
<div style="display: flex; flex-direction: column; width: 100%">
<div
style="display: flex; justify-content: flex-end; width: 100%"
>
<button
matChipRemove
[attr.aria-label]="'remove ' + sharedUser"
>
<mat-icon>cancel</mat-icon>
</button>
</div>
<div
style="
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
"
>
<img
style="width: 30px; height: 30px"
src="../../../../assets/images/user-profile-black.png"
/>
<span
class="team-user-box"
[title]="
[sharedUser.firstName, sharedUser.lastName].join(' ')
"
>
{{
[sharedUser.firstName, sharedUser.lastName].join(" ")
| truncate: 8
}}
</span>
</div>
</div>
<!-- <div
style="display: flex; flex-direction: row; justify-content: end"
>
<button matChipRemove [attr.aria-label]="'remove ' + sharedUser">
<mat-icon>cancel</mat-icon>
</button>
</div>
<div
style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
"
>
<img
style="width: 30px; height: 30px"
src="../../../../assets/images/user-profile-black.png"
/>
<span
[title]="[sharedUser.firstName, sharedUser.lastName].join(' ')"
>
{{
[sharedUser.firstName, sharedUser.lastName].join(" ")
| truncate: 8
}}
</span>
</div> -->
</mat-chip>
}
</mat-chip-set>
</div>
</div>
<mat-divider></mat-divider>
<div
style="display: flex; flex-direction: row; gap: 4px"
class="manage-models"
>
<span class="purple">Sharing "{{ solution.name }}" </span>
|<span> Version - {{ selectedRevision.version }}</span>
|
<gp-solution-id [solutionId]="solutionId"></gp-solution-id>
</div>
<form>
<mat-form-field class="example-chip-list">
<mat-label>Find a user to share with</mat-label>
<mat-chip-grid #chipGrid>
@for (user of users; track user) {
<mat-chip-row (removed)="remove(user)">
{{ user.firstName }} {{ user.lastName }}
<button matChipRemove [attr.aria-label]="'remove ' + user">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
</mat-chip-grid>
<input
#userInput
[formControl]="userCtrl"
[matChipInputFor]="chipGrid"
[matAutocomplete]="auto"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
/>
<mat-autocomplete
#auto="matAutocomplete"
(optionSelected)="selected($event)"
>
@for (user of filteredUsers | async; track user) {
<mat-option [value]="user"
><span style="overflow: hidden; white-space: nowrap"
>{{ user.firstName }} {{ user.lastName }}</span
></mat-option
>
}
</mat-autocomplete>
</mat-form-field>
</form>
<button
style="width: 80px"
[disabled]="users.length <= 0"
color="primary"
mat-raised-button
(click)="OnclickShareButton()"
>
Share
</button>
</div>
.example-chip-list {
width: 100%;
}
.mat-divider {
border-top-color: #dbcbe8 !important;
border-top-width: 1px !important;
}
.mat-mdc-chip.mat-mdc-standard-chip {
--mdc-chip-container-height: 100% !important;
}
::ng-deep.mat-mdc-standard-chip.mdc-evolution-chip--with-trailing-action
.mdc-evolution-chip__action--primary {
padding: 0px !important;
width: 100% !important;
}
::ng-deep.mat-mdc-standard-chip {
--mdc-chip-container-shape-radius: 3px 3x 3px 3px;
border: 1px solid #e0e0e0 !important;
--mdc-chip-elevated-container-color: transparent !important;
}
::ng-deep.mat-mdc-standard-chip.mdc-evolution-chip--with-trailing-action
.mdc-evolution-chip__action--trailing {
padding-left: 0px !important;
padding-right: 2px !important;
}
::ng-deep.mat-mdc-standard-chip .mdc-evolution-chip__cell--primary,
::ng-deep.mat-mdc-standard-chip .mdc-evolution-chip__action--primary,
::ng-deep.mat-mdc-standard-chip .mat-mdc-chip-action-label {
width: 100% !important;
}
.team-user-box {
padding: 0 5px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
color: 666;
font-weight: 600;
}
.manage-models {
font-size: 14px;
letter-spacing: 0;
line-height: 24px;
word-break: break-word;
overflow-wrap: break-word;
hyphens: auto;
}
.purple {
color: #671c9d;
}
.green {
color: #009901;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.actions {
display: flex;
justify-content: flex-end;
}
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
Component,
ElementRef,
OnInit,
ViewChild,
inject,
} from '@angular/core';
import { AsyncPipe, CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatDividerModule } from '@angular/material/divider';
import {
MatAutocompleteModule,
MatAutocompleteSelectedEvent,
} from '@angular/material/autocomplete';
import { Observable, Subscription, map, startWith } from 'rxjs';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips';
import { LiveAnnouncer } from '@angular/cdk/a11y';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service';
import {
Alert,
AlertType,
PublicSolutionDetailsModel,
Revision,
UserDetails,
} from '../../models';
import { ActivatedRoute } from '@angular/router';
import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { DeleteUserDialogConfirmationActionComponent } from '../delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component';
import { AlertService } from 'src/app/core/services/alert.service';
import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service';
import { SolutionIdComponent } from '../solution-id/solution-id.component';
import { TruncatePipe } from '../../pipes/truncate.pipe';
export interface State {
flag: string;
name: string;
population: string;
}
@Component({
selector: 'gp-share-with-team-page',
standalone: true,
imports: [CommonModule],
imports: [
CommonModule,
MatButtonModule,
MatIconModule,
FormsModule,
MatFormFieldModule,
MatChipsModule,
MatIconModule,
MatAutocompleteModule,
ReactiveFormsModule,
MatDividerModule,
AsyncPipe,
SolutionIdComponent,
TruncatePipe,
],
templateUrl: './share-with-team-page.component.html',
styleUrl: './share-with-team-page.component.scss'
styleUrl: './share-with-team-page.component.scss',
})
export class ShareWithTeamPageComponent {
export class ShareWithTeamPageComponent implements OnInit {
separatorKeysCodes: number[] = [ENTER, COMMA];
fruitCtrl = new FormControl('');
userCtrl = new FormControl('');
filteredFruits: Observable<string[]>;
filteredUsers: Observable<UserDetails[]>;
fruits: string[] = [''];
users: UserDetails[] = [];
allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];
allUsersList: UserDetails[] = [];
allUserDetails: UserDetails[] = [];
sharedWith: UserDetails[] = [];
solutionId!: string;
revisionId!: string;
selectedRevision!: Revision;
selectedRevisionSubscription!: Subscription;
solution!: PublicSolutionDetailsModel;
@ViewChild('fruitInput') fruitInput!: ElementRef<HTMLInputElement>;
@ViewChild('userInput') userInput!: ElementRef<HTMLInputElement>;
announcer = inject(LiveAnnouncer);
constructor(
private publicSolutionsService: PublicSolutionsService,
private privateCatalogsService: PrivateCatalogsService,
private sharedDataService: SharedDataService,
private activatedRoute: ActivatedRoute,
public dialog: MatDialog,
private alertService: AlertService,
) {
this.filteredFruits = this.fruitCtrl.valueChanges.pipe(
startWith(null),
map((fruit: string | null) =>
fruit ? this._filter(fruit) : this.allFruits.slice(),
),
);
this.filteredUsers = this.userCtrl.valueChanges.pipe(
startWith(''), // Start with an empty string
map((value) => {
return this.transformValue(value);
}),
map((name) =>
name ? this._filterUser(name) : this.allUsersList.slice(),
),
);
}
transformValue(value: string | UserDetails | null): string {
if (typeof value === 'string') {
return value; // Directly return the string
} else if (value) {
return this.displayFn(value); // Convert UserDetails to string if not null
}
return ''; // Return empty string if value is null
}
displayFn(user: UserDetails): string {
return user ? `${user.firstName} ${user.lastName}`.trim() : '';
}
ngOnInit(): void {
this.activatedRoute.parent?.params.subscribe((params) => {
this.solutionId = params['solutionId'];
this.revisionId = params['revisionId'];
this.getShareWithTeam(this.solutionId);
this.loadSolutionDetails(this.solutionId, this.revisionId);
this.selectedRevisionSubscription =
this.sharedDataService.selectedRevision$.subscribe(
(revision: Revision) => {
this.selectedRevision = revision;
},
);
});
}
/* addUser(event: MatChipInputEvent): void {
const value = (event.value || '').trim();
this.allUsersList.filter(
(user) =>
user.firstName.toLowerCase().includes(value) ||
user.lastName?.toLowerCase().includes(value),
);
} */
remove(user: UserDetails) {
const index = this.users.indexOf(user);
if (index >= 0) {
this.users.splice(index, 1);
this.announcer.announce(`Removed ${user}`);
}
}
selected(event: MatAutocompleteSelectedEvent): void {
this.users.push(event.option.value);
this.userInput.nativeElement.value = '';
this.userCtrl.setValue(null);
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.allFruits.filter((fruit) =>
fruit.toLowerCase().includes(filterValue),
);
}
private _filterUser(value: string): UserDetails[] {
const filterValue = value.toLowerCase();
return this.allUsersList.filter(
(user) =>
user.firstName.toLowerCase().includes(filterValue) ||
user.lastName?.toLowerCase().includes(filterValue),
);
}
getUsersChips(): void {
const userActiveStatus = true;
this.privateCatalogsService.getAllActiveUsers(userActiveStatus).subscribe({
next: (users) => {
const sharedWithIds = new Set(
this.sharedWith.map((user) => user.userId),
);
this.allUserDetails = users.filter((user) => {
return (
!sharedWithIds.has(user.userId) &&
user.userId != this.solution.ownerId
);
});
this.allUsersList = this.allUserDetails;
},
error: (error) => {
console.error('Error fetching users:', error);
},
});
}
getShareWithTeam(solutionId: string): void {
this.privateCatalogsService.getShareWithTeam(solutionId).subscribe({
next: (users) => {
this.sharedWith = users;
this.getUsersChips();
},
error: (error) => {
console.error('Error fetching users:', error);
},
});
}
loadSolutionDetails(solutionId: string, revisionId: string) {
this.publicSolutionsService
.getSolutionDetails(solutionId, revisionId)
.subscribe((res) => {
this.solution = res;
});
}
OnclickShareButton() {
const selectedUsersIds: string[] = this.users.map(
(user) => user.userId ?? '',
);
this.privateCatalogsService
.insertMultipleShare(selectedUsersIds, this.solutionId)
.subscribe((res) => {
const alert: Alert = {
message: '',
type: AlertType.Success,
};
if (res.error_code === '100') {
alert.message = 'Shared successfully. ';
}
this.alertService.notify(alert, 3000);
this.getShareWithTeam(this.solutionId);
this.users = [];
});
}
removeUser(user: UserDetails) {
const dialogRef: MatDialogRef<DeleteUserDialogConfirmationActionComponent> =
this.dialog.open(DeleteUserDialogConfirmationActionComponent, {
data: {
dataKey: {
solutionId: this.solutionId,
user: user,
},
},
autoFocus: false,
});
dialogRef.afterClosed().subscribe((result) => {
this.getShareWithTeam(this.solutionId);
});
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment