Commit 8cd1c29d by GD-A-150752

message-engine-hiring-team

parent 812d5215
......@@ -7,7 +7,7 @@ import { DeviceDetectorModule } from 'ngx-device-detector';
import { DndModule } from 'ngx-drag-drop';
import {
ConfirmationService,
DragDropModule,
DragDropModule, FileUploadModule,
InputMaskModule,
MultiSelectModule,
OrderListModule
......@@ -45,7 +45,8 @@ import { OneITModule } from './oneit/oneit.module';
DragDropModule,
OrderListModule,
MultiSelectModule,
DndModule
DndModule,
FileUploadModule
],
declarations: [
AppComponent,
......
......@@ -122,7 +122,7 @@ export const routes: Routes = [
canActivate: [AuthGuard]
},
{
path: 'message-engine/:jobId',
path: 'message-engine',
component: MessageEngineApplicantViewComponent
}
]
......
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { MessageTemplateModel } from "./models/message-template.model";
import { environment } from '../environments/environment';
import { MessageTemplateModel } from './models/message-template.model';
import { PlaceholderOptionsEnum } from './models/placeholder-options.enum';
import { TemplateTypeEnum } from './models/template-type.enum';
import { ApiService } from './oneit/services/api.service';
import { EnumService } from './oneit/services/enum.service';
import { SearchService } from './oneit/services/search.service';
import { UtilsService } from './oneit/services/utils.service';
......@@ -14,7 +16,8 @@ export class AppService {
constructor(
private enumService: EnumService,
private searchService: SearchService,
private utilsService: UtilsService
private utilsService: UtilsService,
private apiService: ApiService
) {
}
......@@ -53,4 +56,20 @@ export class AppService {
}
);
}
processObjects(serviceName: string, dataParams): Observable<any> {
const params: any = {
environment: environment.envName, // Fetch this from environment e.g. environment.envName
...dataParams
};
return this.apiService.post(`svc/${serviceName}`, params)
.map(
data => {
if (this.utilsService.isSuccessfulResponse(data)) {
return data;
}
}
);
}
}
......@@ -7,7 +7,7 @@
<div class="search-bar">
<div class="header-select" *ngIf="companyUser">
<select2 [data]="hiringTeams" [value]="selectedTeamID" (valueChanged)="selectedTeamChanged($event)"
[options]="select2Options">
[options]="select2Options">
</select2>
</div>
</div>
......@@ -28,7 +28,7 @@
<div class="user-profile-dropdown" dropdown *ngIf="userMenu">
<a class="user-name" dropdownToggle href="javascript:void(0)">
{{ userMenu.label }}
<img src="assets/images/arrow.svg" />
<img src="assets/images/arrow.svg"/>
</a>
<ul class="profile-dropdown dropdown-menu" *dropdownMenu>
<span class="arrow-up"></span>
......@@ -43,8 +43,9 @@
</ul>
</div>
<div class="create-job-btn">
<a *ngIf="selectedTeamID && companyUser" [ngClass]="{'disabled': createJobDisabled}" href="javascript:void(0)"
(click)="createJobClicked()">
<a *ngIf="selectedTeamID && companyUser" [ngClass]="{'disabled': createJobDisabled}"
href="javascript:void(0)"
(click)="createJobClicked()">
Create Job
</a>
</div>
......@@ -55,21 +56,26 @@
<ng-template #reachedCapModal>
<div class="modal-body main-welcome-popup">
<h2>Your account reached monthly cap!</h2>
<p *ngIf="isStandardUser">Your account has reached the monthly cap for number of jobs, contact your Administrator to have the Cap increased.</p>
<p *ngIf="isStandardUser">Your account has reached the monthly cap for number of jobs, contact your
Administrator to have the Cap increased.</p>
<ng-container *ngIf="!isStandardUser">
<p>Your account has reached the monthly cap for number of jobs. Please make a request by contacting us to make changes.</p>
<p>Your account has reached the monthly cap for number of jobs. Please make a request by contacting us to
make changes.</p>
<div class="create-y-f-job">
<a href=" https://www.matchd.com/support/" target="_blank">Make a Request</a>
</div>
</ng-container>
</div>
</div>
</ng-template>
<ng-template #trialNotAllowedModal>
<div class="modal-body main-welcome-popup">
<h2>Your account is on trial!</h2>
<p *ngIf="isStandardUser">Only one Job can be created during the Trial. Please contact your Administrator to set up billing.</p>
<p *ngIf="isStandardUser">Only one Job can be created during the Trial. Please contact your Administrator to set
up billing.</p>
<ng-container *ngIf="!isStandardUser">
<p>Only one Job can be created during the Trial. {{ !selectedTeam || !selectedTeam.CardID ? "Enter Billing Method and" : "" }} Select Plan to enable creation of additional jobs.</p>
<p>Only one Job can be created during the
Trial. {{ !selectedTeam || !selectedTeam.CardID ? "Enter Billing Method and" : "" }} Select Plan to
enable creation of additional jobs.</p>
<div class="create-y-f-job">
<a [routerLink]="['admin/iframe-page', redirectURL]">{{ !selectedTeam || !selectedTeam.CardID ? "Billing" : "Payment Plan" }}</a>
</div>
......@@ -97,5 +103,11 @@
<router-outlet (activate)="onRouteUpdate()"></router-outlet>
</div>
</div>
<p-dialog #messageEngine [(visible)]="showChat" header="" [modal]="true" [responsive]="true"
class="message-engine" [style]="{width: '300px', height: '500px'}">
<app-message-engine-applicant-view *ngIf="showChat" [embedded]="true"
(minimize)="showChat = false"></app-message-engine-applicant-view>
</p-dialog>
<div *ngIf="showBubble" class="chat-icon" (click)="showChat = !showChat"></div>
<p-progressSpinner animationDuration="1s" *ngIf="showLoader"></p-progressSpinner>
<app-feedback></app-feedback>
\ No newline at end of file
<app-feedback></app-feedback>
......@@ -6,12 +6,12 @@ import { BsModalService } from 'ngx-bootstrap/modal';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subscription } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { IframeMsgHandlingService } from "../../../oneit/services/iframe-msg-handling.service";
import { MsgsService } from '../../../oneit/services/msgs.service';
import { UserService } from '../../../oneit/services/user.service';
import { UtilsService } from '../../../oneit/services/utils.service';
import { AdminPortalLayoutService } from './admin-portal-layout.service';
@Component({
selector: 'app-admin-portal-layout',
templateUrl: './admin-portal-layout.component.html'
......@@ -22,7 +22,7 @@ export class AdminPortalLayoutComponent implements OnInit, OnDestroy {
@ViewChild('trialNotAllowedModal') trialNotAllowedModal;
showLoader: boolean;
subscriptions: Array<Subscription> = [];
successMsgs: Message[] = [];
successMsgs: Array<Message> = [];
clientName: string;
userName: string;
homeURL: string;
......@@ -31,16 +31,17 @@ export class AdminPortalLayoutComponent implements OnInit, OnDestroy {
selectedTeam: any;
selectedTeamID: string;
redirectURL: string;
createJobDisabled : boolean;
createJobDisabled: boolean;
isStandardUser: boolean;
hiringTeams: any[];
hiringTeams: Array<any>;
userMenu: any;
sidebarMenu: any;
select2Options = {
minimumResultsForSearch: Infinity
}
};
showChat = false;
showBubble = false;
constructor(
private deviceService: DeviceDetectorService,
private msgsService: MsgsService,
......@@ -49,12 +50,28 @@ export class AdminPortalLayoutComponent implements OnInit, OnDestroy {
private utilsService: UtilsService,
private titleService: Title,
private router: Router,
private modalService: BsModalService
) { }
private modalService: BsModalService,
private iframeMsgHandlingService: IframeMsgHandlingService
) {
}
ngOnInit(): void {
// Subscribe to msgReceived of iframeMsgHandlingService to get JobId
this.subscriptions.push(this.iframeMsgHandlingService.msgReceived.subscribe(
(message: any) => {
if (!message || !message.name) {
return;
}
ngOnInit() {
if(this.deviceService.isMobile()) {
window.location.href = (environment.baseUrl + "extensions/adminportal/responsive_alert.jsp");
if (message.name !== 'HiringTeamChat' || message.message === null) {
return;
}
this.showBubble = true;
}
));
if (this.deviceService.isMobile()) {
window.location.href = `${environment.baseUrl}extensions/adminportal/responsive_alert.jsp`;
}
this.subscriptions.push(
this.msgsService.successMsgsUpdated.subscribe(
......@@ -69,41 +86,41 @@ export class AdminPortalLayoutComponent implements OnInit, OnDestroy {
this.loadData();
}
onRouteUpdate() {
onRouteUpdate(): void {
this.loadData();
}
loadData() {
loadData(): void {
this.userService.reloadUserDetails();
this.msgsService.clearErrorMessages();
this.adminPortalLayoutService.reloadAdminUserDetails();
this.loadMenu();
this.userName = this.userService.getUsername();
this.userName = this.userService.getUsername();
}
subscribeToUserData() {
subscribeToUserData(): void {
this.subscriptions.push(this.adminPortalLayoutService.userDataUpdated.subscribe(
data => {
this.clientName = data.ClientName || this.userService.getFullName();
this.homeURL = data.HomeURL;
this.companyName = data.CompanyName;
this.companyUser = data.CompanyUser;
this.selectedTeam = data.SelectedTeam;
this.selectedTeamID = data.SelectedTeam ? data.SelectedTeam.ObjectID : null;
this.hiringTeams = data.HiringTeams;
this.createJobDisabled = data.CreateJobDisabled;
if(this.hiringTeams) {
//this.utilsService.addNULLOptionForAssocSelect(this.hiringTeams, 'HiringTeamName');
for(let hiringTeam of this.hiringTeams) {
hiringTeam.id = hiringTeam.ObjectID; //Added for select2
hiringTeam.text = hiringTeam.HiringTeamName;
this.clientName = data.ClientName || this.userService.getFullName();
this.homeURL = data.HomeURL;
this.companyName = data.CompanyName;
this.companyUser = data.CompanyUser;
this.selectedTeam = data.SelectedTeam;
this.selectedTeamID = data.SelectedTeam ? data.SelectedTeam.ObjectID : null;
this.hiringTeams = data.HiringTeams;
this.createJobDisabled = data.CreateJobDisabled;
if (this.hiringTeams) {
// this.utilsService.addNULLOptionForAssocSelect(this.hiringTeams, 'HiringTeamName');
for (const hiringTeam of this.hiringTeams) {
hiringTeam.id = hiringTeam.ObjectID; // Added for select2
hiringTeam.text = hiringTeam.HiringTeamName;
}
}
if(this.companyName) {
this.titleService.setTitle('Matchd - ' + this.companyName);
if (this.companyName) {
this.titleService.setTitle(`Matchd - ${this.companyName}`);
} else {
this.titleService.setTitle('Matchd');
}
......@@ -114,66 +131,68 @@ export class AdminPortalLayoutComponent implements OnInit, OnDestroy {
));
}
loadMenu() {
this.adminPortalLayoutService.getAdminMenu().subscribe(
data => {
this.userMenu = data.userMenu;
this.sidebarMenu= data.sidebarMenu;
},
error => {
this.utilsService.handleError(error);
}
)
}
selectedTeamChanged(event : any): void {
this.selectedTeamID = event.value;
this.showLoader = true;
this.subscriptions.push(
this.adminPortalLayoutService.selectHiringTeam(this.selectedTeamID).subscribe (
loadMenu(): void {
this.adminPortalLayoutService.getAdminMenu()
.subscribe(
data => {
this.router.navigate(['admin/iframe-page', this.homeURL]);
this.loadData();
this.showLoader = false;
this.userMenu = data.userMenu;
this.sidebarMenu = data.sidebarMenu;
},
error => {
this.showLoader = false;
this.utilsService.handleError(error);
}
)
);
}
selectedTeamChanged(event: any): void {
this.selectedTeamID = event.value;
this.showLoader = true;
this.subscriptions.push(
this.adminPortalLayoutService.selectHiringTeam(this.selectedTeamID)
.subscribe(
() => {
this.router.navigate(['admin/iframe-page', this.homeURL]);
this.loadData();
this.showLoader = false;
},
error => {
this.showLoader = false;
this.utilsService.handleError(error);
}
)
);
}
createJobClicked(): void {
this.showLoader = true;
this.subscriptions.push(
this.adminPortalLayoutService.createJob(this.selectedTeamID, this.companyUser).subscribe (
data => {
if(data.AllowCreateJob) {
if(data.AllowCreateJob === 'REACHED_CAP') {
this.modalService.show(this.reachedCapModal);
this.adminPortalLayoutService.createJob(this.selectedTeamID, this.companyUser)
.subscribe(
data => {
if (data.AllowCreateJob) {
if (data.AllowCreateJob === 'REACHED_CAP') {
this.modalService.show(this.reachedCapModal);
} else if (data.AllowCreateJob === 'TRIAL') {
this.modalService.show(this.trialNotAllowedModal);
} else {
this.router.navigate(['admin/iframe-page', data.redirectURL]);
}
this.isStandardUser = data.StandardUser;
this.redirectURL = data.redirectURL;
this.showLoader = false;
}
else if(data.AllowCreateJob === 'TRIAL') {
this.modalService.show(this.trialNotAllowedModal);
} else {
this.router.navigate(['admin/iframe-page', data.redirectURL]);
}
this.isStandardUser = data.StandardUser;
this.redirectURL = data.redirectURL;
},
error => {
this.showLoader = false;
this.utilsService.handleError(error);
}
},
error => {
this.showLoader = false;
this.utilsService.handleError(error);
}
)
)
);
}
ngOnDestroy() {
ngOnDestroy(): void {
this.utilsService.unsubscribeSubscriptions(this.subscriptions);
}
}
......@@ -24,7 +24,7 @@
<label for="MessageTemplate{{messageTemplate.ObjectID}}">Message Template</label>
<input [(ngModel)]="messageTemplate.TemplateName"
name="MessageTemplate{{messageTemplate.ObjectID}}" tabindex="1"
autofocus
autofocus required
fieldLabel="Message Template" type="text" [disabled]="showLoader"
class="form-control" id="MessageTemplate{{messageTemplate.ObjectID}}">
</div>
......@@ -44,7 +44,7 @@
name="Subject{{messageTemplate.ObjectID}}"
fieldLabel="Subject" placeholder="Subject" type="text"
class="form-control" tabindex="2"
[disabled]="showLoader">
[disabled]="showLoader" required>
</div>
<div class="col-md-6" *ngIf="subjectPlaceholderOptions.length">
<label>Placeholder for Subject</label>
......
......@@ -341,7 +341,7 @@ export class EditWorkflowTemplateComponent extends BaseComponent implements OnIn
attribsByName: 'Autocomplete'
};
if(this.isGlobalHT) {
if (this.isGlobalHT) {
this.subscriptions.push(
combineLatest(
this.editWorkflowTemplateService.getMessageTemplates([], sharedMsgParams)
......
<div class="dashboard-content-area second-part {{embedded ? 'openedFromWorkflow' : '' }}">
<div class="{{embedded ? 'openedFromWorkflow' : 'dashboard-content-area second-part' }}">
<app-error-message></app-error-message>
<form #form="ngForm">
<div class="ui-g ui-fluid">
<div class="ui-g-12 ui-md-12">
<div class="main-tab-template pl-1">
<div class="main-tab-template pl-1 {{embedded ? 'h-45' : '' }}">
<div class="chief-officer mb-0">
<a [routerLink]="['/admin/list-message-templates']" class="arrow-btn-blue ml-0">
<a [routerLink]="[previousUrl]" class="arrow-btn-blue ml-0" *ngIf="!embedded">
<img src="assets/images/arrow-left-prev_blue.svg">
</a>
Mine Manager - Lone Star Gold
{{jobApplication?.Job?.JobTitle}} - {{jobApplication?.Job?.HiringTeam?.HiringTeamName}}
</div>
<a class="arrow-btn-blue ml-0 ng-star-inserted minimize" *ngIf="embedded" (click)="minimize.emit()">
<img src="assets/images/arrow-left-prev_blue.svg">
</a>
</div>
<div class="ui-g ui-fluid form">
<div class="ui-g ui-fluid {{embedded ? '' : 'form' }}">
<div class="ui-g-12 ui-md-12">
<div class="ui-g ui-fluid">
<div class="ui-g-10 message-block">
<div class="ui-g-12 ui-md-1 name other">
<label>M</label>
</div>
<div class="ui-g-12 ui-md-11">
<div>
<label> Hi John, </label><br>
<label> Thanks for applying. Please click on the following link to complete your
application. </label><br>
<a class=" data-link " data-elementid="httpsbitly2aBi0jj"
data-fielduid="4b7f9f1e27010d23b5c5"
href="#" style="">https://bit.ly/2aBi0jj</a>
<div class="ui-g-12 ui-md-12 messages-wrapper">
<div class="ui-g ui-fluid" *ngFor="let message of jobApplication.Messages">
<div class="ui-g-10 message-block" *ngIf="message.SentBy.ObjectID !== loggedInId">
<div class="ui-g-12 ui-md-1 name other {{embedded ? 'pad-5' : '' }}">
<label>{{message.SentBy.Name[0]}}</label>
</div>
<div class="message-footer">
<div>via Email</div>
<div>01/03/2019 11:43am</div>
<div class="ui-g-12 ui-md-11">
<div [innerHTML]="message.MessageContent"></div>
<div class="attachments">
<a *ngFor="let attachment of message.Attachments"
href="{{apiUrl+attachment.File.URI}}"
target="_blank">{{attachment.File.Name}}</a>
</div>
<div class="message-footer">
<div>via {{message.SentVia.Description}}</div>
<div>{{message.ObjectCreatedStr}}</div>
</div>
</div>
</div>
</div>
<div class="ui-g-offset-2 ui-g-10 message-block">
<div class="ui-g-10 ui-md-11">
<div>
<label> Hi John, </label><br>
<label> Thanks for applying. Please click on the following link to complete your
application. </label><br>
<a class=" data-link " data-elementid="httpsbitly2aBi0jj"
data-fielduid="4b7f9f1e27010d23b5c5"
href="#" style="">https://bit.ly/2aBi0jj</a>
<div class="ui-g-offset-2 ui-g-10 message-block"
*ngIf="message.SentBy.ObjectID === loggedInId">
<div class="ui-g-10 ui-md-11">
<div [innerHTML]="message.MessageContent"></div>
<div class="attachments">
<a *ngFor="let attachment of message.Attachments"
href="{{apiUrl+attachment.File.URI}}"
target="_blank">{{attachment.File.Name}}</a>
</div>
<div class="message-footer">
<div>via {{message.SentVia.Description}}</div>
<div>{{message.ObjectCreatedStr}}</div>
</div>
</div>
<div class="message-footer">
<div>via Email</div>
<div>01/03/2019 11:43am</div>
<div class="ui-g-12 ui-md-1 name owner {{embedded ? 'pad-5' : '' }}">
<label>{{message.SentBy.Name[0]}}</label>
</div>
</div>
<div class="ui-g-12 ui-md-1 name owner">
<label>J</label>
</div>
<div class="ui-g ui-fluid"
*ngIf="jobApplication.Messages && jobApplication.Messages.length === 0">
<div class="ui-g-10 text-center">
Start a new conversation...
</div>
</div>
</div>
<div class="separator mt-3"></div>
<div class="ui-g ui-fluid">
<div class="ui-g-10">
<p-editor #message>
<div class="ui-g-12 ui-fluid">
<div class="ui-g-9">
<p-editor #message [(ngModel)]="Message.MessageContent" name="MessageContent">
<p-header>
<span class="ql-formats">
<button class="ql-bold" aria-label="Bold"></button>
......@@ -65,25 +73,47 @@
</p-header>
</p-editor>
</div>
<div class="ui-g-2">
<button class="sendBtn">
<p>Send</p>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<div class="ui-g-3">
<app-select-2 *ngIf="sentViaEnum && !applicantMode" (valChange)="updateSentVia($event)"
[data]="sentViaEnum"
[value]="Message.SentVia"
fieldLabel="Description">
</app-select-2>
<div class="buttons-wrapper">
<button class="sendBtn" (click)="saveEngineApplicantView()"
[disabled]="showLoader">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" enable-background="new 0 0 512 512"
xml:space="preserve">
<path id="paper-plane-icon" d="M462,54.955L355.371,437.187l-135.92-128.842L353.388,167l-179.53,124.074L50,260.973L462,54.955z
M202.992,332.528v124.517l58.738-67.927L202.992,332.528z"></path>
</svg>
</button>
<div class="attachment-icon">
<i class="fa fa fa-paperclip fa-2x"></i>
</button>
<button *ngIf="!applicantMode" type="button" pButton label="Read"
icon="ui-icon-check"
(click)="markAsRead()"></button>
</div>
<span class="mt-3">&nbsp;</span>
<p-fileUpload *ngIf="Message.Attachments"
name="File" [withCredentials]="true"
id="File" url="{{apiUrl}}uploadFile" auto="true"
(onUpload)="onUpload($event)" [disabled]="showLoader"
chooseLabel="Browse"
multiple="multiple" accept="image/*" maxFileSize="1000000">
<ng-template pTemplate="content">
<ul *ngIf="Message.Attachments.length">
<li *ngFor="let file of Message.Attachments">{{file.File.Name}}</li>
</ul>
</ng-template>
</p-fileUpload>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="showPlainText"></div>
<p-progressSpinner *ngIf="showLoader"></p-progressSpinner>
</form>
</div>
......@@ -2,6 +2,33 @@ a {
color: rgb(3, 160, 231);
}
::ng-deep {
.ui-fileupload-buttonbar {
padding: 0 !important;
.ui-button {
width: 100% !important;
background-color: #667281 !important;
}
}
.ui-fileupload-row {
div:nth-child(n+3) {
display: none;
}
}
.ui-button-text {
padding: 0 !important;
margin-top: 1px;
}
}
.attachments {
display: flex;
flex-direction: column;
}
.message-block {
background-color: white;
border-radius: 20px;
......@@ -41,6 +68,11 @@ a {
}
}
.messages-wrapper {
max-height: 300px;
overflow-y: auto;
}
* {
transition: all .15s;
......@@ -51,12 +83,27 @@ a {
margin-top: 25px;
}
.buttons-wrapper {
display: flex;
flex-direction: row;
margin-top: 10px;
justify-content: space-between;
:last-child {
width: 60%;
min-height: 45px;
display: inline-block;
cursor: pointer;
border-radius: 100px;
}
}
.sendBtn {
letter-spacing: 1px;
color: #fff;
overflow: visible;
position: relative;
width: 100%;
width: 33%;
cursor: pointer;
border-radius: 100px;
background-color: #667281;
......@@ -64,7 +111,6 @@ a {
min-height: 45px;
text-transform: uppercase;
border-color: #667281;
padding-right: 35px;
p {
color: #fff;
......@@ -83,8 +129,8 @@ a {
svg {
position: absolute;
top: 4px;
right: 10px;
top: 0;
right: 30%;
height: 30px;
width: auto;
transition: transform .15s;
......@@ -95,51 +141,21 @@ a {
}
}
@keyframes flyaway {
0% {
transform: rotate(10deg);
top: 13px;
right: 25px;
height: 30px;
}
5% {
transform: rotate(10deg);
top: 13px;
right: 0px;
height: 30px;
}
20% {
transform: rotate(-20deg);
top: 13px;
right: -130px;
height: 45px;
}
40% {
transform: rotate(10deg);
top: -40px;
right: -280px;
opacity: 1;
}
100% {
transform: rotate(60deg);
top: -200px;
right: -1000px;
height: 0;
opacity: 0;
}
}
.main-tab-template {
position: relative;
@keyframes bounce-in {
0% {
padding-right: 30px;
}
40% {
padding-right: 6px;
}
50% {
padding-left: 30px;
}
100% {
padding-left: 6px;
.minimize {
position: absolute;
right: 10px;
transform: rotate(-90deg);
cursor: pointer;
height: 20px;
width: 20px;
line-height: normal;
img {
height: 10px;
width: 10px;
}
}
}
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Editor } from 'primeng/editor';
import { Subscription } from 'rxjs/Subscription';
import { environment } from '../../../environments/environment';
import { AppService } from '../../app.service';
import { ASSOCS } from '../../constants';
import { JobApplicationModel } from "../../models/job-application.model";
import { ChatAttachmentModel } from '../../models/chat-attachment.model';
import { JobApplicationModel } from '../../models/job-application.model';
import { MessageModel } from '../../models/message.model';
import { SentViaEnum } from '../../models/sent-via.enum';
import { IframeMsgHandlingService } from '../../oneit/services/iframe-msg-handling.service';
import { MsgsService } from '../../oneit/services/msgs.service';
import { SaveService } from '../../oneit/services/save.service';
import { UtilsService } from '../../oneit/services/utils.service';
import { AdminPortalLayoutService } from '../admin-portal/admin-portal-layout/admin-portal-layout.service';
import { BaseComponent } from '../admin-portal/base/base.component';
import { MessageEngineApplicantViewService } from './message-engine-applicant-view.service';
import { EngineApplicantView } from './message-engine-applicant-view.model';
@Component({
selector: 'app-message-engine-applicant-view',
templateUrl: './message-engine-applicant-view.component.html',
......@@ -24,6 +27,8 @@ import { EngineApplicantView } from './message-engine-applicant-view.model';
export class MessageEngineApplicantViewComponent extends BaseComponent implements OnInit {
@Input() embedded = false;
// tslint:disable-next-line:prefer-output-readonly
@Output() minimize: EventEmitter<any> = new EventEmitter<any>();
subscriptions: Array<Subscription> = [];
@ViewChild('form') form: NgForm;
@ViewChild('message') messageEditor: Editor;
......@@ -31,9 +36,14 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
updatedObjs = {};
deletedObjs = {};
engineApplicantView = new EngineApplicantView();
jobApplication = new JobApplicationModel();
sentViaEnum: Array<SentViaEnum>;
Message = new MessageModel();
apiUrl = environment.baseUrl;
jobId: string;
loggedInId: string;
showLoader = false;
previousUrl: string;
constructor(
private router: Router,
......@@ -42,28 +52,75 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
private saveService: SaveService,
private appService: AppService,
private messageEngineApplicantViewService: MessageEngineApplicantViewService,
private adminPortalLayoutService: AdminPortalLayoutService,
private iframeMsgHandlingService: IframeMsgHandlingService,
private adminPortalLayoutService: AdminPortalLayoutService
private msgService: MsgsService
) {
super(utilsService);
router.events
.filter(event => event instanceof NavigationEnd)
.subscribe((e: any) => {
this.previousUrl = e.url;
});
}
ngOnInit(): void {
this.utilsService.resetCounter();
this.setEditorClass();
this.showLoader = true;
this.subscriptions.push(this.activatedRoute.params
.subscribe(
(params: Params) => {
this.showLoader = true;
if (params.jobId) {
this.getEngineApplicantViewByID(params.jobId);
} else {
this.utilsService.createObject(this.engineApplicantView, this.createdObjs);
this.showLoader = false;
}
// Subscribe to msgReceived of iframeMsgHandlingService to get JobId
this.subscriptions.push(this.iframeMsgHandlingService.msgReceived.subscribe(
(message: any) => {
if (!message || !message.name) {
return;
}
if (message.name !== 'HiringTeamChat' || message.message === null) {
return;
}
));
const msg = JSON.parse(message.message);
this.jobId = msg.JobApplicationID;
this.showLoader = true;
this.subscriptions.push(
this.appService.getTypes('SentVia')
.subscribe((data: Array<SentViaEnum>) => {
this.sentViaEnum = data;
if (this.embedded) {
if (this.adminPortalLayoutService.userData) {
this.loggedInId = this.adminPortalLayoutService.userData.CompanyUser.User;
this.initComponent();
} else {
this.subscriptions.push(this.adminPortalLayoutService.userDataUpdated
.first()
.subscribe(() => {
this.loggedInId = this.adminPortalLayoutService.userData.CompanyUser.User;
this.initComponent();
}));
}
} else {
// For applicant
this.embedded = false;
this.loggedInId = msg.CandidateID;
this.initComponent();
// Use candidate ID fetched from iFrameService
}
})
);
}
));
}
initComponent(): void {
if (this.jobId) {
this.getEngineApplicantViewByID(this.jobId);
} else {
this.utilsService.createObject(this.jobApplication, this.createdObjs);
this.Message.JobApplication = this.jobApplication;
this.Message.Attachments = [];
this.showLoader = false;
this.setEditorClass();
this.createMessage();
}
}
getEngineApplicantViewByID(jobId: string): void {
......@@ -71,18 +128,27 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
this.showLoader = true;
this.utilsService.resetCounter();
this.utilsService.clearErrorMessages();
this.createdObjs = {};
this.createMessage();
const assocs = [ASSOCS.JOB, [ASSOCS.CANDIDATE, ASSOCS.USER].join('.')];
const assocs =
[ASSOCS.JOB, [ASSOCS.JOB, ASSOCS.HIRING_TEAM].join('.'), ASSOCS.MESSAGES, [ASSOCS.MESSAGES, ASSOCS.SENT_BY].join('.'),
[ASSOCS.MESSAGES, ASSOCS.ATTACHMENTS].join('.')];
this.subscriptions.push(this.messageEngineApplicantViewService.getEngineApplicantViewByID(jobId, assocs)
.subscribe(
data => {
console.log(data);
this.engineApplicantView = data;
this.updatedObjs[this.engineApplicantView.ObjectID] = this.engineApplicantView;
// Loop over other multirefs here, which can be updated on screen e.g
this.jobApplication = data;
this.jobApplication.Messages = this.jobApplication.Messages || [];
this.Message.JobApplication = this.jobApplication;
this.Message.Attachments = [];
this.utilsService.sort(this.jobApplication.Messages, ['ObjectCreated'], [1]);
this.showLoader = false;
setTimeout(() => {
const msgWrapper = document.getElementsByClassName('messages-wrapper')[0];
msgWrapper.scrollTop = msgWrapper.scrollHeight;
}, 0);
this.setEditorClass();
},
error => {
this.showLoader = false;
......@@ -92,10 +158,27 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
);
}
saveEngineApplicantView(reload: boolean): void {
markAsRead(): void {
this.showLoader = true;
const params = {
formParams: {
JobApplication: this.jobApplication.ObjectID
}
};
this.appService.processObjects('MarkAsRead', params)
.subscribe(
() => this.showLoader = false,
err => {
this.utilsService.handleError(err);
this.showLoader = false;
}
);
}
saveEngineApplicantView(): void {
this.utilsService.clearErrorMessages();
if (this.form.invalid) {
if (this.form.invalid || this.IsMessageEmpty()) {
this.utilsService.showAllErrorMessages();
} else {
this.showLoader = true;
......@@ -103,18 +186,11 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
.subscribe(
data => {
this.utilsService.handleSuccess();
if (reload) {
let idToNavigate = this.engineApplicantView.ObjectID;
if (data.created[idToNavigate]) {
idToNavigate = data.created[idToNavigate];
this.router.navigate(['/message-engine-applicant-view', idToNavigate]);
return;
}
this.getEngineApplicantViewByID(idToNavigate);
} else {
this.router.navigate(['']);
let idToNavigate = this.jobApplication.ObjectID;
if (data.created[idToNavigate]) {
idToNavigate = data.created[idToNavigate];
}
this.getEngineApplicantViewByID(idToNavigate);
},
error => {
this.showLoader = false;
......@@ -125,6 +201,31 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
}
}
onUpload(event: any): void {
const chatAttachment = new ChatAttachmentModel();
this.utilsService.createObject(chatAttachment, this.createdObjs);
chatAttachment.File = {
FileToken: JSON.parse(event.xhr.response).files[0].token,
Name: JSON.parse(event.xhr.response).files[0].fileName
};
chatAttachment.Message = this.Message;
this.Message.Attachments.push(chatAttachment);
}
createMessage(): void {
this.Message.SentBy = this.loggedInId;
this.Message.SentVia = this.sentViaEnum[2] ? this.sentViaEnum[2] : this.sentViaEnum[0];
this.utilsService.createObject(this.Message, this.createdObjs);
}
/**
* Helper functions
*/
updateSentVia($event): void {
this.Message.SentVia = this.sentViaEnum.find(opt => opt.Value === $event.Value);
}
setEditorClass(): void {
setTimeout(() => {
const editElement = this.messageEditor.getQuill().container;
......@@ -141,7 +242,40 @@ export class MessageEngineApplicantViewComponent extends BaseComponent implement
editor[0].classList.add('form-control');
editor[0].classList.add('editor');
editor[0].innerHTML = '';
}, 0);
}
/**
* Convert rich text into simple text and check if is empty or not!
*/
showPlainText(HTMLTitle: string): string {
if (HTMLTitle === undefined) {
return '';
}
const temp = document.getElementById('showPlainText');
temp.innerHTML = HTMLTitle;
const title = temp.innerText.trim();
temp.innerHTML = '';
return title;
}
IsMessageEmpty(): boolean {
if (this.showPlainText(this.Message.MessageContent) === '') {
this.msgService.addErrorMessages(
[this.utilsService.getValidationMessage('required', 'Message Content', {})]
);
this.messageEditor.getQuill()
.focus();
return true;
}
return false;
}
}
export class EngineApplicantView {
ObjectID: string;
ObjectClass = 'EngineApplicantView';
ComposeSection: string;
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { SaveService } from "../../oneit/services/save.service";
import { SearchService } from '../../oneit/services/search.service';
import { UtilsService } from '../../oneit/services/utils.service';
......@@ -8,7 +9,8 @@ import { UtilsService } from '../../oneit/services/utils.service';
export class MessageEngineApplicantViewService {
constructor(
private searchService: SearchService,
private utilsService: UtilsService
private utilsService: UtilsService,
private saveService: SaveService
) {
}
......
......@@ -29,7 +29,7 @@ export class SelectTwoComponent {
}
@Input() set value(value) {
this._value = value.ObjectID || value.Value;
this._value = value.ObjectID ? value.ObjectID : value.Value;
}
@ViewChild('mySelect') mySelect: Select2Component;
......
......@@ -37,5 +37,8 @@ export const ASSOCS = {
JOB: 'Job',
CANDIDATE: 'Candidate',
USER: 'User',
MESSAGE: 'Message'
MESSAGES: 'Messages',
HIRING_TEAM: 'HiringTeam',
SENT_BY: 'SentBy',
ATTACHMENTS: 'Attachments'
};
......@@ -4,6 +4,6 @@ import { MessageModel } from './message.model';
export class ChatAttachmentModel {
ObjectID: string;
ObjectClass = CLASSES.CHAT_ATTACHMENT;
File: string;
File: {};
Message: MessageModel;
}
export class HiringTeamModel {
ObjectID: string;
HiringTeamName: string;
}
......@@ -33,5 +33,5 @@ export class JobApplicationModel {
Notes: Array<string>;
ScheduledEmails: Array<string>;
SentEmails: Array<string>;
Messages: Array<string>;
Messages: Array<MessageModel>;
}
import { CLASSES } from '../constants';
import { HiringTeamModel } from './hiring-team.model';
export class JobModel {
ObjectID: string;
......@@ -54,7 +55,7 @@ export class JobModel {
Client: string;
JobOwner: string;
CreatedBy: string;
HiringTeam: string;
HiringTeam: HiringTeamModel;
Occupation: string;
ShortenedURL: string;
AssessmentTemplate: string;
......
import { CLASSES } from '../constants';
import { ChatAttachmentModel } from './chat-attachment.model';
import { HiringTeamModel } from './hiring-team.model';
import { JobApplicationModel } from './job-application.model';
import { SentViaEnum } from './sent-via.enum';
import { UserModel } from './user.model';
import { WorkflowMessageModel } from './workflow-message.model';
export class MessageModel {
......@@ -10,8 +12,9 @@ export class MessageModel {
SentVia: SentViaEnum;
MessageContent: string;
IsRead: boolean;
SentBy: string;
SentBy: UserModel | HiringTeamModel | string;
WorkFlowMessage: WorkflowMessageModel;
JobApplication: JobApplicationModel;
Attachments: ChatAttachmentModel;
Attachments: Array<ChatAttachmentModel>;
ObjectCreatedStr: string;
}
......@@ -9,6 +9,7 @@ export class UserModel {
PasswordExpiryDate: string;
FirstName: string;
LastName: string;
Name: string;
UserDescription: string;
Email: string;
SupportUser: string;
......
......@@ -272,16 +272,28 @@
width: 100% !important;
}
.ui-dialog {
&.ui-dialog-draggable {
left: 130px !important;
right: 130px !important;
overflow-y: scroll;
height: 80% !important;
.edit-message-template {
.ui-dialog {
.ui-dialog-titlebar {
display: none;
}
.ui-dialog-content {
padding: 0 !important;
}
}
.ui-dialog {
&.ui-dialog-draggable {
left: 130px !important;
right: 130px !important;
overflow-y: scroll;
height: 80% !important;
}
}
}
.edit-message-template {
.message-engine {
.ui-dialog {
.ui-dialog-titlebar {
display: none;
......@@ -291,8 +303,36 @@
padding: 0 !important;
}
}
.ui-dialog {
&.ui-dialog-draggable {
left: auto !important;
right: 10px !important;
height: 85% !important;
bottom: 0 !important;
overflow-y: scroll;
top: auto !important;
min-width: 600px;
width: 55%;
}
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 200px rgba(183, 183, 183, 0.2);
border-radius: 6px;
}
::-webkit-scrollbar-thumb {
border-radius: 6px;
-webkit-box-shadow: inset 0 0 200px rgba(100, 100, 100, 0.42);
}
}
.editor {
min-height: 150px !important;
}
......@@ -416,3 +456,40 @@ body .ui-dropdown-panel .ui-dropdown-filter-container {
.ui-button.ui-button-icon-only {
margin: 1px;
}
.chat-icon {
width: 70px;
height: 70px;
border-radius: 100px;
position: fixed;
bottom: 10px;
right: 20px;
background-image: url("assets/images/chat-icon.jpg");
background-repeat: round;
cursor: pointer;
}
app-message-engine-applicant-view {
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 200px rgba(183, 183, 183, 0.2);
border-radius: 6px;
}
::-webkit-scrollbar-thumb {
border-radius: 6px;
-webkit-box-shadow: inset 0 0 200px rgba(100, 100, 100, 0.42);
}
}
.pad-5 {
padding: 5px;
}
.h-45 {
height: 45px !important;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment