All src files update

Transactions
Dan 2017-09-01 15:54:09 -06:00
parent c22da5c6de
commit fbb92cae1e
139 changed files with 4124 additions and 49 deletions

View File

@ -4,6 +4,9 @@
"license": "MIT",
"scripts": {
"ng": "ng",
"servehelena":"ng serve -host 192.168.43.144",
"servebutte":"ng serve -host 192.168.2.5",
"servebutteprod":"ng serve -host 192.168.2.5",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
@ -13,11 +16,13 @@
"private": true,
"dependencies": {
"@angular/animations": "^4.0.0",
"@angular/cdk": "^2.0.0-beta.8",
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/forms": "^4.0.0",
"@angular/http": "^4.0.0",
"@angular/material": "^2.0.0-beta.8",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"@angular/router": "^4.0.0",

View File

@ -1,20 +0,0 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
<img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo=">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" href="https://blog.angular.io//">Angular blog</a></h2>
</li>
</ul>

View File

@ -1,10 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}

View File

@ -1,16 +1,160 @@
import { WindowRefService } from './services/window-ref.service';
import { EmailService } from './services/email.service';
import { SermonService } from './services/sermon.service';
import { LoginService } from './services/login.service';
import { ProgressService } from './services/xhr-progress.service';
import { ProgressXhr } from './extensions/xhr-progress.extension';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgModule, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule, BrowserXhr } from '@angular/http';
import { MdButtonModule,
MdInputModule,
MdSliderModule,
MdSnackBarModule,
MdDialogModule,
MdCardModule } from '@angular/material';
import { RouterModule } from '@angular/router';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
//import 'hammerjs';
import { AppComponent } from './app.component';
//Components
import { AppComponent } from './components/app/app.component';
import { MenuComponent } from './components/menu/menu.component';
import { IconButtonComponent } from './components/icon-button/icon-button.component';
import { HomeComponent } from './components/home/home.component';
import { WhoWeAreComponent } from './components/whoweare/whoweare.component';
import { ServicesComponent } from './components/services/services.component';
import { SecondaryPageComponent } from './components/secondary-page/secondary-page.component';
import { RecentSermonsComponent } from './components/recent-sermons/recent-sermons.component';
import { SermonSmallComponent } from './components/sermon-small/sermon-small.component';
import { DateComponent } from './components/date/date.component';
import { UpcomingEventsComponent } from './components/upcoming-events/upcoming-events.component';
import { EventComponent } from './components/event/event.component';
import { SermonsComponent } from './components/sermons/sermons.component';
import { AudioPlayerComponent } from './components/audio-player/audio-player.component';
import { LocationComponent } from './components/location/location.component';
import { SermonLargeComponent } from './components/sermon-large/sermon-large.component';
import { AddSermonPopupComponent } from './components/popups/add-sermon-popup/add-sermon-popup.component';
import { LoginPopupComponent } from './components/popups/login-popup/login-popup.component';
import { InputPopupComponent } from './components/popups/input-popup/input-popup.component';
//Directives
import { FadeInOnScrollDirective } from './directives/fade-in-on-scroll.directive';
import { IconDirective } from './directives/icon.directive';
//Pipes
import { DurationPipe } from './pipes/duration.pipe';
import { OkPopupComponent } from './components/popups/ok-popup/ok-popup.component';
import { YesNoPopupComponent } from './components/popups/yes-no-popup/yes-no-popup.component';
import { UpdateSermonPopupComponent } from './components/popups/update-sermon-popup/update-sermon-popup.component';
import { ContactPageComponent } from './components/contact-page/contact-page.component';
import { SharePopupComponent } from './components/popups/share-popup/share-popup.component';
import { SafeUrlPipe } from './pipes/safe-url.pipe';
import { EventsPageComponent } from './components/events-page/events-page.component';
const Routes =
[
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},{
path: 'home',
component: HomeComponent
},
{
path: 'whoweare',
component: WhoWeAreComponent
},
{
path: 'services',
component: ServicesComponent
},
{
path: 'contact',
component: ContactPageComponent
},
{
path: 'sermons',
redirectTo: 'sermons/0'
},
{
path: 'sermons/:id',
component: SermonsComponent
},
{
path: 'location',
component: LocationComponent
},
{
path: 'events',
component: EventsPageComponent
}
]
@NgModule({
declarations: [
AppComponent
AppComponent,
MenuComponent,
IconButtonComponent,
HomeComponent,
WhoWeAreComponent,
ServicesComponent,
FadeInOnScrollDirective,
IconDirective,
SecondaryPageComponent,
RecentSermonsComponent,
SermonSmallComponent,
DateComponent,
UpcomingEventsComponent,
EventComponent,
SermonsComponent,
AudioPlayerComponent,
DurationPipe,
LocationComponent,
SermonLargeComponent,
AddSermonPopupComponent,
LoginPopupComponent,
OkPopupComponent,
InputPopupComponent,
YesNoPopupComponent,
UpdateSermonPopupComponent,
ContactPageComponent,
SharePopupComponent,
SafeUrlPipe,
EventsPageComponent
],
imports: [
BrowserModule
BrowserModule,
FormsModule,
HttpModule,
BrowserAnimationsModule,
//Angular Material Components
MdButtonModule,
MdInputModule,
MdSliderModule,
MdSnackBarModule,
MdDialogModule,
MdCardModule,
RouterModule.forRoot(Routes)
],
providers: [],
providers: [LoginService,SermonService,ProgressService,EmailService,WindowRefService,{provide:BrowserXhr,useClass:ProgressXhr}],
entryComponents: [AddSermonPopupComponent,
LoginPopupComponent,
OkPopupComponent,
InputPopupComponent,
YesNoPopupComponent,
UpdateSermonPopupComponent,
SharePopupComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {
public routes = Routes;
}

View File

@ -0,0 +1,139 @@
header{
position:fixed;
top:0;
left:0;
width:100%;
height: 50px;
color: white;
vertical-align: middle;
z-index: 1000;
}
#header-background{
background-color: rgb(0, 188, 212);
width: 100%;
height: 100%;
position: absolute;
opacity: 0;
box-shadow: 0 2px 5px 0 rgba(0,0,0,0.24);
}
#logo{
margin-left: -5px;
margin-right: 10px;
}
#main-menu-button{
float: right;
margin-right: 10px;
margin-top: 5px;
}
.hideOnMobile{
display:inline-block;
width: 50px;
}
.header-button, .header-button-home{
height: 100%;
font-size: 18px;
}
.content{
margin-top: 50px;
min-height: 100%;
margin-bottom: -130px;
padding-bottom: 130px;
}
footer{
background-color: rgb(50,50,50);
padding-top: 20px;
padding-bottom: 20px;
color: white;
font-size: 16px;
height: 140px;
}
#footer-content{
margin: auto;
text-align: center;
}
.footer-panel{
display: inline-block;
box-sizing: border-box;
width: calc(33% - 20px);
margin: 10px;
min-height: 100px;
}
@media(max-width: 900px){
.header-button, .hideOnMobile{
display: none;
}
}
@media(max-width: 800px){
footer{
height: 360px;
}
.footer-panel{
display: block;
width: calc(100% - 20px);
}
.content{
margin-bottom: -350px;
padding-bottom: 350px;
}
}
.copyright{
font-size: 18px;
width: auto;
height: auto;
vertical-align: top;
}
a{
color: inherit;
}
a:visited{
color: inherit;
}
.audio-player-filler{
height: 70px;
background-color: inherit;
}
.audio-player{
position: fixed;
bottom: -65px;
width: 100%;
height: 65px;
text-align: center;
background-color: rgb(100,100,100);
box-shadow: 0 -2px 5px 0 rgba(0,0,0,0.24);
background-color: rgb(100,100,100);
color: white;
transition: .5s ease-in-out bottom;
}
.audio-player-slide-up{
bottom:0;
}
audio-player-component{
width: 100%;
max-width: 1000px;
margin: auto;
display: inline-block;
}

View File

@ -0,0 +1,58 @@
<header>
<div id="header-background" [ngStyle]="{'opacity':headerOpacity}"></div>
<button md-button class="header-button-home" routerLink="/home"><img id="logo" src="assets/images/logo.png" height="30" alt="logo"> Old Fashion Baptist</button>
<span class="hideOnMobile"></span>
<button md-button class="header-button" routerLink="/whoweare">Who We Are!</button>
<button md-button class="header-button" routerLink="/services">Service Times</button>
<button md-button class="header-button" routerLink="/location">Location</button>
<button md-button class="header-button" routerLink="/sermons">Sermons</button>
<button md-icon-button id="main-menu-button"
(click)="mainMenuClick()">
<i ofbicon class="example-icon" style="line-height:20px;">menu</i>
</button>
</header>
<div class="content">
<router-outlet></router-outlet>
</div>
<footer>
<div id="footer-content">
<div id="footer-contact-content" class="footer-panel">
<a target="_blank" href="https://www.google.com/maps/place/Old+Fashion+Baptist+Church/@45.9814004,-112.5320574,11.87z/data=!4m12!1m6!3m5!1s0x535b078c3c74ea33:0xac299097142c5894!2sOld+Fashion+Baptist+Church!8m2!3d45.951287!4d-112.511978!3m4!1s0x535b078c3c74ea33:0xac299097142c5894!8m2!3d45.951287!4d-112.511978">
<p>5003 Wynne Ave</p>
<p>Butte, MT 59701</p>
</a>
<p><a href="tel:+1-406-494-5028" class="phone">(406) 494 - 5028</a></p>
<p>Pastor Ron Derksen</p>
</div>
<div id="footer-services-content" class="footer-panel">
<p>Sunday School: 10AM</p>
<p>Sunday Worship: 11AM</p>
<p>Sunday Evening: 7PM</p>
<p>Wednesday Evening: 7PM</p>
</div>
<div id="footer-website-content" class="footer-panel">
<p><i ofbicon class="copyright">copyright</i> Copyright {{copyrightYear}}</p>
<p>Old Fashion Baptist</p>
<p><a routerLink="/home">ofbbutte.com</a></p>
<p>Powered by God</p>
</div>
</div>
<div class="audio-player-filler" [hidden]="!showAudioPlayer" ></div>
</footer>
<div class="audio-player" [class.audio-player-slide-up]="showAudioPlayer">
<audio-player-component (closed)="audioPlayerClosed()" (started)="audioPlayerStarted()"></audio-player-component>
</div>
<menu-component [menuOpen]="menuOpen" (closed)="mainMenuClick()"></menu-component>

View File

@ -1,15 +1,17 @@
import { TestBed, async } from '@angular/core/testing';
/* tslint:disable:no-unused-variable */
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
});
TestBed.compileComponents();
});
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
@ -17,16 +19,16 @@ describe('AppComponent', () => {
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
it(`should have as title 'app works!'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
expect(app.title).toEqual('app works!');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
expect(compiled.querySelector('h1').textContent).toContain('app works!');
}));
});

View File

@ -0,0 +1,82 @@
import { Component, Inject, Injectable, HostListener } from '@angular/core';
import { Router, NavigationStart, Event } from '@angular/router';
import { EventService } from '../../services/event.service';
import { AudioPlayerService } from '../../services/audio-player.service';
import { BibleVerseService } from '../../services/bible-verse.service';
@Injectable()
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers:[EventService, AudioPlayerService, BibleVerseService]
})
export class AppComponent {
title = 'app works w!';
menuOpen: boolean = false;
headerOpacity: number = 0;
fadeHeader: boolean = true;
copyrightYear: number = (new Date()).getUTCFullYear();
lastRoute: string = '';
currRoute: string = '';
lastScrollPos: number = 0;
showAudioPlayer: boolean = false;
constructor(private router: Router, private audioPlayerService: AudioPlayerService){
this.router.events.subscribe((event:Event) => {
if(event instanceof NavigationStart) {
console.log("last: " + this.lastRoute + "; curr: " + this.currRoute + "; evt: " + event.url);
this.lastRoute = this.currRoute;
this.currRoute = event.url;
let doc = document.documentElement;
let scrollPos = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
//console.log("Scroll: " + scrollPos + "; lastRoute: " + this.lastRoute + "; thisRoute: " + event.url);
if (event.url === '/home'){
this.fadeHeader = true;
this.headerOpacity = 0;
} else {
this.fadeHeader = false;
this.headerOpacity = 1;
}
if (this.lastRoute === event.url){
window.scrollTo(0,this.lastScrollPos);
//console.log("Last POS");
} else {
window.scrollTo(0, 0);
}
this.lastRoute = event.url;
this.lastScrollPos = scrollPos;
}
});
}
mainMenuClick(){
this.menuOpen = !this.menuOpen;
}
audioPlayerClosed(): void{
this.showAudioPlayer = false;
this.audioPlayerService.updateAudioPlayerOpen(this.showAudioPlayer);
}
audioPlayerStarted(): void{
this.showAudioPlayer = true;
this.audioPlayerService.updateAudioPlayerOpen(this.showAudioPlayer);
}
@HostListener('window:scroll', ['$event'])
onScroll(event){
if (!this.fadeHeader){
return;
}
//this.scrollElement = event.target.documentElement || event.target.body || window;
let scrollTop = event.target.documentElement.scrollTop || event.target.body.scrollTop || window.pageYOffset;
let allIn = 100;
this.headerOpacity = scrollTop / allIn;
this.headerOpacity = this.headerOpacity > 1 ? 1 : this.headerOpacity;
}
}

View File

@ -0,0 +1,45 @@
.wrapper{
text-align: left;
}
.audio-control-button{
font-size: 40px;
margin: 10px;
display: table-cell;
vertical-align: middle;
}
.padding5{
padding: 5px;
}
.duration{
display: table-cell;
vertical-align: middle;
}
.audio-control-button:hover{
cursor: pointer;
}
.audio-control-button-c{
display: table-cell;
vertical-align: middle;
}
.slider{
width: 100%;
max-width: 1000px;
display: table;
}
.slider-control{
width: 100%;
display: table-cell;
vertical-align: middle;
}
.text{
text-align: center;
margin-top: -15px;
padding-bottom: 20px;
}

View File

@ -0,0 +1,28 @@
<div class="wrapper">
<div class="slider">
<span [ngSwitch]="audioState" >
<span *ngSwitchDefault><i ofbicon class="audio-control-button">slow_motion_video</i></span>
<span *ngSwitchCase="audioStates.Loading"><i ofbicon class="audio-control-button padding5">slow_motion_video</i></span>
<span *ngSwitchCase="audioStates.Paused"><i ofbicon (click)="play()" class="audio-control-button padding5">play_arrow</i></span>
<span *ngSwitchCase="audioStates.Playing"><i ofbicon (click)="pause()" class="audio-control-button padding5">pause</i></span>
<span *ngSwitchCase="audioStates.Error"><i ofbicon (click)="play()" class="audio-control-button padding5">play_arrow</i></span>
</span>
<md-slider class="slider-control padding5" min="0" [max]="audioDuration" [value]="currentTime" (change)="changeTime($event)"></md-slider>
<span class="duration padding5">{{ currentTime | duration:audioDuration }}</span>
<span><i ofbicon class="audio-control-button padding5" (click)="close()">close</i></span>
</div>
<div [ngSwitch]="audioState" class="text">
<div *ngSwitchCase="audioStates.Loading">
Loading...
</div>
<div *ngSwitchCase="audioStates.Paused">
{{ audioFileTitle }}
</div>
<div *ngSwitchCase="audioStates.Playing">
{{ audioFileTitle }}
</div>
<div *ngSwitchCase="audioStates.Error">
Error Playing... {{ errorMessage }}
</div>
</div>
</div>

View File

@ -0,0 +1,84 @@
import { Component, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core';
import { AudioPlayerService } from '../../services/audio-player.service';
import { AudioStates } from '../../enum/audio-states';
@Component({
selector: 'audio-player-component',
templateUrl: './audio-player.component.html',
styleUrls: ['./audio-player.component.css'],
})
export class AudioPlayerComponent implements OnInit, OnDestroy {
audioStates = AudioStates; //Store reference to enum so we can access it in the template
audioState: AudioStates;
audioFileId: number;
audioFileTitle: string;
audioFileAuthor: string;
audioDuration: number;
currentTime: number;
primarySourceUrl: string = '';
errorMessage: string = 'Unknown Error';
private interval: any;
onStateChangedSubscription: any;
@Output()
closed: EventEmitter<string> = new EventEmitter();
@Output()
started: EventEmitter<string> = new EventEmitter();
constructor(private audioPlayerService: AudioPlayerService){
}
ngOnInit(): void{
this.onStateChangedSubscription = this.audioPlayerService.onStateChanged().subscribe(({metaData,state,error})=>{
this.parseMetaData(metaData);
this.audioState = state;
this.errorMessage = error;
this.audioDuration = this.audioPlayerService.getDuration();
this.currentTime = this.audioPlayerService.getCurrentTime();
if (this.audioState == AudioStates.Loading){
this.started.emit("loading");
}
if (this.audioState == AudioStates.Playing){
this.started.emit("playing");
this.interval = setInterval(()=>{
this.audioDuration = this.audioPlayerService.getDuration();
this.currentTime = this.audioPlayerService.getCurrentTime();
},1000);
} else {
clearInterval(this.interval);
}
});
}
play(): void{
this.audioPlayerService.resume();
}
pause(): void{
this.audioPlayerService.pause();
}
close(): void{
this.audioPlayerService.stop();
this.closed.emit("closed");
}
changeTime(event){
this.audioPlayerService.setPosition(event.value);
}
ngOnDestroy(): void{
this.onStateChangedSubscription.unsubscribe();
}
private parseMetaData(metaData): void{
this.audioFileId = metaData.id;
this.audioFileTitle = metaData.title;
this.audioFileAuthor = metaData.author;
}
}

View File

@ -0,0 +1,15 @@
.full-width{
width: 100%;
}
.hide{
display: none;
}
.errorMessages{
color: white;
background-color: rgb(255,90,90);
padding: 10px;
border-radius: 3px;
margin-bottom: 5px;
}

View File

@ -0,0 +1,35 @@
<secondary-page-component [hideSideBarOnMobile]="true" >
<div mainContent>
<br>
<div *ngIf="!formSubmitted">
<form class="form" #contactForm="ngForm" (ngSubmit)="onSubmit()">
<md-input-container class="full-width">
<input mdInput type="text" placeholder="Name" required value="" [(ngModel)]="name" name="name" >
</md-input-container>
<md-input-container class="full-width">
<input mdInput type="email" placeholder="Email" required value="" [(ngModel)]="email" name="email" pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$">
</md-input-container>
<md-input-container class="full-width">
<input mdInput type="tel" placeholder="Phone" value="" [(ngModel)]="phone" name="phone">
</md-input-container>
<md-input-container class="full-width">
<textarea mdInput type="text" placeholder="Message" required value="" [(ngModel)]="body" name="body" rows="5" ></textarea>
</md-input-container>
<md-input-container class="hide">
<input mdInput type="text" placeholder="hp" required value="" [(ngModel)]="hp" name="subject">
</md-input-container>
<div class="errorMessages" *ngIf="errorMessages.length > 0">
<p *ngFor="let error of errorMessages">{{error}}</p>
</div>
<button md-raised-button type="submit" [disabled]="!contactForm.form.valid || submitButtonDisabled">{{submitButtonText}}</button>
</form>
</div>
<div *ngIf="formSubmitted">
<p><b>Thank You!</b></p>
<p>Your message has been sent.</p>
</div>
</div>
<div sideBar ofbFadeInOnScroll>
</div>
</secondary-page-component>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ContactPageComponent } from './contact-page.component';
describe('ContactPageComponent', () => {
let component: ContactPageComponent;
let fixture: ComponentFixture<ContactPageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContactPageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContactPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,79 @@
import { Router } from '@angular/router';
import { MdDialogConfig } from '@angular/material';
import { OkPopupComponent } from './../popups/ok-popup/ok-popup.component';
import { EmailService } from './../../services/email.service';
import { Component, OnInit } from '@angular/core';
import { MdDialog } from '@angular/material';
@Component({
selector: 'app-contact-page',
templateUrl: './contact-page.component.html',
styleUrls: ['./contact-page.component.css']
})
export class ContactPageComponent implements OnInit {
public submitButtonText: string = "Submit";
public submitButtonDisabled: boolean = false;
public formSubmitted: boolean = false;
public name: string;
public email: string;
public phone: string;
public body: string;
public hp: string = ".";
public errorMessages: string[] = [];
constructor(private emailService: EmailService,
private mdDialog: MdDialog,
private router: Router) { }
ngOnInit() {
}
onSubmit(){
this.errorMessages = [];
if (this.name == null || this.name == ""){
this.errorMessages.push("Please enter a name");
}
if (this.email == null || this.email == ""){
this.errorMessages.push("Please enter an email address");
}
if (this.body == null || this.body == ""){
this.errorMessages.push("Please enter a message");
}
if (this.errorMessages.length > 0){ return; }
this.submitButtonText = "Please Wait...";
this.submitButtonDisabled = true;
this.emailService.sendEmail(this.name,
this.email,
this.phone,
this.body,
this.hp)
.subscribe(
success => {this.emailSuccess();},
error => {this.emailError();});
}
private emailSuccess(){
let opts = new MdDialogConfig;
opts.data = { title:'Email Sent','message':'Thank You! Your message has been sent.' };
let popup = this.mdDialog.open(OkPopupComponent,opts);
this.submitButtonText = "Submit";
this.submitButtonDisabled = false;
popup.afterClosed().subscribe(()=>{
this.formSubmitted = true;
});
}
private emailError(){
console.log("error");
let opts = new MdDialogConfig;
opts.data = { title:'Email Error','message':'Please make sure that you have entered a valid email address.' };
let popup = this.mdDialog.open(OkPopupComponent,opts);
this.submitButtonText = "Submit";
this.submitButtonDisabled = false;
}
}

View File

@ -0,0 +1,25 @@
import { Component, Input, OnInit } from '@angular/core';
import { MONTHS } from '../../constants/months';
@Component({
selector: 'date-component',
template: '<div class="wrapper"><div class="month">{{ month }}</div><div class="day">{{ day }}</div></div>',
styles: ['.month{ color:white; background-color:red; width:40px; font-size: .75rem; text-align:center; } .day{ text-align:center; background:linear-gradient(to bottom, #ededed 0%,#ffffff 100%); }'],
})
export class DateComponent implements OnInit {
@Input()
date: Date = new Date();
month: number;
day: number;
constructor(){
}
ngOnInit(): void{
let monthNum = this.date.getMonth();
this.month = MONTHS[monthNum];
this.day = this.date.getDate();
}
}

View File

@ -0,0 +1,23 @@
.inner-wrapper{
position:relative;
}
.title{
display: table;
font-size: 1.25em;
}
.title-text{
vertical-align: middle;
display: table-cell;
padding-left: 10px;
font-size: .95rem;
}
a{
position: absolute;
right: 0;
bottom: 0;
left: 0;
top: 0;
}

View File

@ -0,0 +1,9 @@
<div class="wrapper" [@inout]="startFadeIn">
<div class="inner-wrapper">
<div class="title">
<a></a>
<date-component class="title-date" [date]="startDate"></date-component>
<span class="title-text">{{ title }}</span>
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
import { Component, AfterContentInit, Input } from '@angular/core';
import { trigger, state, style, transition, animate } from '@angular/animations';
@Component({
selector: 'event-component',
templateUrl: './event.component.html',
styleUrls: ['./event.component.css'],
animations:[
trigger("inout",[
state("1", style({ opacity: '1', transform:'translateX(0)' })),
state("0",style({ opacity: '0', transform:'translateX(5%)' })),
transition('* => 1',[
animate('500ms ease-in-out')
]),
transition(':enter',[
animate('0ms')
])
])
]
})
export class EventComponent implements AfterContentInit {
@Input()
title: string;
@Input()
description: string;
@Input()
startDate: Date;
@Input()
endDate: Date;
public startFadeIn: boolean = false;
@Input()
public delayFadeIn: number = 100;
constructor(){
console.log(this.title);
}
ngAfterContentInit(): void{
console.log(this.delayFadeIn);
setTimeout(() => this.startFadeIn = true, this.delayFadeIn);
}
}

View File

@ -0,0 +1,40 @@
ul{
list-style: none;
}
li{
margin: 40px 0px 40px 0px; /* top right bottom left */
}
li:first-child{
margin-top: 0px;
}
li:last-child{
margin-bottom: 0px;
}
.side-bar{
position: fixed;
}
.width100{
width: 100%;
}
.fab-buttons{
display: none;
}
@media(max-width:800px){
.mobile-search{
display: block;
}
.fab-buttons{
display: inline-block;
position: fixed;
bottom: 20px;
right: 20px;
}
}

View File

@ -0,0 +1,15 @@
<secondary-page-component [hideSideBarOnMobile]="true" >
<div mainContent>
<ul>
<li *ngFor="let event of events; let i = index;">
</li>
</ul>
<div class="fab-buttons" >
<button md-fab *ngIf="loggedIn" (click)="addEvent()"><i ofbicon>add</i></button>
</div>
</div>
<div sideBar class="side-bar">
<button md-raised-button class="width100" (click)="addEvent()" >Add Event</button>
</div>
</secondary-page-component>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EventsPageComponent } from './events-page.component';
describe('EventsPageComponent', () => {
let component: EventsPageComponent;
let fixture: ComponentFixture<EventsPageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EventsPageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EventsPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,28 @@
import { Component, OnInit } from '@angular/core';
import { Event } from '../../interfaces/event';
import { LoginService } from '../../services/login.service';
@Component({
selector: 'app-events-page',
templateUrl: './events-page.component.html',
styleUrls: ['./events-page.component.css']
})
export class EventsPageComponent implements OnInit {
public events: Event[];
public loggedIn: boolean;
constructor(private loginService: LoginService) {
this.loginService.isLoggedIn(true).subscribe(is => { this.loggedIn = is });
this.loginService.onLogin().subscribe(is => { this.loggedIn = is.isLoggedIn; });
}
ngOnInit() {
}
addEvent(){
}
}

View File

@ -0,0 +1,155 @@
#content-wrapper{
background-color: transparent;
}
a{
color: inherit;
}
a:visited{
color: inherit;
}
img{
width: 70%;
height: auto;
}
.inline-block{
display: inline-block;
width: calc(60% - 10px);
}
.row{
position: relative;
vertical-align: middle;
padding-top: 10px;
background-color: white;
overflow: hidden;
}
.row-background{
width: 100%;
position: absolute;
z-index: -1000;
left: 0;
top: -10px;
}
.row-content{
width: 1000px;
margin: auto;
max-width: 100%;
overflow: hidden; /*Keep floating children inside this element */
}
.row-content-single-col{
text-align: center;
padding: 20px;
padding-top: 40px;
padding-bottom: 40px;
font-size: 1.5rem;
}
.row-content-col-left, .row-content-col-right{
display: inline-block;
width: calc(50% - 5px);
padding: 20px;
}
.row-content-col-right{
float: right;
}
.row-content-header{
font-weight: bold;
margin-bottom: 10px;
font-size: 1.15em;
}
.align-top{
vertical-align: top;
}
#background-image{
position: fixed;
top: 0px;
left: 0px;
width: 100%;
z-index: -1000;
}
@media(min-width:400px){
#background-image{
top: -15px;
}
}
@media(min-width:500px){
#background-image{
top: -30px;
}
}
@media(min-width:700px){
#background-image{
top: -45px;
}
}
@media(min-width:900px){
#background-image{
top: -60px;
}
}
@media(min-width:1100px){
#background-image{
top: -75px;
}
}
@media(min-width:1300px){
#background-image{
top: -100px;
}
}
#filler{
width: 100%;
padding-bottom: 35%;
}
.tint{
background-color: rgb(240,240,240);
border-top: 1px solid rgb(200,200,200);
border-bottom: 1px solid rgb(220,220,220);
}
.see-through{
background-color: rgba(0,0,0,.8);
}
.see-through-light{
background-color: rgba(0,0,0,.3);
}
.verse{
font-style: italic;
margin: 10px;
}
@media(max-width: 850px){
.row-content-col-left, .row-content-col-right{
display: block;
width: 100%;
float:none;
text-align: center;
}
}

View File

@ -0,0 +1,82 @@
<img id="background-image" src="assets/images/home-images/sunset_b.jpg" alt="background image" width="100%">
<div id="filler">
</div>
<div id="content-wrapper">
<div class="row">
<div class="row-content">
<div class="row-content-col-left align-top">
<p ofbFadeInOnScroll class="row-content-header">...that ye also may have fellowship with us...</p>
<p ofbFadeInOnScroll>It is exciting to gather together in the name of the Lord and
we sincerily hope that YOU will join us. Guests are always welcome at Old Fashion
Baptist and we look forward to seeing you!</p>
<p class="verse" ofbFadeInOnScroll>For where two or three are gathered together in my name, there am I in the midst of them. - Matthew 18:20</p>
<p ofbFadeInOnScroll><i ofbicon>info_outline</i> <a href="#" routerLink="/whoweare" class="align-top">Learn more about us</a></p>
</div>
<div class="row-content-col-right">
<!-- <img ofbFadeInOnScroll src="assets/images/home-images/2-church-color.png"> -->
<img ofbFadeInOnScroll src="assets/images/home-images/family.jpg">
</div>
</div>
</div>
<div class="row tint">
<div class="row-content">
<div class="row-content-single-col">
<p ofbFadeInOnScroll ofbGrowWhenCenter class="verse">O give thanks unto the Lord; for he is good: because his mercy endureth for ever. - Psalm 118:1</p>
</div>
</div>
</div>
<div class="row">
<div class="row-content">
<div class="row-content-col-right align-top">
<p ofbFadeInOnScroll class="row-content-header">Need a ride?</p>
<p ofbFadeInOnScroll>
Want to come but don't have a way to get here? We would be happy
to pick you up! Give us a call to schedule a ride on Sunday Morning.
</p>
<br>
<p ofbFadeInOnScroll>
<i ofbicon>phone</i> <a href="tel:+1-406-494-5028" class="align-top">406-494-5028</a>
</p>
</div>
<div class="row-content-col-left">
<img ofbFadeInOnScroll src="assets/images/home-images/bus2.jpg" height="200">
</div>
</div>
</div>
<div class="row tint">
<div class="row-content">
<div class="row-content-single-col">
<p ofbFadeInOnScroll class="verse">The fear of the LORD is the beginning of wisdom: and the knowledge of the holy is understanding. - Proverbs 9:10</p>
</div>
</div>
</div>
<div class="row">
<div class="row-content">
<div class="row-content-col-left align-top">
<p ofbFadeInOnScroll class="row-content-header">The Holy Bible</p>
<div ofbFadeInOnScroll>
Here at Old Fashion Baptist Church we love the Word of God!
<p class="verse">In the beginning was the Word, and the Word was with God, and the Word was God. - John 1:1</p>
We encourage you to come and join as as we study, teach and preach Gods Word!
<br><br>
<p>
<i ofbicon>directions</i> <a target="_blank" class="align-top" href="https://www.google.com/maps/place/Old+Fashion+Baptist+Church/@45.9814004,-112.5320574,11.87z/data=!4m12!1m6!3m5!1s0x535b078c3c74ea33:0xac299097142c5894!2sOld+Fashion+Baptist+Church!8m2!3d45.951287!4d-112.511978!3m4!1s0x535b078c3c74ea33:0xac299097142c5894!8m2!3d45.951287!4d-112.511978">Get Directions</a>
</p>
</div>
</div>
<div class="row-content-col-right">
<img ofbFadeInOnScroll src="assets/images/home-images/bible.jpg">
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'home-component',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
})
export class HomeComponent {
backgroundTop: string = "0px";
@HostListener('window:scroll', ['$event'])
onScroll(event){
let scrollTop = event.target.documentElement.scrollTop || event.target.body.scrollTop || window.pageYOffset;
//this.backgroundTop = Math.min((scrollTop * .30),100) * -1 + "px";
}
}

View File

@ -0,0 +1,45 @@
import { Component, OnChanges, SimpleChanges, Input } from '@angular/core';
import { trigger, transition, state, style, animate } from '@angular/animations';
@Component({
selector: 'icon-button-component',
template: `<button md-button *ngIf="routerLink" [@menuOpened]="menuOpened" class="width100" style="text-align: left;" routerLink="{{routerLink}}"><i ofbicon [iconName]="icon">{{icon}}</i> {{text}}</button>
<button md-button *ngIf="!routerLink" [@menuOpened]="menuOpened" class="width100" style="text-align: left;"><i ofbicon [iconName]="icon">{{icon}}</i> {{text}}</button>`,
styles: ['.width100{width: 100%;}button{font-size: 16px;margin-bottom: 10px;}'],
animations: [trigger(
'menuOpened',
[
state('1',style({transform:'translateX(0)'})),
state('0',style({transform: 'translateX(80%)'})),
transition("0 => 1", [
animate('400ms ease-in-out')
]),
transition("1 => 0", [
animate('300ms ease-in-out')
])
])]
})
export class IconButtonComponent implements OnChanges {
@Input()
public routerLink: string;
@Input()
public icon: string;
@Input()
public text: string;
@Input()
public menuOpen: boolean = true;
public menuOpened: boolean = false;
@Input()
public animationDelay: number = 100;
ngOnChanges(changes: SimpleChanges){
var self = this;
if(changes.hasOwnProperty("menuOpen")){
if (self.menuOpen === true){
setTimeout(function(){ self.menuOpened = self.menuOpen; },self.animationDelay);
} else {
setTimeout(function(){ self.menuOpened = self.menuOpen; },self.animationDelay);
}
}
}
}

View File

@ -0,0 +1,9 @@
.map{
width: 100%;
height: 450px;
}
#verseFrame{
display: block;
border: none;
}

View File

@ -0,0 +1,13 @@
<secondary-page-component [hideSideBarOnMobile]="true" >
<div mainContent class="mapWrapper">
<p *ngIf="mapLoading">Loading Map...</p>
<iframe class="map" (load)="mapLoaded()" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2773.999802164379!2d-112.51416668494458!3d45.951286979109824!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x535b078c3c74ea33%3A0xac299097142c5894!2sOld+Fashion+Baptist+Church!5e0!3m2!1sen!2sus!4v1493451790286" frameborder="0" style="border:0" allowfullscreen></iframe>
</div>
<div sideBar ofbFadeInOnScroll>
We are located South West of the Copper King hotel in Butte, Montana just off of Motor View Road.
<br><br>
<iframe id="verseFrame" (load)="verseLoaded()" src="http://www.kingjamesbibleonline.org/popular-bible-verses-widget.php">
</iframe>
</div>
</secondary-page-component>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LocationComponent } from './location.component';
describe('LocationComponent', () => {
let component: LocationComponent;
let fixture: ComponentFixture<LocationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LocationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LocationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,30 @@
import { BibleVerseService } from './../../services/bible-verse.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'location-component',
templateUrl: './location.component.html',
styleUrls: ['./location.component.css']
})
export class LocationComponent implements OnInit {
public mapLoading: boolean = true;
constructor(private bibleVerseService: BibleVerseService) { }
ngOnInit() {
this.bibleVerseService.randomVerse().subscribe(
verse => {
},
error => console.log(error) );
}
mapLoaded(){
this.mapLoading = false;
}
verseLoaded(){
console.log("DONE");
}
}

View File

@ -0,0 +1,32 @@
#menu-background{
position:fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,.7);
z-index: 10000;
}
.width100{
width: 100%;
}
#close-button{
margin-left: 7px;
}
#header-menu{
position: fixed;
top: 0px;
bottom: 0px;
right: 0px;
width: 160px;
overflow-y: auto;
background-color: rgba(50,50,50,1);
color: white;
overflow-x: hidden;
}

View File

@ -0,0 +1,16 @@
<div id="menu-background" [@backgroundMenuOpen]="menuOpen" (click)="menuClick($event)">
<div id="header-menu" [@menuOpen]="menuOpen">
<ul class="width100">
<button md-icon-button id="close-button" (click)="menuClick($event)"><i ofbicon>close</i></button>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="0" icon="help_outline" routerLink="/whoweare" text="Who We Are"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="50" icon="access_time" routerLink="/services" text="Service Times"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="100" icon="place" routerLink="/location" text="Location"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="150" icon="headset" routerLink="/sermons" text="Sermons"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="200" icon="event" routerLink="/events" text="Events"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="250" icon="mail_outline" routerLink="/contact" text="Contact"></icon-button-component></li>
<li class="width100"><icon-button-component [menuOpen]="menuOpen" animationDelay="300" icon="input" (click)="showLogin($event)" text="Login"></icon-button-component></li>
</ul>
</div>
</div>

View File

@ -0,0 +1,59 @@
import { Component,
Input,
Output,
EventEmitter } from '@angular/core';
import { trigger,
state,
style,
transition,
animate } from '@angular/animations';
import { MdDialog } from '@angular/material';
import { LoginPopupComponent } from '../popups/login-popup/login-popup.component';
@Component({
selector: 'menu-component',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css'],
animations: [
trigger('menuOpen', [
state('1', style({transform: 'translateX(0)'})),
state('0', style({transform: 'translateX(100%)'})),
transition('0 => 1', [
animate('400ms ease-in-out', style({transform: 'translateX(0)'}))
]),
transition('1 => 0', [
animate('400ms 100ms ease-in-out', style({transform: 'translateX(100%)'}))
])
]),
trigger('backgroundMenuOpen', [
state('1', style({opacity: '1'})),
state('0', style({opacity: '0', display:'none'})),
transition('0 => 1', [
animate('400ms ease-in-out', style({opacity: '1'}))
]),
transition('1 => 0', [
animate('400ms 100ms ease-in-out', style({opacity: '0'}))
])
])]
})
export class MenuComponent {
@Input()
menuOpen: boolean = false;
@Output()
closed: EventEmitter<boolean> = new EventEmitter<boolean>();
constructor(private mdDialog: MdDialog){
}
menuClick(event): void{
event.stopPropagation();
this.menuOpen = !this.menuOpen;
this.closed.emit(this.menuOpen);
}
showLogin(event){
event.preventDefault();
let dialog = this.mdDialog.open(LoginPopupComponent);
}
}

View File

@ -0,0 +1,34 @@
.full-width{
width: 100%;
}
form{
margin-top: 7px;
}
.progressPct{
display: inline-block;
width: 80px;
margin-right: 10px;
}
.progressBar{
width: calc(100% - 100px);
}
button{
margin: 20px 0px 20px 20px;
}
.first{
margin-left: 0px;
}
.errorMessages{
color: white;
background-color: rgb(255,90,90);
padding: 10px;
border-radius: 3px;
margin-bottom: 5px;
}

View File

@ -0,0 +1,35 @@
<div md-dialog-title>
Add Sermon<br>
<div *ngIf="monitorProgress">
<span class="progressPct">{{ uploadProgress/uploadTotal | percent:'1.0-2' }}</span>
<md-slider class="progressBar" min="0" [max]="uploadTotal" step="1" [value]="uploadProgress"></md-slider>
</div>
</div>
<div md-dialog-content>
<form #addSermonForm="ngForm" (ngSubmit)="onSubmit()">
<md-input-container class="full-width">
<input mdInput placeholder="Title" required [(ngModel)]="sermonTitle" name="title" >
</md-input-container>
<md-input-container>
<input mdInput placeholder="Date" required [ngModel]="sermonDate | date:'yyyy-MM-ddTHH:mm'" (ngModelChange)="sermonDate = $event" name="date" type="datetime-local">
</md-input-container>
<md-input-container class="full-width">
<input mdInput placeholder="Speaker" required [(ngModel)]="sermonSpeaker" name="speaker" >
</md-input-container>
<md-input-container class="full-width">
<input mdInput placeholder="Description" required [(ngModel)]="sermonDescription" name="description" >
</md-input-container>
<input type="file" (change)="onFileChange($event)" placeholder="Choose File" accept=".mp3,audio/mpeg3" >
<br><br>
<div *ngIf="errorMessages.length > 0" class="errorMessages">
<p *ngFor="let error of errorMessages">
{{error}}
</p>
</div>
<button md-raised-button class="first" (click)="cancel($event)" >Cancel</button><!--
--><button md-raised-button type="submit" [disabled]="!addSermonForm.form.valid || addSermonButtonDisabled">{{ addSermonButtonText }}</button>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AddSermonPopupComponent } from './add-sermon-popup.component';
describe('AddSermonPopupComponent', () => {
let component: AddSermonPopupComponent;
let fixture: ComponentFixture<AddSermonPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AddSermonPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AddSermonPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,144 @@
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
import { Observable, Subscription } from 'rxjs';
import { ProgressService } from './../../../services/xhr-progress.service';
import { LoginPopupComponent } from './../login-popup/login-popup.component';
import { MdDialog, MdDialogRef, MdSnackBar } from '@angular/material';
import { Sermon } from './../../../interfaces/sermon';
import { SermonService } from './../../../services/sermon.service';
import { LoginService } from './../../../services/login.service';
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'app-add-sermon-popup',
templateUrl: './add-sermon-popup.component.html',
styleUrls: ['./add-sermon-popup.component.css']
})
export class AddSermonPopupComponent implements OnInit, OnDestroy {
public addSermonButtonText: string = "Add Sermon";
public addSermonButtonDisabled: boolean = false;
public sermonTitle: string;
public sermonDate: Date = new Date();
public sermonSpeaker: string;
public sermonDescription: string;
public sermonFile: File;
public errorMessages: string[] = [];
private _uploadTotal: number = 100;
private _uploadProgress: number = 25;
public uploadTotal: number = 100;
public uploadProgress: number = 0;
public monitorProgress: boolean;
private progressSubscription: Subscription;
constructor(private progressService: ProgressService, private mdDialog: MdDialog, private mdDialogRef: MdDialogRef<AddSermonPopupComponent>, private loginService: LoginService, private sermonService: SermonService) { }
ngOnInit() {
this.progressSubscription = this.progressService.uploadProgress.subscribe(evt => {
this._uploadTotal = evt.total;
this._uploadProgress = evt.loaded;
});
}
ngOnDestroy(){
this.progressSubscription.unsubscribe();
}
onSubmit(){
this.updateAddButton(false);
//First check to see if we are logged in
this.loginService.isLoggedIn(true).subscribe(is => {
if (is === true){
this.addSermon();
} else {
let popup = this.mdDialog.open(LoginPopupComponent);
popup.afterClosed().subscribe(r => {
if (r === true){
this.addSermon();
} else {
this.updateAddButton(true);
}
});
}
},
error =>{
this.updateAddButton(true);
let errorDialog = this.mdDialog.open(OkPopupComponent,{data:{title:'Upload Error',message:'There was an error uploading the sermon\n' + error}});
});
}
updateAddButton(enable: boolean){
if (enable){
this.addSermonButtonText = "Add Sermon";
} else {
this.addSermonButtonText = "Please Wait...";
}
this.addSermonButtonDisabled = !enable;
}
private addSermon(): void {
//Check fields
this.errorMessages = [];
if (this.sermonTitle == null || this.sermonTitle == ""){
this.errorMessages.push("Please enter a title");
}
if (this.sermonDate == null){
this.errorMessages.push("Please enter a sermon date");
}
if (this.sermonSpeaker == null || this.sermonSpeaker == ""){
this.errorMessages.push("Please enter a speaker");
}
if (this.sermonDescription == null || this.sermonDescription == ""){
this.errorMessages.push("Please enter a description");
}
if (this.sermonFile == null){
this.errorMessages.push("Please add a sermon MP3 file");
}
if (this.sermonFile != null && this.sermonFile.type != 'audio/mp3'){
console.log(this.sermonFile.type);
this.errorMessages.push("File must be a MP3");
}
if (this.errorMessages.length > 0){ this.updateAddButton(true); return; }
let s = new Sermon();
s.title = this.sermonTitle;
s.author = this.sermonSpeaker;
s.description = this.sermonDescription;
s.sermonDate = this.sermonDate;
//Start monitoring Progress
this.monitorProgress = true;
let timer = setInterval(()=>{
this.uploadTotal = this._uploadTotal;
this.uploadProgress = this._uploadProgress;
},500);
this.sermonService.addSermon(s,this.sermonFile).subscribe(
data=>{
console.log(data);
this.updateAddButton(true);
this.monitorProgress = false;
clearInterval(timer);
this.mdDialogRef.close(data.sermon);
},
error => {
alert(error);
this.updateAddButton(true);
this.monitorProgress = false;
clearInterval(timer);
let errorDialog = this.mdDialog.open(OkPopupComponent,{data:{title:'Upload Error',message:'There was an error uploading the sermon\n' + error}});
});
}
onFileChange(event){
this.sermonFile = event.srcElement.files[0];
}
cancel(evt){
evt.preventDefault();
this.mdDialogRef.close();
}
}

View File

@ -0,0 +1,7 @@
.align-right{
text-align: right;
}
.display-block{
display: block;
}

View File

@ -0,0 +1,10 @@
<div md-dialog-title>{{title}}</div>
<div md-dialog-content>
{{message}}<br>
<md-input-container>
<input mdInput [(ngModel)]="searchTerm" (keyup.enter)="onEnter()" name="search" placeholder="Search">
</md-input-container>
</div>
<div md-dialog-actions class="align-right display-block">
<button md-raised-button (click)="ok()" class="display-inline">OK</button>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InputPopupComponent } from './input-popup.component';
describe('InputPopupComponent', () => {
let component: InputPopupComponent;
let fixture: ComponentFixture<InputPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ InputPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InputPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,32 @@
import { MdDialogRef } from '@angular/material';
import { MD_DIALOG_DATA } from '@angular/material';
import { Component, OnInit, Inject } from '@angular/core';
@Component({
selector: 'app-input-popup',
templateUrl: './input-popup.component.html',
styleUrls: ['./input-popup.component.css']
})
export class InputPopupComponent implements OnInit {
public title: string;
public message: string;
public searchTerm: string = "";
constructor(@Inject(MD_DIALOG_DATA) public data: any, private mdDialogRef: MdDialogRef<InputPopupComponent>) {
this.title = data.title;
this.message = data.message;
}
ngOnInit() {
}
ok(){
this.mdDialogRef.close(this.searchTerm);
}
onEnter(){
this.mdDialogRef.close(this.searchTerm);
}
}

View File

@ -0,0 +1,14 @@
.input-container{
display: block;
padding: 10px 0px 10px 0px;
}
button{
margin: 20px 0px 20px 20px;
}
.first{
margin-left: 0px;
}

View File

@ -0,0 +1,15 @@
<div md-dialog-title>
Login
</div>
<div md-dialog-content>
<form class="form" #loginForm="ngForm" (ngSubmit)="onSubmit()">
<md-input-container class="input-container">
<input mdInput placeholder="Username" required value="" [(ngModel)]="username" name="username">
</md-input-container>
<md-input-container class="input-container">
<input type="password" mdInput placeholder="Password" required value="" [(ngModel)]="password" name="password">
</md-input-container>
<button md-raised-button type="button" class="first" (click)="cancel()">Cancel</button><!--
--><button md-raised-button type="submit" [disabled]="!loginForm.form.valid || loginButtonDisabled">{{loginButtonText}}</button>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginPopupComponent } from './login-popup.component';
describe('LoginPopupComponent', () => {
let component: LoginPopupComponent;
let fixture: ComponentFixture<LoginPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,58 @@
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
import { MdSnackBar, MdDialogRef, MdDialog, MdDialogConfig } from '@angular/material';
import { LoginService } from './../../../services/login.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-login-popup',
templateUrl: './login-popup.component.html',
styleUrls: ['./login-popup.component.css']
})
export class LoginPopupComponent implements OnInit {
public loginButtonText: string = 'Login';
public loginButtonDisabled: boolean = false;
public username: string;
public password: string;
constructor(private mdDialog: MdDialog, private mdDialogRef: MdDialogRef<LoginPopupComponent>, private loginService: LoginService, private snackbar: MdSnackBar) { }
ngOnInit() {
}
onSubmit(){
this.loginButtonText = 'Please Wait...';
this.loginButtonDisabled = true;
this.loginService.login(this.username,this.password).subscribe(
data => {
if (data.message === 'Logged In'){
this.mdDialogRef.close(true);
let s = this.snackbar.open("Logged In","OK");
s.onAction().subscribe(()=>{ s.dismiss(); });
s.afterOpened().subscribe(()=>{ setTimeout(()=>{ s.dismiss(); },3000); });
} else {
this.showLoginError(data.message);
}
console.log(data);
this.loginButtonText = 'Login';
this.loginButtonDisabled = false;
},
error => {
console.log(error);
this.showLoginError(error);
this.loginButtonText = 'Login';
this.loginButtonDisabled = false;
});
}
showLoginError(message: string){
let opts = new MdDialogConfig;
opts.data = { title:'Login Error','message':message };
let popup = this.mdDialog.open(OkPopupComponent,opts);
}
cancel(){
this.mdDialogRef.close();
}
}

View File

@ -0,0 +1,5 @@
<div md-dialog-title>{{title}}</div>
<div md-dialog-content>{{message}}</div>
<div md-dialog-actions>
<button md-raised-button (click)="close()">OK</button>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OkPopupComponent } from './ok-popup.component';
describe('OkPopupComponent', () => {
let component: OkPopupComponent;
let fixture: ComponentFixture<OkPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OkPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OkPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,27 @@
import { MdDialogRef } from '@angular/material';
import { MD_DIALOG_DATA } from '@angular/material';
import { Component, OnInit, Inject } from '@angular/core';
@Component({
selector: 'app-ok-popup',
templateUrl: './ok-popup.component.html',
styleUrls: ['./ok-popup.component.css']
})
export class OkPopupComponent implements OnInit {
public title: string;
public message: string;
constructor(@Inject(MD_DIALOG_DATA) public data: any, private mdDialogRef: MdDialogRef<OkPopupComponent>) {
this.title = data.title;
this.message = data.message;
}
ngOnInit() {
}
close(){
this.mdDialogRef.close();
}
}

View File

@ -0,0 +1,41 @@
.width100{
width: 100%;
}
.shareHeader{
font-size: 25px;
}
.social-wrapper{
box-sizing: border-box;
width: calc(100% - 10px);
text-align: center;
color: white;
padding: 10px;
border-radius: 5px;
margin: 5px;
}
.social-wrapper:hover{
cursor: pointer;
}
.social-wrapper > span{
vertical-align: top;
}
.facebook{
background-color: #3B5998;
}
.facebook:hover{
background-color: #3B5998;
}
.twitter{
background-color: #55acee;
}
.copy{
background-color: #7d7d7d;
}

View File

@ -0,0 +1,39 @@
<div md-dialog-title>Share</div>
<div md-dialog-content>
<a [href]="facebookIframeUrl | safeUrl" target="_blank">
<div class="social-wrapper facebook" data-network="facebook" draggable="false" style="display: inline-block;">
<svg fill="#fff" preserveAspectRatio="xMidYMid meet" height="1.2em" width="1.2em" viewBox="0 0 40 40">
<g>
<path d="m21.7 16.7h5v5h-5v11.6h-5v-11.6h-5v-5h5v-2.1c0-2 0.6-4.5 1.8-5.9 1.3-1.3 2.8-2 4.7-2h3.5v5h-3.5c-0.9 0-1.5 0.6-1.5 1.5v3.5z"></path>
</g>
</svg>
<span class="st-label">Share</span>
</div>
</a>
<a [href]="twitterUrl | safeUrl" target="_blank">
<div class="social-wrapper twitter" data-network="facebook" draggable="false" style="display: inline-block;">
<svg fill="#fff" preserveAspectRatio="xMidYMid meet" height="1.2em" width="1.2em" viewBox="0 0 40 40">
<g>
<path d="m31.5 11.7c1.3-0.8 2.2-2 2.7-3.4-1.4 0.7-2.7 1.2-4 1.4-1.1-1.2-2.6-1.9-4.4-1.9-1.7 0-3.2 0.6-4.4 1.8-1.2 1.2-1.8 2.7-1.8 4.4 0 0.5 0.1 0.9 0.2 1.3-5.1-0.1-9.4-2.3-12.7-6.4-0.6 1-0.9 2.1-0.9 3.1 0 2.2 1 3.9 2.8 5.2-1.1-0.1-2-0.4-2.8-0.8 0 1.5 0.5 2.8 1.4 4 0.9 1.1 2.1 1.8 3.5 2.1-0.5 0.1-1 0.2-1.6 0.2-0.5 0-0.9 0-1.1-0.1 0.4 1.2 1.1 2.3 2.1 3 1.1 0.8 2.3 1.2 3.6 1.3-2.2 1.7-4.7 2.6-7.6 2.6-0.7 0-1.2 0-1.5-0.1 2.8 1.9 6 2.8 9.5 2.8 3.5 0 6.7-0.9 9.4-2.7 2.8-1.8 4.8-4.1 6.1-6.7 1.3-2.6 1.9-5.3 1.9-8.1v-0.8c1.3-0.9 2.3-2 3.1-3.2-1.1 0.5-2.3 0.8-3.5 1z"></path>
</g>
</svg>
<span class="st-label">Tweet</span>
</div>
</a>
<a (click)="copyLink(shareText)">
<div class="social-wrapper copy" data-network="facebook" draggable="false" style="display: inline-block;">
<svg fill="#fff" preserveAspectRatio="xMidYMid meet" height="1.2em" width="1.2em" viewBox="0 0 40 40">
<g>
<path d="m30 26.8c2.7 0 4.8 2.2 4.8 4.8s-2.1 5-4.8 5-4.8-2.3-4.8-5c0-0.3 0-0.7 0-1.1l-11.8-6.8c-0.9 0.8-2.1 1.3-3.4 1.3-2.7 0-5-2.3-5-5s2.3-5 5-5c1.3 0 2.5 0.5 3.4 1.3l11.8-6.8c-0.1-0.4-0.2-0.8-0.2-1.1 0-2.8 2.3-5 5-5s5 2.2 5 5-2.3 5-5 5c-1.3 0-2.5-0.6-3.4-1.4l-11.8 6.8c0.1 0.4 0.2 0.8 0.2 1.2s-0.1 0.8-0.2 1.2l11.9 6.8c0.9-0.7 2.1-1.2 3.3-1.2z"></path>
</g>
</svg>
<span class="st-label">Copy Link</span>
</div>
</a>
<md-input-container class="width100">
<input mdInput #shareText value="{{shareUrl}}">
</md-input-container>
</div>
<div md-dialog-actions>
<button md-raised-button (click)="close()">OK</button>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SharePopupComponent } from './share-popup.component';
describe('SharePopupComponent', () => {
let component: SharePopupComponent;
let fixture: ComponentFixture<SharePopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SharePopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SharePopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,52 @@
import { MdDialogRef, MdSnackBar } from '@angular/material';
import { MD_DIALOG_DATA } from '@angular/material';
import { Component, OnInit, Inject } from '@angular/core';
@Component({
selector: 'app-share-popup',
templateUrl: './share-popup.component.html',
styleUrls: ['./share-popup.component.css']
})
export class SharePopupComponent implements OnInit {
//private urlPartA: string = "https://www.facebook.com/plugins/share_button.php?href=";
//private urlPartB: string = "&layout=button_count&size=large&mobile_iframe=true&width=106&height=28&appId";
private urlPartA: string = "https://www.facebook.com/sharer/sharer.php?kid_directed_site=0&u=";
private urlPartB: string = "&display=popup&ref=plugin&src=share_button";
private twitterPartA: string = "https://twitter.com/intent/tweet?text=";
private twitterPartB: string = "https://twitter.com/intent/tweet?text=ShareThis&url=http%3A%2F%2Fwww.sharethis.com%2F";
public twitterUrl: string;
private sermonId: string;
public facebookIframeUrl: string;
private shareBaseUrl: string = "https://ofbbutte.com/api/share/s";
public shareUrl: string;
constructor(@Inject(MD_DIALOG_DATA) public data: any, private mdDialogRef: MdDialogRef<SharePopupComponent>, private snackbar: MdSnackBar) {
this.sermonId = data.sermonId;
this.shareUrl = this.shareBaseUrl + this.sermonId;
this.facebookIframeUrl = this.urlPartA + this.shareUrl + this.urlPartB;
this.twitterUrl = this.twitterPartA + data.sermonTitle + " - " + data.sermonDescription + "&url=" + this.shareUrl;
}
ngOnInit() {
}
close(){
this.mdDialogRef.close();
}
copyLink(target){
console.log(target);
target.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
target.blur();
let s = this.snackbar.open("Link Copied","OK");
s.onAction().subscribe(()=>{ s.dismiss(); });
s.afterOpened().subscribe(()=>{ setTimeout(()=>{ s.dismiss(); },3000); });
} catch (err) {
console.log('Oops, unable to copy');
}
}
}

View File

@ -0,0 +1,15 @@
md-input-container{
display:block;
padding-top: 10px;
padding-bottom: 10px;
}
button{
margin: 20px 0px 20px 20px;
}
.first{
margin-left: 0px;
}

View File

@ -0,0 +1,23 @@
<div md-dialog-title>
Add Sermon
</div>
<div md-dialog-content>
<form #updateSermonForm="ngForm" (ngSubmit)="onSubmit()">
<md-input-container class="example-full-width">
<input mdInput required [(ngModel)]="sermonTitle" name="title" placeholder="Title">
</md-input-container>
<md-input-container>
<input mdInput required [ngModel]="sermonDate | date:'yyyy-MM-ddTHH:mm'" (ngModelChange)="sermonDate = $event" name="date" type="datetime-local" placeholder="Choose a date">
</md-input-container>
<md-input-container class="example-full-width">
<input mdInput required [(ngModel)]="sermonSpeaker" name="speaker" placeholder="Speaker">
</md-input-container>
<md-input-container class="example-full-width">
<input mdInput required [(ngModel)]="sermonDescription" name="description" placeholder="Description">
</md-input-container>
<button md-raised-button class="first" type="button" (click)="cancel()" >Cancel</button><!--
--><button md-raised-button type="submit" [disabled]="!updateSermonForm.form.valid || updateSermonButtonDisabled">{{ updateSermonButtonText }}</button>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { UpdateSermonPopupComponent } from './update-sermon-popup.component';
describe('UpdateSermonPopupComponent', () => {
let component: UpdateSermonPopupComponent;
let fixture: ComponentFixture<UpdateSermonPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ UpdateSermonPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(UpdateSermonPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,98 @@
import { LoginPopupComponent } from './../login-popup/login-popup.component';
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
import { Sermon } from './../../../interfaces/sermon';
import { SermonService } from './../../../services/sermon.service';
import { LoginService } from './../../../services/login.service';
import { MdDialog, MdDialogRef, MD_DIALOG_DATA } from '@angular/material';
import { Component, OnInit, Inject } from '@angular/core';
@Component({
selector: 'app-update-sermon-popup',
templateUrl: './update-sermon-popup.component.html',
styleUrls: ['./update-sermon-popup.component.css']
})
export class UpdateSermonPopupComponent implements OnInit {
public updateSermonButtonText: string = "Update Sermon";
public updateSermonButtonDisabled: boolean = false;
public sermonId: number;
public sermonTitle: string;
public sermonDate: Date = new Date();
public sermonSpeaker: string;
public sermonDescription: string;
constructor(@Inject(MD_DIALOG_DATA) private data: any,
private mdDialog: MdDialog,
private mdDialogRef: MdDialogRef<UpdateSermonPopupComponent>,
private loginService: LoginService,
private sermonService: SermonService) {
this.sermonId = this.data.id;
this.sermonTitle = this.data.title;
this.sermonDate = this.data.date;
this.sermonSpeaker = this.data.author;
this.sermonDescription = this.data.description;
}
ngOnInit() {
}
onSubmit(){
this.updateButton(false);
//First check to see if we are logged in
this.loginService.isLoggedIn(true).subscribe(is => {
if (is === true){
this.updateSermon();
} else {
let popup = this.mdDialog.open(LoginPopupComponent);
popup.afterClosed().subscribe(r => {
if (r === true){
this.updateSermon();
} else {
this.updateButton(true);
}
});
}
},
error =>{
this.updateButton(true);
let errorDialog = this.mdDialog.open(OkPopupComponent,{data:{title:'Upload Error',message:'There was an error uploading the sermon\n' + error}});
});
}
private updateSermon(): void {
let s = new Sermon;
s.id = this.sermonId;
s.title = this.sermonTitle;
s.author = this.sermonSpeaker;
s.description = this.sermonDescription;
s.sermonDate = this.sermonDate;
//Start monitoring Progress
this.sermonService.updateSermon(s).subscribe(
data=>{
console.log(data);
this.mdDialogRef.close(data.sermon);
},
error => {
this.updateButton(true);
let errorDialog = this.mdDialog.open(OkPopupComponent,{data:{title:'Update Error',message:'There was an error updating the sermon\n' + error}});
});
}
updateButton(enable: boolean){
if (enable){
this.updateSermonButtonText = "Update Sermon";
} else {
this.updateSermonButtonText = "Please Wait...";
}
this.updateSermonButtonDisabled = !enable;
}
cancel(){
this.mdDialogRef.close();
}
}

View File

@ -0,0 +1,6 @@
<div md-dialog-title>{{title}}</div>
<div md-dialog-content>{{message}}</div>
<div md-dialog-actions>
<button md-raised-button (click)="yes()">YES</button>
<button md-raised-button (click)="no()">NO</button>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { YesNoPopupComponent } from './yes-no-popup.component';
describe('YesNoPopupComponent', () => {
let component: YesNoPopupComponent;
let fixture: ComponentFixture<YesNoPopupComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ YesNoPopupComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(YesNoPopupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,31 @@
import { MdDialogRef } from '@angular/material';
import { MD_DIALOG_DATA } from '@angular/material';
import { Component, OnInit, Inject } from '@angular/core';
@Component({
selector: 'app-yes-no-popup',
templateUrl: './yes-no-popup.component.html',
styleUrls: ['./yes-no-popup.component.css']
})
export class YesNoPopupComponent implements OnInit {
public title: string;
public message: string;
constructor(@Inject(MD_DIALOG_DATA) public data: any, private mdDialogRef: MdDialogRef<YesNoPopupComponent>) {
this.title = data.title;
this.message = data.message;
}
ngOnInit() {
}
yes(){
this.mdDialogRef.close(true);
}
no(){
this.mdDialogRef.close(false);
}
}

View File

@ -0,0 +1,16 @@
.sermon-header{
font-size: 1.2em;
font-weight: bold;
text-align: center;
border-bottom: 1px solid gray;
margin-bottom: 10px;
}
ul{
list-style: none;
}
li{
padding: 5px;
}

View File

@ -0,0 +1,15 @@
<div class="sermon-container">
<p class="sermon-header" >Recent Sermons</p>
<p *ngIf="loading">Loading...</p>
<ul class="sermons">
<li *ngFor="let sermon of sermons; let i = index;">
<sermon-small-component
[title]="sermon.title"
[date]="sermon.sermonDate"
[delayFadeIn]="(i+1)*200"
[url]="sermon.url"
[id]="sermon.id"
></sermon-small-component>
</li>
</ul>
</div>

View File

@ -0,0 +1,34 @@
import { Component, OnInit, Input } from '@angular/core';
import { Sermon } from '../../interfaces/sermon';
import { SermonService } from '../../services/sermon.service';
@Component({
selector: 'recent-sermons-component',
templateUrl: './recent-sermons.component.html',
styleUrls: ['./recent-sermons.component.css']
})
export class RecentSermonsComponent implements OnInit {
sermons: Sermon[];
loading: boolean = false;
@Input()
numberOfSermonsToShow = 3;
constructor(private sermonService: SermonService){
}
ngOnInit(): void {
this.getSermons();
}
getSermons(): void{
this.sermons = [];
this.loading = true;
this.sermonService.getSermons(this.numberOfSermonsToShow).subscribe(sermons => {
this.sermons = sermons;
this.loading = false;
console.log(this.sermons)
});
}
}

View File

@ -0,0 +1,39 @@
#content{
margin: auto;
width: 100%;
max-width: 1000px;
display: table;
}
.main-content{
width: 70%;
display: table-cell;
padding: 20px 10px 10px 10px;
}
.side-bar{
width: 30%;
display: table-cell;
height: 100%;
padding: 20px;
}
.align-top{
vertical-align: top;
}
@media(max-width:800px){
.side-bar{
display: block;
width: 100%;
}
.hide-on-mobile{
display: none;
}
.main-content{
display: block;
width: 100%;
}
}

View File

@ -0,0 +1,10 @@
<div id="content-wrapper">
<div id="content">
<div class="main-content align-top">
<ng-content select="[mainContent]"></ng-content>
</div><!--
--><div class="side-bar align-top" [class.hide-on-mobile]="hideSideBarOnMobile">
<ng-content select="[sideBar]"></ng-content>
</div>
</div>
</div>

View File

@ -0,0 +1,19 @@
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'secondary-page-component',
templateUrl: './secondary-page.component.html',
styleUrls: ['./secondary-page.component.css'],
})
export class SecondaryPageComponent implements OnInit {
@Input()
public hideSideBarOnMobile: boolean;
constructor(){
}
ngOnInit(){
}
}

View File

@ -0,0 +1,92 @@
.wrapper{
box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
}
.photo{
box-sizing: border-box;
display: inline-block;
max-width: 100px;
margin: 0;
vertical-align: top;
}
.fade{
text-align: center;
vertical-align: bottom;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 20px;
padding-bottom: 2px;
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ffffff+0,ffffff+100&0+0,0.8+100 */
background: -moz-linear-gradient(top, rgba(255,255,255,0) 0%, rgba(255,255,255,0.8) 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,0.8) 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,0.8) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ccffffff',GradientType=0 ); /* IE6-9 */
}
.photo button{
padding: 0;
vertical-align: top;
}
button img{
display: block;
height: 100%;
width: 100%;
}
.info{
display: inline-block;
vertical-align: top;
padding: 2px 2px 8px 5px;
box-sizing: border-box;
width: calc(100% - 100px);
overflow-y: hidden;
position: relative;
height: 100px;
}
.title{
font-weight: bold;
}
.date, .author{
font-style: italic;
font-size: 14px;
}
.description{
font-size: 14px;
color: darkgray;
word-wrap: none;
border-top: 0px solid lightgray;
padding-top:6px;
margin-top: 6px;
}
.expanded{
overflow-y: hidden;
}
.expanded-content{
margin: 10px;
}
.buttons, .buttons-edit{
background-color: lightgray;
}
.buttons button{
display: inline-block;
width: 33.33333%;
}
.border{
margin: 0px 5px 0px 5px;
border-top: 1px inset lightgray;
}
.buttons-edit button{
display: inline-block;
width: 50%;
}

View File

@ -0,0 +1,32 @@
<div class="wrapper" [@inout]="startFadeIn">
<div class="photo">
<button md-button (click)="play()">
<img src="../../assets/images/facebookplay.png" />
</button>
</div><!--
--><div class="info" (click)="toggleState()">
<span class="title">{{ title }}</span>
<br>
<span class="date">{{ date |date:'yyyy-MM-dd' }}</span> | <span class="author">{{ author }}</span>
<br>
<p class="description" [@toggleAnimationFade]="state">
{{ description }}
</p>
<div class="fade"><i ofbicon *ngIf="state === 'closed'">arrow_drop_down</i><i ofbicon *ngIf="state === 'open'">arrow_drop_up</i></div>
</div>
<div class="expanded" [@toggleAnimation]="state" (click)="toggleState()">
<p class="expanded-content">
{{ description }}
</p>
</div>
<div class="buttons">
<button md-button class="action pct40" (click)="play()" ><i ofbicon>headset</i> Listen</button><!--
--><button md-button class="action pct50" (click)="download()" ><i ofbicon>file_download</i> Download</button><!--
--><button md-button class="action pct10" (click)="share()" ><i ofbicon>share</i> Share</button>
</div>
<div class="buttons-edit" *ngIf="loggedIn">
<div class="border"></div>
<button md-button class="action" (click)="edit()" ><i ofbicon>edit</i> Edit</button><!--
--><button md-button class="action" (click)="delete()" ><i ofbicon>delete_forever</i> Delete</button>
</div>
</div>

View File

@ -0,0 +1,35 @@
.inner-wrapper{
position:relative;
padding: 0px 0px 10px 0px;
padding: 10px;
box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
}
.title{
display: inline-block;
font-size: 1.15em;
font-weight: bold;
}
.action-buttons{
text-align: right;
}
.speaker-date{
font-style: italic;
color: darkslategray;
float: right;
}
.description{
margin: 15px 0px 15px 0px;
}
@media(max-width:700px){
.speaker-date{
float: none;
}
}

View File

@ -0,0 +1,21 @@
<div class="wrapper" [@inout]="startFadeIn">
<div class="inner-wrapper">
<p class="title">{{ title }}</p>
<div class="speaker-date">
<p>{{ author }} | {{ date |date:'yyyy-MM-dd' }}</p>
</div>
<div class="info">
<div class="description">{{ description }}</div><!--
--><div class="action-buttons">
<button md-button class="action pct40" (click)="play()" ><i ofbicon>headset</i> Listen</button><!--
--><button md-button class="action pct50" (click)="download()" ><i ofbicon>file_download</i> Download</button><!--
--><button md-button class="action pct10" (click)="share()" ><i ofbicon>share</i> Share</button>
</div><!--
--><div class="action-buttons" *ngIf="loggedIn">
<button md-button class="action" (click)="edit()" ><i ofbicon>edit</i> Edit</button><!--
--><button md-button class="action" (click)="delete()" ><i ofbicon>delete_forever</i> Delete</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SermonLargeComponent } from './sermon-large.component';
describe('SermonLargeComponent', () => {
let component: SermonLargeComponent;
let fixture: ComponentFixture<SermonLargeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SermonLargeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SermonLargeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,126 @@
import { SharePopupComponent } from './../popups/share-popup/share-popup.component';
import { Sermon } from './../../interfaces/sermon';
import { UpdateSermonPopupComponent } from './../popups/update-sermon-popup/update-sermon-popup.component';
import { SermonService } from './../../services/sermon.service';
import { YesNoPopupComponent } from './../popups/yes-no-popup/yes-no-popup.component';
import { MdDialog, MdDialogConfig, MdSnackBar } from '@angular/material';
import { Component, OnInit, Input, AfterContentInit } from '@angular/core';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { SermonSmallComponent } from '../sermon-small/sermon-small.component';
import { AudioPlayerService } from '../../services/audio-player.service';
import { SERMON_DOWNLOAD_URL } from '../../constants/urls';
@Component({
selector: 'sermon-large-component',
templateUrl: './sermon-large-pic.component.html',
styleUrls: ['./sermon-large-pic.component.css'],
animations:[
trigger("inout",[
state("1", style({ opacity: '1' })),
state("0",style({ opacity: '0' })),
transition('* => 1',[
animate('500ms ease-in-out')
]),
transition(':enter',[
animate('0ms')
])
]),
trigger('toggleAnimation', [
state('open', style({
height: '*',
})),
state('closed', style({
height: '0px',
})),
transition('open <=> closed', animate('500ms ease-in-out'))
]),
trigger('toggleAnimationFade', [
state('open', style({
opacity: 0,
})),
state('closed', style({
opacity: 1,
})),
transition('open <=> closed', animate('500ms ease-in-out'))
])
]
})
export class SermonLargeComponent extends SermonSmallComponent implements OnInit, AfterContentInit {
public state: string = 'closed';
@Input()
public loggedIn: boolean;
constructor(private aplayer: AudioPlayerService
,private dialog: MdDialog
,private sermonService: SermonService
,private snackbar: MdSnackBar) {
super(aplayer);
}
ngOnInit() {
}
toggleState(){
this.state = this.state === 'open' ? 'closed' : 'open'
}
download(){
window.location.href = SERMON_DOWNLOAD_URL + this.id;
}
share(){
let opts = new MdDialogConfig;
opts.data = { sermonId: this.id, sermonTitle: this.title, sermonDescription: this.description };
let dialog = this.dialog.open(SharePopupComponent, opts);
}
edit(){
let config = new MdDialogConfig();
config.data = {
id: this.id,
title: this.title,
description: this.description,
date: this.date,
author: this.author
};
let dialog = this.dialog.open(UpdateSermonPopupComponent,config);
dialog.afterClosed().subscribe(s => {
s = s as Sermon;
if (s){
this.title = s.title;
this.description = s.description;
this.author = s.author;
this.date = s.date;
let snack = this.snackbar.open(s.title + " was updated!", "Ok");
snack.onAction().subscribe(()=>{
snack.dismiss();
});
setTimeout(()=>{snack.dismiss();},3000);
}
});
}
delete(){
let opts = new MdDialogConfig;
opts.data = { title:'Delete','message':'Are you sure you want to delete "' + this.title + '"?' };
let dialog = this.dialog.open(YesNoPopupComponent, opts);
dialog.afterClosed().subscribe(s => {
s = s as boolean;
if (s === true){
this.sermonService.deleteSermon(this.id).subscribe(
success => { console.log(success); },
error => { console.log(error); }
);
}
});
}
}

View File

@ -0,0 +1,31 @@
.inner-wrapper{
position:relative;
}
.title{
display: table;
font-size: 1.25em;
}
.title-text{
vertical-align: middle;
display: table-cell;
padding-left: 10px;
font-size: .95rem;
}
button{
position: absolute;
width: 100%;
height: 100%;
}
ofb-button{
position: absolute;
right: 0;
bottom: 0;
left: 0;
top: 0;
}

View File

@ -0,0 +1,9 @@
<div class="wrapper" [@inout]="startFadeIn">
<div class="inner-wrapper">
<div class="title">
<button md-button (click)="play()"></button>
<date-component class="title-date" [date]="date"></date-component>
<span class="title-text">{{ title }}</span>
</div>
</div>
</div>

View File

@ -0,0 +1,58 @@
import { Component, AfterContentInit, Input } from '@angular/core';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { AudioPlayerService } from '../../services/audio-player.service';
@Component({
selector: 'sermon-small-component',
templateUrl: './sermon-small.component.html',
styleUrls: ['./sermon-small.component.css'],
animations:[
trigger("inout",[
state("1", style({ opacity: '1', transform:'translateX(0)' })),
state("0",style({ opacity: '0', transform:'translateX(5%)' })),
transition('* => 1',[
animate('500ms ease-in-out')
]),
transition(':enter',[
animate('0ms')
])
])
]
})
export class SermonSmallComponent implements AfterContentInit {
@Input()
id: number;
@Input()
title: string;
@Input()
description: string;
@Input()
date: Date;
@Input()
author: string;
@Input()
url: string;
public startFadeIn: boolean = false;
@Input()
public delayFadeIn: number = 100;
constructor(private audioPlayer: AudioPlayerService){
}
play(): void{
if (this.audioPlayer.getIsPlaying() == true && this.audioPlayer.getMetaData() != null && this.audioPlayer.getMetaData().id == this.id){
this.audioPlayer.pause();
} else {
if (this.audioPlayer.getMetaData() != null && this.audioPlayer.getMetaData().id == this.id){
this.audioPlayer.resume();
} else {
this.audioPlayer.play(this.url,{id:this.id,title:this.title,author:this.author});
}
}
}
ngAfterContentInit(): void{
setTimeout(() => this.startFadeIn = true, this.delayFadeIn);
}
}

View File

@ -0,0 +1,49 @@
ul{
list-style: none;
}
li{
margin: 40px 0px 40px 0px; /* top right bottom left */
}
li:first-child{
margin-top: 0px;
}
li:last-child{
margin-bottom: 0px;
}
.side-bar{
position: fixed;
}
.width100{
width: 100%;
}
.mobile-search{
display: none;
}
.fab-buttons{
display: none;
}
#audio-player-filler{
height: 60px;
background-color: inherit;
}
@media(max-width:800px){
.mobile-search{
display: block;
}
.fab-buttons{
display: inline-block;
position: fixed;
bottom: 20px;
right: 20px;
}
}

View File

@ -0,0 +1,41 @@
<secondary-page-component [hideSideBarOnMobile]="true" >
<div mainContent>
<div class="mobile-search">
<md-input-container class="width100">
<input #searchMobile mdInput placeholder="Search Sermons" [value]="searchTerm" (keyup)="searchChange(searchMobile.value)">
</md-input-container>
<br><br>
</div>
<ul>
<li *ngFor="let sermon of sermons; let i = index;">
<sermon-large-component
[id]="sermon.id"
[title]="sermon.title"
[date]="sermon.sermonDate"
[description]="sermon.description"
[author]="sermon.author"
[delayFadeIn]="(i-((((sermons.length*10)/10)-10) > 0 ? (((sermons.length*10)/10)-10) : 0))*200"
[url]="sermon.url"
[loggedIn]="loggedIn"
></sermon-large-component>
</li>
<button md-button class="width100" style="text-align: center;" (click)="loadMoreSermonsClick()">
<i ofbicon *ngIf="loading">access_time</i><span *ngIf="loading"> Loading...</span>
<i ofbicon *ngIf="!loading">expand_more</i><span *ngIf="!loading"> Load More</span>
</button>
</ul>
<div class="fab-buttons" >
<button md-fab (click)="searchFabClick()"><i ofbicon>search</i></button>
<button md-fab *ngIf="loggedIn" (click)="addSermon()"><i ofbicon>add</i></button>
<div id="audio-player-filler" *ngIf="audioPlayerOpen"></div>
</div>
</div>
<div sideBar class="side-bar">
<div class="search-bar">
<md-input-container class="width100">
<input #search mdInput placeholder="Search Sermons" [value]="searchTerm" (keyup)="searchChange(search.value)">
</md-input-container>
</div>
<button md-raised-button class="width100" (click)="addSermon()" >Add Sermon</button>
</div>
</secondary-page-component>

View File

@ -0,0 +1,143 @@
import { InputPopupComponent } from './../popups/input-popup/input-popup.component';
import { AudioPlayerService } from './../../services/audio-player.service';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';
import { SermonService } from '../../services/sermon.service';
import { LoginService } from '../../services/login.service';
import { Sermon } from '../../interfaces/sermon';
import { MdSnackBar, MdDialog, MdDialogConfig } from '@angular/material';
import { AddSermonPopupComponent } from '../popups/add-sermon-popup/add-sermon-popup.component';
import 'rxjs/add/operator/switchMap';
@Component({
selector: 'sermons-component',
templateUrl: './sermons.component.html',
styleUrls: ['./sermons.component.css'],
})
export class SermonsComponent implements OnInit {
public sermons: Sermon[];
public loading: boolean = false;
public page: number = 1;
public searchTerm: string = '';
public loggedIn: boolean = false;
public audioPlayerOpen: boolean;
private searchWait: any;
private dialogConfig: MdDialogConfig;
constructor(private loginService: LoginService,
private snackbar: MdSnackBar,
private dialog: MdDialog,
private sermonService: SermonService,
private route: ActivatedRoute,
private location: Location,
private audioPlayerService: AudioPlayerService){
this.loginService.isLoggedIn(true).subscribe(is => { this.loggedIn = is; });
this.loginService.onLogin().subscribe(is => { this.loggedIn = is.isLoggedIn; });
this.audioPlayerService.onAudioPlayerOpenClose.subscribe(is => { this.audioPlayerOpen = is; });
}
ngOnInit(): void{
this.route.params
// (+) converts string 'id' to a number
.subscribe((params: Params) => {
let id = +params['id'];
id = Number.isNaN(id) ? -1 : id;
if (id > -1){
this.page = 0;
this.getSingleSermon(id);
} else {
this.getSermons(true);
}
});
}
searchChange(searchTerm): void{
this.searchTerm = searchTerm;
if (this.searchWait) clearTimeout(this.searchWait);
this.searchWait = setTimeout(()=>this.getSermons(true),400);
}
loadMoreSermonsClick(): void{
this.page++;
//this.location.go("/sermons/" + this.page);
this.getSermons(false);
}
getSingleSermon(id: number){
this.loading = true;
this.sermons = this.sermons || [];
this.sermons = [];
this.sermonService.getSermonById(id).subscribe(
sermons => {
this.sermons.push(sermons)
this.loading = false;
},
error => {
this.getSermons(true);
} );
}
getSermons(clearExisting): void{
this.loading = true;
this.sermons = this.sermons || [];
if (clearExisting) {
this.sermons = [];
this.page = 1;
}
this.sermonService.searchSermons(this.searchTerm,this.page).subscribe(
sermons => {
this.addSermons(sermons);
this.loading = false;
},
error => console.log(error) );
}
addSermons(sermons: Sermon[]): void{
for(let i = 0; i < sermons.length; i++){
this.sermons.push(sermons[i]);
}
}
addSermon(){
let dialog = this.dialog.open(AddSermonPopupComponent,this.dialogConfig);
dialog.afterClosed().subscribe(s => {
s = s as Sermon;
if (s){
this.sermons.unshift(s);
let snack = this.snackbar.open(s.title + " was added!", "Ok");
snack.onAction().subscribe(()=>{
snack.dismiss();
});
setTimeout(()=>{snack.dismiss();},3000);
}
});
}
searchFabClick(){
let opts = new MdDialogConfig;
opts.data = { title:'Search','message':'' };
let dialog = this.dialog.open(InputPopupComponent,opts);
dialog.afterClosed().subscribe(search => {
if (typeof search !== 'undefined' && this.searchTerm != search){
this.searchTerm = search;
this.searchChange(this.searchTerm);
window.scrollTo(0, 0);
}
});
}
}

View File

@ -0,0 +1,28 @@
.verse{
text-align: center;
font-style: italic;
}
.reference{
font-weight: bold;
}
.side-bar-header{
text-align: center;
background-color: gray;
}
.section-header{
font-size: 1.2em;
font-weight: bold;
border-bottom: 1px solid gray;
margin-bottom: 10px;
}
img{
border-radius: 5px;
width: 100%;
-webkit-box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
}

View File

@ -0,0 +1,51 @@
<secondary-page-component [hideSideBarOnMobile]="true">
<div mainContent>
<div>
<p ofbFadeInOnScroll class="section-header">Service Times</p>
<p ofbFadeInOnScroll class="section-paragraph">
Join Us every Sunday and Wednesday for challenging messages from the Bible and fellowship with others!
Bring the whole family!
<br><br>
Nursery is available during all services.
</p>
<br>
<div ofbFadeInOnScroll class="imageBorder">
<img class="image" src="assets/images/sign.png" alt="Church Image" />
</div>
<br><br>
<p ofbFadeInOnScroll class="section-header">Sunday School 10 AM</p>
<p ofbFadeInOnScroll class="section-paragraph">
During the Sunday morning service, kids are allowed to separate from the adults to attend a class that is appropriate for thier age group. We have a nursery and Sunday School classes for all age groups.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header">Sunday Morning 11 AM</p>
<p ofbFadeInOnScroll class="section-paragraph">
Sunday Morning church service immediately follows Sunday School service with a short break inbetween. Nursery and childrens church for ages up through age 4 is available during the Sunday morning hour.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header">Sunday Evening 7 PM</p>
<p ofbFadeInOnScroll class="section-paragraph">
Sunday night is the last opportunity to hear a great message before the work week starts. We encourage you to come visit us each sunday night at 7 P.M. Nursery services are available.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header">Wednesday Evening 7 PM</p>
<p ofbFadeInOnScroll class="section-paragraph">
Join us on Wednesday night for a Bible study that will surely challenge you in your walk with the Lord. Wednesday evening is a great time to come and hear a great message from the Bible to stay focused during the week. Nursery and childrens church are also available.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header"></p>
<div ofbFadeInOnScroll class="section-paragraph">
<p class="verse">Not forsaking the assembling of ourselves together, as the manner of some is; but exhorting one another: and so much the more, as ye see the day approaching.</p>
<p class="verse reference">Hebrews 10:25</p>
</div>
</div>
</div>
<div sideBar class="side-bar">
<upcoming-events-component [numberOfEventsToShow]="4" ></upcoming-events-component>
</div>
</secondary-page-component>

View File

@ -0,0 +1,34 @@
import { WindowRefService } from './../../services/window-ref.service';
import { Component, HostListener, OnInit } from '@angular/core';
@Component({
selector: 'services-component',
templateUrl: './services.component.html',
styleUrls: ['./services.component.css'],
})
export class ServicesComponent implements OnInit {
public columnCount: number = 2;
private smallColumnCount: number = 1;
private medColumnCount: number = 2;
private smallWidth: number = 500;
constructor(private windowRef: WindowRefService){ }
ngOnInit(){
let event = { target:this.windowRef.getWindow() };
this.onResize(event);
}
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < this.smallWidth){
this.columnCount = this.smallColumnCount;
} else {
this.columnCount = this.medColumnCount;
}
}
}

View File

@ -0,0 +1,15 @@
.event-header{
font-size: 1.2em;
font-weight: bold;
text-align: center;
border-bottom: 1px solid gray;
margin-bottom: 10px;
}
ul{
list-style: none;
}
li{
padding: 5px;
}

View File

@ -0,0 +1,13 @@
<div class="event-container">
<p class="event-header" >Upcoming Events</p>
<p *ngIf="loading">Loading...</p>
<ul class="events">
<li *ngFor="let event of events; let i = index;">
<event-component
[title]="event.title"
[startDate]="event.startDate"
[delayFadeIn]="(i+1)*200"
></event-component>
</li>
</ul>
</div>

View File

@ -0,0 +1,34 @@
import { Component, OnInit, Input } from '@angular/core';
import { Event } from '../../interfaces/event';
import { EventService } from '../../services/event.service';
@Component({
selector: 'upcoming-events-component',
templateUrl: './upcoming-events.component.html',
styleUrls: ['./upcoming-events.component.css']
})
export class UpcomingEventsComponent implements OnInit {
events: Event[];
loading: boolean = false;
@Input()
numberOfEventsToShow = 3;
constructor(private eventService: EventService){
}
ngOnInit(): void {
this.getSermons();
}
getSermons(): void{
this.events = [];
this.loading = true;
this.eventService.getEvents(this.numberOfEventsToShow).then(events => {
this.events = events;
this.loading = false;
console.log(this.events)
});
}
}

View File

@ -0,0 +1,25 @@
.main-content-header{
font-weight: bold;
font-size: 1.2em;
}
.side-bar-header{
text-align: center;
background-color: gray;
}
.section-header{
font-size: 1.2em;
font-weight: bold;
border-bottom: 1px solid gray;
margin-bottom: 10px;
}
img{
border-radius: 5px;
width: 100%;
-webkit-box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
box-shadow: 3px 3px 5px 0px rgba(50, 50, 50, 0.75);
}

View File

@ -0,0 +1,47 @@
<secondary-page-component [hideSideBarOnMobile]="true" >
<div mainContent>
<div>
<p ofbFadeInOnScroll class="section-header">Who We Are</p>
<p ofbFadeInOnScroll class="section-paragraph">
Old Fashion Baptist Church is a small church located in Butte, Montana. We meet regularly throughout the week
to spread the word of God as well as encourage and challenge believers in their Christian life.
For service times click <a routerLink="/services">here</a>. Contact information and directions are available
<a routerLink="/contact">here</a>
</p>
<br><br>
<div ofbFadeInOnScroll class="imageBorder">
<img class="image" src="assets/images/home-images/church.jpg" alt="Church Image" />
</div>
<br><br>
<p ofbFadeInOnScroll class="section-header">What to expect</p>
<p ofbFadeInOnScroll class="section-paragraph">
Sometimes it can be difficult to attend if you are not familiar with church and don't know what to expect.
One thing you can always expect is to be welcomed at Old Fashion Baptist. We count it a privalege to have
visitors attend our church services so the first thing you will find is a friendly church family.
<br><br>
Each service begins with a few songs along with prayer. Prayer and praise are a great way to help prepare
our hearts for the message that follows. You can expect the message to last aproximately 45 - 60
minutes and will be straight from the Bible. We want you to know that the message is from the Bible and will
turn to verses throughout the service. You are welcome to just listen or follow along in your Bible.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header">Nursery</p>
<p ofbFadeInOnScroll class="section-paragraph">
Nursery workers are available for every service. Our nursery is available so that you can attend the church service
without interruption.
</p>
<br><br>
<p ofbFadeInOnScroll class="section-header">Kids</p>
<p ofbFadeInOnScroll class="section-paragraph">
We also offer Sunday School classes for all age groups of kids. This is a great opportunity for
children to recieve a message that is appropriate for their age.
</p>
</div>
</div>
<div sideBar ofbFadeInOnScroll>
<recent-sermons-component [numberOfSermonsToShow]="4" ></recent-sermons-component>
</div>
</secondary-page-component>

View File

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'whoweare-component',
templateUrl: './whoweare.component.html',
styleUrls: ['./whoweare.component.css'],
})
export class WhoWeAreComponent {
}

View File

@ -1,14 +1,42 @@
<!doctype html>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<title>Client</title>
<base href="/">
<meta charset="utf-8">
<title>Ofb1</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style>
.loader-background{
background-color: rgb(0, 188, 212);
position: fixed;
left:0px;
top:0px;
height: 100%;
width: 100%;
text-align: center;
}
.loader {
color: #ffffff;
margin: 100px auto;
position: relative;
font-size: 24px;
}
.loader-small{
color: #ffffff;
margin: 20px auto;
position: relative;
font-size: 18px;
}
</style>
</head>
<body>
<app-root></app-root>
<body>
<app-root>
<div class="loader-background">
<div class="loader">Old Fashion Baptist</div>
<div class="loader-small">Please Wait...</div>
</div>
</app-root>
</body>
</html>
</html>

View File

@ -1 +1,53 @@
/* You can add global styles to this file, and also import other style files */
@import '../node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
*{
padding: 0px;
margin: 0px;
box-sizing: border-box;
}
html, body{
height: 100%;
}
/*MATERIAL FONT FOR ICONS*/
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(./assets/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(./assets/fonts/MaterialIcons-Regular.woff2) format('woff2'),
url(./assets/fonts/MaterialIcons-Regular.woff) format('woff'),
url(./assets/fonts/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icon {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}
/* END MATERIAL FONT ICONS*/

View File

@ -0,0 +1,14 @@
export const MONTHS = {
0: "JAN",
1: "FEB",
2: "MAR",
3: "APR",
4: "MAY",
5: "JUN",
6: "JUL",
7: "AUG",
8: "SEP",
9: "OCT",
10: "NOV",
11: "DEC"
};

View File

@ -0,0 +1,12 @@
export const SERMONS_BY_ID = '//ofbbutte.com/api/sermons/';
export const SERMONS_BY_PAGE_URL = '//ofbbutte.com/api/sermons/page/';
export const SERMONS_BY_SEARCH_URL = '//ofbbutte.com/api/sermons/search';
export const SERMON_MP3_BASE_URL = '//ofbbutte.com/static/media/';
export const SERMON_ADD_URL = "//ofbbutte.com/api/sermons/a/";
export const SERMON_DELETE_URL = "//ofbbutte.com/api/sermons/a/";
export const SERMON_UPDATE_URL = "//ofbbutte.com/api/sermons/a/";
export const SERMON_DOWNLOAD_URL = "//ofbbutte.com/api/sermons/download/";
export const LOGIN_URL = '//ofbbutte.com/api/login';
export const LOGIN_VALIDATE_TOKEN = '';
export const EMAIL_URL = "//ofbbutte.com/api/email";
export const RANDOM_VERSE_URL = "//www.kingjamesbibleonline.org/popular-bible-verses-widget.php";

View File

@ -0,0 +1,44 @@
import { Directive,
ElementRef,
Input,
HostListener,
HostBinding,
OnInit } from '@angular/core';
@Directive({
selector: '[ofbFadeInOnScroll]',
host:{
//'[class.animation-fade-in]':'true',
'[style.transition]':'"all .5s ease-in-out"'
}
})
export class FadeInOnScrollDirective implements OnInit {
@HostBinding('style.opacity')
opacity: number = 0;
constructor(private el: ElementRef) {
}
ngOnInit(): void{
this.checkScroll();
}
checkScroll(): void{
if (this.opacity === 1) return;
let viewPort = this.el.nativeElement.getBoundingClientRect();
let winHeight = window.innerHeight;
let dif = winHeight - viewPort.top;
let maxMargin = 100;
if (dif >= 50 && this.opacity != 1){
this.opacity = 1;
}
}
@HostListener('window:scroll', ['$event'])
onScroll(event){
this.checkScroll();
}
}

View File

@ -0,0 +1,27 @@
export const ICONS = {
access_time: '&#xE192;',
add: '&#xE145;',
close: '&#xE5CD;',
copyright: '&#xE90C;',
delete_forever: '&#xE92B;',
arrow_drop_down: '&#xE5C5;',
arrow_drop_up: '&#xE5C7;',
directions: '&#xE52E;',
edit: '&#xE3C9;',
event: '&#xE878;',
expand_more: '&#xE5CF;',
file_download: '&#xE2C4;',
headset: '&#xE310;',
help_outline: '&#xE8FD;',
info_outline: '&#xE88F;',
input: '&#xE890;',
mail_outline: '&#xE0E1;',
menu: '&#xE5D2;',
pause: '&#xE034;',
phone: '&#xE0CD;',
place: '&#xE55F;',
play_arrow: '&#xE037;',
search: '&#xE8B6;',
share: '&#xE80D;',
slow_motion_video: '&#xE068;',
};

View File

@ -0,0 +1,46 @@
import { Directive,
ElementRef,
OnInit,
Input,
OnChanges,
SimpleChanges } from '@angular/core';
import { ICONS } from './icon-code-map';
@Directive({
selector: '[ofbicon]',
host:{
'[class.material-icon]':'true'
}
})
export class IconDirective implements OnInit, OnChanges {
@Input()
iconName: string;
iconCode: string;
constructor(private el: ElementRef) {
}
ngOnInit(): void{
if (this.el.nativeElement.innerText != ''){
this.iconName = this.el.nativeElement.innerText;
this.setIcon();
}
}
ngOnChanges(changes: SimpleChanges): void{
this.setIcon();
}
setIcon(){
let iconCode = ICONS[this.iconName];
if (typeof iconCode !== 'undefined'){
this.iconCode = iconCode;
this.el.nativeElement.innerHTML = this.iconCode;
}
}
}

View File

@ -0,0 +1,6 @@
export enum AudioStates{
Loading,
Paused,
Playing,
Error
}

View File

@ -0,0 +1,24 @@
import { ProgressService } from './../services/xhr-progress.service';
import { Injectable } from '@angular/core';
import { BrowserXhr } from '@angular/http';
@Injectable()
export class ProgressXhr extends BrowserXhr {
constructor(private service: ProgressService) { super(); }
build(): any {
let xhr = super.build();
xhr.onprogress = (event) => {
this.service.downloadProgress.next(event);
};
xhr.upload.onprogress = (event) => {
this.service.uploadProgress.next(event);
};
return <any>(xhr);
}
}

View File

@ -0,0 +1,7 @@
export interface Event{
id: number,
title: string,
startDate: Date,
endDate: Date,
description: string
}

View File

@ -0,0 +1,9 @@
export class Sermon{
id: number;
title: string;
sermonDate: Date;
uploadDate: Date;
description: string;
author: string;
url: string;
}

Some files were not shown because too many files have changed in this diff Show More