Update 0.0.3:
All checks were successful
Docker Image CI / build-and-push (push) Successful in 2m1s
Docker Image CI / deploy (push) Successful in 28s
Docker Image CI / notify-failure (push) Has been skipped

-delen van agenda toegevoegd
-popup aangepast
-accepteren van uitnodiging toegevoegd
This commit is contained in:
2025-04-18 22:38:21 +02:00
parent aaa712c37c
commit 781723fddf
26 changed files with 681 additions and 40 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "pay-point", "name": "pay-point",
"version": "0.0.21", "version": "0.0.3",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",

View File

@@ -3,6 +3,8 @@ import {AgendaComponent} from './pages/agenda/agenda.component';
import {LoginComponent} from './pages/login/login.component'; import {LoginComponent} from './pages/login/login.component';
import {HomeComponent} from './pages/home/home.component'; import {HomeComponent} from './pages/home/home.component';
import {KlantenComponent} from './pages/klanten/klanten.component'; import {KlantenComponent} from './pages/klanten/klanten.component';
import {AgendaInviteComponent} from './pages/agenda-invite/agenda-invite.component';
import {AgendaDelenComponent} from './pages/agenda-delen/agenda-delen.component';
export const routes: Routes = [ export const routes: Routes = [
{path: '', redirectTo: 'login', pathMatch: 'full'}, {path: '', redirectTo: 'login', pathMatch: 'full'},
@@ -19,6 +21,14 @@ export const routes: Routes = [
path: 'klanten', path: 'klanten',
component: KlantenComponent, component: KlantenComponent,
}, },
{
path: 'agenda-invite',
component: AgendaInviteComponent
},
{
path: 'agenda-delen',
component: AgendaDelenComponent
}
// { // {
// path: 'dashboard', // path: 'dashboard',
// component: DashboardComponent, // component: DashboardComponent,

View File

@@ -0,0 +1,34 @@
<div class="dropdown-content">
<div>
<div class="dropdown-section-title">Agenda Beheer</div>
<tui-data-list>
<button tuiOption class="dropdown-item" (click)="shareAgenda();">
<tui-icon
icon="@tui.share-2"
[style.color]="'var(--tui-background-accent-1)'"/>
Agenda delen
</button>
<button tuiOption class="dropdown-item" (click)="switchAgenda();">
<tui-icon
icon="@tui.arrow-left-right"
[style.color]="'var(--tui-background-accent-1)'"/>
Agenda wisselen
</button>
</tui-data-list>
</div>
<div>
<div class="dropdown-section-title">Weergave Instellingen</div>
<tui-data-list>
<button tuiOption class="dropdown-item" (click)="setView('day');">
Dagweergave
</button>
<button tuiOption class="dropdown-item" (click)="setView('week');">
Weekweergave
</button>
<button tuiOption class="dropdown-item" (click)="setView('year');">
Jaarweergave
</button>
</tui-data-list>
</div>
</div>

View File

@@ -0,0 +1,35 @@
.dropdown-content {
border-radius: 12px;
background-color: white;
min-width: 220px;
}
.dropdown-section-title {
font-size: 0.75rem;
font-weight: 600;
color: #6b7280;
text-transform: uppercase;
margin-bottom: 0.5rem;
margin-top: 1rem;
padding-left: 0.25rem;
}
.dropdown-item {
display: flex;
align-items: center;
padding: 0.5rem 0.75rem;
border-radius: 8px;
transition: background-color 0.2s ease;
font-size: 0.95rem;
gap: 0.5rem;
white-space: nowrap;
&:hover {
background-color: #f3f4f6;
}
&:focus {
outline: none;
background-color: #e5e7eb;
}
}

View File

@@ -0,0 +1,37 @@
import {Component, EventEmitter, Output} from '@angular/core';
import {TuiDataListComponent, TuiIcon, TuiOption} from '@taiga-ui/core';
import {Router} from '@angular/router';
@Component({
selector: 'dropdown-content',
imports: [
TuiDataListComponent,
TuiOption,
TuiIcon
],
templateUrl: './dropdown-content.component.html',
styleUrl: './dropdown-content.component.scss'
})
export class DropdownContentComponent {
constructor(private router: Router) {
}
currentView: 'day' | 'week' | 'year' = 'day'
@Output() close = new EventEmitter()
shareAgenda() {
this.close.emit()/* open modal etc */
this.router.navigate(['/home/agenda-delen'])
}
switchAgenda() {
this.close.emit()/* toggle agenda */
}
setView(view: 'day' | 'week' | 'year') {
this.close.emit()
this.currentView = view;
}
}

View File

@@ -118,7 +118,7 @@
size="m" size="m"
tuiButton tuiButton
type="button" (click)="registerAppointment()" type="button" (click)="registerAppointment()"
id="afspraakMaken" id="afspraakPlannen"
[tuiAppearanceState]="formIsValid()"> [tuiAppearanceState]="formIsValid()">
Afspraak maken Afspraak maken
</button> </button>

View File

@@ -1,16 +1,15 @@
import {HttpInterceptorFn} from '@angular/common/http'; import {HttpInterceptorFn} from '@angular/common/http';
import {inject} from '@angular/core'; import {inject} from '@angular/core';
import {AuthService} from '../services/auth.service'; import {UserService} from '../services/user.service';
const excludedUrls = ['/auth/login']; const excludedUrls = ['/auth/login'];
export const AuthInterceptor: HttpInterceptorFn = (req, next) => { export const AuthInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService); const userService = inject(UserService);
const token = authService.getToken();
if (excludedUrls.some(url => req.url.includes(url))) { if (excludedUrls.some(url => req.url.includes(url))) {
return next(req); return next(req);
} }
const token: string | null = userService.userValue.token ?? null;
if (token) { if (token) {
const cloned = req.clone({ const cloned = req.clone({

View File

@@ -0,0 +1,29 @@
export class AppUserDto {
id: number;
username: string;
email: string;
firstName: string;
lastName: string;
role: string;
token: string;
companies: UserCompanyDTO[];
}
export interface CompanyDTO {
id: number;
name: string;
email: string;
address: string;
postalCode: string;
city: string;
imgHref: string;
}
export type AccessLevel = 'READ_ONLY' | 'USER';
export interface UserCompanyDTO {
id: string;
accessLevel: AccessLevel;
company: CompanyDTO;
}

View File

@@ -0,0 +1,9 @@
export class InviteEntity {
id: string;
company_id: number;
email: string;
token: string;
expiresAt: string; // ISO date string
used: boolean;
createdAt: string; // ISO date string
}

View File

@@ -1,9 +0,0 @@
export class UserDto {
username: string
fullName: string
email: string
token: string
constructor() {
}
}

View File

@@ -0,0 +1,30 @@
<div class="share-wrapper">
<h1>Deel je agenda</h1>
<p>Kies het bedrijf waarvoor je de agenda wilt delen:</p>
<select [formControl]="companyForm" class="custom-select">
<option *ngFor="let item of companies" [value]="item.id">{{ item.name }}</option>
</select>
<div class="link-section">
<div class="share-media">
<h3>
Uitnodigen via email:
</h3>
<div class="link-box">
<input placeholder="Email" type="email" [formControl]="email"/>
<button tuiButton size="m" appearance="primary" [disabled]="email.invalid" (click)="sendInvite()">
Versturen
</button>
</div>
</div>
<br>
<p class="label" *ngIf="shareLink">Kopieerbare link:</p>
<div class="link-box" *ngIf="shareLink">
<input type="text" [value]="shareLink" readonly/>
<button tuiButton size="m" iconStart="@tui.copy" appearance="secondary" (click)="copyLink()"></button>
</div>
</div>
</div>

View File

@@ -0,0 +1,139 @@
@keyframes fadeInOut {
0% {
opacity: 0;
transform: translateY(5px);
}
10% {
opacity: 1;
transform: translateY(0);
}
90% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-5px);
}
}
.share-wrapper {
max-width: 500px;
margin: 2rem auto;
padding: 2rem;
background: #fff;
border-radius: 1rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
font-family: 'Segoe UI', sans-serif;
h1 {
font-size: 1.8rem;
margin-bottom: 1rem;
}
p {
margin-bottom: 0.5rem;
font-weight: 500;
}
.custom-select {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
font-size: 1rem;
appearance: none;
background-color: #f9f9f9;
background-image: url('data:image/svg+xml;utf8,<svg fill="%23333" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/></svg>');
background-repeat: no-repeat;
background-position: right 1rem center;
background-size: 1rem;
cursor: pointer;
transition: border-color 0.3s, box-shadow 0.3s;
&:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
}
.link-section {
margin-top: 2rem;
.label {
font-weight: 600;
margin-bottom: 0.5rem;
}
.link-box {
display: flex;
align-items: center;
gap: 0.5rem;
input[type="text"], input[type="email"] {
flex: 1;
padding: 0.6rem 1rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
font-size: 0.95rem;
background-color: #f5f5f5;
transition: box-shadow 0.3s;
&:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(0, 150, 136, 0.25);
}
}
.copy-button {
background: #eee;
border: none;
border-radius: 0.5rem;
padding: 0.5rem 0.75rem;
font-size: 1.2rem;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
&:hover {
background: #ddd;
}
&:active {
transform: scale(0.95);
}
}
}
.copied-msg {
margin-top: 0.5rem;
color: #28a745;
font-weight: 600;
animation: fadeInOut 2.5s ease-in-out forwards;
}
}
}
a{
text-decoration: none;
color: white;
}
.share-wrapper{
animation: fadeIn 0.4s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(15px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.share-media button {
margin-right: 8px;
}

View File

@@ -0,0 +1,101 @@
import {Component, Inject, OnInit} from '@angular/core';
import {TuiSelectModule} from '@taiga-ui/legacy';
import {FormControl, FormsModule, ReactiveFormsModule, Validators} from '@angular/forms';
import {TuiAlertService, TuiButton} from '@taiga-ui/core';
import {NgForOf, NgIf} from '@angular/common';
import {Company} from '../../models/company';
import {CompanyService} from '../../services/company.service';
import {AgendaService} from '../../services/agenda.service';
import {Router} from '@angular/router';
import {InviteEntity} from '../../models/invite-entity';
import {UserService} from '../../services/user.service';
import {CompanyDTO} from '../../models/app-user-dto';
@Component({
selector: 'app-agenda-delen',
imports: [
TuiSelectModule,
FormsModule,
NgIf,
FormsModule,
NgForOf,
ReactiveFormsModule,
TuiButton,
],
templateUrl: './agenda-delen.component.html',
styleUrl: './agenda-delen.component.scss'
})
export class AgendaDelenComponent implements OnInit {
companies: CompanyDTO[];
selectedCompany: CompanyDTO | null = null;
companyForm: FormControl;
email: FormControl;
invite: InviteEntity;
constructor(@Inject(TuiAlertService) private readonly alerts: TuiAlertService, private companyService: CompanyService, private agendaService: AgendaService, private router: Router, private userService: UserService) {
}
ngOnInit(): void {
this.companyForm = new FormControl('');
this.email = new FormControl('', [
Validators.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/),
Validators.required]);
this.companyForm.valueChanges.subscribe(
companyToSelect => {
console.log(companyToSelect);
this.selectCompany(companyToSelect);
}
)
this.email.valueChanges.subscribe(
() => {
if (this.email.valid) {
this.createInvite()
}
}
)
this.companies = this.userService.userValue.companies.map(a => a.company)
this.selectedCompany = this.companies[0]
this.companyForm.setValue(this.selectedCompany.id);
}
get shareLink(): string | null {
if (!this.invite) return null;
return `${window.location.origin}/#/home/agenda-invite?token=${this.invite.token}`;
}
copyLink(): void {
if (this.shareLink) {
navigator.clipboard.writeText(this.shareLink);
this.alerts.open('Link gekopieerd naar klembord.').subscribe();
}
}
selectCompany(companyId: number): void {
console.log(companyId);
this.selectedCompany = this.companies.find(company =>
company.id == companyId
);
console.log(this.selectedCompany);
}
sendInvite(): void {
this.agendaService.sendInvite(this.shareLink, this.email.value).subscribe(
() => {
console.log('Successfully sent invite')
this.router.navigate(['/home/agenda']);
this.alerts.open(`Email is verstuurd naar: <strong>${this.email.value}`).subscribe();
}
)
}
createInvite(): void {
this.agendaService.createInvite(this.selectedCompany.id, this.email.value).subscribe(
response => {
this.invite = response
}
)
}
protected readonly encodeURIComponent = encodeURIComponent;
}

View File

@@ -0,0 +1,22 @@
<div class="invite-wrapper" *ngIf="company">
<h1>Agenda-uitnodiging ontvangen</h1>
<p *ngIf="agendaName">
Je bent uitgenodigd om toegang te krijgen tot de agenda:
<br>
<strong>{{ company.name }}</strong>
</p>
<p *ngIf="!company.name">
Je bent uitgenodigd om toegang te krijgen tot een agenda. Wil je deze uitnodiging accepteren?
</p>
<button
tuiButton
appearance="primary"
size="m"
(click)="acceptInvite()"
>
Uitnodiging accepteren
</button>
</div>

View File

@@ -0,0 +1,54 @@
.invite-wrapper {
max-width: 500px;
margin: 4rem auto;
padding: 2rem;
border-radius: 1rem;
background-color: #ffffff;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.05);
text-align: center;
font-family: 'Inter', sans-serif;
h1 {
font-size: 1.5rem;
margin-bottom: 1rem;
font-weight: 600;
color: #1f2937; // donkergrijs
}
p {
font-size: 1rem;
color: #4b5563; // medium grijs
margin-bottom: 2rem;
strong {
color: #111827; // bijna zwart
}
}
button {
font-size: 1rem;
padding: 0.75rem 1.5rem;
border-radius: 0.75rem;
font-weight: 500;
transition: background-color 0.2s ease;
&:hover {
background-color: #5b6dfb; // iets donkerder blauw
}
}
}
.invite-wrapper {
animation: fadeIn 0.4s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(15px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -0,0 +1,51 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {TuiAlertService, TuiButton} from '@taiga-ui/core';
import {NgIf} from '@angular/common';
import {CompanyService} from '../../services/company.service';
import {Company} from '../../models/company';
import {AgendaService} from '../../services/agenda.service';
import {InviteEntity} from '../../models/invite-entity';
import {CompanyDTO} from '../../models/app-user-dto';
import {UserService} from '../../services/user.service';
@Component({
selector: 'app-agenda-invite',
imports: [
TuiButton,
NgIf
],
templateUrl: './agenda-invite.component.html',
styleUrl: './agenda-invite.component.scss'
})
export class AgendaInviteComponent implements OnInit {
token: string = '';
agendaName: string = '...';
company: CompanyDTO;
inviteEntity: InviteEntity;
constructor(private route: ActivatedRoute, private router: Router, private companyService: CompanyService, private agendaService: AgendaService, private userService: UserService, private alerts: TuiAlertService) {
}
ngOnInit(): void {
this.token = this.route.snapshot.queryParamMap.get('token');
this.agendaService.verifyInvite(this.token).subscribe({
next: (invite: InviteEntity) => {
this.inviteEntity = invite
this.companyService.getCompany(invite.company_id).subscribe(companyResponse => {
this.company = companyResponse;
})
},
error: (error) => console.log(error),
});
}
acceptInvite(): void {
this.companyService.linkCompany(this.userService.userValue.id, this.inviteEntity.token).subscribe(
() => {
this.alerts.open(`Agenda ${this.company.name} is toegevoegd.`).subscribe();
this.router.navigate(['home/agenda']);
}
)
}
}

View File

@@ -75,7 +75,9 @@
</tui-icon> </tui-icon>
</button> </button>
<ng-template #dropdownContent> <ng-template #dropdownContent>
<div class="dropdown">But there is nothing to choose...</div> <div class="dropdown">
<dropdown-content (close)="open = false"></dropdown-content>
</div>
</ng-template> </ng-template>
</div> </div>
<div class="content"> <div class="content">
@@ -115,3 +117,5 @@
<app-details [appointment]="selectedAppointment" (appointmentDeleted)="appointmentIsDeleted($event)" <app-details [appointment]="selectedAppointment" (appointmentDeleted)="appointmentIsDeleted($event)"
(appointmentEdited)="appointmentIsEdited($event)"></app-details> (appointmentEdited)="appointmentIsEdited($event)"></app-details>
</app-modal> </app-modal>
<app-modal title="Agenda delen" *ngIf="false"></app-modal>

View File

@@ -139,3 +139,23 @@ strong, p {
.date:hover { .date:hover {
text-decoration: underline; text-decoration: underline;
} }
.dropdown{
padding-left: 12px;
padding-right: 12px;
}
.calendar {
animation: fadeIn 0.4s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-15px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -18,13 +18,14 @@ import {DateFormatter} from '../../utils/date-formatter';
import {WeekDay} from '../../models/week-day'; import {WeekDay} from '../../models/week-day';
import {NewItemComponent} from '../../components/new-item/new-item.component'; import {NewItemComponent} from '../../components/new-item/new-item.component';
import {timeAfterStartValidator} from '../../models/validators/time-after-start-validator'; import {timeAfterStartValidator} from '../../models/validators/time-after-start-validator';
import {DropdownContentComponent} from '../../components/dropdown-content/dropdown-content.component';
@Component({ @Component({
selector: 'app-agenda', selector: 'app-agenda',
imports: [NgFor, imports: [NgFor,
TuiButton, CommonModule, NgIf, ModalComponent, ReactiveFormsModule, TuiButton, CommonModule, NgIf, ModalComponent, ReactiveFormsModule,
TuiInputTimeModule, TuiTextfieldControllerModule, TuiInputTimeModule, TuiTextfieldControllerModule,
TuiInputModule, TuiTextareaModule, TuiInputDateModule, TuiIcon, DetailsComponent, TuiCalendar, NewItemComponent], TuiInputModule, TuiTextareaModule, TuiInputDateModule, TuiIcon, DetailsComponent, TuiCalendar, NewItemComponent, DropdownContentComponent],
templateUrl: './agenda.component.html', templateUrl: './agenda.component.html',
providers: [tuiDateFormatProvider({separator: '-'}), AppointmentService], providers: [tuiDateFormatProvider({separator: '-'}), AppointmentService],
styleUrl: './agenda.component.scss' styleUrl: './agenda.component.scss'

View File

@@ -48,9 +48,7 @@ tui-avatar {
font-size: 0.8125rem; font-size: 0.8125rem;
line-height: 1.25rem; line-height: 1.25rem;
padding: 0.25rem 0.75rem; padding: 0.25rem 0.75rem;
margin-left: 4px; margin: 20px 20px 8px 4px;
margin-right: 20px;
margin-bottom: 8px;
min-width: 200px; min-width: 200px;
} }

View File

@@ -3,13 +3,13 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {Router, RouterLink, RouterLinkActive, RouterModule} from '@angular/router'; import {Router, RouterLink, RouterLinkActive, RouterModule} from '@angular/router';
import {TuiAvatar, TuiChevron,} from '@taiga-ui/kit'; import {TuiAvatar, TuiChevron,} from '@taiga-ui/kit';
import {AuthService} from '../../services/auth.service'; import {AuthService} from '../../services/auth.service';
import {User} from '../../models/user';
import {TuiButton, TuiDropdown} from '@taiga-ui/core'; import {TuiButton, TuiDropdown} from '@taiga-ui/core';
import {TuiActiveZone, TuiObscured} from '@taiga-ui/cdk'; import {TuiActiveZone, TuiObscured} from '@taiga-ui/cdk';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
import {Company} from '../../models/company'; import {Company} from '../../models/company';
import {CompanyService} from '../../services/company.service';
import {TuiSelectModule} from '@taiga-ui/legacy'; import {TuiSelectModule} from '@taiga-ui/legacy';
import {UserService} from '../../services/user.service';
import {AppUserDto, CompanyDTO} from '../../models/app-user-dto';
@Component({ @Component({
selector: 'app-home', selector: 'app-home',
@@ -18,12 +18,13 @@ import {TuiSelectModule} from '@taiga-ui/legacy';
styleUrl: './home.component.scss' styleUrl: './home.component.scss'
}) })
export class HomeComponent implements OnInit { export class HomeComponent implements OnInit {
user: User user: AppUserDto;
fullName: string fullName: string
companies: Company[] companies: CompanyDTO[];
currentCompany: CompanyDTO;
getInitials(): string { getInitials(): string {
this.user = this.authService.getUserInfo(); this.user = this.userService.userValue
this.fullName = this.user.firstName + ' ' + this.user.lastName; this.fullName = this.user.firstName + ' ' + this.user.lastName;
return this.fullName.split(' ').map((n) => n[0]).join('').substring(0, 2); return this.fullName.split(' ').map((n) => n[0]).join('').substring(0, 2);
} }
@@ -44,29 +45,23 @@ export class HomeComponent implements OnInit {
this.open = active && this.open; this.open = active && this.open;
} }
constructor(private authService: AuthService, private router: Router, private companyService: CompanyService) { constructor(private authService: AuthService, private router: Router, private userService: UserService) {
} }
ngOnInit(): void { ngOnInit(): void {
if (!this.authService.isAuthenticated()) { if (!this.userService.userValue) {
this.router.navigate(['login']); this.router.navigate(['login']);
} else { } else {
this.companyService.getCompanies().subscribe( this.companies = this.userService.userValue.companies.map(a => a.company)
response => { this.currentCompany = this.companies[0];
this.companies = response
this.authService.setCurrentCompany(response[0])
console.log(this.companies)
}
)
} }
} }
logout() { logout() {
this.authService.logout(); this.userService.clearUser();
this.router.navigate(['login']); this.router.navigate(['login']);
} }
protected readonly environment = environment; protected readonly environment = environment;
currentCompany: Company;
} }

View File

@@ -4,10 +4,11 @@ import {Router} from '@angular/router';
import {TuiAppearance, TuiButton, TuiError, TuiTextfield,} from '@taiga-ui/core'; import {TuiAppearance, TuiButton, TuiError, TuiTextfield,} from '@taiga-ui/core';
import {TuiCardLarge, TuiForm, TuiHeader} from '@taiga-ui/layout'; import {TuiCardLarge, TuiForm, TuiHeader} from '@taiga-ui/layout';
import {AuthService} from '../../services/auth.service'; import {AuthService} from '../../services/auth.service';
import {UserDto} from '../../models/user-dto'; import {AppUserDto} from '../../models/app-user-dto';
import {HttpErrorResponse} from '@angular/common/http'; import {HttpErrorResponse} from '@angular/common/http';
import {TuiValidationError} from '@taiga-ui/cdk'; import {TuiValidationError} from '@taiga-ui/cdk';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
import {UserService} from '../../services/user.service';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
@@ -35,7 +36,7 @@ export class LoginComponent {
return this.enabled ? this.error : null; return this.enabled ? this.error : null;
} }
constructor(private router: Router, private authService: AuthService) { constructor(private router: Router, private authService: AuthService, private userService: UserService) {
this.form = new FormGroup({ this.form = new FormGroup({
username: new FormControl('', Validators.required), username: new FormControl('', Validators.required),
password: new FormControl('', Validators.required) password: new FormControl('', Validators.required)
@@ -44,9 +45,10 @@ export class LoginComponent {
login() { login() {
console.log('IM LOGGING IN')
this.authService.login(this.form.get('username').value, this.form.get('password').value).subscribe({ this.authService.login(this.form.get('username').value, this.form.get('password').value).subscribe({
next: (user: UserDto) => { next: (user: AppUserDto) => {
localStorage.setItem('token', user.token); this.userService.setUser(user);
this.router.navigate(['/home/agenda']); this.router.navigate(['/home/agenda']);
}, },
error: (err: HttpErrorResponse) => { error: (err: HttpErrorResponse) => {

View File

@@ -0,0 +1,32 @@
import {Injectable} from '@angular/core';
import {environment} from '../../environments/environment';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
import {InviteEntity} from '../models/invite-entity';
@Injectable({
providedIn: 'root'
})
export class AgendaService {
baseApi = `${environment.baseApi}/agenda`;
constructor(private http: HttpClient) {
}
sendInvite(url: string, email: string): Observable<any> {
return this.http.post(`${this.baseApi}/${email}`, {url});
}
createInvite(companyId: number, email: string): Observable<InviteEntity> {
return this.http.post<InviteEntity>(`${this.baseApi}/createinvite`, {companyId: companyId, email: email});
}
verifyInvite(token: string) {
return this.http.get(this.baseApi + `/verify?token=${token}`, {})
}
acceptInvite(user: number, company: number): Observable<any> {
return this.http.post(this.baseApi + `/link?user=${user}&company=${company}`, {})
}
}

View File

@@ -18,6 +18,7 @@ export class AuthService {
} }
login(username: string, password: string): Observable<any> { login(username: string, password: string): Observable<any> {
console.log(username + ' is logging in');
return this.http.post(this.baseApi, {username, password}); return this.http.post(this.baseApi, {username, password});
} }

View File

@@ -3,6 +3,7 @@ import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {environment} from '../../environments/environment'; import {environment} from '../../environments/environment';
import {Company} from '../models/company'; import {Company} from '../models/company';
import {CompanyDTO} from '../models/app-user-dto';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -16,4 +17,13 @@ export class CompanyService {
getCompanies(): Observable<Company[]> { getCompanies(): Observable<Company[]> {
return this.http.get<Company[]>(`${this.baseApi}`); return this.http.get<Company[]>(`${this.baseApi}`);
} }
getCompany(id: number): Observable<CompanyDTO> {
console.log(id)
return this.http.get<CompanyDTO>(`${this.baseApi}/${id}`);
}
linkCompany(user: number, token: string): Observable<any> {
return this.http.post(this.baseApi + `/link?user=${user}&token=${token}`, {})
}
} }

View File

@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import {AppUserDto} from '../models/app-user-dto';
@Injectable({
providedIn: 'root'
})
export class UserService {
private userSubject = new BehaviorSubject<AppUserDto | null>(null);
get user$(): Observable<AppUserDto | null> {
return this.userSubject.asObservable();
}
get userValue(): AppUserDto | null {
return this.userSubject.value;
}
constructor() {
const storedUser = localStorage.getItem('appUser');
if (storedUser) {
this.userSubject.next(JSON.parse(storedUser));
}
}
setUser(user: AppUserDto): void {
localStorage.setItem('appUser', JSON.stringify(user));
this.userSubject.next(user);
}
clearUser(): void {
localStorage.removeItem('appUser');
this.userSubject.next(null);
}
}