From 5093cff1da665f1d983d9a22c3cd66049842f073 Mon Sep 17 00:00:00 2001 From: Claudiu Farcas Date: Mon, 20 Feb 2017 18:36:42 +0200 Subject: [PATCH] Initial commit by angular2-firebase-bootstrap generator --- .editorconfig | 13 ++ .gitignore | 35 +++++ README.md | 54 ++++++++ angular-cli.json | 60 +++++++++ e2e/app.e2e-spec.ts | 14 ++ e2e/app.po.ts | 11 ++ e2e/tsconfig.json | 16 +++ karma.conf.js | 43 ++++++ package.json | 50 +++++++ protractor.conf.js | 32 +++++ src/app/app.component.css | 0 src/app/app.component.html | 16 +++ src/app/app.component.spec.ts | 41 ++++++ src/app/app.component.ts | 19 +++ src/app/app.module.ts | 33 +++++ .../display-user/display-user.component.css | 0 .../display-user/display-user.component.html | 20 +++ .../display-user.component.spec.ts | 42 ++++++ .../display-user/display-user.component.ts | 22 ++++ src/app/index.ts | 2 + src/app/login-user/login-user.component.css | 33 +++++ src/app/login-user/login-user.component.html | 39 ++++++ .../login-user/login-user.component.spec.ts | 39 ++++++ src/app/login-user/login-user.component.ts | 35 +++++ .../register-user/register-user.component.css | 37 ++++++ .../register-user.component.html | 56 ++++++++ .../register-user.component.spec.ts | 37 ++++++ .../register-user/register-user.component.ts | 61 +++++++++ src/app/shared/auth.service.stub.ts | 34 +++++ src/app/shared/auth.service.ts | 124 ++++++++++++++++++ src/app/shared/user-info.ts | 8 ++ src/assets/.gitkeep | 0 src/environments/environment.prod.ts | 3 + src/environments/environment.ts | 8 ++ src/environments/firebaseConfig.ts | 17 +++ src/favicon.ico | Bin 0 -> 5430 bytes src/index.html | 14 ++ src/main.ts | 12 ++ src/polyfills.ts | 19 +++ src/styles.css | 1 + src/test.ts | 32 +++++ src/tsconfig.json | 18 +++ src/typings.d.ts | 2 + tslint.json | 114 ++++++++++++++++ 44 files changed, 1266 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 README.md create mode 100644 angular-cli.json create mode 100644 e2e/app.e2e-spec.ts create mode 100644 e2e/app.po.ts create mode 100644 e2e/tsconfig.json create mode 100644 karma.conf.js create mode 100644 package.json create mode 100644 protractor.conf.js create mode 100644 src/app/app.component.css create mode 100644 src/app/app.component.html create mode 100644 src/app/app.component.spec.ts create mode 100644 src/app/app.component.ts create mode 100644 src/app/app.module.ts create mode 100644 src/app/display-user/display-user.component.css create mode 100644 src/app/display-user/display-user.component.html create mode 100644 src/app/display-user/display-user.component.spec.ts create mode 100644 src/app/display-user/display-user.component.ts create mode 100644 src/app/index.ts create mode 100644 src/app/login-user/login-user.component.css create mode 100644 src/app/login-user/login-user.component.html create mode 100644 src/app/login-user/login-user.component.spec.ts create mode 100644 src/app/login-user/login-user.component.ts create mode 100644 src/app/register-user/register-user.component.css create mode 100644 src/app/register-user/register-user.component.html create mode 100644 src/app/register-user/register-user.component.spec.ts create mode 100644 src/app/register-user/register-user.component.ts create mode 100644 src/app/shared/auth.service.stub.ts create mode 100644 src/app/shared/auth.service.ts create mode 100644 src/app/shared/user-info.ts create mode 100644 src/assets/.gitkeep create mode 100644 src/environments/environment.prod.ts create mode 100644 src/environments/environment.ts create mode 100644 src/environments/firebaseConfig.ts create mode 100644 src/favicon.ico create mode 100644 src/index.html create mode 100644 src/main.ts create mode 100644 src/polyfills.ts create mode 100644 src/styles.css create mode 100644 src/test.ts create mode 100644 src/tsconfig.json create mode 100644 src/typings.d.ts create mode 100644 tslint.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6e87a00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce200cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp + +# dependencies +/node_modules +/bower_components + +# IDEs and editors +/.idea +/.vscode +.project +.classpath +.c9/ +*.launch +.settings/ + +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +#System Files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..f24896b --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# kanban2 + +## Purpose + +This project is a generator for creating new projects with the following features: + +* Angular 2 (based on angular-cli) +* Firebase via AngualarFire2 +* Bootstrap with ng2-bootstrap + +## Configuration + +You will need to configure your firebase credentials in firebaseConfig.ts. This can be copied +almost directly from the proposed configuration from the Firebase console. + +```angular2html + apiKey: "????", + authDomain: "????", + databaseURL: "???", + storageBucket: "???", + messagingSenderId: "???" +``` + +#Angular 2 Specifics + +This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.21. + +## 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`. + +## 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/). +Before running the tests make sure you are serving the app via `ng serve`. + +## Deploying to Github Pages + +Run `ng github-pages:deploy` to deploy to Github Pages. + +## 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). diff --git a/angular-cli.json b/angular-cli.json new file mode 100644 index 0000000..60e12db --- /dev/null +++ b/angular-cli.json @@ -0,0 +1,60 @@ +{ + "project": { + "version": "1.0.0-beta.21", + "name": "kanban2" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "test": "test.ts", + "tsconfig": "tsconfig.json", + "prefix": "app", + "mobile": false, + "styles": [ + "styles.css", + "../node_modules/bootstrap/dist/css/bootstrap.min.css" + ], + "scripts": [], + "environments": { + "source": "environments/environment.ts", + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "addons": [], + "packages": [], + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "prefixInterfaces": false, + "inline": { + "style": false, + "template": false + }, + "spec": { + "class": false, + "component": true, + "directive": true, + "module": false, + "pipe": true, + "service": true + } + } +} diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts new file mode 100644 index 0000000..11804a8 --- /dev/null +++ b/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { ValuationJsPage } from './app.po'; + +describe('kanban2 App', function() { + let page: ValuationJsPage; + + beforeEach(() => { + page = new ValuationJsPage(); + }); + + it('should display message saying app works', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('app works!'); + }); +}); diff --git a/e2e/app.po.ts b/e2e/app.po.ts new file mode 100644 index 0000000..c07b268 --- /dev/null +++ b/e2e/app.po.ts @@ -0,0 +1,11 @@ +import { browser, element, by } from 'protractor'; + +export class ValuationJsPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root h1')).getText(); + } +} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 0000000..656bdb1 --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../dist/out-tsc-e2e", + "sourceMap": true, + "target": "es5", + "typeRoots": [ + "../node_modules/@types" + ] + } +} diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..1f2613a --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,43 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/0.13/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', 'angular-cli'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-remap-istanbul'), + require('angular-cli/plugins/karma') + ], + files: [ + { pattern: './src/test.ts', watched: false } + ], + preprocessors: { + './src/test.ts': ['angular-cli'] + }, + mime: { + 'text/x-typescript': ['ts','tsx'] + }, + remapIstanbulReporter: { + reports: { + html: 'coverage', + lcovonly: './coverage/coverage.lcov' + } + }, + angularCli: { + config: './angular-cli.json', + environment: 'dev' + }, + reporters: config.angularCli && config.angularCli.codeCoverage + ? ['progress', 'karma-remap-istanbul'] + : ['progress'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..ff930f3 --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "kanban2", + "version": "0.0.0", + "license": "MIT", + "angular-cli": {}, + "scripts": { + "start": "ng serve", + "lint": "tslint \"src/**/*.ts\"", + "test": "ng test", + "pree2e": "webdriver-manager update", + "e2e": "protractor" + }, + "private": true, + "dependencies": { + "@angular/common": "2.4.7", + "@angular/compiler": "2.4.7", + "@angular/core": "2.4.7", + "@angular/forms": "2.4.7", + "@angular/http": "2.4.7", + "@angular/platform-browser": "2.4.7", + "@angular/platform-browser-dynamic": "2.4.7", + "@angular/router": "3.4.7", + "angularfire2": "^2.0.0-beta.7", + "firebase": "3.6.9", + "bootstrap": "3.3.7", + "core-js": "2.4.1", + "ng2-bootstrap": "^1.3.3", + "rxjs": "5.0.3", + "ts-helpers": "1.1.2", + "zone.js": "0.7.6" + }, + "devDependencies": { + "@angular/compiler-cli": "2.4.7", + "@types/jasmine": "2.5.38", + "@types/node": "^6.0.60", + "angular-cli": "1.0.0-beta.28.3", + "codelyzer": "~1.0.0-beta.3", + "jasmine-core": "2.5.2", + "jasmine-spec-reporter": "2.5.0", + "karma": "1.2.0", + "karma-chrome-launcher": "2.0.0", + "karma-cli": "1.0.1", + "karma-jasmine": "1.0.2", + "karma-remap-istanbul": "0.2.1", + "protractor": "4.0.13", + "ts-node": "1.2.1", + "tslint": "4.2.0", + "typescript": "~2.1.6" + } +} diff --git a/protractor.conf.js b/protractor.conf.js new file mode 100644 index 0000000..169743b --- /dev/null +++ b/protractor.conf.js @@ -0,0 +1,32 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/docs/referenceConf.js + +/*global jasmine */ +var SpecReporter = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + useAllAngular2AppRoots: true, + beforeLaunch: function() { + require('ts-node').register({ + project: 'e2e' + }); + }, + onPrepare: function() { + jasmine.getEnv().addReporter(new SpecReporter()); + } +}; diff --git a/src/app/app.component.css b/src/app/app.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/app.component.html b/src/app/app.component.html new file mode 100644 index 0000000..70462b4 --- /dev/null +++ b/src/app/app.component.html @@ -0,0 +1,16 @@ +
+

+ {{title}} +

+
+ +
+
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts new file mode 100644 index 0000000..4141d1d --- /dev/null +++ b/src/app/app.component.spec.ts @@ -0,0 +1,41 @@ +/* tslint:disable:no-unused-variable */ +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import {TestBed, async} from "@angular/core/testing"; +import {AppComponent} from "./app.component"; +import {AuthService} from "app/shared/auth.service"; +import {AuthServiceStub} from "app/shared/auth.service.stub"; + +describe('AppComponent', () => { + beforeEach(() => { + let authServiceStub = new AuthServiceStub(true); + + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + {provide: AuthService, useValue: authServiceStub} + ] + });; + }); + + it('should create the app', async(() => { + let fixture = TestBed.createComponent(AppComponent); + let app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + + it(`should have as title 'app works!'`, async(() => { + let fixture = TestBed.createComponent(AppComponent); + let app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app works! - kanban2'); + })); + + it('should render title in a h1 tag', async(() => { + let fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('app works! - kanban2'); + })); +}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts new file mode 100644 index 0000000..7b9cc33 --- /dev/null +++ b/src/app/app.component.ts @@ -0,0 +1,19 @@ +import {Component} from "@angular/core"; +import {AuthService} from "app/shared/auth.service"; +import {Observable} from "rxjs"; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'app works! - kanban2'; + + constructor(private authService: AuthService) { + } + + isLoggedIn(): Observable { + return this.authService.isLoggedIn(); + } +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..34e9d1b --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,33 @@ +import {BrowserModule} from "@angular/platform-browser"; +import {NgModule} from "@angular/core"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {HttpModule} from "@angular/http"; +import {AppComponent} from "./app.component"; +import {authConfig, firebaseConfig} from "environments/firebaseConfig"; +import {AngularFireModule} from "angularfire2"; +import {AuthService} from "app/shared/auth.service"; +import {LoginUserComponent} from "app/login-user/login-user.component"; +import {DisplayUserComponent} from "app/display-user/display-user.component"; +import {RegisterUserComponent} from "app/register-user/register-user.component"; +import {AlertModule} from "ng2-bootstrap"; + +@NgModule({ + declarations: [ + AppComponent, + DisplayUserComponent, + LoginUserComponent, + RegisterUserComponent + ], + imports: [ + BrowserModule, + FormsModule, + ReactiveFormsModule, + HttpModule, + AlertModule.forRoot(), + AngularFireModule.initializeApp(firebaseConfig, authConfig) + ], + providers: [AuthService], + bootstrap: [AppComponent] +}) +export class AppModule { +} diff --git a/src/app/display-user/display-user.component.css b/src/app/display-user/display-user.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/display-user/display-user.component.html b/src/app/display-user/display-user.component.html new file mode 100644 index 0000000..6a92bb8 --- /dev/null +++ b/src/app/display-user/display-user.component.html @@ -0,0 +1,20 @@ +
+
+
+
User Information
+
    +
  • Email: {{(currentUser()|async).email}}
  • +
  • Display Name: {{(currentUser()|async).displayName}}
  • +
  • Uid: {{(currentUser()|async).uid}}
  • +
  • Provider Id: {{(currentUser()|async).providerId}}
  • +
  • +
+
+
+
+
+
+ Log out +
+
\ No newline at end of file diff --git a/src/app/display-user/display-user.component.spec.ts b/src/app/display-user/display-user.component.spec.ts new file mode 100644 index 0000000..eac1f6c --- /dev/null +++ b/src/app/display-user/display-user.component.spec.ts @@ -0,0 +1,42 @@ +/* tslint:disable:no-unused-variable */ +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {DisplayUserComponent} from "./display-user.component"; +import {AsyncSubject, Observable, ReplaySubject} from "rxjs"; +import {FormsModule} from "@angular/forms"; +import {AuthService} from "app/shared/auth.service"; +import {UserInfo} from "app/shared/user-info"; +import {By} from "@angular/platform-browser"; +import {AuthServiceStub} from "app/shared/auth.service.stub"; + +describe('DisplayUserComponent', () => { + + let component: DisplayUserComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + let authServiceStub = new AuthServiceStub(true); + + TestBed.configureTestingModule({ + imports: [FormsModule], + declarations: [DisplayUserComponent], + providers: [ + {provide: AuthService, useValue: authServiceStub} + ] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DisplayUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should display userinfo when logged in', () => { + expect(component).toBeTruthy(); + let elements = fixture.debugElement.queryAll(By.css(".list-group-item")); + expect(elements[0].nativeElement.textContent).toContain("Email: my-email"); + expect(elements[1].nativeElement.textContent).toContain("Display Name: my-display-name"); + expect(elements[2].nativeElement.textContent).toContain("Uid: my-uid"); + expect(elements[3].nativeElement.textContent).toContain("Provider Id: my-provider-id"); + }); +}); diff --git a/src/app/display-user/display-user.component.ts b/src/app/display-user/display-user.component.ts new file mode 100644 index 0000000..c55258e --- /dev/null +++ b/src/app/display-user/display-user.component.ts @@ -0,0 +1,22 @@ +import {Component, OnInit} from "@angular/core"; +import {AuthService} from "app/shared/auth.service"; +import {UserInfo} from "app/shared/user-info"; +import {Observable} from "rxjs"; + +@Component({ + selector: 'app-display-user', + templateUrl: './display-user.component.html', + styleUrls: ['./display-user.component.css'] +}) +export class DisplayUserComponent { + + constructor(private authService: AuthService) {} + + currentUser(): Observable { + return this.authService.currentUser(); + } + + logout() { + this.authService.logout(); + } +} diff --git a/src/app/index.ts b/src/app/index.ts new file mode 100644 index 0000000..875bdb2 --- /dev/null +++ b/src/app/index.ts @@ -0,0 +1,2 @@ +export * from './app.component'; +export * from './app.module'; diff --git a/src/app/login-user/login-user.component.css b/src/app/login-user/login-user.component.css new file mode 100644 index 0000000..db40d23 --- /dev/null +++ b/src/app/login-user/login-user.component.css @@ -0,0 +1,33 @@ + +.login-or { + position: relative; + font-size: 18px; + color: #aaa; + margin-top: 10px; + margin-bottom: 10px; + padding-top: 10px; + padding-bottom: 10px; +} + +.span-or { + display: block; + position: absolute; + left: 50%; + top: -2px; + margin-left: -25px; + background-color: #fff; + width: 50px; + text-align: center; +} + +.hr-or { + background-color: #cdcdcd; + height: 1px; + margin-top: 0px !important; + margin-bottom: 0px !important; +} + +h3 { + text-align: center; + line-height: 300%; +} \ No newline at end of file diff --git a/src/app/login-user/login-user.component.html b/src/app/login-user/login-user.component.html new file mode 100644 index 0000000..42a80ad --- /dev/null +++ b/src/app/login-user/login-user.component.html @@ -0,0 +1,39 @@ +

Please Log In

+
+
+ Twitter +
+
+ Google +
+
+ + +
+
+ + +
+
    +
  • Enter your email address
  • +
  • An email address is required
  • +
+
+
+
+ + +
+
    +
  • Enter your password
  • +
  • A password is required
  • +
+
+
+ +
diff --git a/src/app/login-user/login-user.component.spec.ts b/src/app/login-user/login-user.component.spec.ts new file mode 100644 index 0000000..c5329fc --- /dev/null +++ b/src/app/login-user/login-user.component.spec.ts @@ -0,0 +1,39 @@ +/* tslint:disable:no-unused-variable */ +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {LoginUserComponent} from "./login-user.component"; +import {AuthService} from "app/shared/auth.service"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {AsyncSubject, Observable, ReplaySubject} from "rxjs"; +import {UserInfo} from "app/shared/user-info"; +import {AuthServiceStub} from "app/shared/auth.service.stub"; + +describe('LoginUserComponent', () => { + let component: LoginUserComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + let authServiceStub = new AuthServiceStub(true); + + TestBed.configureTestingModule({ + imports: [ + FormsModule, + ReactiveFormsModule + ], + declarations: [LoginUserComponent], + providers: [ + {provide: AuthService, useValue: authServiceStub} + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/login-user/login-user.component.ts b/src/app/login-user/login-user.component.ts new file mode 100644 index 0000000..c67ce24 --- /dev/null +++ b/src/app/login-user/login-user.component.ts @@ -0,0 +1,35 @@ +import {Component} from "@angular/core"; +import {Observable} from "rxjs"; +import {AuthService} from "app/shared/auth.service"; +import {FormBuilder, Validators, AbstractControl, FormGroup} from "@angular/forms"; + +@Component({ + selector: 'app-login-user', + templateUrl: './login-user.component.html', + styleUrls: ['./login-user.component.css'] +}) +export class LoginUserComponent { + form: FormGroup; + email: AbstractControl; + password: AbstractControl; + + constructor(private authService: AuthService, private fb: FormBuilder) { + this.form = fb.group({ + 'email': ['', Validators.required], + 'password': ['', Validators.required] + }); + this.email = this.form.controls['email']; + this.password = this.form.controls['password']; + } + + login(value: any) { + if (this.form.valid) { + this.authService.login(this.email.value, this.password.value); + this.form.reset(); + } + } + + loginVia(provider: string) { + this.authService.loginViaProvider(provider); + } +} \ No newline at end of file diff --git a/src/app/register-user/register-user.component.css b/src/app/register-user/register-user.component.css new file mode 100644 index 0000000..93bae47 --- /dev/null +++ b/src/app/register-user/register-user.component.css @@ -0,0 +1,37 @@ +.main { + max-width: 320px; + margin: 0 auto; +} + +.login-or { + position: relative; + font-size: 18px; + color: #aaa; + margin-top: 10px; + margin-bottom: 10px; + padding-top: 10px; + padding-bottom: 10px; +} + +.span-or { + display: block; + position: absolute; + left: 50%; + top: -2px; + margin-left: -25px; + background-color: #fff; + width: 50px; + text-align: center; +} + +.hr-or { + background-color: #cdcdcd; + height: 1px; + margin-top: 0px !important; + margin-bottom: 0px !important; +} + +h3 { + text-align: center; + line-height: 300%; +} \ No newline at end of file diff --git a/src/app/register-user/register-user.component.html b/src/app/register-user/register-user.component.html new file mode 100644 index 0000000..13a3410 --- /dev/null +++ b/src/app/register-user/register-user.component.html @@ -0,0 +1,56 @@ +

Register

+
+
+ + +
+
    +
  • Enter your name
  • +
  • A name is required
  • +
+
+
+
+ + +
+
    +
  • Enter your email address
  • +
  • An email address is required
  • +
  • Please enter a valid email address
  • +
+
+
+
+ + +
+
    +
  • Enter your password
  • +
  • A password is required
  • +
+
+
+
+ + +
+
    +
  • Repeat + your + password +
  • +
  • A password is required
  • +
  • Passwords + don't + match +
  • +
+
+
+ +
\ No newline at end of file diff --git a/src/app/register-user/register-user.component.spec.ts b/src/app/register-user/register-user.component.spec.ts new file mode 100644 index 0000000..a2d13bf --- /dev/null +++ b/src/app/register-user/register-user.component.spec.ts @@ -0,0 +1,37 @@ +/* tslint:disable:no-unused-variable */ +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {RegisterUserComponent} from "./register-user.component"; +import {ReactiveFormsModule, FormsModule} from "@angular/forms"; +import {AuthService} from "app/shared/auth.service"; +import {AuthServiceStub} from "app/shared/auth.service.stub"; + +describe('RegisterUserComponent', () => { + let component: RegisterUserComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + let authServiceStub = new AuthServiceStub(true); + + TestBed.configureTestingModule({ + declarations: [RegisterUserComponent], + imports: [ + FormsModule, + ReactiveFormsModule + ], + providers: [ + {provide: AuthService, useValue: authServiceStub} + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RegisterUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/register-user/register-user.component.ts b/src/app/register-user/register-user.component.ts new file mode 100644 index 0000000..91c9629 --- /dev/null +++ b/src/app/register-user/register-user.component.ts @@ -0,0 +1,61 @@ +import {Component, OnInit} from "@angular/core"; +import {AuthService} from "app/shared/auth.service"; +import {Observable} from "rxjs"; +import {FormGroup, AbstractControl, FormBuilder, Validators} from "@angular/forms"; + +@Component({ + selector: 'app-register-user', + templateUrl: './register-user.component.html', + styleUrls: ['./register-user.component.css'] +}) +export class RegisterUserComponent implements OnInit { + form: FormGroup; + email: AbstractControl; + name: AbstractControl; + password: AbstractControl; + password2: AbstractControl; + + constructor(private authService: AuthService, + private fb: FormBuilder) { + this.form = fb.group({ + 'name': ['', Validators.required], + 'email': ['', Validators.compose([ + Validators.required, + Validators.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)] + )], + 'password': ['', Validators.required], + 'password2': ['', Validators.required] + }, {validator: this.matchingPasswords('password', 'password2')}); + this.name = this.form.controls['name']; + this.email = this.form.controls['email']; + this.password = this.form.controls['password']; + this.password2 = this.form.controls['password2']; + } + + ngOnInit(): void { + } + + isLoggedIn(): Observable { + return this.authService.isLoggedIn(); + } + + onSubmit(value: any) { + if (this.form.valid) { + this.authService.createUser(this.email.value, this.password.value, this.name.value); + this.form.reset(); + } + } + + matchingPasswords(passwordKey: string, confirmPasswordKey: string) { + return (group: FormGroup): {[key: string]: any} => { + let password = group.controls[passwordKey]; + let confirmPassword = group.controls[confirmPasswordKey]; + + if (password.value !== confirmPassword.value) { + return { + mismatchedPasswords: true + }; + } + } + } +} diff --git a/src/app/shared/auth.service.stub.ts b/src/app/shared/auth.service.stub.ts new file mode 100644 index 0000000..2f0ea90 --- /dev/null +++ b/src/app/shared/auth.service.stub.ts @@ -0,0 +1,34 @@ +import {AsyncSubject, Observable, ReplaySubject} from "rxjs"; +import {UserInfo} from "app/shared/user-info"; + +export class AuthServiceStub { + + constructor(private loggedin: boolean) { + } + + login(email: string, password: string) { + } + + currentUser(): Observable { + let userInfo = new UserInfo(); + userInfo.displayName = "my-display-name"; + userInfo.email = "my-email"; + userInfo.uid = "my-uid"; + userInfo.isAnonymous = false; + userInfo.photoURL = "my-photo-url"; + userInfo.providerId = "my-provider-id"; + + let replaySubject = new ReplaySubject(); + if (this.loggedin) { + replaySubject.next(userInfo); + } + return replaySubject; + } + + isLoggedIn(): Observable { + let isLoggedInBS = new AsyncSubject(); + isLoggedInBS.next(true); + isLoggedInBS.complete(); + return isLoggedInBS; + } +} diff --git a/src/app/shared/auth.service.ts b/src/app/shared/auth.service.ts new file mode 100644 index 0000000..4119c46 --- /dev/null +++ b/src/app/shared/auth.service.ts @@ -0,0 +1,124 @@ +import {Injectable, EventEmitter, Output} from "@angular/core"; +import {User} from "firebase"; +import {AngularFireAuth, AuthProviders, AuthMethods} from "angularfire2"; +import {BehaviorSubject} from "rxjs/BehaviorSubject"; +import {UserInfo} from "./user-info"; +import {Observable, Subject, ReplaySubject, AsyncSubject} from "rxjs"; + +@Injectable() +export class AuthService { + private userInfoSubject: ReplaySubject; + private auth: User; + + constructor(private angularFireAuth: AngularFireAuth) { + this.initUserInfoSubject(); + // console.log("AuthService"); + angularFireAuth.subscribe(auth => { + // console.log("auth: ", JSON.stringify(auth)); + let userInfo = new UserInfo(); + if (auth != null) { + this.auth = auth.auth; + userInfo.isAnonymous = auth.auth.isAnonymous; + userInfo.email = auth.auth.email; + userInfo.displayName = auth.auth.displayName; + userInfo.providerId = auth.auth.providerId; + userInfo.photoURL = auth.auth.photoURL; + userInfo.uid = auth.auth.uid; + } else { + this.auth = null; + userInfo.isAnonymous = true; + } + this.userInfoSubject.next(userInfo); + }); + } + + login(email: string, password: string) { + // console.log("login: ", email); + this.initUserInfoSubject(); + this.angularFireAuth.login({email: email, password: password}); + } + + private initUserInfoSubject() { + this.userInfoSubject = new ReplaySubject(1); + } + + currentUser(): Observable { + return this.userInfoSubject.asObservable(); + } + + logout() { + this.initUserInfoSubject(); + this.angularFireAuth.logout(); + } + + isLoggedIn(): Observable { + let isLoggedInBS = new AsyncSubject(); + this.userInfoSubject.subscribe(ui => { + // console.log("isLoggedIn: anonymous=" + ui.isAnonymous); + isLoggedInBS.next(!ui.isAnonymous); + isLoggedInBS.complete(); + // setTimeout(() => { + // }, 0); + }); + return isLoggedInBS; + } + + updateDisplayName(displayName: string): Observable { + let result = new Subject(); + //noinspection TypeScriptUnresolvedFunction + this.auth.updateProfile({displayName: displayName, photoURL: null}).then(a => { + result.next("success"); + }).catch(err => result.error(err)); + return result; + } + + createUser(email: string, password: string, displayName: string) { + //noinspection TypeScriptUnresolvedFunction + this.angularFireAuth.createUser({email: email, password: password}) + .then(auth => auth.auth.updateProfile({displayName: displayName, photoURL: null})); + } + + updateEmail(email: string): Observable { + let result = new Subject(); + //noinspection TypeScriptUnresolvedFunction + this.auth.updateEmail(email).then(a => { + result.next("success"); + }).catch(err => result.error(err)); + return result.asObservable(); + } + + updatePassword(password: string): Observable { + let result = new Subject(); + //noinspection TypeScriptUnresolvedFunction + this.auth.updatePassword(password).then(a => { + result.next("success"); + }).catch(err => result.error(err)); + return result.asObservable(); + } + + loginViaProvider(provider: string): Observable { + let result = new Subject(); + if (provider === "google") { + //noinspection TypeScriptUnresolvedFunction + this.angularFireAuth + .login({provider: AuthProviders.Google, method: AuthMethods.Popup}) + //noinspection TypeScriptUnresolvedFunction + . //noinspection TypeScriptUnresolvedFunction + then(auth => result.next("success")) + .catch(err => result.error(err)); + return result.asObservable(); + } + else if (provider === "twitter") { + //noinspection TypeScriptUnresolvedFunction + this.angularFireAuth + .login({provider: AuthProviders.Twitter, method: AuthMethods.Popup}) + //noinspection TypeScriptUnresolvedFunction + . //noinspection TypeScriptUnresolvedFunction + then(auth => result.next("success")) + .catch(err => result.error(err)); + return result.asObservable(); + } + result.error("Not a supported authentication method: " + provider) + return result.asObservable(); + } +} diff --git a/src/app/shared/user-info.ts b/src/app/shared/user-info.ts new file mode 100644 index 0000000..f71d801 --- /dev/null +++ b/src/app/shared/user-info.ts @@ -0,0 +1,8 @@ +export class UserInfo { + isAnonymous: boolean; + email: string; + displayName: string; + photoURL?: string; + providerId: string; + uid: string; +} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts new file mode 100644 index 0000000..3612073 --- /dev/null +++ b/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts new file mode 100644 index 0000000..00313f1 --- /dev/null +++ b/src/environments/environment.ts @@ -0,0 +1,8 @@ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `angular-cli.json`. + +export const environment = { + production: false +}; diff --git a/src/environments/firebaseConfig.ts b/src/environments/firebaseConfig.ts new file mode 100644 index 0000000..2c805c4 --- /dev/null +++ b/src/environments/firebaseConfig.ts @@ -0,0 +1,17 @@ + +import {AuthMethods, AuthProviders} from "angularfire2"; + + +export const firebaseConfig = { + // Paste all this from the Firebase console... + apiKey: "***REMOVED***", + authDomain: "***REMOVED***", + databaseURL: "***REMOVED***", + storageBucket: "***REMOVED***", + messagingSenderId: "***REMOVED***" +}; + +export const authConfig = { + provider: AuthProviders.Password, + method: AuthMethods.Password +}; diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8081c7ceaf2be08bf59010158c586170d9d2d517 GIT binary patch literal 5430 zcmc(je{54#6vvCoAI3i*G5%$U7!sA3wtMZ$fH6V9C`=eXGJb@R1%(I_{vnZtpD{6n z5Pl{DmxzBDbrB>}`90e12m8T*36WoeDLA&SD_hw{H^wM!cl_RWcVA!I+x87ee975; z@4kD^=bYPn&pmG@(+JZ`rqQEKxW<}RzhW}I!|ulN=fmjVi@x{p$cC`)5$a!)X&U+blKNvN5tg=uLvuLnuqRM;Yc*swiexsoh#XPNu{9F#c`G zQLe{yWA(Y6(;>y|-efAy11k<09(@Oo1B2@0`PtZSkqK&${ zgEY}`W@t{%?9u5rF?}Y7OL{338l*JY#P!%MVQY@oqnItpZ}?s z!r?*kwuR{A@jg2Chlf0^{q*>8n5Ir~YWf*wmsh7B5&EpHfd5@xVaj&gqsdui^spyL zB|kUoblGoO7G(MuKTfa9?pGH0@QP^b#!lM1yHWLh*2iq#`C1TdrnO-d#?Oh@XV2HK zKA{`eo{--^K&MW66Lgsktfvn#cCAc*(}qsfhrvOjMGLE?`dHVipu1J3Kgr%g?cNa8 z)pkmC8DGH~fG+dlrp(5^-QBeEvkOvv#q7MBVLtm2oD^$lJZx--_=K&Ttd=-krx(Bb zcEoKJda@S!%%@`P-##$>*u%T*mh+QjV@)Qa=Mk1?#zLk+M4tIt%}wagT{5J%!tXAE;r{@=bb%nNVxvI+C+$t?!VJ@0d@HIyMJTI{vEw0Ul ze(ha!e&qANbTL1ZneNl45t=#Ot??C0MHjjgY8%*mGisN|S6%g3;Hlx#fMNcL<87MW zZ>6moo1YD?P!fJ#Jb(4)_cc50X5n0KoDYfdPoL^iV`k&o{LPyaoqMqk92wVM#_O0l z09$(A-D+gVIlq4TA&{1T@BsUH`Bm=r#l$Z51J-U&F32+hfUP-iLo=jg7Xmy+WLq6_tWv&`wDlz#`&)Jp~iQf zZP)tu>}pIIJKuw+$&t}GQuqMd%Z>0?t%&BM&Wo^4P^Y z)c6h^f2R>X8*}q|bblAF?@;%?2>$y+cMQbN{X$)^R>vtNq_5AB|0N5U*d^T?X9{xQnJYeU{ zoZL#obI;~Pp95f1`%X3D$Mh*4^?O?IT~7HqlWguezmg?Ybq|7>qQ(@pPHbE9V?f|( z+0xo!#m@Np9PljsyxBY-UA*{U*la#8Wz2sO|48_-5t8%_!n?S$zlGe+NA%?vmxjS- zHE5O3ZarU=X}$7>;Okp(UWXJxI%G_J-@IH;%5#Rt$(WUX?6*Ux!IRd$dLP6+SmPn= z8zjm4jGjN772R{FGkXwcNv8GBcZI#@Y2m{RNF_w8(Z%^A*!bS*!}s6sh*NnURytky humW;*g7R+&|Ledvc- + + + + kanban2 + + + + + + + Loading... + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..5c3c520 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,12 @@ +import './polyfills.ts'; + +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core'; +import { environment } from './environments/environment'; +import { AppModule } from './app/'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/src/polyfills.ts b/src/polyfills.ts new file mode 100644 index 0000000..3b4c55b --- /dev/null +++ b/src/polyfills.ts @@ -0,0 +1,19 @@ +// This file includes polyfills needed by Angular 2 and is loaded before +// the app. You can add your own extra polyfills to this file. +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/set'; +import 'core-js/es6/reflect'; + +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..90d4ee0 --- /dev/null +++ b/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..81af890 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,32 @@ +import './polyfills.ts'; + +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. +declare var __karma__: any; +declare var require: any; + +// Prevent Karma from running prematurely. +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +let context = require.context('./', true, /\.spec\.ts/); +// And load the modules. +context.keys().map(context); +// Finally, start Karma to run the tests. +__karma__.start(); diff --git a/src/tsconfig.json b/src/tsconfig.json new file mode 100644 index 0000000..1cf713a --- /dev/null +++ b/src/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "", + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "mapRoot": "./", + "module": "es6", + "moduleResolution": "node", + "outDir": "../dist/out-tsc", + "sourceMap": true, + "target": "es5", + "typeRoots": [ + "../node_modules/@types" + ] + } +} diff --git a/src/typings.d.ts b/src/typings.d.ts new file mode 100644 index 0000000..ea52695 --- /dev/null +++ b/src/typings.d.ts @@ -0,0 +1,2 @@ +// Typings reference file, you can add your own global typings here +// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..ad0093e --- /dev/null +++ b/tslint.json @@ -0,0 +1,114 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "label-position": true, + "label-undefined": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + "static-before-instance", + "variables-before-functions" + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-key": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-unreachable": 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" + ], + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + + "directive-selector-prefix": [true, "app"], + "component-selector-prefix": [true, "app"], + "directive-selector-name": [true, "camelCase"], + "component-selector-name": [true, "kebab-case"], + "directive-selector-type": [true, "attribute"], + "component-selector-type": [true, "element"], + "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, + "templates-use-public": true, + "invoke-injectable": true + } +}