aggiunti link per navigare quadno loggati e la apgian dei producers
This commit is contained in:
parent
74c9984994
commit
f63bac4457
|
|
@ -5,6 +5,11 @@
|
||||||
"packageManager": "npm"
|
"packageManager": "npm"
|
||||||
},
|
},
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
"projects": {
|
"projects": {
|
||||||
"validator-gui": {
|
"validator-gui": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1 @@
|
||||||
<header>
|
<app-main-layout></app-main-layout>
|
||||||
<app-header></app-header>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
|
||||||
<main class="content">
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
</main>
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { HomePage } from './pages/home/home';
|
import { HomePage } from './pages/home/home';
|
||||||
import { LoginPage } from './pages/login/login';
|
import { LoginPage } from './pages/login/login';
|
||||||
|
import { authGuard } from './guards/auth-guard';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
|
@ -12,6 +13,14 @@ export const routes: Routes = [
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: LoginPage
|
component: LoginPage
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
canActivate: [authGuard],
|
||||||
|
children: [
|
||||||
|
{ path: '', redirectTo: 'producers', pathMatch: 'full' },
|
||||||
|
{ path: 'producers', loadComponent: () => import('./pages/producers/producers').then(m => m.ProducersComponent) },
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '**',
|
path: '**',
|
||||||
redirectTo: ''
|
redirectTo: ''
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,13 @@
|
||||||
import { Component, inject, signal } from '@angular/core';
|
import { Component, signal } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { MainLayout } from "./layouts/main-layout/main-layout";
|
||||||
import { Header } from "./components/header/header";
|
|
||||||
import { AuthenticationService } from './services/authentication';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [ RouterOutlet, Header],
|
imports: [MainLayout],
|
||||||
templateUrl: './app.html',
|
templateUrl: './app.html',
|
||||||
styleUrl: './app.css'
|
styleUrl: './app.css'
|
||||||
})
|
})
|
||||||
export class App {
|
export class App {
|
||||||
protected readonly title = signal('validator-gui');
|
protected readonly title = signal('validator-gui');
|
||||||
|
|
||||||
protected authService = inject(AuthenticationService);
|
|
||||||
|
|
||||||
loggedInUser = this.authService.loggedInUser;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,23 @@
|
||||||
<it-header slimTitle="ISTI CNR - Istituto di Scienza e Tecnologie dell'Informazione"
|
<it-header slimTitle="ISTI CNR - Istituto di Scienza e Tecnologie dell'Informazione"
|
||||||
slimTitleLink="https://www.isti.cnr.it" [loginStyle]="'none'" [light]="false" [showSearch]="false" [sticky]="true"
|
slimTitleLink="https://www.isti.cnr.it" [loginStyle]="getLoginStyle()" [smallHeader]="false" [light]="false"
|
||||||
[megamenu]="true">
|
[showSearch]="false" [sticky]="true" [megamenu]="false" (loginClick)="login()">
|
||||||
<ng-container slimRightZone>
|
|
||||||
@if(loggedInUser()) {
|
@if(loggedInUser()) {
|
||||||
<a itAvatar size="md" href="#" color="blue"
|
<ng-container slimRightZone>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<a itAvatar size="md" color="blue"
|
||||||
itTooltip="<strong>{{loggedInUser()!.username}}</strong><br/><em>{{loggedInUser()!.email}}</em>"
|
itTooltip="<strong>{{loggedInUser()!.username}}</strong><br/><em>{{loggedInUser()!.email}}</em>"
|
||||||
tooltipPlacement="top" tooltipHtml="true">
|
tooltipPlacement="top" tooltipHtml="true">
|
||||||
<p aria-hidden="true">{{ loggedInUser()!.username | initials }}</p>
|
<p aria-hidden="true">{{ loggedInUser()!.username | initials }}</p>
|
||||||
<span class="visually-hidden">Mario Rossi</span>
|
<span class="visually-hidden">{{ loggedInUser()!.username }}</span>
|
||||||
</a>
|
</a>
|
||||||
} @else {
|
|
||||||
<a class="btn btn-primary btn-sm mx-auto text-decoration-none" routerLink="/login">
|
<it-icon class="logout-icon" color="white" name="logout" role="button" tabindex="0" (click)="logout()">
|
||||||
<div class="d-flex text-decoration-none gap-1 align-items-center">
|
</it-icon>
|
||||||
<it-icon name="user"></it-icon>
|
|
||||||
<span>Accedi all'area riservata</span>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
}
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
}
|
||||||
<ng-container brand>
|
<ng-container brand>
|
||||||
<a href="#">
|
<a routerLink="home">
|
||||||
<it-icon name="pa"></it-icon>
|
<it-icon name="pa"></it-icon>
|
||||||
<div class="it-brand-text">
|
<div class="it-brand-text">
|
||||||
<div class="it-brand-title">Validatore Sistemi Fiscali</div>
|
<div class="it-brand-title">Validatore Sistemi Fiscali</div>
|
||||||
|
|
@ -27,9 +25,5 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container navItems>
|
|
||||||
<it-navbar-item>
|
|
||||||
<a class="nav-link active" routerLink="/" aria-current="page"><span>Home</span></a>
|
|
||||||
</it-navbar-item>
|
|
||||||
</ng-container>
|
|
||||||
</it-header>
|
</it-header>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
.logout-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,36 @@
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, computed, inject } from '@angular/core';
|
||||||
import { DesignAngularKitModule, ItTooltipDirective } from 'design-angular-kit';
|
import { DesignAngularKitModule, ItTooltipDirective } from 'design-angular-kit';
|
||||||
import { AuthenticationService } from '../../services/authentication';
|
import { AuthenticationService } from '../../services/authentication';
|
||||||
import { InitialsPipe } from '../../pipes/initials-pipe-pipe';
|
import { InitialsPipe } from '../../pipes/initials-pipe-pipe';
|
||||||
import { RouterLink } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
imports: [DesignAngularKitModule, InitialsPipe, RouterLink],
|
imports: [DesignAngularKitModule, InitialsPipe],
|
||||||
templateUrl: './header.html',
|
templateUrl: './header.html',
|
||||||
styleUrl: './header.css',
|
styleUrl: './header.scss',
|
||||||
})
|
})
|
||||||
export class Header {
|
export class Header {
|
||||||
|
|
||||||
|
private router = inject(Router);
|
||||||
|
|
||||||
protected authService = inject(AuthenticationService);
|
protected authService = inject(AuthenticationService);
|
||||||
|
|
||||||
loggedInUser = this.authService.loggedInUser;
|
getLoginStyle() {
|
||||||
|
return this.authService.loggedInUser() ? 'none' : 'full';
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.authService.logout();
|
||||||
|
this.router.navigate(['/home']);
|
||||||
|
}
|
||||||
|
|
||||||
|
loggedInUser() {
|
||||||
|
return this.authService.loggedInUser();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<it-list>
|
||||||
|
<it-list-item iconLeft="true" href="#" externalLink="true">
|
||||||
|
<div>
|
||||||
|
<h4 class="text m-0">Link lista 1</h4>
|
||||||
|
<p class="small m-0">Lorem ipsum dolor sit amet.</p>
|
||||||
|
</div>
|
||||||
|
<ng-container multiple>
|
||||||
|
<a href="#" aria-label="Testo - Azione 1">
|
||||||
|
<it-icon name="code-circle" color="primary"></it-icon>
|
||||||
|
</a>
|
||||||
|
<a href="#" aria-label="Testo - Azione 2">
|
||||||
|
<it-icon name="code-circle" color="primary"></it-icon>
|
||||||
|
</a>
|
||||||
|
<a href="#" aria-label="Testo - Azione 3">
|
||||||
|
<it-icon name="code-circle" color="primary"></it-icon>
|
||||||
|
</a>
|
||||||
|
</ng-container>
|
||||||
|
</it-list-item>
|
||||||
|
</it-list>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProducersList } from './producers-list';
|
||||||
|
|
||||||
|
describe('ProducersList', () => {
|
||||||
|
let component: ProducersList;
|
||||||
|
let fixture: ComponentFixture<ProducersList>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProducersList]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProducersList);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { DesignAngularKitModule } from 'design-angular-kit';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-producers-list',
|
||||||
|
imports: [DesignAngularKitModule],
|
||||||
|
templateUrl: './producers-list.html',
|
||||||
|
styleUrl: './producers-list.scss',
|
||||||
|
})
|
||||||
|
export class ProducersListComponent {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ export const authGuard: CanActivateFn = (route, state) => {
|
||||||
if (authService.isLoggedIn()) {
|
if (authService.isLoggedIn()) {
|
||||||
return true; // Allow access
|
return true; // Allow access
|
||||||
} else {
|
} else {
|
||||||
router.navigate(['/']);
|
router.navigate(['/login']);
|
||||||
return false; // Deny access
|
return false; // Deny access
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<header>
|
||||||
|
<app-header></app-header>
|
||||||
|
</header>
|
||||||
|
<nav class="pa-nav" aria-label="Navigazione principale">
|
||||||
|
<ul class="pa-nav__list">
|
||||||
|
<li class="pa-nav__item"
|
||||||
|
routerLinkActive="is-active"
|
||||||
|
[routerLinkActiveOptions]="{ exact: true }">
|
||||||
|
<a class="pa-nav__link" [routerLink]="['/']">
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@if(loggedInUser()) {
|
||||||
|
<li class="pa-nav__item"
|
||||||
|
routerLinkActive="is-active"
|
||||||
|
[routerLinkActiveOptions]="{ exact: true }">
|
||||||
|
<a class="pa-nav__link" [routerLink]="['/producers']">
|
||||||
|
Produttori
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<main class="content">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</main>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
/* wrapper nav (opzionale se già su header) */
|
||||||
|
.pa-nav {
|
||||||
|
background-color: #0066cc; // azzurro PA
|
||||||
|
display: flex;
|
||||||
|
padding: 0 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lista */
|
||||||
|
.pa-nav__list {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* link base */
|
||||||
|
.pa-nav__link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.55rem 0.9rem;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
opacity: 0.92;
|
||||||
|
transition: background-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pa-nav__item.is-active > .pa-nav__link {
|
||||||
|
color: beige;
|
||||||
|
background-color: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MainLayout } from './main-layout';
|
||||||
|
|
||||||
|
describe('MainLayout', () => {
|
||||||
|
let component: MainLayout;
|
||||||
|
let fixture: ComponentFixture<MainLayout>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [MainLayout]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(MainLayout);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
|
||||||
|
import { DesignAngularKitModule } from 'design-angular-kit';
|
||||||
|
import { Header } from '../../components/header/header';
|
||||||
|
import { AuthenticationService } from '../../services/authentication';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-main-layout',
|
||||||
|
imports: [RouterOutlet, Header, DesignAngularKitModule, RouterLink, RouterLinkActive],
|
||||||
|
templateUrl: './main-layout.html',
|
||||||
|
styleUrl: './main-layout.scss',
|
||||||
|
})
|
||||||
|
export class MainLayout {
|
||||||
|
|
||||||
|
protected authService = inject(AuthenticationService);
|
||||||
|
|
||||||
|
loggedInUser() {
|
||||||
|
return this.authService.loggedInUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface LoginData {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
export type User = {
|
|
||||||
username: string;
|
export type Role = 'admin' | 'user';
|
||||||
email: string;
|
|
||||||
|
export class User {
|
||||||
|
constructor(public username: string, public email: string, public role: Role = "user") {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -15,7 +15,9 @@
|
||||||
attraverso regole configurabili e controlli avanzati.
|
attraverso regole configurabili e controlli avanzati.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@if(!isLoggedIn()) {
|
||||||
<p class="home-content__text">
|
<p class="home-content__text">
|
||||||
L’accesso alle funzionalità complete è riservato agli utenti autenticati.
|
L’accesso alle funzionalità complete è riservato agli utenti autenticati. <a routerLink="/login">Accedi</a> per iniziare a utilizzare il sistema.
|
||||||
</p>
|
</p>
|
||||||
|
}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Variabili Bootstrap Italia già disponibili se importi bootstrap-italia
|
||||||
|
$primary: var(--bs-primary);
|
||||||
|
$gray-700: var(--bs-gray-700);
|
||||||
|
$gray-600: var(--bs-gray-600);
|
||||||
|
$gray-300: var(--bs-gray-300);
|
||||||
|
|
||||||
|
.home-content {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 3rem 1.5rem;
|
||||||
|
|
||||||
|
// Titolo principale
|
||||||
|
&__title {
|
||||||
|
font-family: var(--bs-font-sans-serif);
|
||||||
|
font-size: 2.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.2;
|
||||||
|
color: $primary;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sottotitolo / testo introduttivo
|
||||||
|
&__lead {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $gray-700;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Testo standard
|
||||||
|
&__text {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $gray-600;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separatore soft
|
||||||
|
&__divider {
|
||||||
|
margin: 2.5rem 0;
|
||||||
|
border-top: 1px solid $gray-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link istituzionale
|
||||||
|
a {
|
||||||
|
color: $primary;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.home-content {
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, computed, inject } from '@angular/core';
|
||||||
|
import { AuthenticationService } from '../../services/authentication';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
imports: [],
|
imports: [RouterLink],
|
||||||
templateUrl: './home.html',
|
templateUrl: './home.html',
|
||||||
styleUrl: './home.css',
|
styleUrl: './home.scss',
|
||||||
})
|
})
|
||||||
export class HomePage {
|
export class HomePage {
|
||||||
|
|
||||||
|
authService = inject(AuthenticationService);
|
||||||
|
|
||||||
|
isLoggedIn(){
|
||||||
|
return this.authService.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,47 @@
|
||||||
<p>login works!</p>
|
<div class="it-login-wrapper">
|
||||||
|
<div class="it-login-card">
|
||||||
|
<h1 class="it-login-title">Accedi</h1>
|
||||||
|
<p class="it-login-subtitle">
|
||||||
|
Inserisci le tue credenziali
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form (ngSubmit)="submit()">
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<div class="it-form-group">
|
||||||
|
<label for="email" class="it-label">Email</label>
|
||||||
|
<input
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
[formField] = "loginForm.email"
|
||||||
|
class="it-input"
|
||||||
|
placeholder="nome.cognome@email.it"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="it-form-group">
|
||||||
|
<label for="password" class="it-label">Password</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
[formField] = "loginForm.password"
|
||||||
|
class="it-input"
|
||||||
|
placeholder="••••••••"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<div class="it-actions">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="it-btn-primary"
|
||||||
|
[disabled]="loginForm().invalid()"
|
||||||
|
>
|
||||||
|
Accedi
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
.it-login-wrapper {
|
||||||
|
padding-top: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-login-card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 2.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-login-title {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: #17324d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-login-subtitle {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #5c6f82;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-form-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: #17324d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-input {
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #cbd5e1;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: border-color 0.2s ease;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #0066cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-actions {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.it-btn-primary {
|
||||||
|
width: 100%;
|
||||||
|
height: 46px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #0066cc;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: #0052a3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: #cbd5e1;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,38 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, inject, signal, WritableSignal } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import {form, FormField} from '@angular/forms/signals';
|
||||||
|
import { ItFormModule } from "design-angular-kit";
|
||||||
|
import { AuthenticationService } from '../../services/authentication';
|
||||||
|
import { LoginData } from '../../model/login-data';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
imports: [],
|
imports: [FormsModule, ItFormModule, FormField],
|
||||||
templateUrl: './login.html',
|
templateUrl: './login.html',
|
||||||
styleUrl: './login.css',
|
styleUrl: './login.scss',
|
||||||
})
|
})
|
||||||
export class LoginPage {
|
export class LoginPage {
|
||||||
|
|
||||||
|
authService = inject(AuthenticationService);
|
||||||
|
router = inject(Router);
|
||||||
|
|
||||||
|
loginModel = signal<LoginData>({
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
});
|
||||||
|
loginForm = form(this.loginModel);
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
if (this.loginForm().valid()) {
|
||||||
|
console.log('Login data:', this.loginModel());
|
||||||
|
this.authService.login(this.loginModel()).subscribe(() => {
|
||||||
|
console.log('Login successful');
|
||||||
|
this.router.navigate(['/home']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<app-producers-list></app-producers-list>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { Producers } from './producers';
|
||||||
|
|
||||||
|
describe('Producers', () => {
|
||||||
|
let component: Producers;
|
||||||
|
let fixture: ComponentFixture<Producers>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [Producers]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(Producers);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { ProducersListComponent } from "../../components/producers-list/producers-list";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-producers',
|
||||||
|
imports: [ProducersListComponent],
|
||||||
|
templateUrl: './producers.html',
|
||||||
|
styleUrls: ['./producers.scss'],
|
||||||
|
})
|
||||||
|
export class ProducersComponent {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { Injectable, signal } from '@angular/core';
|
import { Injectable, signal } from '@angular/core';
|
||||||
import { User } from '../model/user';
|
import { User } from '../model/user';
|
||||||
|
import { LoginData } from '../model/login-data';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -8,12 +10,21 @@ export class AuthenticationService {
|
||||||
|
|
||||||
private user = signal<User | null>(null);
|
private user = signal<User | null>(null);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
const storedUser = localStorage.getItem('loggedInUser');
|
||||||
|
if (storedUser) {
|
||||||
|
this.user.set(JSON.parse(storedUser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loggedInUser = this.user.asReadonly();
|
login(loginData: LoginData): Observable<void> {
|
||||||
|
const user = new User('John Doe', loginData.email); // Simulate a user based on login data
|
||||||
login(username: string, password: string) {
|
this.user.set(user);
|
||||||
this.user.set({ username, email: 'test@email.it' }); // Simulate a successful login with a dummy user
|
localStorage.setItem('loggedInUser', JSON.stringify(user));
|
||||||
localStorage.setItem('loggedInUser', JSON.stringify({ username, email: '' }));
|
return new Observable((observer) => {
|
||||||
|
observer.next();
|
||||||
|
observer.complete();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
|
|
@ -22,8 +33,10 @@ export class AuthenticationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoggedIn(): boolean {
|
isLoggedIn(): boolean {
|
||||||
const storedUser = localStorage.getItem('loggedInUser');
|
return this.user() != null;
|
||||||
this.user.set(storedUser != null ? JSON.parse(storedUser) : null);
|
}
|
||||||
return storedUser != null;
|
|
||||||
|
loggedInUser(): User | null {
|
||||||
|
return this.user();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,5 @@
|
||||||
/* 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 */
|
||||||
@use 'bootstrap-italia/src/scss/bootstrap-italia';
|
@use 'bootstrap-italia/src/scss/bootstrap-italia';
|
||||||
|
|
||||||
// Variabili Bootstrap Italia già disponibili se importi bootstrap-italia
|
|
||||||
$primary: var(--bs-primary);
|
|
||||||
$gray-700: var(--bs-gray-700);
|
|
||||||
$gray-600: var(--bs-gray-600);
|
|
||||||
$gray-300: var(--bs-gray-300);
|
|
||||||
|
|
||||||
.home-content {
|
|
||||||
max-width: 960px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 3rem 1.5rem;
|
|
||||||
|
|
||||||
// Titolo principale
|
|
||||||
&__title {
|
|
||||||
font-family: var(--bs-font-sans-serif);
|
|
||||||
font-size: 2.25rem;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.2;
|
|
||||||
color: $primary;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sottotitolo / testo introduttivo
|
|
||||||
&__lead {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: $gray-700;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Testo standard
|
|
||||||
&__text {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: $gray-600;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separatore soft
|
|
||||||
&__divider {
|
|
||||||
margin: 2.5rem 0;
|
|
||||||
border-top: 1px solid $gray-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link istituzionale
|
|
||||||
a {
|
|
||||||
color: $primary;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.home-content {
|
|
||||||
padding: 2rem 1rem;
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-size: 1.75rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue