Skip to content
Snippets Groups Projects
Commit cfea9f5b authored by Hugo BAYOUD's avatar Hugo BAYOUD
Browse files

Merge branch '3-front-creer-le-composant-drinks-et-la-card-pour-une-maquette' into 'master'

Resolve "[FRONT] Créer le composant drinks et la card pour une maquette"

Closes #3

See merge request !3
parents 81831ee8 a14d938d
No related branches found
No related tags found
1 merge request!3Resolve "[FRONT] Créer le composant drinks et la card pour une maquette"
Showing
with 326 additions and 38 deletions
...@@ -24,9 +24,11 @@ import { environment } from 'src/environments/environment'; ...@@ -24,9 +24,11 @@ import { environment } from 'src/environments/environment';
import { reducersMap } from './share/store'; import { reducersMap } from './share/store';
import { AuthEffects } from './share/store/effects/auth.effects'; import { AuthEffects } from './share/store/effects/auth.effects';
import { BarEffects } from './share/store/effects/bar.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({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent, ToDegreePipe],
imports: [ imports: [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
......
import { Route } from "@angular/router"; import { Route } from "@angular/router";
import { BarsComponent } from "./components/bars/bars.component"; import { BarsComponent } from "./components/bars/bars.component";
import { DrinksComponent } from "./components/drinks/drinks.component";
import { SigninComponent } from "./components/signin/signin.component"; import { SigninComponent } from "./components/signin/signin.component";
import { SignupComponent } from "./components/signup/signup.component"; import { SignupComponent } from "./components/signup/signup.component";
import { WelcomeComponent } from "./components/welcome/welcome.component"; import { WelcomeComponent } from "./components/welcome/welcome.component";
...@@ -11,6 +12,7 @@ export const APP_ROUTING: Route[] = [ ...@@ -11,6 +12,7 @@ export const APP_ROUTING: Route[] = [
{ path: 'photos', canActivate: [AuthGuard], loadChildren: () => import('./photos/photos.module').then(m => m.PhotosModule) }, { 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: 'profile', canActivate: [AuthGuard], loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule) },
{ path: 'bars', canActivate: [AuthGuard], component: BarsComponent }, { path: 'bars', canActivate: [AuthGuard], component: BarsComponent },
{ path: 'menu/:id', canActivate: [AuthGuard], component: DrinksComponent },
{ path: 'signup', canActivate: [AlreadyLoggedInGuard], component: SignupComponent }, { path: 'signup', canActivate: [AlreadyLoggedInGuard], component: SignupComponent },
{ path: 'signin', canActivate: [AlreadyLoggedInGuard], component: SigninComponent }, { path: 'signin', canActivate: [AlreadyLoggedInGuard], component: SigninComponent },
{ path: '', redirectTo: '', pathMatch: 'full' }, { path: '', redirectTo: '', pathMatch: 'full' },
......
...@@ -13,21 +13,7 @@ ...@@ -13,21 +13,7 @@
<div>{{ bar.address }}</div> <div>{{ bar.address }}</div>
</div> </div>
<div class="card-action"> <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>
</div> </div>
</section> </section>
\ No newline at end of file
<!-- <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> -->
...@@ -4,8 +4,7 @@ import { Bar } from '../../share/models/bar.model'; ...@@ -4,8 +4,7 @@ import { Bar } from '../../share/models/bar.model';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { State } from '../../share/store'; import { State } from '../../share/store';
import { allBarsSelector } from '../../share/store/selectors/bar.selectors'; import { allBarsSelector } from '../../share/store/selectors/bar.selectors';
import { BarActionsTypes, FetchBars, FetchBarsSuccess } from 'src/app/share/store/actions/bar.actions'; import { FetchBars } from 'src/app/share/store/actions/bar.actions';
import { BarService } from 'src/app/share/services/bar.service';
@Component({ @Component({
selector: 'app-bars', 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 @@ ...@@ -3,9 +3,9 @@
<!-- <span *ngIf="!(isLoggedIn$ | async)" fxLayoutGap="15px" fxLayout="row" fxLayoutAlign="center center"> <!-- <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="/signin">login</mat-icon>
<mat-icon class="link" routerLink="/signup">launch</mat-icon> <mat-icon class="link" routerLink="/signup">launch</mat-icon>
</span> </span> -->
<span *ngIf="isLoggedIn$ | async" fxLayoutGap="15px" fxLayout="row" fxLayoutAlign="center center"> <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> <mat-icon class="link" routerLink="/" (click)="onLogout()">power_settings_new</mat-icon>
</span> --> </span>
</mat-toolbar> </mat-toolbar>
\ No newline at end of file
...@@ -5,7 +5,6 @@ import { Observable } from 'rxjs'; ...@@ -5,7 +5,6 @@ import { Observable } from 'rxjs';
import { State } from '../../store'; import { State } from '../../store';
import { Logout } from '../../store/actions/auth.actions'; import { Logout } from '../../store/actions/auth.actions';
import { isLoggedInAuthSelector } from '../../store/selectors/auth.selectors'; import { isLoggedInAuthSelector } from '../../store/selectors/auth.selectors';
import { FetchPhotos, SetFilter } from 'src/app/photos/shared/store/photos.actions';
@Component({ @Component({
selector: 'app-topbar', selector: 'app-topbar',
......
export interface Bar { export interface Bar {
_id: string;
shortname: string; shortname: string;
longname: string; longname: string;
description: 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 @@ ...@@ -2,6 +2,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
// Modules // Modules
import { LayoutModule } from './layout.module'; import { LayoutModule } from './layout.module';
...@@ -17,19 +18,20 @@ import { AuthGuard } from '../guards/auth.guard'; ...@@ -17,19 +18,20 @@ import { AuthGuard } from '../guards/auth.guard';
import { SignupComponent } from '../../components/signup/signup.component'; import { SignupComponent } from '../../components/signup/signup.component';
import { SigninComponent } from '../../components/signin/signin.component'; import { SigninComponent } from '../../components/signin/signin.component';
import { TopbarComponent } from '../components/topbar/topbar.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 // Interceptors
import { AuthInterceptor } from '../interceptors/auth.interceptor'; 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 = [ const COMPONENTS = [
SignupComponent, SignupComponent,
SigninComponent, SigninComponent,
WelcomeComponent, WelcomeComponent,
BarsComponent, BarsComponent,
TopbarComponent TopbarComponent,
DrinksComponent
]; ];
@NgModule({ @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 { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Menu } from '../models/menu.model';
import { Bar } from '../models/bar.model'; import { Bar } from '../models/bar.model';
@Injectable({ @Injectable({
...@@ -14,4 +16,8 @@ export class BarService { ...@@ -14,4 +16,8 @@ export class BarService {
public getAll(): Observable<Bar[]> { public getAll(): Observable<Bar[]> {
return this.http.get<Bar[]>('/api/v1/bars'); 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 { Action } from "@ngrx/store";
import { Bar } from "../../models/bar.model"; import { Bar } from "../../models/bar.model";
import { Menu } from "../../models/menu.model";
export enum BarActionsTypes { export enum BarActionsTypes {
FETCH_BARS = '[bars/api] fetch all bars', FETCH_BARS = '[bars/api] fetch all bars',
FETCH_BARS_SUCCESS = '[bars/api] fetch bars success', 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 { export class FetchBars implements Action {
...@@ -21,4 +25,24 @@ export class FetchBarsFailed implements Action { ...@@ -21,4 +25,24 @@ export class FetchBarsFailed implements Action {
constructor(public payload: string) {} constructor(public payload: string) {}
} }
export type BarsActions = FetchBars | FetchBarsSuccess | FetchBarsFailed; export class FetchBarMenu implements Action {
\ No newline at end of file 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 { Actions, createEffect, ofType } from "@ngrx/effects";
import { Injectable } from "@angular/core"; 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 { 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 { BarService } from "../../services/bar.service";
import { Bar } from "../../models/bar.model"; 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() @Injectable()
export class BarEffects { export class BarEffects {
constructor( constructor(
private actions$: Actions, private actions$: Actions,
private barService: BarService private barService: BarService,
private store: Store<State>
) {} ) {}
loadBars$ = createEffect(() => this.actions$.pipe( loadBars$ = createEffect(() => this.actions$.pipe(
...@@ -22,4 +27,14 @@ export class BarEffects { ...@@ -22,4 +27,14 @@ export class BarEffects {
catchError(() => of(new FetchBarsFailed('failed fetching all bars'))) 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 { Bar } from "../../models/bar.model";
import { Menu } from "../../models/menu.model";
import { BarsActions, BarActionsTypes } from "../actions/bar.actions"; import { BarsActions, BarActionsTypes } from "../actions/bar.actions";
export interface BarState { export interface BarState {
bars: Bar[]; bars: Bar[];
currentBar: Bar; currentMenu: Menu;
currentBarId: string;
error: string; error: string;
} }
const defaultBarState = { const defaultBarState = {
bars: [], bars: [],
currentBar: null, currentMenu: null,
currentBarId: '',
error: '', error: '',
} }
export function barReducer(state: BarState = defaultBarState, action: BarsActions): BarState { export function barReducer(state: BarState = defaultBarState, action: BarsActions): BarState {
switch (action.type) { switch (action.type) {
case BarActionsTypes.FETCH_BAR_MENU: {
return {
...state,
currentBarId: action.payload
};
}
case BarActionsTypes.FETCH_BARS_SUCCESS: { case BarActionsTypes.FETCH_BARS_SUCCESS: {
return { return {
...state, ...state,
...@@ -23,6 +33,14 @@ export function barReducer(state: BarState = defaultBarState, action: BarsAction ...@@ -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: { case BarActionsTypes.FETCH_BARS_FAILED: {
return { return {
...state, ...state,
......
...@@ -5,4 +5,6 @@ export const baseSelector = createFeatureSelector('bars'); ...@@ -5,4 +5,6 @@ export const baseSelector = createFeatureSelector('bars');
export const allBarsSelector = createSelector(baseSelector, (barState: BarState) => barState?.bars); export const allBarsSelector = createSelector(baseSelector, (barState: BarState) => barState?.bars);
export const currentBarSelector = createSelector(baseSelector, (barState: BarState) => barState?.currentBar); export const currentMenuSelector = createSelector(baseSelector, (barState: BarState) => barState?.currentMenu);
\ No newline at end of file
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 */ /* You can add global styles to this file, and also import other style files */
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; @import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
html, body { height: 100%; } html, body {
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; background-color: #f1f1f1; text-align: center; color: #222222} height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
background-color: #f1f1f1;
text-align: center;
color: #222222;
}
.link { .link {
outline: 0; outline: 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment