SharanB commited on
Commit
08eaca3
·
verified ·
1 Parent(s): aa0610f

Upload 20 files

Browse files
src/app/app-routing.module.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NgModule } from '@angular/core';
2
+ import { RouterModule, Routes } from '@angular/router';
3
+
4
+ const routes: Routes = [];
5
+
6
+ @NgModule({
7
+ imports: [RouterModule.forRoot(routes)],
8
+ exports: [RouterModule]
9
+ })
10
+ export class AppRoutingModule { }
src/app/app.component.css ADDED
File without changes
src/app/app.component.html ADDED
@@ -0,0 +1 @@
 
 
1
+ <app-chatbot></app-chatbot>
src/app/app.component.spec.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { RouterTestingModule } from '@angular/router/testing';
3
+ import { AppComponent } from './app.component';
4
+
5
+ describe('AppComponent', () => {
6
+ beforeEach(async () => {
7
+ await TestBed.configureTestingModule({
8
+ imports: [
9
+ RouterTestingModule
10
+ ],
11
+ declarations: [
12
+ AppComponent
13
+ ],
14
+ }).compileComponents();
15
+ });
16
+
17
+ it('should create the app', () => {
18
+ const fixture = TestBed.createComponent(AppComponent);
19
+ const app = fixture.componentInstance;
20
+ expect(app).toBeTruthy();
21
+ });
22
+
23
+ it(`should have as title 'bot'`, () => {
24
+ const fixture = TestBed.createComponent(AppComponent);
25
+ const app = fixture.componentInstance;
26
+ expect(app.title).toEqual('bot');
27
+ });
28
+
29
+ it('should render title', () => {
30
+ const fixture = TestBed.createComponent(AppComponent);
31
+ fixture.detectChanges();
32
+ const compiled = fixture.nativeElement as HTMLElement;
33
+ expect(compiled.querySelector('.content span')?.textContent).toContain('bot app is running!');
34
+ });
35
+ });
src/app/app.component.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'app-root',
5
+ templateUrl: './app.component.html',
6
+ styleUrls: ['./app.component.css']
7
+ })
8
+ export class AppComponent {
9
+ title = 'Chainbot';
10
+ }
src/app/app.module.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { BrowserModule } from '@angular/platform-browser';
2
+ import { NgModule } from '@angular/core';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { HttpClientModule } from '@angular/common/http';
5
+
6
+ import { AppComponent } from './app.component';
7
+ import { ChatbotComponent } from './chatbot/chatbot.component';
8
+ import { CouchdbService } from './couchdb.service'; // Import the service
9
+
10
+ @NgModule({
11
+ declarations: [
12
+ AppComponent,
13
+ ChatbotComponent
14
+ ],
15
+ imports: [
16
+ BrowserModule,
17
+ FormsModule,
18
+ HttpClientModule
19
+ ],
20
+ providers: [CouchdbService],
21
+ bootstrap: [AppComponent]
22
+ })
23
+ export class AppModule { }
src/app/chatbot/chatbot.component.css ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Chat container */
2
+ .chat-container {
3
+ position: fixed;
4
+ bottom: 20px;
5
+ right: 20px;
6
+ width: 350px;
7
+ max-height: 500px;
8
+ border-radius: 10px;
9
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
10
+ overflow: hidden;
11
+ display: flex;
12
+ flex-direction: column;
13
+ background-color: #fff;
14
+ }
15
+
16
+ .chat-container.minimized {
17
+ width: 50px;
18
+ height: 50px;
19
+ border-radius: 50%;
20
+ box-shadow: none;
21
+ cursor: pointer;
22
+ }
23
+
24
+ .chat-container.minimized .chat-header,
25
+ .chat-container.minimized .chat-content {
26
+ display: none;
27
+ }
28
+
29
+ .chat-container.minimized .chat-minimized {
30
+ display: flex;
31
+ }
32
+
33
+ .chat-minimized {
34
+ display: none;
35
+ justify-content: center;
36
+ align-items: center;
37
+ width: 60px;
38
+ height: 60px;
39
+ border-radius: 50%;
40
+ cursor: pointer;
41
+ position: fixed;
42
+ bottom: 20px;
43
+ right: 20px;
44
+ }
45
+
46
+ .chat-header {
47
+ display: flex;
48
+ justify-content: space-between;
49
+ align-items: center;
50
+ background: linear-gradient(to bottom, #0083bf, #0083bf);
51
+ color: #fff;
52
+ padding: 10px;
53
+ border-top-left-radius: 10px;
54
+ border-top-right-radius: 10px;
55
+ }
56
+
57
+ .chat-header img {
58
+ width: 30px;
59
+ height: 30px;
60
+ }
61
+
62
+ .chat-title {
63
+ flex-grow: 1;
64
+ text-align: center;
65
+ font-weight: bold;
66
+ }
67
+
68
+ .minimize-btn, .close-btn {
69
+ background: none;
70
+ border: none;
71
+ color: #fff;
72
+ font-size: 18px;
73
+ cursor: pointer;
74
+ outline: none;
75
+ }
76
+
77
+ .minimize-btn:hover, .close-btn:hover {
78
+ color: #e0e0e0;
79
+ }
80
+
81
+ /* Chat messages container */
82
+ .chat-content {
83
+ display: flex;
84
+ flex-direction: column;
85
+ padding: 10px;
86
+ height: 300px;
87
+ overflow-y: auto;
88
+ }
89
+
90
+ /* Chat messages */
91
+ .message {
92
+ display: flex;
93
+ justify-content: flex-start;
94
+ margin: 10px;
95
+ }
96
+
97
+ /* Bot message bubble */
98
+ .bot-message .message-text {
99
+ background-color: #e0e0e0;
100
+ color: #000;
101
+ border-radius: 10px;
102
+ padding: 10px;
103
+ max-width: 70%;
104
+ }
105
+
106
+ /* User message bubble */
107
+ .user-message .message-text {
108
+ background-color: #1056ecee;
109
+ color: #fff;
110
+ border-radius: 10px;
111
+ padding: 10px;
112
+ max-width: 70%;
113
+ justify-content: flex-end;
114
+ }
115
+
116
+ .user-message {
117
+ justify-content: flex-end;
118
+ }
119
+
120
+ /* Answers container */
121
+ .answers {
122
+ display: flex;
123
+ flex-wrap: wrap;
124
+ justify-content: flex-start;
125
+ margin: 10px;
126
+ }
127
+
128
+ /* Answer button */
129
+ .answers button {
130
+ background-color: #1056ecee;
131
+ color: #fff;
132
+ border: none;
133
+ border-radius: 20px;
134
+ padding: 10px 20px;
135
+ margin: 5px;
136
+ cursor: pointer;
137
+ outline: none;
138
+ }
139
+
140
+ .answers button:hover {
141
+ background-color: #0c83e4;
142
+ }
143
+
144
+ /* User input container */
145
+ .user-input {
146
+ display: flex;
147
+ justify-content: flex-end;
148
+ align-items: center;
149
+ margin: 0px;
150
+ }
151
+
152
+ /* Input icon */
153
+ .input-icon {
154
+ display: flex;
155
+ align-items: center;
156
+ margin-right: 10px;
157
+ }
158
+
159
+ /* Input field */
160
+ .user-input input {
161
+ flex: 1;
162
+ padding: 10px;
163
+ border: 1px solid #ccc;
164
+ border-radius: 20px;
165
+ margin-right: 10px;
166
+ outline: none;
167
+ }
168
+
169
+ /* Submit button */
170
+ .user-input button {
171
+ background-color: #4CAF50;
172
+ color: #fff;
173
+ border: none;
174
+ border-radius: 20px;
175
+ padding: 10px 20px;
176
+ cursor: pointer;
177
+ outline: none;
178
+ }
179
+
180
+ .user-input button:hover {
181
+ background-color: #45a049;
182
+ }
183
+
184
+ /* Error message */
185
+ .error-message {
186
+ color: red;
187
+ margin-top: 5px;
188
+ }
189
+
190
+ .error-alert {
191
+ background: #ffcccc;
192
+ color: #a94442;
193
+ padding: 0px;
194
+ border: 1px solid #a94442;
195
+ border-radius: 5px;
196
+ margin: 2px;
197
+ position: absolute;
198
+ top: 50px; /* Adjust based on your header height */
199
+ width: calc(95% - 25px); /* Adjust width to fit within container */
200
+ left: 10px;
201
+ }
202
+
203
+ @keyframes fadeOut {
204
+ 0% { opacity: 1; }
205
+ 100% { opacity: 0; }
206
+ }
207
+ /* Responsive design */
208
+ @media (max-width: 500px) {
209
+ .chat-container {
210
+ width: 100%;
211
+ border-radius: 0;
212
+ bottom: 0;
213
+ right: 0;
214
+ max-height: 100%;
215
+ }
216
+
217
+ .chat-minimized {
218
+ bottom: 10px;
219
+ right: 10px;
220
+ }
221
+ }
src/app/chatbot/chatbot.component.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="chat-container" [ngClass]="{ minimized: isMinimized }" (click)="isMinimized ? toggleMinimize() : null" id="chat-container">
2
+ <div class="chat-header">
3
+ <span class="chat-title">ChainBot</span>
4
+ <button class="minimize-btn" (click)="toggleMinimize($event)">_</button>
5
+ <button class="close-btn" (click)="closeChat($event)">x</button>
6
+ </div>
7
+ <div *ngIf="errorMessage" class="error-alert">
8
+ {{ errorMessage }}
9
+ </div>
10
+ <div class="chat-content" id="chat-content" #chatContent>
11
+ <div *ngFor="let message of conversation" class="message" [ngClass]="{ 'user-message': message.speaker === 'user', 'bot-message': message.speaker === 'bot' }">
12
+ <div *ngIf="message.speaker === 'bot'" class="message-icon">
13
+ <img style="width: 35px; height: 35px;" src="https://static.thenounproject.com/png/1156284-200.png" alt="Bot Icon">
14
+ </div>
15
+ <div class="message-text">
16
+ {{ message.text }}
17
+ </div>
18
+ </div>
19
+
20
+ <div *ngIf="currentNode.type === 'question'" class="answers">
21
+ <button *ngFor="let answer of currentNode.answers" (click)="selectAnswer(answer)">
22
+ {{ answer.text }}
23
+ </button>
24
+ </div>
25
+
26
+ <div *ngIf="currentNode.type === 'input'" class="user-input">
27
+ <div class="input-icon">
28
+ <img style="width: 20px; height: 20px;" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSnRWFs0zshslKNFEmRVUuHgYNfmk5_-M4Qgw&s" alt="User Icon" />
29
+ </div>
30
+ <input [(ngModel)]="userInput" placeholder="Type your response..." />
31
+ <button (click)="submitInput()">Submit</button>
32
+ </div>
33
+ </div>
34
+
35
+ <div class="chat-minimized" id="chat-minimized" (click)="toggleMinimize()" *ngIf="isMinimized">
36
+ <img style="width: 50px; height: 50px;" src="https://chatbot.design/favicon.ico">
37
+ </div>
38
+ </div>
src/app/chatbot/chatbot.component.spec.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { ChatbotComponent } from './chatbot.component';
4
+
5
+ describe('ChatbotComponent', () => {
6
+ let component: ChatbotComponent;
7
+ let fixture: ComponentFixture<ChatbotComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ ChatbotComponent ]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(ChatbotComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
src/app/chatbot/chatbot.component.ts ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Component, OnInit, AfterViewChecked, ElementRef, ViewChild } from '@angular/core';
2
+ import { HttpClient, HttpHeaders } from '@angular/common/http';
3
+ import { CouchdbService } from '../couchdb.service'; // Import the service
4
+ import emailjs, { EmailJSResponseStatus } from 'emailjs-com';
5
+
6
+ interface Answer {
7
+ text: string;
8
+ next: string;
9
+ }
10
+
11
+ interface Node {
12
+ type: string;
13
+ text: string;
14
+ answers?: Answer[];
15
+ next?: string;
16
+ }
17
+
18
+ interface DecisionTree {
19
+ startNode: string;
20
+ nodes: { [key: string]: Node };
21
+ }
22
+
23
+ @Component({
24
+ selector: 'app-chatbot',
25
+ templateUrl: './chatbot.component.html',
26
+ styleUrls: ['./chatbot.component.css']
27
+ })
28
+ export class ChatbotComponent implements OnInit, AfterViewChecked {
29
+ decisionTree: DecisionTree = { startNode: '', nodes: {} };
30
+ currentNode: Node = { type: '', text: '' };
31
+ conversation: { speaker: string; text: string }[] = [];
32
+ userInput = '';
33
+ errorMessage = '';
34
+ isMinimized = true;
35
+ leaveDetails: any = {};
36
+ leaveBalance = 0;
37
+
38
+ @ViewChild('chatContent') private chatContent!: ElementRef;
39
+
40
+ constructor(private couchdbService: CouchdbService, private http: HttpClient) {} // Inject the service
41
+
42
+ ngOnInit(): void {
43
+ this.couchdbService.getDecisionTree().subscribe(data => {
44
+ this.decisionTree = data.data;
45
+ this.currentNode = this.decisionTree.nodes[this.decisionTree.startNode];
46
+ this.addMessage('bot', this.currentNode.text);
47
+ });
48
+ }
49
+
50
+ ngAfterViewChecked() {
51
+ this.scrollToBottom();
52
+ }
53
+
54
+ addMessage(speaker: string, text: string): void {
55
+ this.conversation.push({ speaker, text });
56
+ this.scrollToBottom();
57
+ }
58
+
59
+ selectAnswer(answer: Answer): void {
60
+ this.addMessage('user', answer.text);
61
+
62
+ // Check for redirection conditions
63
+ if (this.currentNode.text === "Welcome to our Ticket service!") {
64
+ if (answer.text === 'Raise Ticket' || answer.text === 'Ticket Status') {
65
+ window.open('https://e.chain.portal.url', '_blank');
66
+ }
67
+ } else if (this.currentNode.text === "Welcome to our Technical service!") {
68
+ if (answer.text === 'Raise Support') {
69
+ window.open('https://appTrack.portal.url', '_blank');
70
+ }
71
+ }
72
+
73
+ if (this.currentNode.text === "Are you sure you want to submit the form?") {
74
+ if (answer.text === 'Yes, submit') {
75
+ this.sendLeaveApplicationEmail();
76
+ this.userInput = ''; // Clear user input
77
+ return;
78
+ } else {
79
+ // Handle other options if needed
80
+ }
81
+ }
82
+
83
+ // Move to the next node based on the selected answer
84
+ this.currentNode = this.decisionTree.nodes[answer.next];
85
+ this.processNode();
86
+ }
87
+
88
+ submitInput(): void {
89
+ if (!this.userInput.trim()) {
90
+ this.displayErrorMessage('Please enter a value');
91
+ return;
92
+ }
93
+
94
+ // Validate email ID
95
+ if (this.currentNode.text === "Enter your Email ID" || this.currentNode.text === "Enter manager Email ID") {
96
+ if (!this.validateEmail(this.userInput)) {
97
+ this.displayErrorMessage('Please enter a valid email ID');
98
+ return;
99
+ }
100
+ }
101
+
102
+ // Validate dates
103
+ if (this.currentNode.text === "Please provide the start date for your leave. (Format: YYYY-MM-DD)" || this.currentNode.text === "Please provide the end date for your leave. (Format: YYYY-MM-DD)") {
104
+ if (!this.validateDate(this.userInput)) {
105
+ this.displayErrorMessage('Please enter a valid date in the format YYYY-MM-DD');
106
+ return;
107
+ }
108
+
109
+ if (new Date(this.userInput) <= new Date()) {
110
+ this.displayErrorMessage('Please enter a date greater than today\'s date');
111
+ return;
112
+ }
113
+ }
114
+
115
+ this.addMessage('user', this.userInput);
116
+ this.errorMessage = '';
117
+ this.leaveDetails[this.currentNode.text] = this.userInput; // Store user input in leaveDetails
118
+
119
+ if (this.currentNode.text === "Please provide your employee ID") {
120
+ this.checkEmployeeEligibility(this.userInput);
121
+ } else {
122
+ this.currentNode = this.decisionTree.nodes[this.currentNode.next || ''];
123
+ this.processNode();
124
+ }
125
+
126
+ this.userInput = '';
127
+ }
128
+
129
+ validateEmail(email: string): boolean {
130
+ const emailPattern = /^[a-zA-Z]+\.[a-zA-Z]+@chainsys\.com$/;
131
+ return emailPattern.test(email);
132
+ }
133
+
134
+ validateDate(date: string): boolean {
135
+ const datePattern = /^\d{4}-\d{2}-\d{2}$/;
136
+ return datePattern.test(date);
137
+ }
138
+
139
+ checkEmployeeEligibility(employeeId: string): void {
140
+ const url = `https://192.168.57.185:5984/employee-db/${employeeId}`;
141
+ const headers = new HttpHeaders({
142
+ 'Authorization': 'Basic ' + btoa('d_couchdb:Welcome#2')
143
+ });
144
+
145
+ this.http.get<any>(url, { headers }).subscribe(
146
+ data => {
147
+ data.leaveBalance = data.leaveBalance || 0; // Ensure leaveBalance is initialized if null
148
+
149
+ this.leaveBalance = data.leaveBalance;
150
+ this.leaveDetails['leaveBalance'] = this.leaveBalance;
151
+
152
+ if (this.leaveBalance > 0) {
153
+ this.currentNode = this.decisionTree.nodes['nodeEligibilityResult'];
154
+ } else {
155
+ this.addMessage('bot', 'You are not eligible to apply for leave.');
156
+ this.currentNode = this.decisionTree.nodes[this.decisionTree.startNode];
157
+ }
158
+ this.processNode();
159
+ },
160
+ error => {
161
+ this.addMessage('bot', 'No record found.');
162
+ this.currentNode = this.decisionTree.nodes[this.decisionTree.startNode];
163
+ this.processNode();
164
+ }
165
+ );
166
+ }
167
+
168
+ processNode(): void {
169
+ if (!this.currentNode) {
170
+ console.error('Invalid node configuration');
171
+ return;
172
+ }
173
+
174
+ if (this.currentNode.type === 'question' && this.currentNode.text === 'No. of days') {
175
+ // Adjust leave options based on leave balance
176
+ const maxDays = Math.min(this.leaveBalance, 5); // Maximum of 5 days or leave balance, whichever is smaller
177
+ this.currentNode.answers = this.currentNode.answers?.filter(answer => parseInt(answer.text, 10) <= maxDays);
178
+ }
179
+
180
+ const botMessage = this.replaceVariables(this.currentNode.text);
181
+ this.addMessage('bot', botMessage);
182
+ }
183
+
184
+ replaceVariables(text: string): string {
185
+ return text.replace(/\[\w+\]/g, match => this.leaveDetails[match.slice(1, -1)] || match);
186
+ }
187
+
188
+ toggleMinimize(event?: Event): void {
189
+ if (event) {
190
+ event.stopPropagation();
191
+ }
192
+ this.isMinimized = !this.isMinimized;
193
+ }
194
+
195
+ closeChat(event?: Event): void {
196
+ const confirmClose = confirm("Are you sure you want to close the chat?");
197
+ if (event) {
198
+ event.stopPropagation();
199
+ }
200
+ this.isMinimized = !this.isMinimized;
201
+ }
202
+
203
+ private scrollToBottom(): void {
204
+ try {
205
+ this.chatContent.nativeElement.scrollTop = this.chatContent.nativeElement.scrollHeight;
206
+ } catch (err) {
207
+ console.error('Scroll to bottom failed:', err);
208
+ }
209
+ }
210
+
211
+ displayErrorMessage(message: string): void {
212
+ this.errorMessage = message;
213
+ setTimeout(() => {
214
+ this.errorMessage = '';
215
+ }, 2000);
216
+ }
217
+
218
+ sendLeaveApplicationEmail(): void {
219
+ const templateParams = {
220
+ employee_email: this.leaveDetails['Enter your Email ID'],
221
+ manager_email: this.leaveDetails['Enter manager Email ID'],
222
+ employee_id: this.leaveDetails['Please provide your employee ID'],
223
+ leave_type: this.leaveDetails['Type of leave'],
224
+ leave_reason: this.leaveDetails['Reason for the leave'],
225
+ leave_days: this.leaveDetails['No. of days'],
226
+ start_date: this.leaveDetails['Please provide the start date for your leave. (Format: YYYY-MM-DD)'],
227
+ end_date: this.leaveDetails['Please provide the end date for your leave. (Format: YYYY-MM-DD)']
228
+ };
229
+
230
+ emailjs.send('service_g7y50fu', 'template_20nsgam', templateParams, '8pjnXdcFSoOVX9B6c')
231
+ .then((response: EmailJSResponseStatus) => {
232
+ console.log('SUCCESS!', response.status, response.text);
233
+ this.currentNode = this.decisionTree.nodes['node13'];
234
+ this.processNode();
235
+ }, (error) => {
236
+ console.error('FAILED...', error);
237
+ });
238
+ }
239
+ }
src/app/couchdb.service.spec.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { TestBed } from '@angular/core/testing';
2
+
3
+ import { CouchdbService } from './couchdb.service';
4
+
5
+ describe('CouchdbService', () => {
6
+ let service: CouchdbService;
7
+
8
+ beforeEach(() => {
9
+ TestBed.configureTestingModule({});
10
+ service = TestBed.inject(CouchdbService);
11
+ });
12
+
13
+ it('should be created', () => {
14
+ expect(service).toBeTruthy();
15
+ });
16
+ });
src/app/couchdb.service.ts ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Injectable } from '@angular/core';
2
+ import { HttpClient, HttpHeaders } from '@angular/common/http';
3
+ import { Observable } from 'rxjs';
4
+
5
+ interface DecisionTree {
6
+ startNode: string;
7
+ nodes: { [key: string]: Node };
8
+ }
9
+
10
+ interface Node {
11
+ type: string;
12
+ text: string;
13
+ answers?: Answer[];
14
+ next?: string;
15
+ }
16
+
17
+ interface Answer {
18
+ text: string;
19
+ next: string;
20
+ }
21
+
22
+ @Injectable({
23
+ providedIn: 'root'
24
+ })
25
+ export class CouchdbService {
26
+ private dbUrl = 'https://192.168.57.185:5984/decison-tree-db/decisiontree_2';
27
+ private username = 'd_couchdb'; // Replace with your CouchDB username
28
+ private password = 'Welcome#2'; // Replace with your CouchDB password
29
+
30
+ constructor(private http: HttpClient) { }
31
+
32
+ getDecisionTree(): Observable<{ data: DecisionTree }> {
33
+ const headers = new HttpHeaders({
34
+ 'Authorization': 'Basic ' + btoa(this.username + ':' + this.password)
35
+ });
36
+
37
+ return this.http.get<{ data: DecisionTree }>(this.dbUrl, { headers });
38
+ }
39
+
40
+ }
src/app/email.service.spec.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { TestBed } from '@angular/core/testing';
2
+
3
+ import { EmailService } from './email.service';
4
+
5
+ describe('EmailService', () => {
6
+ let service: EmailService;
7
+
8
+ beforeEach(() => {
9
+ TestBed.configureTestingModule({});
10
+ service = TestBed.inject(EmailService);
11
+ });
12
+
13
+ it('should be created', () => {
14
+ expect(service).toBeTruthy();
15
+ });
16
+ });
src/app/email.service.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // email.service.ts
2
+ import { Injectable } from '@angular/core';
3
+ import emailjs, { EmailJSResponseStatus } from 'emailjs-com';
4
+
5
+ @Injectable({
6
+ providedIn: 'root'
7
+ })
8
+ export class EmailService {
9
+
10
+ constructor() { }
11
+
12
+ sendEmail(templateParams: any): Promise<EmailJSResponseStatus> {
13
+ const serviceId = 'service_22wzxai'; // Replace with your EmailJS service ID
14
+ const templateId = 'template_ok25x9n'; // Replace with your EmailJS template ID
15
+ const userId = 'nQusk6dPtAR0vTe3I'; // Replace with your EmailJS user ID
16
+
17
+ return emailjs.send(serviceId, templateId, templateParams, userId);
18
+ }
19
+ }
src/assets/.gitkeep ADDED
File without changes
src/assets/decision-tree.json ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_id": "decisiontree_2",
3
+ "_rev": "12-17c8adc47887ebb4b2d7c9227002a6c7",
4
+ "data": {
5
+ "type": "decisiontree",
6
+ "startNode": "node1",
7
+ "nodes": {
8
+ "node1": {
9
+ "type": "question",
10
+ "text": "Hi! I am Chainbot, an online assistant for the employees!",
11
+ "options": [
12
+ {
13
+ "text": "Take Leave",
14
+ "next": "node2"
15
+ },
16
+ {
17
+ "text": "Ticket Service",
18
+ "next": "node14"
19
+ },
20
+ {
21
+ "text": "Technical Support",
22
+ "next": "node16"
23
+ }
24
+ ]
25
+ },
26
+ "node2": {
27
+ "type": "question",
28
+ "text": "Welcome to our leave application service",
29
+ "answers": [
30
+ {
31
+ "text": "Apply here!",
32
+ "next": "node3"
33
+ }
34
+ ]
35
+ },
36
+ "node3": {
37
+ "type": "input",
38
+ "text": "Please provide your employee ID",
39
+ "next": "nodeCheckEligibility"
40
+ },
41
+ "nodeCheckEligibility": {
42
+ "type": "statement",
43
+ "text": "Checking your eligibility...",
44
+ "next": "nodeEligibilityResult"
45
+ },
46
+ "nodeEligibilityResult": {
47
+ "type": "question",
48
+ "text": "You are eligible to apply for leave. Your available leave balance is [leaveBalance].",
49
+ "answers": [
50
+ {
51
+ "text": "Proceed",
52
+ "next": "node4"
53
+ },
54
+ {
55
+ "text": "Cancel",
56
+ "next": "node1"
57
+ }
58
+ ]
59
+ },
60
+ "node4": {
61
+ "type": "question",
62
+ "text": "Type of leave",
63
+ "answers": [
64
+ {
65
+ "text": "Casual Leave",
66
+ "next": "node5"
67
+ },
68
+ {
69
+ "text": "Medical Leave",
70
+ "next": "node6"
71
+ }
72
+ ]
73
+ },
74
+ "node5": {
75
+ "type": "question",
76
+ "text": "Reason for the leave",
77
+ "answers": [
78
+ {
79
+ "text": "Function",
80
+ "next": "node7"
81
+ },
82
+ {
83
+ "text": "Vacation",
84
+ "next": "node7"
85
+ },
86
+ {
87
+ "text": "Others",
88
+ "next": "node7"
89
+ }
90
+ ]
91
+ },
92
+ "node6": {
93
+ "type": "question",
94
+ "text": "Reason for the leave",
95
+ "answers": [
96
+ {
97
+ "text": "Fever",
98
+ "next": "node7"
99
+ },
100
+ {
101
+ "text": "Headache",
102
+ "next": "node7"
103
+ },
104
+ {
105
+ "text": "Others",
106
+ "next": "node7"
107
+ }
108
+ ]
109
+ },
110
+ "node7": {
111
+ "type": "question",
112
+ "text": "No. of days",
113
+ "answers": [
114
+ {
115
+ "text": "1",
116
+ "next": "node8"
117
+ },
118
+ {
119
+ "text": "2",
120
+ "next": "node8"
121
+ },
122
+ {
123
+ "text": "3",
124
+ "next": "node8"
125
+ },
126
+ {
127
+ "text": "4",
128
+ "next": "node8"
129
+ },
130
+ {
131
+ "text": "5",
132
+ "next": "node8"
133
+ }
134
+ ]
135
+ },
136
+ "node8": {
137
+ "type": "input",
138
+ "text": "Please provide the start date for your leave. (Format: YYYY-MM-DD)",
139
+ "next": "node9"
140
+ },
141
+ "node9": {
142
+ "type": "input",
143
+ "text": "Please provide the end date for your leave. (Format: YYYY-MM-DD)",
144
+ "next": "node10"
145
+ },
146
+ "node10": {
147
+ "type": "input",
148
+ "text": "Enter your Email ID",
149
+ "next": "node11"
150
+ },
151
+ "node11": {
152
+ "type": "input",
153
+ "text": "Enter manager Email ID",
154
+ "next": "node12"
155
+ },
156
+ "node12": {
157
+ "type": "question",
158
+ "text": "Are you sure you want to submit the form?",
159
+ "answers": [
160
+ {
161
+ "text": "Yes, submit",
162
+ "next": "node13"
163
+ },
164
+ {
165
+ "text": "No, make changes",
166
+ "next": "node2"
167
+ }
168
+ ]
169
+ },
170
+ "node13": {
171
+ "type": "question",
172
+ "text": "Your leave application has been successfully submitted! You will receive a confirmation email shortly. Is there anything else I can help you with?",
173
+ "answers": [
174
+ {
175
+ "text": "Take Leave",
176
+ "next": "node2"
177
+ },
178
+ {
179
+ "text": "Ticket Service",
180
+ "next": "node14"
181
+ },
182
+ {
183
+ "text": "Technical Support",
184
+ "next": "node16"
185
+ }
186
+ ]
187
+ },
188
+ "node14": {
189
+ "type": "question",
190
+ "text": "Welcome to our Ticket service!",
191
+ "answers": [
192
+ {
193
+ "text": "Raise Ticket",
194
+ "next": "node15"
195
+ },
196
+ {
197
+ "text": "Ticket Status",
198
+ "next": "node15"
199
+ }
200
+ ]
201
+ },
202
+ "node15": {
203
+ "type": "question",
204
+ "text": "You will be redirected to our e.chain portal!",
205
+ "answers": [
206
+ {
207
+ "text": "Take Leave",
208
+ "next": "node2"
209
+ },
210
+ {
211
+ "text": "Ticket Service",
212
+ "next": "node14"
213
+ },
214
+ {
215
+ "text": "Technical Support",
216
+ "next": "node16"
217
+ }
218
+ ]
219
+ },
220
+ "node16": {
221
+ "type": "question",
222
+ "text": "Welcome to our Technical service!",
223
+ "answers": [
224
+ {
225
+ "text": "Raise Support",
226
+ "next": "node17"
227
+ }
228
+ ]
229
+ },
230
+ "node17": {
231
+ "type": "question",
232
+ "text": "You will be redirected to our appTrack portal!",
233
+ "answers": [
234
+ {
235
+ "text": "Take Leave",
236
+ "next": "node2"
237
+ },
238
+ {
239
+ "text": "Ticket Service",
240
+ "next": "node14"
241
+ },
242
+ {
243
+ "text": "Technical Support",
244
+ "next": "node16"
245
+ }
246
+ ]
247
+ }
248
+ }
249
+ }
250
+ }
src/favicon.ico ADDED
src/index.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Bot</title>
6
+ <base href="/">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
9
+ </head>
10
+ <body>
11
+ <app-root></app-root>
12
+ </body>
13
+ </html>
src/main.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2
+
3
+ import { AppModule } from './app/app.module';
4
+
5
+
6
+ platformBrowserDynamic().bootstrapModule(AppModule)
7
+ .catch(err => console.error(err));
src/styles.css ADDED
@@ -0,0 +1 @@
 
 
1
+ /* You can add global styles to this file, and also import other style files */