mirror of
https://github.com/fergalmoran/podnoms.git
synced 2025-12-22 09:18:08 +00:00
Basic fbchat kinda working
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -15,3 +15,5 @@
|
||||
</div>
|
||||
<app-footer *ngIf="loggedIn()"></app-footer>
|
||||
<ng2-toasty [position]="'top-right'"></ng2-toasty>
|
||||
|
||||
<app-chat-widget></app-chat-widget>
|
||||
|
||||
@@ -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]
|
||||
|
||||
230
client/src/app/components/chat-widget/chat-widget.component.css
Normal file
230
client/src/app/components/chat-widget/chat-widget.component.css
Normal 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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
6
client/src/app/models/firebaseuser.model.ts
Normal file
6
client/src/app/models/firebaseuser.model.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface FirebaseUser {
|
||||
uid: string;
|
||||
email?: string | null;
|
||||
photoURL?: string;
|
||||
displayName?: string;
|
||||
}
|
||||
58
client/src/app/services/firebase-auth.service.ts
Normal file
58
client/src/app/services/firebase-auth.service.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
BIN
client/src/assets/img/alex-1.png
Normal file
BIN
client/src/assets/img/alex-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Reference in New Issue
Block a user