Added the ability to have mutliple buy options for product
This commit is contained in:
		@@ -6,8 +6,9 @@ import { MatDialog } from '@angular/material';
 | 
			
		||||
import { LoginComponent } from './login/login.component';
 | 
			
		||||
import { LocalStorage } from 'webstorage-decorators';
 | 
			
		||||
import { AppStore } from './app.store';
 | 
			
		||||
import { AngularFireAuth } from '../../node_modules/angularfire2/auth';
 | 
			
		||||
import { SwUpdate } from '../../node_modules/@angular/service-worker';
 | 
			
		||||
import { AngularFireAuth } from 'angularfire2/auth';
 | 
			
		||||
import { SwUpdate } from '@angular/service-worker';
 | 
			
		||||
import { POption } from './store/products/product';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-root',
 | 
			
		||||
@@ -15,7 +16,7 @@ import { SwUpdate } from '../../node_modules/@angular/service-worker';
 | 
			
		||||
})
 | 
			
		||||
export class AppComponent implements OnInit {
 | 
			
		||||
  @LocalStorage({ defaultValue: [], encryptionKey: 'HmRoBFUEVWqW5uvy' })
 | 
			
		||||
  cart: { id: string; item: string; price: number; currency: 'CAD' | 'USD'; quantity: number }[];
 | 
			
		||||
  cart: { id: string; item: string; option: POption, quantity: number}[];
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private router: Router,
 | 
			
		||||
@@ -30,8 +31,8 @@ export class AppComponent implements OnInit {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cartAdd(id: string, item: string, price: number, currency: 'CAD' | 'USD', quantity: number) {
 | 
			
		||||
    this.cart = [{ id: id, item: item, price: Number(price), currency: currency, quantity: Number(quantity) }].concat(
 | 
			
		||||
  cartAdd(id: string, name: string, option: POption, quantity: number) {
 | 
			
		||||
    this.cart = [{ id: id, item: name, option: option, quantity: Number(quantity)}].concat(
 | 
			
		||||
      this.cart
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
import {Injectable} from '@angular/core';
 | 
			
		||||
import {AngularFirestore} from 'angularfire2/firestore';
 | 
			
		||||
import {Category} from './store/category';
 | 
			
		||||
import {Observable, combineLatest} from 'rxjs';
 | 
			
		||||
import {map, shareReplay} from 'rxjs/operators';
 | 
			
		||||
import {DomSanitizer} from '@angular/platform-browser';
 | 
			
		||||
import {Product} from './store/product';
 | 
			
		||||
import {AngularFireAuth} from '../../node_modules/angularfire2/auth';
 | 
			
		||||
import {Component} from './formulaManager/component';
 | 
			
		||||
import {Formula} from './formulaManager/formula';
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { AngularFirestore } from 'angularfire2/firestore';
 | 
			
		||||
import { Category } from './store/category';
 | 
			
		||||
import { Observable, combineLatest } from 'rxjs';
 | 
			
		||||
import { map, shareReplay } from 'rxjs/operators';
 | 
			
		||||
import { DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
import { Product } from './store/product';
 | 
			
		||||
import { AngularFireAuth } from '../../node_modules/angularfire2/auth';
 | 
			
		||||
import { Component } from './formulaManager/component';
 | 
			
		||||
import { Formula } from './formulaManager/formula';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AppStore {
 | 
			
		||||
@@ -24,7 +24,7 @@ export class AppStore {
 | 
			
		||||
      .pipe(
 | 
			
		||||
        map(rows =>
 | 
			
		||||
          rows.map((row: any) => {
 | 
			
		||||
            let temp = Object.assign({id: row.payload.doc.id, ref: row.payload.doc.ref}, row.payload.doc.data());
 | 
			
		||||
            let temp = Object.assign({ id: row.payload.doc.id, ref: row.payload.doc.ref }, row.payload.doc.data());
 | 
			
		||||
            temp.image = this.domSanitizer.bypassSecurityTrustUrl(temp.image);
 | 
			
		||||
            return <Category>temp;
 | 
			
		||||
          })
 | 
			
		||||
@@ -38,7 +38,7 @@ export class AppStore {
 | 
			
		||||
      .pipe(
 | 
			
		||||
        map(rows =>
 | 
			
		||||
          rows.map((row: any) => {
 | 
			
		||||
            let temp = Object.assign({id: row.payload.doc.id, ref: row.payload.doc.ref}, row.payload.doc.data());
 | 
			
		||||
            let temp = Object.assign({ id: row.payload.doc.id, ref: row.payload.doc.ref }, row.payload.doc.data());
 | 
			
		||||
            temp.created = temp.created.toDate();
 | 
			
		||||
            return <Component>temp;
 | 
			
		||||
          })
 | 
			
		||||
@@ -52,12 +52,12 @@ export class AppStore {
 | 
			
		||||
    ).pipe(
 | 
			
		||||
      map(data =>
 | 
			
		||||
        data[0].map(row => {
 | 
			
		||||
          let temp = <any>Object.assign({id: row.payload.doc.id, ref: row.payload.doc.ref}, row.payload.doc.data());
 | 
			
		||||
          let temp = <any>Object.assign({ id: row.payload.doc.id, ref: row.payload.doc.ref }, row.payload.doc.data());
 | 
			
		||||
          temp.created = temp.created.toDate();
 | 
			
		||||
 | 
			
		||||
          temp.components = temp.components.map(row => {
 | 
			
		||||
            let component = data[1].filter(c => c.id == row.component.id)[0];
 | 
			
		||||
            return {component: component, quantity: row.quantity};
 | 
			
		||||
            return { component: component, quantity: row.quantity };
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return <Formula>temp;
 | 
			
		||||
@@ -72,13 +72,12 @@ export class AppStore {
 | 
			
		||||
      .pipe(
 | 
			
		||||
        map(rows =>
 | 
			
		||||
          rows.map((row: any) => {
 | 
			
		||||
            let temp = Object.assign({id: row.payload.doc.id, ref: row.payload.doc.ref}, row.payload.doc.data());
 | 
			
		||||
            let temp = Object.assign({ id: row.payload.doc.id, ref: row.payload.doc.ref }, row.payload.doc.data());
 | 
			
		||||
            temp.originalImage = temp.image;
 | 
			
		||||
            temp.image = this.domSanitizer.bypassSecurityTrustUrl(temp.image);
 | 
			
		||||
            temp.originalDescription = temp.description;
 | 
			
		||||
            temp.description = this.domSanitizer.bypassSecurityTrustHtml(
 | 
			
		||||
              temp.description.replace(/(\r\n|\r|\n)/g, '<br>')
 | 
			
		||||
            );
 | 
			
		||||
            temp.description = this.domSanitizer.bypassSecurityTrustHtml(temp.description);
 | 
			
		||||
 | 
			
		||||
            return <Product>temp;
 | 
			
		||||
          })
 | 
			
		||||
        ),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,75 +1,75 @@
 | 
			
		||||
import {Component, Inject} from '@angular/core';
 | 
			
		||||
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';
 | 
			
		||||
import {AngularFirestore} from 'angularfire2/firestore';
 | 
			
		||||
import {LocalStorage} from '../../../../node_modules/webstorage-decorators';
 | 
			
		||||
import {AppStore} from '../../app.store';
 | 
			
		||||
import {ConvertToGPipe} from '../units.pipe';
 | 
			
		||||
import { Component, Inject } from '@angular/core';
 | 
			
		||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 | 
			
		||||
import { AngularFirestore } from 'angularfire2/firestore';
 | 
			
		||||
import { LocalStorage } from 'webstorage-decorators';
 | 
			
		||||
import { AppStore } from '../../app.store';
 | 
			
		||||
import { ConvertToGPipe } from '../units.pipe';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'new-formula',
 | 
			
		||||
  templateUrl: './newFormula.component.html'
 | 
			
		||||
	selector: 'new-formula',
 | 
			
		||||
	templateUrl: './newFormula.component.html'
 | 
			
		||||
})
 | 
			
		||||
export class NewFormulaComponent {
 | 
			
		||||
  name: string;
 | 
			
		||||
  amount: number;
 | 
			
		||||
  approved: boolean = false;
 | 
			
		||||
  component: string;
 | 
			
		||||
  components: {component: string; name: string; quantity: number}[] = [];
 | 
			
		||||
  componentsList = [];
 | 
			
		||||
  @LocalStorage({defaultValue: 'kg', fieldName: 'newFormulaUnit'})
 | 
			
		||||
  unit;
 | 
			
		||||
	name: string;
 | 
			
		||||
	amount: number;
 | 
			
		||||
	approved: boolean = false;
 | 
			
		||||
	component: string;
 | 
			
		||||
	components: { component: string; name: string; quantity: number }[] = [];
 | 
			
		||||
	componentsList = [];
 | 
			
		||||
	@LocalStorage({ defaultValue: 'kg', fieldName: 'newFormulaUnit' })
 | 
			
		||||
	unit;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private dialogRef: MatDialogRef<NewFormulaComponent>,
 | 
			
		||||
    private db: AngularFirestore,
 | 
			
		||||
    private store: AppStore,
 | 
			
		||||
    @Inject(MAT_DIALOG_DATA) public data
 | 
			
		||||
  ) {
 | 
			
		||||
    this.store.components.subscribe(rows => (this.componentsList = rows));
 | 
			
		||||
	constructor(
 | 
			
		||||
		private dialogRef: MatDialogRef<NewFormulaComponent>,
 | 
			
		||||
		private db: AngularFirestore,
 | 
			
		||||
		private store: AppStore,
 | 
			
		||||
		@Inject(MAT_DIALOG_DATA) public data
 | 
			
		||||
	) {
 | 
			
		||||
		this.store.components.subscribe(rows => (this.componentsList = rows));
 | 
			
		||||
 | 
			
		||||
    if (this.data) {
 | 
			
		||||
      this.name = this.data.name;
 | 
			
		||||
      this.approved = this.data.approved;
 | 
			
		||||
      this.components = this.data.components.map(row => {
 | 
			
		||||
        return {component: row.component.id, name: row.component.name, quantity: row.quantity};
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
		if (this.data) {
 | 
			
		||||
			this.name = this.data.name;
 | 
			
		||||
			this.approved = this.data.approved;
 | 
			
		||||
			this.components = this.data.components.map(row => {
 | 
			
		||||
				return { component: row.component.id, name: row.component.name, quantity: row.quantity };
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  add() {
 | 
			
		||||
    let id = this.componentsList.filter(row => row.name == this.component)[0].id;
 | 
			
		||||
    console.log(id);
 | 
			
		||||
    let amount = new ConvertToGPipe().transform(Number(this.amount), this.unit);
 | 
			
		||||
    this.components.push({component: id, name: this.component, quantity: amount});
 | 
			
		||||
    this.component = null;
 | 
			
		||||
    this.amount = null;
 | 
			
		||||
  }
 | 
			
		||||
	add() {
 | 
			
		||||
		let id = this.componentsList.filter(row => row.name == this.component)[0].id;
 | 
			
		||||
		console.log(id);
 | 
			
		||||
		let amount = new ConvertToGPipe().transform(Number(this.amount), this.unit);
 | 
			
		||||
		this.components.push({ component: id, name: this.component, quantity: amount });
 | 
			
		||||
		this.component = null;
 | 
			
		||||
	    this.amount = null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  remove(i) {
 | 
			
		||||
    this.components.splice(i, 1);
 | 
			
		||||
  }
 | 
			
		||||
	remove(i) {
 | 
			
		||||
		this.components.splice(i, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  submit() {
 | 
			
		||||
    let newFormula = {
 | 
			
		||||
      name: this.name,
 | 
			
		||||
      approved: this.approved,
 | 
			
		||||
      components: this.components.map((row: any) => {
 | 
			
		||||
        return {component: this.db.collection('components').doc(row.component).ref, quantity: row.quantity};
 | 
			
		||||
      })
 | 
			
		||||
    };
 | 
			
		||||
	submit() {
 | 
			
		||||
		let newFormula = {
 | 
			
		||||
			name: this.name,
 | 
			
		||||
			approved: this.approved,
 | 
			
		||||
			components: this.components.map((row: any) => {
 | 
			
		||||
				return { component: this.db.collection('components').doc(row.component).ref, quantity: row.quantity };
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
    if (!this.data) {
 | 
			
		||||
      newFormula['created'] = new Date();
 | 
			
		||||
      this.db
 | 
			
		||||
        .collection('formulas')
 | 
			
		||||
        .add(newFormula)
 | 
			
		||||
        .then(data => this.dialogRef.close());
 | 
			
		||||
    } else {
 | 
			
		||||
      this.data.ref.update(newFormula).then(data => this.dialogRef.close());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
		if (!this.data) {
 | 
			
		||||
			newFormula['created'] = new Date();
 | 
			
		||||
			this.db
 | 
			
		||||
				.collection('formulas')
 | 
			
		||||
				.add(newFormula)
 | 
			
		||||
				.then(data => this.dialogRef.close());
 | 
			
		||||
		} else {
 | 
			
		||||
			this.data.ref.update(newFormula).then(data => this.dialogRef.close());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  total() {
 | 
			
		||||
    return this.components.reduce((acc, row) => acc + row.quantity, 0);
 | 
			
		||||
  }
 | 
			
		||||
	total() {
 | 
			
		||||
		return this.components.reduce((acc, row) => acc + row.quantity, 0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ export class CartComponent {
 | 
			
		||||
  constructor(public app: AppComponent) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    console.log(this.app.cart);
 | 
			
		||||
    if (this.app.cartCount()) {
 | 
			
		||||
      window['paypal'].Button.render(
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -13,20 +13,52 @@
 | 
			
		||||
    <mat-form-field class="w-100">
 | 
			
		||||
        <textarea matInput rows="5" placeholder="Description" name="description" [(ngModel)]="description"></textarea>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
    <mat-form-field>
 | 
			
		||||
        <span matPrefix>$ </span>
 | 
			
		||||
        <input matInput placeholder="Price" type="number" name="price" [(ngModel)]="price">
 | 
			
		||||
        <mat-hint *ngIf="!price" align="start">0 will display "Contact For Price"</mat-hint>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
    <mat-radio-group [(ngModel)]="currency" name="currency">
 | 
			
		||||
        <mat-radio-button value="CAD" class="pl-3">CAD</mat-radio-button>
 | 
			
		||||
        <mat-radio-button value="USD" class="pl-3">USD</mat-radio-button>
 | 
			
		||||
    </mat-radio-group>
 | 
			
		||||
    <input #fileInput type="file" (change)="imageChanged($event)" hidden>
 | 
			
		||||
    <mat-form-field class="float-right" style="width: 150px">
 | 
			
		||||
        <input matInput type="number" placeholder="Weight For Shipping" [(ngModel)]="weight">
 | 
			
		||||
        <span matSuffix>lb</span>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
    <div class="mt-3 p-3 border rounded border-muted">
 | 
			
		||||
        <h5 mat-subheader class="mb-4 pl-0">Buying Options</h5>
 | 
			
		||||
        <button mat-stroked-button class="mb-4" color="accent" (click)="addOption()">Add</button>
 | 
			
		||||
        <mat-accordion>
 | 
			
		||||
            <mat-expansion-panel *ngFor="let o of options; let i = index">
 | 
			
		||||
                <mat-expansion-panel-header>
 | 
			
		||||
                    <mat-panel-title>
 | 
			
		||||
                        {{o.name || 'Option'}}
 | 
			
		||||
                    </mat-panel-title>
 | 
			
		||||
                    <mat-panel-description>
 | 
			
		||||
                        {{o.currency}} {{o.price | currency}}
 | 
			
		||||
                    </mat-panel-description>
 | 
			
		||||
                </mat-expansion-panel-header>
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-4">
 | 
			
		||||
                        <mat-form-field>
 | 
			
		||||
                            <input matInput placeholder="Name" [(ngModel)]="o.name">
 | 
			
		||||
                        </mat-form-field>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-4 text-center">
 | 
			
		||||
                        <mat-form-field>
 | 
			
		||||
                            <span matPrefix>$ </span>
 | 
			
		||||
                            <input matInput placeholder="Price" type="number" name="price" [(ngModel)]="o.price">
 | 
			
		||||
                            <mat-hint *ngIf="!price" align="start">0 will display "Contact For Price"</mat-hint>
 | 
			
		||||
                        </mat-form-field>
 | 
			
		||||
                        <mat-radio-group [(ngModel)]="o.currency" name="currency">
 | 
			
		||||
                            <mat-radio-button value="CAD" class="pl-3">CAD</mat-radio-button>
 | 
			
		||||
                            <mat-radio-button value="USD" class="pl-3">USD</mat-radio-button>
 | 
			
		||||
                        </mat-radio-group>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-4">
 | 
			
		||||
                        <mat-form-field class="float-right" style="width: 150px">
 | 
			
		||||
                            <input matInput type="number" placeholder="Weight For Shipping" [(ngModel)]="o.weight">
 | 
			
		||||
                            <span matSuffix>lb</span>
 | 
			
		||||
                        </mat-form-field>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <input #fileInput type="file" (change)="imageChanged($event)" hidden>
 | 
			
		||||
                <mat-action-row>
 | 
			
		||||
                    <button mat-button color="warn" (click)="options.splice(i, 1)">
 | 
			
		||||
                        Delete
 | 
			
		||||
                    </button>
 | 
			
		||||
                </mat-action-row>
 | 
			
		||||
            </mat-expansion-panel>
 | 
			
		||||
        </mat-accordion>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="mt-3 p-3 border rounded border-muted">
 | 
			
		||||
        <h5 mat-subheader class="pl-0">Uploads</h5>
 | 
			
		||||
        <mat-progress-bar *ngIf="uploading" mode="indeterminate"></mat-progress-bar>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,94 +1,98 @@
 | 
			
		||||
import {Component, Inject} from '@angular/core';
 | 
			
		||||
import {AngularFirestore} from 'angularfire2/firestore';
 | 
			
		||||
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
 | 
			
		||||
import {AppStore} from '../../app.store';
 | 
			
		||||
import {AngularFireStorage} from '../../../../node_modules/angularfire2/storage';
 | 
			
		||||
import { Component, Inject } from '@angular/core';
 | 
			
		||||
import { AngularFirestore } from 'angularfire2/firestore';
 | 
			
		||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 | 
			
		||||
import { AppStore } from '../../app.store';
 | 
			
		||||
import { AngularFireStorage } from 'angularfire2/storage';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'new-item',
 | 
			
		||||
  templateUrl: 'newProduct.component.html'
 | 
			
		||||
	selector: 'new-item',
 | 
			
		||||
	templateUrl: 'newProduct.component.html'
 | 
			
		||||
})
 | 
			
		||||
export class NewProductComponent {
 | 
			
		||||
  category;
 | 
			
		||||
  currency = 'CAD';
 | 
			
		||||
  description: string;
 | 
			
		||||
  files: {name: string; link: string; type: string}[] = [];
 | 
			
		||||
  image: string;
 | 
			
		||||
  linkError = false;
 | 
			
		||||
  name: string;
 | 
			
		||||
  price: number = 0.0;
 | 
			
		||||
  weight: number = 0;
 | 
			
		||||
  uploading = false;
 | 
			
		||||
	category;
 | 
			
		||||
	description: string;
 | 
			
		||||
	files: { name: string; link: string; type: string }[] = [];
 | 
			
		||||
	image: string;
 | 
			
		||||
	linkError = false;
 | 
			
		||||
	name: string;
 | 
			
		||||
	options: { name: string, price: number, currency: 'CAD' | 'USD', weight: number }[] = [];
 | 
			
		||||
	uploading = false;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private dialogRef: MatDialogRef<NewProductComponent>,
 | 
			
		||||
    private db: AngularFirestore,
 | 
			
		||||
    private storage: AngularFireStorage,
 | 
			
		||||
    @Inject(MAT_DIALOG_DATA) public data,
 | 
			
		||||
    public store: AppStore
 | 
			
		||||
  ) {
 | 
			
		||||
    if (data.currentCategory) this.category = data.currentCategory;
 | 
			
		||||
	constructor(
 | 
			
		||||
		private dialogRef: MatDialogRef<NewProductComponent>,
 | 
			
		||||
		private db: AngularFirestore,
 | 
			
		||||
		private storage: AngularFireStorage,
 | 
			
		||||
		@Inject(MAT_DIALOG_DATA) public data,
 | 
			
		||||
		public store: AppStore
 | 
			
		||||
	) {
 | 
			
		||||
		if (data.currentCategory) this.category = data.currentCategory;
 | 
			
		||||
 | 
			
		||||
    if (data.product) {
 | 
			
		||||
      this.category = data.product.category;
 | 
			
		||||
      this.currency = data.product.currency;
 | 
			
		||||
      this.description = data.product.originalDescription;
 | 
			
		||||
      this.files = data.product.files;
 | 
			
		||||
      this.name = data.product.name;
 | 
			
		||||
      this.price = data.product.price;
 | 
			
		||||
      this.weight = data.product.weight;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
		if (data.product) {
 | 
			
		||||
			this.category = data.product.category;
 | 
			
		||||
			this.description = data.product.originalDescription;
 | 
			
		||||
			this.files = data.product.files;
 | 
			
		||||
			this.name = data.product.name;
 | 
			
		||||
			this.options = data.product.options;
 | 
			
		||||
		} else {
 | 
			
		||||
			this.addOption();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  async addFile(event) {
 | 
			
		||||
    this.uploading = true;
 | 
			
		||||
    let file = event.target.files[0];
 | 
			
		||||
    let type = 'other';
 | 
			
		||||
    if (file.type.indexOf('image') != -1) type = 'preview';
 | 
			
		||||
    let upload = await this.storage.ref(`${Math.round(Math.random() * 1000000)}/${file.name}`).put(file);
 | 
			
		||||
    this.uploading = false;
 | 
			
		||||
    if (upload.state == 'success')
 | 
			
		||||
      this.files.push({name: file.name, type: type, link: await upload.ref.getDownloadURL()});
 | 
			
		||||
  }
 | 
			
		||||
	async addFile(event) {
 | 
			
		||||
		this.uploading = true;
 | 
			
		||||
		let file = event.target.files[0];
 | 
			
		||||
		let type = 'other';
 | 
			
		||||
		if (file.type.indexOf('image') != -1) type = 'preview';
 | 
			
		||||
		let upload = await this.storage.ref(`${Math.round(Math.random() * 1000000)}/${file.name}`).put(file);
 | 
			
		||||
		this.uploading = false;
 | 
			
		||||
		if (upload.state == 'success')
 | 
			
		||||
			this.files.push({ name: file.name, type: type, link: await upload.ref.getDownloadURL() });
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  addLink(link: string) {
 | 
			
		||||
    let valid: any = new RegExp(
 | 
			
		||||
      '^(?:(?<protocol>https?):\\/\\/)?(?<name>(?:(?<subdomain>[\\d|\\w]+).)?(?:[\\d|\\w]+\\.[\\d|\\w]+))(?:\\:(?<port>\\d+))?.*'
 | 
			
		||||
    ).exec(link);
 | 
			
		||||
    if (!!valid) {
 | 
			
		||||
      if (!valid.groups['protocol']) link = `http://${link}`;
 | 
			
		||||
      this.files.push({name: valid.groups['name'], link: link, type: 'link'});
 | 
			
		||||
      this.linkError = !valid;
 | 
			
		||||
    }
 | 
			
		||||
	addLink(link: string) {
 | 
			
		||||
		let valid: any = new RegExp(
 | 
			
		||||
			'^(?:(?<protocol>https?):\\/\\/)?(?<name>(?:(?<subdomain>[\\d|\\w]+).)?(?:[\\d|\\w]+\\.[\\d|\\w]+))(?:\\:(?<port>\\d+))?.*'
 | 
			
		||||
		).exec(link);
 | 
			
		||||
		if (!!valid) {
 | 
			
		||||
			if (!valid.groups['protocol']) link = `http://${link}`;
 | 
			
		||||
			this.files.push({ name: valid.groups['name'], link: link, type: 'link' });
 | 
			
		||||
			this.linkError = !valid;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    return !!valid;
 | 
			
		||||
  }
 | 
			
		||||
		return !!valid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  imageChanged(event) {
 | 
			
		||||
    let reader = new FileReader();
 | 
			
		||||
    reader.readAsDataURL(event.target.files[0]);
 | 
			
		||||
    reader.onload = (event: any) => (this.image = event.target.result);
 | 
			
		||||
  }
 | 
			
		||||
	addOption() {
 | 
			
		||||
		this.options.push({ name: '', price: 0, currency: 'CAD', weight: 0 });
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  submit() {
 | 
			
		||||
    let newProduct = {
 | 
			
		||||
      category: this.category,
 | 
			
		||||
      currency: this.currency,
 | 
			
		||||
      description: this.description,
 | 
			
		||||
      files: this.files,
 | 
			
		||||
      name: this.name,
 | 
			
		||||
      price: Number(this.price),
 | 
			
		||||
      weight: Number(this.weight) || 0
 | 
			
		||||
    };
 | 
			
		||||
    if (this.image) newProduct['image'] = this.image;
 | 
			
		||||
	imageChanged(event) {
 | 
			
		||||
		let reader = new FileReader();
 | 
			
		||||
		reader.readAsDataURL(event.target.files[0]);
 | 
			
		||||
		reader.onload = (event: any) => (this.image = event.target.result);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if (!this.data.product) {
 | 
			
		||||
      this.db
 | 
			
		||||
        .collection('products')
 | 
			
		||||
        .add(newProduct)
 | 
			
		||||
        .then(data => this.dialogRef.close());
 | 
			
		||||
    } else {
 | 
			
		||||
      this.data.product.ref.update(newProduct).then(data => this.dialogRef.close());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
	submit() {
 | 
			
		||||
		let newProduct = {
 | 
			
		||||
			category: this.category,
 | 
			
		||||
			description: this.description,
 | 
			
		||||
			files: this.files,
 | 
			
		||||
			name: this.name,
 | 
			
		||||
			options: this.options.map(row => {
 | 
			
		||||
				row.price = <number>row.price;
 | 
			
		||||
				row.weight = <number>row.weight;
 | 
			
		||||
				return row;
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
		if (this.image) newProduct['image'] = this.image;
 | 
			
		||||
 | 
			
		||||
		if (!this.data.product) {
 | 
			
		||||
			this.db
 | 
			
		||||
				.collection('products')
 | 
			
		||||
				.add(newProduct)
 | 
			
		||||
				.then(data => this.dialogRef.close());
 | 
			
		||||
		} else {
 | 
			
		||||
			this.data.product.ref.update(newProduct).then(data => this.dialogRef.close());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								src/app/store/products/product.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/app/store/products/product.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import { SafeUrl, SafeHtml } from "@angular/platform-browser";
 | 
			
		||||
 | 
			
		||||
export interface PFile {
 | 
			
		||||
    link: string;
 | 
			
		||||
    name: string;
 | 
			
		||||
    type: 'link' | 'other' | 'preview';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface POption {
 | 
			
		||||
    currency: 'CAD' | 'USD';
 | 
			
		||||
    name: string;
 | 
			
		||||
    price: number;
 | 
			
		||||
    weight: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Product {
 | 
			
		||||
    category: string;
 | 
			
		||||
    description: string | SafeHtml;
 | 
			
		||||
    files: any[]
 | 
			
		||||
    image: string | SafeUrl;
 | 
			
		||||
    name: string;
 | 
			
		||||
    options: POption[];
 | 
			
		||||
    originalDescription: string;
 | 
			
		||||
    originalImage: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -16,18 +16,26 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-12 col-md-9">
 | 
			
		||||
                        <h2 class="roboto">{{product.name}}</h2>
 | 
			
		||||
                        <h5 *ngIf="product.price" class="text-muted">{{product.currency}} {{product.price | currency}}</h5>
 | 
			
		||||
                        <h5 *ngIf="!product.price" class="text-muted">Contact For Price</h5>
 | 
			
		||||
                        <mat-divider class="my-3"></mat-divider>
 | 
			
		||||
                        <p style="overflow: hidden;" [innerHtml]="product.description"></p>
 | 
			
		||||
                        <div class="float-right">
 | 
			
		||||
                        <mat-form-field *ngIf="product.options.length > 1">
 | 
			
		||||
                            <mat-select placeholder="Buying Options" [(ngModel)]="option">
 | 
			
		||||
                                <mat-option *ngFor="let o of product.options" [value]="o">
 | 
			
		||||
                                    {{o.name}} <span class="float-right text-muted">{{o.currency}} {{o.price | currency}}</span>
 | 
			
		||||
                                </mat-option>
 | 
			
		||||
                            </mat-select>
 | 
			
		||||
                        </mat-form-field>
 | 
			
		||||
                        <div class="d-inline ml-3">
 | 
			
		||||
                            <mat-form-field class="mr-1" style="width: 40px">
 | 
			
		||||
                                <span matPrefix>x</span>
 | 
			
		||||
                                <input #quantity matInput type="number" value="1" min="1">
 | 
			
		||||
                            </mat-form-field>
 | 
			
		||||
                            <button mat-raised-button color="primary" [disabled]="quantity.value < 1" (click)="app.cartAdd(product.id, product.name, product.price, product.currency, quantity.value)">
 | 
			
		||||
                            <button mat-raised-button color="primary" [disabled]="quantity.value < 1" (click)="app.cartAdd(product.id, product.name, option, quantity.value)">
 | 
			
		||||
                                <mat-icon>add_shopping_cart</mat-icon> Buy
 | 
			
		||||
                            </button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <h5 *ngIf="product.options.length == 1 && product.options[0].price > 0" class="text-muted">{{product.options[0].currency}} {{product.options[0].price | currency}}</h5>
 | 
			
		||||
                        <h5 *ngIf="product.options.length == 1 && product.options[0].price == 0" class="text-muted">Contact For Price</h5>
 | 
			
		||||
                        <mat-divider class="my-3"></mat-divider>
 | 
			
		||||
                        <p style="overflow: hidden;" [innerHtml]="product.description"></p>
 | 
			
		||||
                        <mat-divider class="my-3"></mat-divider>
 | 
			
		||||
                        <div *ngIf="attachments?.length">
 | 
			
		||||
                            <h5 class="ml-3">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
import {Component} from '@angular/core';
 | 
			
		||||
import {ActivatedRoute} from '@angular/router';
 | 
			
		||||
import {AppComponent} from '../../app.component';
 | 
			
		||||
import {map} from 'rxjs/operators';
 | 
			
		||||
import {AppStore} from '../../app.store';
 | 
			
		||||
import {Product} from '../product';
 | 
			
		||||
import {SafeUrl, DomSanitizer} from '../../../../node_modules/@angular/platform-browser';
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute } from '@angular/router';
 | 
			
		||||
import { AppComponent } from '../../app.component';
 | 
			
		||||
import { map } from 'rxjs/operators';
 | 
			
		||||
import { AppStore } from '../../app.store';
 | 
			
		||||
import { Product } from '../product';
 | 
			
		||||
import { SafeUrl, DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'products',
 | 
			
		||||
@@ -13,15 +13,16 @@ import {SafeUrl, DomSanitizer} from '../../../../node_modules/@angular/platform-
 | 
			
		||||
export class ProductsComponent {
 | 
			
		||||
  product: Product;
 | 
			
		||||
  preview: SafeUrl[];
 | 
			
		||||
  links: {name: string; link: string; type: string}[];
 | 
			
		||||
  attachments: {name: string; link: string; type: string}[];
 | 
			
		||||
  links: { name: string; link: string; type: string }[];
 | 
			
		||||
  attachments: { name: string; link: string; type: string }[];
 | 
			
		||||
  option;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private store: AppStore,
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
    private domSanitizer: DomSanitizer,
 | 
			
		||||
    public app: AppComponent
 | 
			
		||||
  ) {}
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.route.params.subscribe(params => {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user