Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hubayoud/detb-client
1 result
Show changes
Commits on Source (4)
Showing
with 326 additions and 38 deletions
......@@ -24,9 +24,11 @@ import { environment } from 'src/environments/environment';
import { reducersMap } from './share/store';
import { AuthEffects } from './share/store/effects/auth.effects';
import { BarEffects } from './share/store/effects/bar.effects';
import { DrinksComponent } from './components/drinks/drinks.component';
import { ToDegreePipe } from './share/pipes/to-degree.pipe';
@NgModule({
declarations: [AppComponent],
declarations: [AppComponent, ToDegreePipe],
imports: [
BrowserModule,
BrowserAnimationsModule,
......
import { Route } from "@angular/router";
import { BarsComponent } from "./components/bars/bars.component";
import { DrinksComponent } from "./components/drinks/drinks.component";
import { SigninComponent } from "./components/signin/signin.component";
import { SignupComponent } from "./components/signup/signup.component";
import { WelcomeComponent } from "./components/welcome/welcome.component";
......@@ -11,6 +12,7 @@ export const APP_ROUTING: Route[] = [
{ path: 'photos', canActivate: [AuthGuard], loadChildren: () => import('./photos/photos.module').then(m => m.PhotosModule) },
{ path: 'profile', canActivate: [AuthGuard], loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule) },
{ path: 'bars', canActivate: [AuthGuard], component: BarsComponent },
{ path: 'menu/:id', canActivate: [AuthGuard], component: DrinksComponent },
{ path: 'signup', canActivate: [AlreadyLoggedInGuard], component: SignupComponent },
{ path: 'signin', canActivate: [AlreadyLoggedInGuard], component: SigninComponent },
{ path: '', redirectTo: '', pathMatch: 'full' },
......
......@@ -13,21 +13,7 @@
<div>{{ bar.address }}</div>
</div>
<div class="card-action">
<button mat-raised-button color='accent'>choisir</button>
<button mat-raised-button routerLink="/menu/{{bar._id}}" color='accent'>choisir</button>
</div>
</div>
</section>
<!-- <section>
<div class=" card row-container center">
<div class="card-header">
<img class="logo-img" src="https://fakeimg.pl/300/" alt="fake-img">
</div>
<div class="card-content">
<p>Déliriuem Café clermont-ferrand</p>
<div>{{ bar.address }}</div>
</div>
<div class="card-action">
<button mat-raised-button color='accent'>choisir</button>
</div>
</div>
</section> -->
</section>
\ No newline at end of file
......@@ -4,8 +4,7 @@ import { Bar } from '../../share/models/bar.model';
import { Store } from '@ngrx/store';
import { State } from '../../share/store';
import { allBarsSelector } from '../../share/store/selectors/bar.selectors';
import { BarActionsTypes, FetchBars, FetchBarsSuccess } from 'src/app/share/store/actions/bar.actions';
import { BarService } from 'src/app/share/services/bar.service';
import { FetchBars } from 'src/app/share/store/actions/bar.actions';
@Component({
selector: 'app-bars',
......
.row-container {
/* display: flex;
flex-flow: row wrap; */
grid-template-columns: 1fr 1fr 1fr 1fr;
}
/* Au dessus de 430px de large, on place deux cards par ligne */
.band {
width: 90%;
margin: 10px auto;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-gap: 20px;
justify-content: center;
}
@media only screen and (min-width: 430px) {
.band {
grid-template-columns: 1fr 1fr;
}
}
@media only screen and (min-width: 700px) {
.band {
grid-template-columns: 1fr 1fr 1fr;
}
}
@media only screen and (min-width: 950px) {
.band {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
}
.drink-card {
min-height: 100%;
max-width: 200px;
background: white;
padding: 10px;
box-shadow: 0 2px 2px rgba(0,0,0,0.1);
border-radius: 4px;
display: flex;
flex-flow: column nowrap;
color: #222222;
top: 0;
position: relative;
transition: all .1s ease-in;
}
article .xp-number {
color: #EAE000;
font-size: 1.8em;
font-weight: bolder;
}
article .xp {
font-size: 1.3em;
font-weight: bolder;
text-transform: uppercase;
color: #000000;
}
.drink-card:hover {
top: -2px;
box-shadow: 0 4px 5px rgba(0,0,0,0.2);
}
.title {
color: #6E2424;
font-size: 1.1em;
font-weight: bold;
}
.thumb {
padding: 5% 5% 60% 5%;
background-size: cover;
background-position: center center;
}
.drink-card > hr {
margin-top: 0;
margin-bottom: 3px;
}
.description {
font-size: 0.7em;
color: #95A5A6;
}
.drink-card button {
align-self: flex-end;
margin: 0 auto
}
/*a moi*/
.card-header {
background-color: transparent;
align-self: flex-start;
}
.card-content {
align-self: center;
}
.card-action {
align-self: flex-end;
}
.card-header > img {
height: 130px;
width: 130px;
}
.card-header > p {
color: #6E2424;
font-size: 1.1em;
font-weight: bold;
}
.card-header > p, .card-header > img {
margin: 5px auto;
}
.column-container {
display: flex;
flex-flow: column nowrap;
}
.h-center {
text-align: center;
}
.v-center {
text-align: center;
}
\ No newline at end of file
<div class="band">
<div *ngFor="let drink of (menu$ | async).drinks" class="drink-card">
<h3 class="title">{{ drink.shortname }}</h3>
<div class="thumb" style="background-image: url(https://fakeimg.pl/250x250/);"></div>
<hr>
<article>
<p>degrée : <strong>{{ drink.abv }}°</strong> / Prix : <strong>7.5€</strong></p>
<span class="xp-number">1200</span><span class="xp">xp</span>
<p class="description">{{ drink.description }}</p>
</article>
<button mat-raised-button routerLink="/menu" color='accent'>commander</button>
</div>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { currentMenuSelector } from '../../share/store/selectors/bar.selectors';
import { FetchBarMenu } from '../../share/store/actions/bar.actions';
import { Menu } from '../../share/models/menu.model';
import { State } from '../../share/store';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-drinks',
templateUrl: './drinks.component.html',
styleUrls: ['./drinks.component.css']
})
export class DrinksComponent implements OnInit {
public menu$: Observable<Menu> = this.store.select(currentMenuSelector);
public tests: number[] = [0, 1, 2, 3, 4];
constructor(
private activatedRoute: ActivatedRoute,
private store: Store<State>,
) {}
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => {
const barId = params['id'];
if (barId) {
this.store.dispatch(new FetchBarMenu(barId));
}
});
}
}
......@@ -3,9 +3,9 @@
<!-- <span *ngIf="!(isLoggedIn$ | async)" fxLayoutGap="15px" fxLayout="row" fxLayoutAlign="center center">
<mat-icon class="link" routerLink="/signin">login</mat-icon>
<mat-icon class="link" routerLink="/signup">launch</mat-icon>
</span>
</span> -->
<span *ngIf="isLoggedIn$ | async" fxLayoutGap="15px" fxLayout="row" fxLayoutAlign="center center">
<mat-icon class="link" routerLink="/profile">account_circle</mat-icon>
<!-- <mat-icon class="link" routerLink="/profile">account_circle</mat-icon> -->
<mat-icon class="link" routerLink="/" (click)="onLogout()">power_settings_new</mat-icon>
</span> -->
</span>
</mat-toolbar>
\ No newline at end of file
......@@ -5,7 +5,6 @@ import { Observable } from 'rxjs';
import { State } from '../../store';
import { Logout } from '../../store/actions/auth.actions';
import { isLoggedInAuthSelector } from '../../store/selectors/auth.selectors';
import { FetchPhotos, SetFilter } from 'src/app/photos/shared/store/photos.actions';
@Component({
selector: 'app-topbar',
......
export interface Bar {
_id: string;
shortname: string;
longname: string;
description: string;
......
export interface Drink {
id: number,
shortname: string,
longname: string,
description: string,
idFamilyDrink: number,
abv: string,
img: string,
sizes: number[],
}
\ No newline at end of file
import { Bar } from "./bar.model";
import { Drink } from "./drink.model";
export interface Menu {
bar: Bar;
drinks: Drink[];
}
\ No newline at end of file
......@@ -2,6 +2,7 @@
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
// Modules
import { LayoutModule } from './layout.module';
......@@ -17,19 +18,20 @@ import { AuthGuard } from '../guards/auth.guard';
import { SignupComponent } from '../../components/signup/signup.component';
import { SigninComponent } from '../../components/signin/signin.component';
import { TopbarComponent } from '../components/topbar/topbar.component';
import { WelcomeComponent } from '../../components/welcome/welcome.component';
import { BarsComponent } from '../../components/bars/bars.component';
import { DrinksComponent } from '../../components/drinks/drinks.component';
// Interceptors
import { AuthInterceptor } from '../interceptors/auth.interceptor';
import { ReactiveFormsModule } from '@angular/forms';
import { WelcomeComponent } from 'src/app/components/welcome/welcome.component';
import { BarsComponent } from 'src/app/components/bars/bars.component';
const COMPONENTS = [
SignupComponent,
SigninComponent,
WelcomeComponent,
BarsComponent,
TopbarComponent
TopbarComponent,
DrinksComponent
];
@NgModule({
......
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'toDegree'
})
export class ToDegreePipe implements PipeTransform {
transform(value: string, ...args: unknown[]): number {
return (+value) * 100;
}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Menu } from '../models/menu.model';
import { Bar } from '../models/bar.model';
@Injectable({
......@@ -13,5 +15,9 @@ export class BarService {
// authInterceptor add the token in the HTTP request
public getAll(): Observable<Bar[]> {
return this.http.get<Bar[]>('/api/v1/bars');
}
}
public getMenu(barId: string): Observable<Menu> {
return this.http.get<Menu>(`/api/v1/menu/${barId}`)
}
}
import { Action } from "@ngrx/store";
import { Bar } from "../../models/bar.model";
import { Menu } from "../../models/menu.model";
export enum BarActionsTypes {
FETCH_BARS = '[bars/api] fetch all bars',
FETCH_BARS_SUCCESS = '[bars/api] fetch bars success',
FETCH_BARS_FAILED = '[bars/api] fetch bars failed'
FETCH_BARS_FAILED = '[bars/api] fetch bars failed',
FETCH_BAR_MENU = '[bars/menu/api] fetch bar menu',
FETCH_BAR_MENU_SUCCESS = '[bar/menu/api] fetch bar menu success',
FETCH_BAR_MENU_FAILED = '[bars/menu/api] fetch bar menu failed',
}
export class FetchBars implements Action {
......@@ -21,4 +25,24 @@ export class FetchBarsFailed implements Action {
constructor(public payload: string) {}
}
export type BarsActions = FetchBars | FetchBarsSuccess | FetchBarsFailed;
\ No newline at end of file
export class FetchBarMenu implements Action {
readonly type = BarActionsTypes.FETCH_BAR_MENU;
constructor(public payload: string) {}
}
export class FetchBarMenuSuccess implements Action {
readonly type = BarActionsTypes.FETCH_BAR_MENU_SUCCESS;
constructor(public payload: Menu) {}
}
export class FetchBarMenuFailed implements Action {
readonly type = BarActionsTypes.FETCH_BAR_MENU_FAILED;
constructor(public payload: string) {}
}
export type BarsActions = FetchBars |
FetchBarsSuccess |
FetchBarsFailed |
FetchBarMenu |
FetchBarMenuSuccess |
FetchBarMenuFailed;
\ No newline at end of file
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { Injectable } from "@angular/core";
import { catchError, map, mergeMap } from "rxjs/operators";
import { catchError, map, mergeMap, withLatestFrom } from "rxjs/operators";
import { EMPTY, of } from "rxjs";
import { BarActionsTypes, FetchBarsFailed, FetchBarsSuccess } from "../actions/bar.actions";
import { BarActionsTypes, FetchBarMenuFailed, FetchBarMenuSuccess, FetchBarsFailed, FetchBarsSuccess } from "../actions/bar.actions";
import { BarService } from "../../services/bar.service";
import { Bar } from "../../models/bar.model";
import { Menu } from "../../models/menu.model";
import { Store } from "@ngrx/store";
import { State } from "..";
import { currentBarIdSelector } from "../selectors/bar.selectors";
@Injectable()
export class BarEffects {
constructor(
private actions$: Actions,
private barService: BarService
private barService: BarService,
private store: Store<State>
) {}
loadBars$ = createEffect(() => this.actions$.pipe(
......@@ -22,4 +27,14 @@ export class BarEffects {
catchError(() => of(new FetchBarsFailed('failed fetching all bars')))
))
));
loadMenu$ = createEffect(() => this.actions$.pipe(
ofType(BarActionsTypes.FETCH_BAR_MENU),
withLatestFrom(this.store.select(currentBarIdSelector)),
mergeMap(([_, barId]) => this.barService.getMenu(barId)
.pipe(
map((menu: Menu) => (new FetchBarMenuSuccess(menu))),
catchError(() => of(new FetchBarMenuFailed(`failed fetch bar's menu`)))
))
));
}
\ No newline at end of file
import { Bar } from "../../models/bar.model";
import { Menu } from "../../models/menu.model";
import { BarsActions, BarActionsTypes } from "../actions/bar.actions";
export interface BarState {
bars: Bar[];
currentBar: Bar;
currentMenu: Menu;
currentBarId: string;
error: string;
}
const defaultBarState = {
bars: [],
currentBar: null,
currentMenu: null,
currentBarId: '',
error: '',
}
export function barReducer(state: BarState = defaultBarState, action: BarsActions): BarState {
switch (action.type) {
case BarActionsTypes.FETCH_BAR_MENU: {
return {
...state,
currentBarId: action.payload
};
}
case BarActionsTypes.FETCH_BARS_SUCCESS: {
return {
...state,
......@@ -23,6 +33,14 @@ export function barReducer(state: BarState = defaultBarState, action: BarsAction
};
}
case BarActionsTypes.FETCH_BAR_MENU_SUCCESS: {
return {
...state,
currentMenu: action.payload
};
}
case BarActionsTypes.FETCH_BAR_MENU_FAILED:
case BarActionsTypes.FETCH_BARS_FAILED: {
return {
...state,
......
......@@ -5,4 +5,6 @@ export const baseSelector = createFeatureSelector('bars');
export const allBarsSelector = createSelector(baseSelector, (barState: BarState) => barState?.bars);
export const currentBarSelector = createSelector(baseSelector, (barState: BarState) => barState?.currentBar);
\ No newline at end of file
export const currentMenuSelector = createSelector(baseSelector, (barState: BarState) => barState?.currentMenu);
export const currentBarIdSelector = createSelector(baseSelector, (barState: BarState) => barState?.currentBarId);
\ No newline at end of file
/* You can add global styles to this file, and also import other style files */
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; background-color: #f1f1f1; text-align: center; color: #222222}
html, body {
height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
background-color: #f1f1f1;
text-align: center;
color: #222222;
}
.link {
outline: 0;
......