Basic fbchat kinda working

This commit is contained in:
Fergal Moran
2018-05-08 01:00:47 +01:00
parent 14a0208372
commit 2bbf8f637d
9 changed files with 437 additions and 9 deletions

View File

@@ -31,14 +31,14 @@
"@qontu/ngx-inline-editor": "^0.2.0-alpha.12",
"angular2-jwt": "^0.2.3",
"angular2-moment": "^1.8.0",
"angularfire2": "^5.0.0-rc.6",
"angularfire2": "^5.0.0-rc.7",
"angularx-social-login": "^1.1.8",
"applicationinsights-js": "^1.0.15",
"bootstrap": "4.1.0",
"cookieconsent": "^3.0.6",
"core-js": "^2.5.3",
"dropzone": "^5.3.0",
"firebase": "4.12.1",
"firebase": "^4.12.1",
"font-awesome": "^4.7.0",
"howler": "^2.0.9",
"jquery": "^3.3.1",

View File

@@ -15,3 +15,5 @@
</div>
<app-footer *ngIf="loggedIn()"></app-footer>
<ng2-toasty [position]="'top-right'"></ng2-toasty>
<app-chat-widget></app-chat-widget>

View File

@@ -16,6 +16,7 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import { QuillModule } from 'ngx-quill';
import { SocialLoginModule, AuthServiceConfig } from 'angularx-social-login';
@@ -77,6 +78,8 @@ import { SideOverlayComponent } from './components/side-overlay/side-overlay.com
import { UiStateService } from './services/ui-state.service';
import { BoilerplateComponent } from './components/boilerplate/boilerplate.component';
import { BasePageComponent } from './components/base-page/base-page.component';
import { ChatWidgetComponent } from './components/chat-widget/chat-widget.component';
import { FirebaseAuthService } from './services/firebase-auth.service';
const cookieConfig: NgcCookieConsentConfig = {
cookie: {
@@ -143,20 +146,22 @@ export function provideConfig() {
HumaniseTimePipe,
SideOverlayComponent,
BoilerplateComponent,
BasePageComponent
BasePageComponent,
ChatWidgetComponent
],
imports: [
BrowserModule,
AngularFireModule.initializeApp({
apiKey: 'AIzaSyAaIm8LTB0ZgJ-g7RXEjtVa1EOQB381QLI',
authDomain: 'podnoms-797e3.firebaseapp.com',
databaseURL: 'https://podnoms-797e3.firebaseio.com',
projectId: 'podnoms-797e3',
storageBucket: 'podnoms-797e3.appspot.com',
messagingSenderId: '777042345082'
apiKey: 'AIzaSyA5pGl4o1oGJi1Ke-842Lq0VvL2YZU2rfc',
authDomain: 'podnoms-api.firebaseapp.com',
databaseURL: 'https://podnoms-api.firebaseio.com',
projectId: 'podnoms-api',
storageBucket: '',
messagingSenderId: '357461672895'
}),
AngularFireDatabaseModule,
AngularFireAuthModule,
AngularFirestoreModule,
HttpClientModule,
AppRoutingModule,
HttpModule,
@@ -207,6 +212,7 @@ export function provideConfig() {
AppInsightsService,
JobsService,
AudioService,
FirebaseAuthService,
GlobalsService
],
bootstrap: [AppComponent]

View File

@@ -0,0 +1,230 @@
.floated-chat-btn {
z-index: 9999;
position: fixed;
bottom: 10px;
right: 10px;
background: #097cff;
-webkit-box-shadow: 0 2px 20px 0 rgba(46, 130, 255, 0.75);
box-shadow: 0 2px 20px 0 rgba(46, 130, 255, 0.75);
border-radius: 75px;
color: #fff;
padding: 12px 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
vertical-align: middle;
font-size: 1.08rem;
cursor: pointer;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
}
.floated-chat-btn i {
vertical-align: middle;
display: inline-block;
font-size: 24px;
}
.floated-chat-btn span {
vertical-align: middle;
display: inline-block;
font-weight: 500;
}
.floated-chat-btn i + span {
margin-left: 15px;
}
.floated-chat-btn:hover {
-webkit-transform: scale(1.05);
transform: scale(1.05);
background-color: #0064d5;
-webkit-box-shadow: 0 2px 30px 0 rgba(46, 130, 255, 0.8);
box-shadow: 0 2px 30px 0 rgba(46, 130, 255, 0.8);
}
.floated-chat-w {
z-index: 9999;
position: fixed;
bottom: 70px;
right: 10px;
visibility: hidden;
opacity: 0;
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
-webkit-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.floated-chat-w.active {
visibility: visible;
opacity: 1;
-webkit-transform: translateY(0px);
transform: translateY(0px);
}
.floated-chat-w .floated-chat-i {
background-color: #fff;
-webkit-box-shadow: 0 2px 40px 0 rgba(43, 132, 210, 0.41);
box-shadow: 0 2px 40px 0 rgba(43, 132, 210, 0.41);
border-radius: 10px;
width: 320px;
position: relative;
}
.floated-chat-w .floated-chat-i .chat-close {
position: absolute;
top: 10px;
right: 10px;
color: rgba(0, 0, 0, 0.8);
font-size: 10px;
cursor: pointer;
}
.floated-chat-w .chat-head {
padding: 20px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.floated-chat-w .chat-head .user-w {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
.floated-chat-w .chat-head .user-w .user-avatar-w {
width: 50px;
}
.floated-chat-w .chat-head .user-w .user-avatar-w .user-avatar {
border-radius: 40px;
overflow: hidden;
}
.floated-chat-w .chat-head .user-w .user-avatar-w .user-avatar img {
max-width: 100%;
height: auto;
}
.floated-chat-w .chat-head .user-w.with-status .user-avatar-w {
position: relative;
}
.floated-chat-w .chat-head .user-w.with-status .user-avatar-w:before {
content: '';
width: 10px;
height: 10px;
position: absolute;
top: 2px;
right: 2px;
border-radius: 10px;
-webkit-box-shadow: 0px 0px 0px 3px #fff;
box-shadow: 0px 0px 0px 3px #fff;
}
.floated-chat-w
.chat-head
.user-w.with-status.status-green
.user-avatar-w:before {
background-color: #24b314;
}
.floated-chat-w
.chat-head
.user-w.with-status.status-red
.user-avatar-w:before {
background-color: #e65252;
}
.floated-chat-w .chat-head .user-w .user-name {
padding-left: 20px;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.floated-chat-w .chat-head .user-w .user-title {
margin-bottom: 2px;
color: #047bf8;
}
.floated-chat-w .chat-head .user-w .user-role {
font-weight: 500;
font-size: 0.81rem;
}
.floated-chat-w .chat-head .user-w .user-action {
width: 50px;
color: #047bf8;
font-size: 18px;
}
.floated-chat-w .chat-messages {
padding: 20px;
height: 300px;
position: relative;
overflow: hidden;
}
.floated-chat-w .chat-messages .message {
margin-bottom: 12px;
}
.floated-chat-w .chat-messages .message .message-content {
color: #594939;
padding: 10px 20px;
background-color: #fcf6ee;
border-radius: 20px 20px 20px 0px;
max-width: 80%;
display: inline-block;
text-align: left;
}
.floated-chat-w .chat-messages .message.self {
text-align: right;
}
.floated-chat-w .chat-messages .message.self .message-content {
border-radius: 20px 20px 0px 20px;
background-color: #e2efff;
color: #2a4e7f;
}
.floated-chat-w .chat-messages .date-break {
text-align: center;
margin-bottom: 10px;
color: rgba(0, 0, 0, 0.4);
}
.floated-chat-w .chat-controls {
padding: 10px;
padding-top: 0px;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.floated-chat-w .chat-controls .message-input {
border: 1px solid transparent;
background-color: #fff;
padding: 10px;
width: 100%;
display: block;
border-radius: 0px;
}
.floated-chat-w .chat-controls .message-input:focus {
outline: none;
border-bottom: 1px solid #047bf8;
}
.floated-chat-w .chat-controls .chat-extra {
text-align: left;
padding-left: 0px;
padding-top: 10px;
}
.floated-chat-w .chat-controls .chat-extra a {
display: inline-block;
margin-left: 10px;
font-size: 16px;
position: relative;
}
.floated-chat-w .chat-controls .chat-extra a .extra-tooltip {
background-color: rgba(0, 0, 0, 0.9);
color: #fff;
font-weight: 500;
font-size: 0.63rem;
text-transform: uppercase;
display: inline-block;
padding: 2px 7px;
border-radius: 4px;
position: absolute;
top: -20px;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
white-space: nowrap;
display: none;
}
.floated-chat-w .chat-controls .chat-extra a:hover {
text-decoration: none;
}
.floated-chat-w .chat-controls .chat-extra a:hover .extra-tooltip {
display: block;
}

View File

@@ -0,0 +1,50 @@
<div class="floated-chat-w active" *ngIf="chatActive">
<div class="floated-chat-i">
<div class="chat-close">
<i class="os-icon os-icon-close"></i>
</div>
<div class="chat-head">
<div class="user-w with-status status-green">
<div class="user-avatar-w">
<div class="user-avatar">
<img alt="" src="/assets/img/alex-1.png">
</div>
</div>
<div class="user-name">
<h6 class="user-title">Welly Welly Well</h6>
<div class="user-role">The old days are dead and gone days.</div>
</div>
</div>
</div>
<div class="chat-messages ps">
<div class="message self">
<div class="message-content">Tell me where it hurts?</div>
</div>
<div class="message" *ngFor="let message of messages | async">
<div class="message-content">{{message.messageText}}</div>
</div>
</div>
<div class="chat-controls" *ngIf="!loading">
<input class="message-input" placeholder="Type your message here..." type="text" #message (keyup.enter)="sendMessage(message)">
<div class="chat-extra">
<a href="#">
<span class="extra-tooltip">Attach Document</span>
<i class="fa fa-file"></i>
</a>
<a href="#">
<span class="extra-tooltip">Insert Photo</span>
<i class="fa fa-image"></i>
</a>
<a href="#">
<span class="extra-tooltip">Upload Video</span>
<i class="fa fa-video-camera"></i>
</a>
</div>
</div>
</div>
</div>
<div class="floated-chat-btn" (click)="togglePopup()">
<i class="fa fa-comments-o"></i>
<span>Talk to us!</span>
</div>

View File

@@ -0,0 +1,76 @@
import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { FirebaseAuthService } from '../../services/firebase-auth.service';
import {
AngularFirestore,
AngularFirestoreCollection,
AngularFirestoreDocument
} from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import { ProfileService } from '../../services/profile.service';
import { FirebaseUser } from '../../models/firebaseuser.model';
interface ChatMessage {
messageText: string;
name: string;
fromUser: string;
}
@Component({
selector: 'app-chat-widget',
templateUrl: './chat-widget.component.html',
styleUrls: ['./chat-widget.component.css']
})
export class ChatWidgetComponent implements OnInit {
chatActive: boolean = false;
loading: boolean = false;
currentUser: FirebaseUser;
messageCollection: AngularFirestoreCollection<ChatMessage>;
messages: Observable<ChatMessage[]>;
userName: string = 'Anonymous User';
constructor(
private _firebaseAuthService: FirebaseAuthService,
private _profileService: ProfileService,
private afs: AngularFirestore
) {
this._profileService
.getProfile()
.subscribe((p) => (this.userName = p.firstName + ' ' + p.lastName));
}
ngOnInit() {}
togglePopup() {
this.chatActive = !this.chatActive;
if (this.chatActive) {
this.loading = true;
this._firebaseAuthService.user.subscribe((u) => {
if (u === null) {
this._firebaseAuthService
.anonymousLogin()
.then((user) => this._openChat(user));
} else {
this._openChat(u);
}
});
}
}
_openChat(user) {
this.currentUser = user;
this.loading = false;
this.messageCollection = this.afs.collection('supportchat');
this.messages = this.messageCollection.valueChanges();
}
sendMessage(el: HTMLInputElement) {
if (el.value) {
this.afs
.collection('supportchat')
.add({
fromUid: this.currentUser.uid,
messageText: el.value,
name: this.currentUser.displayName
});
}
}
}

View File

@@ -0,0 +1,6 @@
export interface FirebaseUser {
uid: string;
email?: string | null;
photoURL?: string;
displayName?: string;
}

View File

@@ -0,0 +1,58 @@
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase } from 'angularfire2/database';
import {
AngularFirestore,
AngularFirestoreDocument
} from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import { FirebaseUser } from 'app/models/firebaseuser.model';
@Injectable()
export class FirebaseAuthService {
user: Observable<FirebaseUser | null>;
constructor(
private afAuth: AngularFireAuth,
private afs: AngularFirestore
) {
this.user = this.afAuth.authState.switchMap((user) => {
if (user) {
return this.afs
.doc<FirebaseUser>(`users/${user.uid}`)
.valueChanges();
} else {
return Observable.of(null);
}
});
}
private handleError(error: Error) {
console.error(error);
}
private updateUserData(user: FirebaseUser): Promise<FirebaseUser> {
const userRef: AngularFirestoreDocument<FirebaseUser> = this.afs.doc(
`users/${user.uid}`
);
const data: FirebaseUser = {
uid: user.uid,
email: user.email || null,
displayName: user.displayName || 'nameless user',
photoURL: user.photoURL || 'https://goo.gl/Fz9nrQ'
};
return userRef.set(data).then(() => data);
}
anonymousLogin() {
return this.afAuth.auth
.signInAnonymously()
.then((user) => {
return this.updateUserData(user); // if using firestore
})
.catch((error) => {
console.error(error.code);
console.error(error.message);
this.handleError(error);
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB