Update to Angular 7
commit
438fef27a0
|
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events.json
|
||||
speed-measure-plugin.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Ofbclient
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.2.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"ofbclient": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "../Server/www",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/web-app-files"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "ofbclient:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "ofbclient:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "ofbclient:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ofbclient-e2e": {
|
||||
"root": "e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "ofbclient:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "ofbclient:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "ofbclient"
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('Welcome to ofbclient!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"name": "ofbclient",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^7.2.1",
|
||||
"@angular/cdk": "^7.2.1",
|
||||
"@angular/common": "~7.2.0",
|
||||
"@angular/compiler": "~7.2.0",
|
||||
"@angular/core": "~7.2.0",
|
||||
"@angular/forms": "~7.2.0",
|
||||
"@angular/material": "^7.2.1",
|
||||
"@angular/platform-browser": "~7.2.0",
|
||||
"@angular/platform-browser-dynamic": "~7.2.0",
|
||||
"@angular/router": "~7.2.0",
|
||||
"core-js": "^2.5.4",
|
||||
"hammerjs": "^2.0.8",
|
||||
"rxjs": "~6.3.3",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.12.0",
|
||||
"@angular/cli": "~7.2.2",
|
||||
"@angular/compiler-cli": "~7.2.0",
|
||||
"@angular/language-service": "~7.2.0",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/jasmine": "~2.8.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "~4.5.0",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~3.1.1",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~1.1.2",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.4.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.11.0",
|
||||
"typescript": "~3.2.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
//Components
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { WhoWeAreComponent } from './components/whoweare/whoweare.component';
|
||||
import { ServicesComponent } from './components/services/services.component';
|
||||
import { SermonsComponent } from './components/sermons/sermons.component';
|
||||
import { LocationComponent } from './components/location/location.component';
|
||||
import { EventsPageComponent } from './components/events-page/events-page.component';
|
||||
import { ContactPageComponent } from './components/contact-page/contact-page.component';
|
||||
import { SalvationPageComponent } from './components/salvation-page/salvation-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',
|
||||
component: SermonsComponent
|
||||
},
|
||||
{
|
||||
path: 'sermons/:id',
|
||||
component: SermonsComponent
|
||||
},
|
||||
{
|
||||
path: 'location',
|
||||
component: LocationComponent
|
||||
},
|
||||
{
|
||||
path: 'events',
|
||||
component: EventsPageComponent
|
||||
},
|
||||
{
|
||||
path: 'events/:id',
|
||||
component: EventsPageComponent
|
||||
},
|
||||
{
|
||||
path: 'salvation',
|
||||
component: SalvationPageComponent
|
||||
}
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import { EventService } from './services/event.service';
|
||||
import { GoogleAnalyticsService } from './services/google-analytics.service';
|
||||
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 { FormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatButtonModule,
|
||||
MatInputModule,
|
||||
MatSliderModule,
|
||||
MatSnackBarModule,
|
||||
MatDialogModule } from '@angular/material';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import 'hammerjs';
|
||||
|
||||
//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';
|
||||
import { EventsPageComponent } from './components/events-page/events-page.component';
|
||||
import { AddEventPopupComponent } from './components/popups/add-event-popup/add-event-popup.component';
|
||||
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 { EventLargeComponent } from './components/event-large/event-large.component';
|
||||
import { SalvationPageComponent } from './components/salvation-page/salvation-page.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 { SafeUrlPipe } from './pipes/safe-url.pipe';
|
||||
import { OfbDatePipe } from './pipes/ofb-date.pipe';
|
||||
|
||||
// Routing
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
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,
|
||||
AddEventPopupComponent,
|
||||
EventLargeComponent,
|
||||
OfbDatePipe,
|
||||
SalvationPageComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
BrowserAnimationsModule,
|
||||
//Angular Material Components
|
||||
MatButtonModule,
|
||||
MatInputModule,
|
||||
MatSliderModule,
|
||||
MatSnackBarModule,
|
||||
MatDialogModule,
|
||||
],
|
||||
providers: [LoginService,GoogleAnalyticsService,SermonService,EventService,EmailService,WindowRefService],
|
||||
entryComponents: [AddSermonPopupComponent,
|
||||
LoginPopupComponent,
|
||||
OkPopupComponent,
|
||||
InputPopupComponent,
|
||||
YesNoPopupComponent,
|
||||
UpdateSermonPopupComponent,
|
||||
SharePopupComponent,
|
||||
AddEventPopupComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
|
||||
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: -140px;
|
||||
padding-bottom: 140px;
|
||||
}
|
||||
|
||||
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: 380px;
|
||||
}
|
||||
.footer-panel{
|
||||
display: block;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
.content{
|
||||
margin-bottom: -380px;
|
||||
padding-bottom: 380px;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
|
||||
<header>
|
||||
<div id="header-background" [ngStyle]="{'opacity':headerOpacity}"></div>
|
||||
<button mat-button class="header-button-home" routerLink="/home"><img id="logo" src="assets/images/tiny/logo.png" height="30" alt="logo"> Old Fashion Baptist</button>
|
||||
<span class="hideOnMobile"></span>
|
||||
<button mat-button class="header-button" routerLink="/whoweare">Who We Are</button>
|
||||
<button mat-button class="header-button" routerLink="/services">Service Times</button>
|
||||
<button mat-button class="header-button" routerLink="/location">Location</button>
|
||||
<button mat-button class="header-button" routerLink="/sermons">Sermons</button>
|
||||
<button mat-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>
|
||||
<p>Associate Pastor Derek Loewen</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>
|
||||
<br>
|
||||
</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>
|
||||
<br>
|
||||
</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>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
import { GoogleAnalyticsService } from './../../services/google-analytics.service';
|
||||
import { MatDialog, MatDialogConfig, MatSnackBar } from '@angular/material';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { EventService } from './../../services/event.service';
|
||||
import { AudioPlayerService } from './../../services/audio-player.service';
|
||||
import { AddEventPopupComponent } from './../popups/add-event-popup/add-event-popup.component';
|
||||
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 {
|
||||
|
||||
private dialogConfig: MatDialogConfig;
|
||||
public loading: boolean = true;
|
||||
public events: Event[];
|
||||
public loggedIn: boolean = false;
|
||||
public showAllButtonVisible: boolean = false;
|
||||
public audioPlayerOpen: boolean = false;
|
||||
|
||||
constructor(private loginService: LoginService,
|
||||
private eventService: EventService,
|
||||
private dialog: MatDialog,
|
||||
private snackbar: MatSnackBar,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private audioPlayerService: AudioPlayerService,
|
||||
private googleAnalyticsService: GoogleAnalyticsService) {
|
||||
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() {
|
||||
this.activatedRoute.params
|
||||
.subscribe((params: Params) =>{
|
||||
let id = +params['id'];
|
||||
id = Number.isNaN(id) ? -1 : id;
|
||||
if (id > -1){
|
||||
this.getSingleEvent(id);
|
||||
this.showAllButtonVisible = true;
|
||||
} else {
|
||||
this.getEvents(true);
|
||||
this.showAllButtonVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getEvents(clearExisting: boolean): void{
|
||||
this.loading = true;
|
||||
this.events = this.events || [];
|
||||
if (clearExisting){
|
||||
this.events = [];
|
||||
}
|
||||
this.eventService.getEvents(1).subscribe(
|
||||
eventReponse => {
|
||||
this.addEvents(eventReponse.events);
|
||||
this.loading = false;
|
||||
},
|
||||
error => console.error(error)
|
||||
);
|
||||
}
|
||||
|
||||
getSingleEvent(id: Number): void{
|
||||
this.events = [];
|
||||
this.loading = true;
|
||||
this.eventService.getSingleEvent(id).subscribe(event => {
|
||||
this.events.push(event.event);
|
||||
this.loading = false;
|
||||
this.googleAnalyticsService.shareEventConversion(event.event.id,event.event.title);
|
||||
});
|
||||
}
|
||||
|
||||
addEvents(events: Event[]): void{
|
||||
console.log(events);
|
||||
for(let i = 0; i < events.length; i++){
|
||||
this.events.push(events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
addEvent(){
|
||||
let dialog = this.dialog.open(AddEventPopupComponent,this.dialogConfig);
|
||||
|
||||
dialog.afterClosed().subscribe(e => {
|
||||
e = e as Event;
|
||||
if (e != null){
|
||||
this.events.unshift(e);
|
||||
let snack = this.snackbar.open(e.title + " was added!", "Ok");
|
||||
snack.onAction().subscribe(() => {
|
||||
snack.dismiss();
|
||||
});
|
||||
setTimeout(() => { snack.dismiss(); },3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
#content-wrapper{
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
a{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:visited{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
img{
|
||||
width: 70%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
img.full {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.action{
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.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.25em;
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
||||
|
||||
.center{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.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;
|
||||
}
|
||||
img.full {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
<img id="background-image" src="assets/images/home-images/tiny/sunset_b.jpg" alt="background image" width="100%">
|
||||
|
||||
<div id="filler">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content-wrapper">
|
||||
|
||||
<div class="row tint" *ngIf="showSpecial" >
|
||||
<div class="row-content">
|
||||
<div class="row-content-col-left">
|
||||
<a href="assets/images/champ_flyer.jpg" download="champ_flyer.jpg"><img class="full" ofbFadeInOnScroll src="assets/images/home-images/tiny/champ.jpg" height="300"></a>
|
||||
</div>
|
||||
<div class="row-content-col-right align-top center">
|
||||
<p ofbFadeInOnScroll class="row-content-header">Champ the Smiling Trick Horse</p>
|
||||
<p ofbFadeInOnScroll>
|
||||
Come join us for this special event happening September 5th and 6th at Old Fashion Baptist!
|
||||
</p>
|
||||
<br>
|
||||
<p ofbFadeInOnScroll>
|
||||
<b>Wednesday, September 5 @ 7 PM</b>
|
||||
<br>
|
||||
Bible Preaching & Bluegrass Gospel Music
|
||||
</p>
|
||||
<br>
|
||||
<p ofbFadeInOnScroll>
|
||||
<b>Thursday, September 6 @ 5:30 PM</b>
|
||||
<br>
|
||||
Food, Games, Music & Preaching
|
||||
</p>
|
||||
<br>
|
||||
<p ofbFadeInOnScroll>
|
||||
<a href="assets/images/champ_flyer.jpg" download="champ_flyer.jpg"><b>Click here to download the flyer</b></a>
|
||||
</p>
|
||||
<br>
|
||||
<p ofbFadeInOnScroll class="action">
|
||||
<i ofbicon>phone</i> <a href="tel:+1-406-494-5028" class="align-top">406-494-5028</a>
|
||||
</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">...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 class="action"><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"> -->
|
||||
<a routerLink="/whoweare"><img ofbFadeInOnScroll src="assets/images/home-images/tiny/family.jpg"></a>
|
||||
</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 class="action">
|
||||
<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">
|
||||
<a href="tel:+1-406-494-5028"><img ofbFadeInOnScroll src="assets/images/home-images/tiny/bus2.jpg" height="200"></a>
|
||||
</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">
|
||||
But he answered and said, <span class="red">It is written, Man shall not live by bread alone, but by every word that proceedeth out of the mouth of God.</span> - Matthew 4:4</p>
|
||||
We encourage you to come and join as as we study, teach and preach Gods Word!
|
||||
<br><br>
|
||||
<p class="action">
|
||||
<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">
|
||||
<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"><img ofbFadeInOnScroll src="assets/images/home-images/tiny/bible.jpg"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row tint">
|
||||
<div class="row-content">
|
||||
<div class="row-content-single-col">
|
||||
<p ofbFadeInOnScroll 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. - Hebrews 10:25</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">Listen Online</p>
|
||||
<p ofbFadeInOnScroll>
|
||||
Many of our sermons are posted online. It is our prayer that these would be helpful and would encourage you in your walk with the Lord.
|
||||
</p>
|
||||
<br>
|
||||
<p ofbFadeInOnScroll class="action">
|
||||
<i ofbicon>headset</i> <a routerLink="/sermons" class="align-top">Click here to listen online</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row-content-col-left">
|
||||
<a routerLink="/sermons"><img ofbFadeInOnScroll src="assets/images/home-images/tiny/headphones.png" height="200"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { Component, HostListener } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'home-component',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.css'],
|
||||
})
|
||||
export class HomeComponent {
|
||||
backgroundTop: string = "0px";
|
||||
public get showSpecial() : boolean {
|
||||
let maxDate = new Date(2018,8,6); // September 6th 2018 -- Set the month one month behind since JavaScript dates are 0 based
|
||||
let now = new Date();
|
||||
if (now.getFullYear() > maxDate.getFullYear()) return false;
|
||||
if (now.getFullYear() == maxDate.getFullYear()) {
|
||||
if (now.getMonth() > maxDate.getMonth()) return false;
|
||||
if (now.getMonth() == maxDate.getMonth()) {
|
||||
if (now.getDate() > maxDate.getDate()) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@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";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
import { EventService } from './../../../services/event.service';
|
||||
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
|
||||
import { LoginPopupComponent } from './../login-popup/login-popup.component';
|
||||
import { MatDialog, MatDialogRef, MatSnackBar } from '@angular/material';
|
||||
import { Event } from './../../../interfaces/event';
|
||||
import { LoginService } from './../../../services/login.service';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-event-popup',
|
||||
templateUrl: './add-event-popup.component.html',
|
||||
styleUrls: ['./add-event-popup.component.css']
|
||||
})
|
||||
export class AddEventPopupComponent implements OnInit {
|
||||
public addEventButtonText: string = "Add Event";
|
||||
public addEventButtonDisabled: boolean = false;
|
||||
|
||||
public eventTitle: string;
|
||||
public eventStartDate: Date = new Date();
|
||||
private _eventEndDate: Date = new Date();
|
||||
public get eventEndDate(): Date{
|
||||
if (new Date(this.eventStartDate).getTime() > new Date(this._eventEndDate).getTime()){
|
||||
this._eventEndDate = this.eventStartDate;
|
||||
}
|
||||
return this._eventEndDate;
|
||||
}
|
||||
public set eventEndDate(val: Date){
|
||||
this._eventEndDate = val;
|
||||
}
|
||||
public eventDescription: string;
|
||||
|
||||
|
||||
public errorMessages: string[] = [];
|
||||
|
||||
constructor(private MatDialog: MatDialog, private MatDialogRef: MatDialogRef<AddEventPopupComponent>, private loginService: LoginService, private eventService: EventService) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
onSubmit(){
|
||||
this.updateAddButton(false);
|
||||
|
||||
//First check to see if we are logged in
|
||||
this.loginService.isLoggedIn(true).subscribe(is => {
|
||||
if (is === true){
|
||||
this.addEvent();
|
||||
} else {
|
||||
let popup = this.MatDialog.open(LoginPopupComponent);
|
||||
popup.afterClosed().subscribe(r => {
|
||||
if (r === true){
|
||||
this.addEvent();
|
||||
} else {
|
||||
this.updateAddButton(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error =>{
|
||||
this.updateAddButton(true);
|
||||
let errorDialog = this.MatDialog.open(OkPopupComponent,{data:{title:'Error',message:'There was an error adding the event\n' + error}});
|
||||
});
|
||||
}
|
||||
|
||||
updateAddButton(enable: boolean){
|
||||
if (enable){
|
||||
this.addEventButtonText = "Add Event";
|
||||
} else {
|
||||
this.addEventButtonText = "Please Wait...";
|
||||
}
|
||||
this.addEventButtonDisabled = !enable;
|
||||
}
|
||||
|
||||
private addEvent(): void {
|
||||
//Check fields
|
||||
this.errorMessages = [];
|
||||
if (this.eventTitle == null || this.eventTitle == ""){
|
||||
this.errorMessages.push("Please enter a title");
|
||||
}
|
||||
if (this.eventStartDate == null){
|
||||
this.errorMessages.push("Please enter a event start date");
|
||||
}
|
||||
if (this.eventEndDate == null){
|
||||
this.errorMessages.push("Please enter a event end date");
|
||||
}
|
||||
if (this.eventDescription == null || this.eventDescription == ""){
|
||||
this.errorMessages.push("Please enter a description");
|
||||
}
|
||||
if (this.errorMessages.length > 0){ this.updateAddButton(true); return; }
|
||||
|
||||
let e = new Event();
|
||||
e.title = this.eventTitle;
|
||||
e.startDate = this.eventStartDate;
|
||||
e.endDate = this.eventEndDate;
|
||||
e.description = this.eventDescription;
|
||||
|
||||
this.eventService.addEvent(e).subscribe(
|
||||
data=>{
|
||||
this.updateAddButton(true);
|
||||
this.MatDialogRef.close(data['event']);
|
||||
},
|
||||
error => {
|
||||
this.updateAddButton(true);
|
||||
let errorDialog = this.MatDialog.open(OkPopupComponent,{data:{title:'Upload Error',message:'There was an error uploading the sermon\n' + error}});
|
||||
});
|
||||
}
|
||||
|
||||
cancel(evt){
|
||||
evt.preventDefault();
|
||||
this.MatDialogRef.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { LoginPopupComponent } from './../login-popup/login-popup.component';
|
||||
import { MatDialog, MatDialogRef, MatSnackBar } 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';
|
||||
import { HttpEvent, HttpEventType } from '@angular/common/http';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-sermon-popup',
|
||||
templateUrl: './add-sermon-popup.component.html',
|
||||
styleUrls: ['./add-sermon-popup.component.css']
|
||||
})
|
||||
export class AddSermonPopupComponent implements OnInit {
|
||||
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[] = [];
|
||||
|
||||
public uploadTotal: number = 100;
|
||||
public uploadProgress: number = 0;
|
||||
public monitorProgress: boolean;
|
||||
|
||||
private progressSubscription: Subscription;
|
||||
|
||||
constructor(private MatDialog: MatDialog, private MatDialogRef: MatDialogRef<AddSermonPopupComponent>, private loginService: LoginService, private sermonService: SermonService) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
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.MatDialog.open(LoginPopupComponent);
|
||||
popup.afterClosed().subscribe(r => {
|
||||
if (r === true){
|
||||
this.addSermon();
|
||||
} else {
|
||||
this.updateAddButton(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error =>{
|
||||
this.updateAddButton(true);
|
||||
let errorDialog = this.MatDialog.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'){
|
||||
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.date = this.sermonDate;
|
||||
|
||||
//Start monitoring Progress
|
||||
this.monitorProgress = true;
|
||||
|
||||
this.sermonService.addSermon(s,this.sermonFile).subscribe(
|
||||
data => {this.getEventMessage(data); },
|
||||
error => {
|
||||
alert(error);
|
||||
this.updateAddButton(true);
|
||||
this.monitorProgress = false;
|
||||
let errorDialog = this.MatDialog.open(OkPopupComponent,{data:{title:'Upload Error',message:'There was an error uploading the sermon\n' + error}});
|
||||
});
|
||||
}
|
||||
|
||||
private getEventMessage(event: HttpEvent<any>) {
|
||||
switch (event.type) {
|
||||
case HttpEventType.Sent:
|
||||
return;
|
||||
|
||||
case HttpEventType.UploadProgress:
|
||||
this.uploadProgress = event.loaded;
|
||||
this.uploadTotal = event.total;
|
||||
return;
|
||||
|
||||
case HttpEventType.Response:
|
||||
this.updateAddButton(true);
|
||||
this.monitorProgress = false;
|
||||
this.MatDialogRef.close(event['body']['sermon']);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onFileChange(event){
|
||||
this.sermonFile = event.srcElement.files[0];
|
||||
}
|
||||
|
||||
cancel(evt){
|
||||
evt.preventDefault();
|
||||
this.MatDialogRef.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import { OkPopupComponent } from './../ok-popup/ok-popup.component';
|
||||
import { MatSnackBar, MatDialogRef, MatDialog, MatDialogConfig } 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 MatDialog: MatDialog, private MatDialogRef: MatDialogRef<LoginPopupComponent>, private loginService: LoginService, private snackbar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
onSubmit(){
|
||||
this.loginButtonText = 'Please Wait...';
|
||||
this.loginButtonDisabled = true;
|
||||
this.loginService.login(this.username,this.password).subscribe(
|
||||
(data:any) => {
|
||||
if (data.message === 'Logged In'){
|
||||
this.MatDialogRef.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);
|
||||
}
|
||||
this.loginButtonText = 'Login';
|
||||
this.loginButtonDisabled = false;
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
this.showLoginError(error);
|
||||
this.loginButtonText = 'Login';
|
||||
this.loginButtonDisabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
showLoginError(message: string){
|
||||
let opts = new MatDialogConfig;
|
||||
opts.data = { title:'Login Error','message':message };
|
||||
let popup = this.MatDialog.open(OkPopupComponent,opts);
|
||||
}
|
||||
|
||||
cancel(){
|
||||
this.MatDialogRef.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
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 { MatDialog, MatDialogRef, MAT_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(MAT_DIALOG_DATA) private data: any,
|
||||
private MatDialog: MatDialog,
|
||||
private MatDialogRef: MatDialogRef<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.MatDialog.open(LoginPopupComponent);
|
||||
popup.afterClosed().subscribe(r => {
|
||||
if (r === true){
|
||||
this.updateSermon();
|
||||
} else {
|
||||
this.updateButton(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error =>{
|
||||
this.updateButton(true);
|
||||
let errorDialog = this.MatDialog.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.date = this.sermonDate;
|
||||
|
||||
//Start monitoring Progress
|
||||
this.sermonService.updateSermon(s).subscribe(
|
||||
(data:any)=>{
|
||||
this.MatDialogRef.close(data.sermon);
|
||||
},
|
||||
error => {
|
||||
this.updateButton(true);
|
||||
let errorDialog = this.MatDialog.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.MatDialogRef.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.date"
|
||||
[delayFadeIn]="(i+1)*200"
|
||||
[url]="sermon.file"
|
||||
[id]="sermon.id"
|
||||
></sermon-small-component>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -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(response => {
|
||||
this.sermons = response.sermons;
|
||||
this.loading = false;
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<secondary-page-component [hideSideBarOnMobile]="true" >
|
||||
<div mainContent>
|
||||
<div class="mobile-search">
|
||||
<mat-form-field class="width100">
|
||||
<input #searchMobile matInput placeholder="Search Sermons" [value]="searchTerm" (keyup)="searchChange(searchMobile.value)">
|
||||
</mat-form-field>
|
||||
<br><br>
|
||||
</div>
|
||||
<ul>
|
||||
<li *ngFor="let sermon of sermons; let i = index;">
|
||||
<sermon-large-component
|
||||
[id]="sermon.id"
|
||||
[title]="sermon.title"
|
||||
[date]="sermon.date"
|
||||
[description]="sermon.description"
|
||||
[author]="sermon.author"
|
||||
[delayFadeIn]="(i-((((sermons.length*10)/10)-10) > 0 ? (((sermons.length*10)/10)-10) : 0))*200"
|
||||
[url]="sermon.file"
|
||||
[loggedIn]="loggedIn"
|
||||
></sermon-large-component>
|
||||
</li>
|
||||
<button mat-button [disabled]="loading" 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 mat-fab (click)="searchFabClick()"><i ofbicon>search</i></button>
|
||||
<button mat-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">
|
||||
<mat-form-field class="width100">
|
||||
<input #search matInput placeholder="Search Sermons" [value]="searchTerm" (keyup)="searchChange(search.value)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<button mat-raised-button *ngIf="loggedIn" class="width100" (click)="addSermon()" >Add Sermon</button>
|
||||
</div>
|
||||
</secondary-page-component>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
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 { MatSnackBar, MatDialog, MatDialogConfig } from '@angular/material';
|
||||
|
||||
import { AddSermonPopupComponent } from '../popups/add-sermon-popup/add-sermon-popup.component';
|
||||
|
||||
@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: MatDialogConfig;
|
||||
|
||||
|
||||
constructor(private loginService: LoginService,
|
||||
private snackbar: MatSnackBar,
|
||||
private dialog: MatDialog,
|
||||
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(
|
||||
response => {
|
||||
this.sermons.push(response.sermon)
|
||||
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(
|
||||
response => {
|
||||
this.addSermons(response.sermons);
|
||||
this.loading = false;
|
||||
},
|
||||
error => console.error(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 MatDialogConfig;
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
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 {
|
||||
public events: Event[];
|
||||
loading: boolean = false;
|
||||
@Input()
|
||||
numberOfEventsToShow: number = 3;
|
||||
@Input()
|
||||
hideWhenNoEvents: boolean = true;
|
||||
|
||||
constructor(private eventService: EventService){
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getEvents();
|
||||
}
|
||||
|
||||
getEvents(): void{
|
||||
this.events = [];
|
||||
this.loading = true;
|
||||
this.eventService.getEvents(1).subscribe(events => {
|
||||
this.events = events.events.slice(0,this.numberOfEventsToShow);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { environment } from '../../environments/environment';
|
||||
|
||||
export const EVENTS_ADD_URL = environment.baseUrl + "/api2/events/a/";
|
||||
export const EVENT_BY_ID = environment.baseUrl + "/api2/events/";
|
||||
export const EVENTS_BY_PAGE_URL = environment.baseUrl + "/api2/events/page/";
|
||||
export const EVENTS_DELETE_BY_ID_URL = environment.baseUrl + "/api2/events/a/";
|
||||
export const SERMONS_BY_ID = environment.baseUrl + '/api2/sermons/';
|
||||
export const SERMONS_BY_PAGE_URL = environment.baseUrl + '/api2/sermons/page/';
|
||||
export const SERMONS_BY_SEARCH_URL = environment.baseUrl + '/api2/sermons/search';
|
||||
export const SERMON_MP3_BASE_URL = '//ofbbutte.com/static/media/';
|
||||
export const SERMON_ADD_URL = environment.baseUrl + "/api2/sermons/a/";
|
||||
export const SERMON_DELETE_URL = environment.baseUrl + "/api2/sermons/a/";
|
||||
export const SERMON_UPDATE_URL = environment.baseUrl + "/api2/sermons/a/";
|
||||
export const SERMON_DOWNLOAD_URL = environment.baseUrl + "/api2/sermons/download/";
|
||||
export const LOGIN_URL = environment.baseUrl + '/api2/login';
|
||||
export const LOGIN_VALIDATE_TOKEN = '';
|
||||
export const EMAIL_URL = environment.baseUrl + "/api2/email";
|
||||
export const RANDOM_VERSE_URL = "//www.kingjamesbibleonline.org/popular-bible-verses-widget.php";
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
export class Event{
|
||||
id: number;
|
||||
title: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class EventResponse {
|
||||
status: number;
|
||||
events: Event[];
|
||||
}
|
||||
|
||||
export class SingleEventResponse {
|
||||
status: number;
|
||||
event: Event;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
export class Sermon{
|
||||
id: number;
|
||||
title: string;
|
||||
date: Date;
|
||||
uploadDate: Date;
|
||||
description: string;
|
||||
author: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class SingleSermonResponse {
|
||||
status: number;
|
||||
sermon: Sermon;
|
||||
}
|
||||
|
||||
export class MultipleSermonResponse {
|
||||
status: number;
|
||||
sermons: Sermon[];
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Sermon } from '../interfaces/sermon';
|
||||
import { AudioStates } from '../enum/audio-states';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Subject } from 'rxjs';
|
||||
import { SERMON_MP3_BASE_URL } from '../constants/urls';
|
||||
|
||||
@Injectable()
|
||||
export class AudioPlayerService {
|
||||
private audio: any = null;
|
||||
private metaData: any = null;
|
||||
|
||||
public loading: boolean = true;
|
||||
|
||||
private stateChanged: Subject<{metaData:any,state:AudioStates,error:any}>;
|
||||
|
||||
public onAudioPlayerOpenClose: BehaviorSubject<boolean>;
|
||||
|
||||
constructor(){
|
||||
this.stateChanged = new Subject<{metaData:any,state:AudioStates,error:any}>();
|
||||
this.onAudioPlayerOpenClose = new BehaviorSubject<boolean>(false);
|
||||
this.audio = new Audio();
|
||||
this.audio.addEventListener("loadeddata",()=>this.doPlay());
|
||||
this.audio.addEventListener("error",()=>this.error());
|
||||
this.audio.addEventListener("ended",()=>this.ended());
|
||||
}
|
||||
|
||||
updateAudioPlayerOpen(isOpen: boolean){
|
||||
this.onAudioPlayerOpenClose.next(isOpen);
|
||||
}
|
||||
|
||||
play(src: string, metaData?: any): void{
|
||||
src = SERMON_MP3_BASE_URL + src;
|
||||
try{
|
||||
if (typeof src === 'undefined' || src == null) return;
|
||||
this.loading = true;
|
||||
this.metaData = metaData;
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Loading,error:null});
|
||||
|
||||
if (this.audio == null){
|
||||
this.audio = new Audio(src);
|
||||
} else {
|
||||
this.audio.pause();
|
||||
this.audio.src = src;
|
||||
this.audio.load();
|
||||
}
|
||||
} catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private doPlay(){
|
||||
this.loading = false;
|
||||
try{
|
||||
if (this.audio.readyState >= 3){
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Playing,error:null});
|
||||
this.audio.play();
|
||||
}
|
||||
} catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private error(){
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Error,error:this.audio.error});
|
||||
this.audio = null;
|
||||
this.metaData = null;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
private ended(){
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Paused,error:null});
|
||||
}
|
||||
|
||||
resume(): void{
|
||||
if (this.audio == null) {
|
||||
console.error("nothing to resume");
|
||||
return;
|
||||
}
|
||||
this.audio.play();
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Playing,error:null});
|
||||
}
|
||||
|
||||
pause(): void{
|
||||
if (this.audio == null) return;
|
||||
this.audio.pause();
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Paused,error:null});
|
||||
}
|
||||
|
||||
stop(): void{
|
||||
if (this.audio == null) return;
|
||||
this.audio.pause();
|
||||
this.stateChanged.next({metaData:this.metaData,state:AudioStates.Paused,error:null});
|
||||
this.metaData = null;
|
||||
}
|
||||
|
||||
cleanup(): void{
|
||||
this.audio = null;
|
||||
}
|
||||
|
||||
setPosition(position: number): void{
|
||||
if (this.audio == null) return;
|
||||
this.audio.currentTime = position;
|
||||
}
|
||||
|
||||
getIsPlaying(): boolean{
|
||||
if (this.audio == null) return false;
|
||||
return !this.audio.paused;
|
||||
}
|
||||
|
||||
getCurrentTime(): number{
|
||||
if (this.audio == null) return null;
|
||||
return this.audio.currentTime;
|
||||
}
|
||||
|
||||
getDuration(): number{
|
||||
if (this.audio == null) return null;
|
||||
return this.audio.duration;
|
||||
}
|
||||
|
||||
getMetaData(): any{
|
||||
return this.metaData;
|
||||
}
|
||||
|
||||
onStateChanged(): Observable<{metaData:any,state:AudioStates,error:any}>{
|
||||
return this.stateChanged.asObservable();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpResponse } from '@angular/common/http';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { RANDOM_VERSE_URL } from '../constants/urls';
|
||||
|
||||
@Injectable()
|
||||
export class BibleVerseService {
|
||||
constructor(private httpClient: HttpClient){}
|
||||
|
||||
randomVerse(){
|
||||
//return this.http.get(RANDOM_VERSE_URL).map(this.gotData).catch(this.dataError);
|
||||
}
|
||||
|
||||
gotData(res: Response){
|
||||
console.log(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import { throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { EMAIL_URL } from '../constants/urls';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
|
||||
constructor(private httpClient: HttpClient){
|
||||
|
||||
}
|
||||
|
||||
sendEmail(fromName: string,
|
||||
fromEmail: string,
|
||||
fromPhone: string,
|
||||
message: string,
|
||||
hp: string){
|
||||
|
||||
let body = {
|
||||
name: fromName,
|
||||
email: fromEmail,
|
||||
phone: fromPhone,
|
||||
message: message,
|
||||
hp: hp
|
||||
};
|
||||
|
||||
return this.httpClient.post(EMAIL_URL, body, {withCredentials:true})
|
||||
.pipe(catchError(this.handleError))
|
||||
|
||||
}
|
||||
|
||||
private handleError(error: HttpErrorResponse) {
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
console.error('An error occurred:', error.error.message);
|
||||
} else {
|
||||
// The backend returned an unsuccessful response code.
|
||||
// The response body may contain clues as to what went wrong,
|
||||
console.error(
|
||||
`Backend returned code ${error.status}, ` +
|
||||
`body was: ${error.error}`);
|
||||
}
|
||||
// return an observable with a user-facing error message
|
||||
return throwError(
|
||||
'Something bad happened; please try again later.');
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, tap, map } from 'rxjs/operators';
|
||||
import { Event, EventResponse, SingleEventResponse } from '../interfaces/event';
|
||||
|
||||
import { EVENTS_BY_PAGE_URL,
|
||||
EVENT_BY_ID,
|
||||
EVENTS_ADD_URL,
|
||||
EVENTS_DELETE_BY_ID_URL } from '../constants/urls';
|
||||
import { getBodyNode } from '@angular/animations/browser/src/render/shared';
|
||||
|
||||
@Injectable()
|
||||
export class EventService {
|
||||
|
||||
constructor(private httpClient: HttpClient){
|
||||
|
||||
}
|
||||
|
||||
getEvents(page: number): Observable<EventResponse> {
|
||||
let url = EVENTS_BY_PAGE_URL + page + "?pageSize=" + 10;
|
||||
return this.httpClient.get<EventResponse>(url)
|
||||
.pipe(tap(e => this.setMultipleEventDates(e)),
|
||||
catchError(this.handleError));
|
||||
};
|
||||
|
||||
getSingleEvent(id: Number): Observable<SingleEventResponse>{
|
||||
let url = EVENT_BY_ID + id;
|
||||
return this.httpClient.get<SingleEventResponse>(url).pipe(tap(e => this.setSingleEventDates(e)), catchError(this.handleError));
|
||||
};
|
||||
|
||||
setEventDates(event: Event): Event {
|
||||
event.startDate = new Date(event.startDate);
|
||||
event.endDate = new Date(event.endDate);
|
||||
return event;
|
||||
}
|
||||
|
||||
setSingleEventDates(event : SingleEventResponse) : SingleEventResponse {
|
||||
event.event = this.setEventDates(event.event);
|
||||
return event;
|
||||
}
|
||||
|
||||
setMultipleEventDates(event: EventResponse) : EventResponse {
|
||||
event.events.forEach(e => {
|
||||
e = this.setEventDates(e);
|
||||
});
|
||||
return event;
|
||||
}
|
||||
|
||||
addEvent(event: Event){
|
||||
let fd = new FormData();
|
||||
fd.append("title",event.title);
|
||||
fd.append("description",event.description);
|
||||
fd.append("startDate",new Date(event.startDate).getTime().toString()); //Pass date as milliseconds since 1970
|
||||
fd.append("endDate",new Date(event.endDate).getTime().toString()); //Pass date as milliseconds since 1970
|
||||
fd.append("timezoneOffset",new Date().getTimezoneOffset().toString());
|
||||
|
||||
return this.httpClient.post(EVENTS_ADD_URL, fd, {withCredentials:true}).pipe(catchError(this.handleError));
|
||||
}
|
||||
|
||||
deleteEvent(eventId: number){
|
||||
let ro = {
|
||||
body: {"id":eventId},
|
||||
withCredentials: true
|
||||
};
|
||||
|
||||
return this.httpClient.delete(EVENTS_DELETE_BY_ID_URL, ro).pipe(catchError(this.handleError));
|
||||
}
|
||||
|
||||
toEvent(json: any): Event{
|
||||
return {
|
||||
id: json.id,
|
||||
title: json.title,
|
||||
startDate: new Date(json.startDate),
|
||||
endDate: new Date(json.endDate),
|
||||
description: json.description
|
||||
}
|
||||
}
|
||||
|
||||
private handleError(error: HttpErrorResponse) {
|
||||
console.error(error);
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
console.error('An error occurred:', error.error.message);
|
||||
} else {
|
||||
// The backend returned an unsuccessful response code.
|
||||
// The response body may contain clues as to what went wrong,
|
||||
console.error(
|
||||
`Backend returned code ${error.status}, ` +
|
||||
`body was: ${error.error}`);
|
||||
}
|
||||
// return an observable with a user-facing error message
|
||||
return throwError(
|
||||
'Something bad happened; please try again later.');
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
|
||||
import { Observable, Subject, throwError, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
import { LOGIN_URL } from '../constants/urls';
|
||||
|
||||
@Injectable()
|
||||
export class LoginService {
|
||||
private loggedIn: boolean = false;
|
||||
private onChange: Subject<{isLoggedIn: boolean}>;
|
||||
private lastLoginCheck: Date;
|
||||
private options: {};
|
||||
|
||||
constructor(private httpClient: HttpClient){
|
||||
this.options = {
|
||||
withCredentials: true
|
||||
};
|
||||
this.lastLoginCheck = new Date();
|
||||
this.lastLoginCheck.setHours(this.lastLoginCheck.getHours() - 2);
|
||||
this.onChange = new Subject<{isLoggedIn: boolean}>();
|
||||
}
|
||||
|
||||
login(username: string, password: string){
|
||||
return this.httpClient.post(LOGIN_URL, {userName: username, password: password}, this.options).pipe(catchError(this.handleError));
|
||||
}
|
||||
|
||||
isLoggedIn(fromServer: boolean = false){
|
||||
var now = new Date();
|
||||
var hours = Math.abs(now.valueOf() - this.lastLoginCheck.valueOf()) / 36e5;
|
||||
if (hours > 0.75 || fromServer === true){
|
||||
return this.httpClient.post(LOGIN_URL + "/isloggedin",{},this.options)
|
||||
.pipe(map((d:any) => {
|
||||
let is = d.loggedIn === true;
|
||||
this.loggedIn = is;
|
||||
this.lastLoginCheck = new Date();
|
||||
this.onChange.next({isLoggedIn: this.loggedIn});
|
||||
return this.loggedIn;
|
||||
}),
|
||||
catchError(this.handleError));
|
||||
|
||||
} else {
|
||||
let val = this.loggedIn;
|
||||
return of(val);
|
||||
}
|
||||
}
|
||||
|
||||
onLogin(): Observable<{isLoggedIn: boolean}>{
|
||||
return this.onChange.asObservable();
|
||||
}
|
||||
|
||||
private handleError(error: HttpErrorResponse) {
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
console.error('An error occurred:', error.error.message);
|
||||
} else {
|
||||
// The backend returned an unsuccessful response code.
|
||||
// The response body may contain clues as to what went wrong,
|
||||
console.error(
|
||||
`Backend returned code ${error.status}, ` +
|
||||
`body was: ${error.error}`);
|
||||
}
|
||||
// return an observable with a user-facing error message
|
||||
return throwError(
|
||||
'Something bad happened; please try again later.');
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpErrorResponse, HttpRequest } from '@angular/common/http';
|
||||
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
|
||||
import { Sermon, MultipleSermonResponse, SingleSermonResponse } from '../interfaces/sermon';
|
||||
import { SERMONS_BY_ID,
|
||||
SERMONS_BY_PAGE_URL,
|
||||
SERMON_MP3_BASE_URL,
|
||||
SERMONS_BY_SEARCH_URL,
|
||||
SERMON_ADD_URL,
|
||||
SERMON_DELETE_URL,
|
||||
SERMON_UPDATE_URL } from '../constants/urls';
|
||||
|
||||
@Injectable()
|
||||
export class SermonService {
|
||||
private pageSize: number = 10;
|
||||
|
||||
constructor(private httpClient: HttpClient){
|
||||
|
||||
}
|
||||
|
||||
getSermons(count: number): Observable<MultipleSermonResponse> {
|
||||
let url = SERMONS_BY_PAGE_URL + 1 + "?pageSize=" + 5;
|
||||
return this.httpClient.get<MultipleSermonResponse>(url).pipe(tap(e => this.setMultipleDates(e)), catchError(this.handleError));
|
||||
};
|
||||
|
||||
getSermonsByPage(page: number): Observable<MultipleSermonResponse>{
|
||||
let url = SERMONS_BY_PAGE_URL + page + "?pageSize=" + this.pageSize;
|
||||
return this.httpClient.get<MultipleSermonResponse>(url).pipe(tap(e => this.setMultipleDates(e)), catchError(this.handleError));
|
||||
}
|
||||
|
||||
getSermonById(id: number): Observable<SingleSermonResponse>{
|
||||
let url = SERMONS_BY_ID + id + "?pageSize=" + this.pageSize;
|
||||
return this.httpClient.get<SingleSermonResponse>(url).pipe(tap(e => this.setSingleDate(e)), catchError(this.handleError));
|
||||
}
|
||||
|
||||
searchSermons(searchTerm: string, page: number): Observable<MultipleSermonResponse>{
|
||||
let url = SERMONS_BY_SEARCH_URL + "?searchTerm=" + searchTerm + "&page=" + page + "&pageSize=" + this.pageSize;
|
||||
return this.httpClient.get<MultipleSermonResponse>(url).pipe(tap(e => this.setMultipleDates(e)), catchError(this.handleError));
|
||||
}
|
||||
|
||||
addSermon(sermon: Sermon, sermonFile: File){
|
||||
let fd = new FormData();
|
||||
fd.append("title",sermon.title);
|
||||
fd.append("description",sermon.description);
|
||||
fd.append("date",new Date(sermon.date).getTime().toString()); //Pas date as milliseconds since 1970
|
||||
fd.append("author",sermon.author);
|
||||
fd.append("file",sermonFile);
|
||||
fd.append("timezoneOffset",new Date().getTimezoneOffset().toString());
|
||||
const req = new HttpRequest('POST', SERMON_ADD_URL, fd, {
|
||||
reportProgress: true,
|
||||
withCredentials: true
|
||||
});
|
||||
return this.httpClient.request(req).pipe(
|
||||
catchError(this.handleError)
|
||||
);
|
||||
}
|
||||
|
||||
updateSermon(sermon: Sermon){
|
||||
let fd = new FormData();
|
||||
fd.append("id",sermon.id.toString());
|
||||
fd.append("title",sermon.title);
|
||||
fd.append("description",sermon.description);
|
||||
fd.append("date",new Date(sermon.date).toUTCString());
|
||||
fd.append("author",sermon.author);
|
||||
fd.append("timezoneOffset",new Date().getTimezoneOffset().toString());
|
||||
return this.httpClient.put<Sermon>(SERMON_UPDATE_URL,fd,{withCredentials:true})
|
||||
.pipe(catchError(this.handleError));
|
||||
}
|
||||
|
||||
|
||||
deleteSermon(sermonId: number){
|
||||
let options = {
|
||||
withCredentials: true,
|
||||
body: {
|
||||
"id" : sermonId
|
||||
}
|
||||
};
|
||||
return this.httpClient.delete(SERMON_DELETE_URL,options)
|
||||
.pipe(catchError(this.handleError));
|
||||
}
|
||||
|
||||
setSingleDate(e : SingleSermonResponse): SingleSermonResponse {
|
||||
e.sermon = this.setDates(e.sermon);
|
||||
return e;
|
||||
}
|
||||
|
||||
setMultipleDates(e : MultipleSermonResponse) : MultipleSermonResponse {
|
||||
e.sermons.forEach(s => {
|
||||
s = this.setDates(s);
|
||||
});
|
||||
return e;
|
||||
}
|
||||
|
||||
setDates(sermon: Sermon): Sermon {
|
||||
sermon.date = new Date(sermon.date);
|
||||
sermon.uploadDate = new Date(sermon.uploadDate);
|
||||
return sermon;
|
||||
}
|
||||
|
||||
private handleError(error: HttpErrorResponse) {
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
console.error('An error occurred:', error.error.message);
|
||||
} else {
|
||||
// The backend returned an unsuccessful response code.
|
||||
// The response body may contain clues as to what went wrong,
|
||||
console.error(
|
||||
`Backend returned code ${error.status}, ` +
|
||||
`body was: ${error.error}`);
|
||||
}
|
||||
// return an observable with a user-facing error message
|
||||
return throwError(
|
||||
'Something bad happened; please try again later.');
|
||||
};
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
|
|
@ -0,0 +1,11 @@
|
|||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
#
|
||||
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export const environment = {
|
||||
production: true,
|
||||
baseUrl: ""
|
||||
};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
baseUrl: "http://localhost:25776"
|
||||
};
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
|
|
@ -0,0 +1,96 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- V2 -->
|
||||
<base href="/">
|
||||
<meta charset="utf-8">
|
||||
<title>Old Fashion Baptist Church</title>
|
||||
|
||||
<!-- Google Analytics -->
|
||||
<!-- Global Site Tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-107601801-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
</script>
|
||||
<!---->
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/web-app-files/apple-touch-icon.png?v=LbWKNzlwGb">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/web-app-files/favicon-32x32.png?v=LbWKNzlwGb">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/web-app-files/favicon-16x16.png?v=LbWKNzlwGb">
|
||||
<link rel="manifest" href="/web-app-files/manifest.json?v=LbWKNzlwGb">
|
||||
<link rel="mask-icon" href="/web-app-files/safari-pinned-tab.svg?v=LbWKNzlwGb" color="#00bcd4">
|
||||
<link rel="shortcut icon" href="/web-app-files/favicon.ico?v=LbWKNzlwGb">
|
||||
<meta name="apple-mobile-web-app-title" content="Old Fashion Baptist">
|
||||
<meta name="application-name" content="Old Fashion Baptist">
|
||||
<meta name="msapplication-config" content="/web-app-files/browserconfig.xml?v=LbWKNzlwGb">
|
||||
<meta name="theme-color" content="#00bcd4">
|
||||
<!-- End Favicons -->
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<style>
|
||||
.loader-background{
|
||||
background-color: rgb(0, 188, 212);
|
||||
position: fixed;
|
||||
left:0px;
|
||||
top:0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.loader {
|
||||
color: #ffffff;
|
||||
margin: 40px auto;
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
}
|
||||
.loader-small{
|
||||
color: #ffffff;
|
||||
margin: 70px auto;
|
||||
position: relative;
|
||||
font-size: 18px;
|
||||
}
|
||||
.address{
|
||||
font-size: 16px;
|
||||
}
|
||||
.service-times{
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
margin: 5px auto;
|
||||
}
|
||||
.ie{
|
||||
padding: 15px;
|
||||
background-color: red;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
}
|
||||
.ie-small{
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<app-root>
|
||||
<div class="loader-background">
|
||||
<!--[if IE]>
|
||||
<div class="ie">Oh No! Looks like your browser is pretty outdated so our site may not work correctly.
|
||||
<p class="ie-small">Please consider updating</p>
|
||||
</div>
|
||||
<![endif]-->
|
||||
<div class="loader">Old Fashion Baptist<p class="address">5003 Wynne Ave | Butte, MT 59701</p></div>
|
||||
<!--[if !IE]><!-->
|
||||
<div class="loader-small">Please Wait...</div>
|
||||
<!--<![endif]-->
|
||||
<p class="service-times"><b>Service Times</b></p>
|
||||
<p class="service-times">Sunday School: 10 AM</p>
|
||||
<p class="service-times">Sunday Morning: 11 AM</p>
|
||||
<p class="service-times">Sunday Evening: 7 PM</p>
|
||||
<p class="service-times">Wednesday Evening: 7 PM</p>
|
||||
</div>
|
||||
</app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../coverage'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10, IE11, and Chrome <55 requires all of the following polyfills.
|
||||
* This also includes Android Emulators with older versions of Chrome and Google Search/Googlebot
|
||||
*/
|
||||
|
||||
import 'core-js/es6/symbol';
|
||||
import 'core-js/es6/object';
|
||||
import 'core-js/es6/function';
|
||||
import 'core-js/es6/parse-int';
|
||||
import 'core-js/es6/parse-float';
|
||||
import 'core-js/es6/number';
|
||||
import 'core-js/es6/math';
|
||||
import 'core-js/es6/string';
|
||||
import 'core-js/es6/date';
|
||||
import 'core-js/es6/array';
|
||||
import 'core-js/es6/regexp';
|
||||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/weak-map';
|
||||
import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags.ts';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
||||
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
|
||||
|
||||
*{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: calc(100% - 50px); /*Less 50 px for height of static header*/
|
||||
}
|
||||
|
||||
.red{
|
||||
color: red;
|
||||
}
|
||||
|
||||
/*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*/
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue