Skip to content

Commit 67fe85d

Browse files
feat: Implement initial Angular frontend and NestJS backend project structure with authentication.
1 parent 6bd5941 commit 67fe85d

12 files changed

Lines changed: 207 additions & 193 deletions

File tree

backend/src/main.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ async function bootstrap() {
1414
transform: true,
1515
}),
1616
);
17+
app.enableCors({
18+
origin: '*',
19+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
20+
credentials: true,
21+
allowedHeaders: '*',
22+
maxAge: 3600,
23+
});
1724
const PORT = configService.get<number>('port') || 3000;
25+
1826
await app.listen(PORT);
1927
}
2028
bootstrap();

frontend/angular.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
"production": {
3434
"fileReplacements": [
3535
{
36-
"replace": "src/environments/environment.ts",
37-
"with": "src/environments/environment.prod.ts"
36+
"replace": "./src/environments/environment.ts",
37+
"with": "./src/environments/environment.prod.ts"
3838
}
3939
],
4040
"outputHashing": "all"
@@ -66,7 +66,7 @@
6666
"buildTarget": "mavluda-beauty:build:production"
6767
},
6868
"development": {
69-
"buildTarget": "mavluda-beauty:build:production"
69+
"buildTarget": "mavluda-beauty:build:development"
7070
},
7171
"en": {
7272
"buildTarget": "mavluda-beauty:build:production,en"

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "0.0.0",
55
"type": "module",
66
"scripts": {
7-
"dev": "ng serve",
7+
"dev": "ng serve --configuration=development",
88
"build": "ng build",
99
"preview": "ng serve --configuration=production"
1010
},

frontend/src/app/app.config.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
22
import { provideRouter, withHashLocation } from '@angular/router';
33
import { routes } from '@src/app.routes';
4-
import { provideHttpClient, withFetch } from '@angular/common/http';
5-
4+
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
5+
import { apiInterceptor } from './core/interceptors/api.interceptor';
66

77
export const appConfig: ApplicationConfig = {
88
providers: [
99
provideZonelessChangeDetection(),
1010
provideRouter(routes, withHashLocation()),
11-
provideHttpClient(withFetch()),
12-
11+
provideHttpClient(withFetch(), withInterceptors([apiInterceptor])),
1312
],
1413
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { HttpInterceptorFn } from '@angular/common/http';
2+
import { environment } from '@environments/environment';
3+
4+
export const apiInterceptor: HttpInterceptorFn = (req, next) => {
5+
if (req.url.startsWith('/')) {
6+
const apiReq = req.clone({
7+
url: `${environment.apiUrl}${req.url}`
8+
});
9+
return next(apiReq);
10+
}
11+
return next(req);
12+
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const environment = {
22
production: true,
3-
apiUrl: 'https://api.yourdomain.com/api',
3+
apiUrl: 'http://localhost:4100',
44
telegramBotName: 'MavludaBeautyBot'
55
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const environment = {
22
production: false,
3-
apiUrl: 'http://localhost:3000/api',
3+
apiUrl: 'http://localhost:4100',
44
telegramBotName: 'test_bot'
55
};

frontend/src/pages/auth/auth.component.html

Lines changed: 99 additions & 173 deletions
Large diffs are not rendered by default.

frontend/src/pages/auth/auth.component.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Component, ChangeDetectionStrategy, inject, signal } from '@angular/cor
33
import { CommonModule, DOCUMENT } from '@angular/common';
44
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
55
import { Router } from '@angular/router';
6-
import { AuthService } from '@shared/services/auth.service';
7-
import { LanguageSwitcherComponent } from '@features/language-selection/language-switcher.component';
6+
import { AuthService } from '../../shared/services/auth.service';
7+
import { LanguageSwitcherComponent } from '../../features/language-selection/language-switcher.component';
88

99
@Component({
1010
selector: 'app-auth',
@@ -25,15 +25,56 @@ export class AuthComponent {
2525
isLoading = signal(false);
2626
showPassword = signal(false);
2727
isDarkMode = signal(this.document.documentElement.classList.contains('dark'));
28+
29+
// 'signin' or 'signup' mode
30+
authMode = signal<'signin' | 'signup'>('signin');
2831

2932
loginForm = this.fb.group({
33+
firstName: [''],
34+
lastName: [''],
35+
phone: [''],
3036
email: ['admin@mavluda.beauty', [Validators.required, Validators.email]],
3137
password: ['password123', [Validators.required, Validators.minLength(6)]],
3238
rememberMe: [false]
3339
});
3440

35-
setRole(role: 'admin' | 'client') {
36-
this.authService.currentUserRole.set(role);
41+
setAuthMode(mode: 'signin' | 'signup') {
42+
this.authMode.set(mode);
43+
const firstNameControl = this.loginForm.get('firstName');
44+
const lastNameControl = this.loginForm.get('lastName');
45+
const phoneControl = this.loginForm.get('phone');
46+
47+
if (mode === 'signup') {
48+
firstNameControl?.setValidators([Validators.required]);
49+
lastNameControl?.setValidators([Validators.required]);
50+
phoneControl?.setValidators([Validators.required]);
51+
52+
// Clear defaults for signup
53+
if (this.loginForm.get('email')?.value === 'admin@mavluda.beauty') {
54+
this.loginForm.patchValue({
55+
firstName: '',
56+
lastName: '',
57+
phone: '',
58+
email: '',
59+
password: ''
60+
});
61+
}
62+
} else {
63+
firstNameControl?.clearValidators();
64+
lastNameControl?.clearValidators();
65+
phoneControl?.clearValidators();
66+
67+
// Restore default admin credentials for demo convenience if empty
68+
if (!this.loginForm.get('email')?.value) {
69+
this.loginForm.patchValue({
70+
email: 'admin@mavluda.beauty',
71+
password: 'password123'
72+
});
73+
}
74+
}
75+
firstNameControl?.updateValueAndValidity();
76+
lastNameControl?.updateValueAndValidity();
77+
phoneControl?.updateValueAndValidity();
3778
}
3879

3980
togglePassword() {
@@ -54,6 +95,15 @@ export class AuthComponent {
5495
onSubmit() {
5596
if (this.loginForm.valid) {
5697
this.isLoading.set(true);
98+
99+
// Auto-determine role based on email credential for MVP demo
100+
const email = this.loginForm.get('email')?.value || '';
101+
if (email.includes('admin')) {
102+
this.authService.currentUserRole.set('admin');
103+
} else {
104+
this.authService.currentUserRole.set('client');
105+
}
106+
57107
// Simulate API call
58108
setTimeout(() => {
59109
this.isLoading.set(false);
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11

2-
import { Component, ChangeDetectionStrategy } from '@angular/core';
2+
import { Component, ChangeDetectionStrategy, inject, OnInit } from '@angular/core';
33
import { CommonModule, NgOptimizedImage } from '@angular/common';
44
import { RouterLink } from '@angular/router';
5+
import { HttpClient } from '@angular/common/http';
6+
import { API_ENDPOINTS } from '@shared/api/api-endpoints';
57

68
@Component({
79
selector: 'app-user-home',
@@ -11,6 +13,12 @@ import { RouterLink } from '@angular/router';
1113
templateUrl: './user-home.component.html',
1214
styleUrls: ['./user-home.component.scss']
1315
})
14-
export class UserHomeComponent {
15-
// Component logic can be added here if needed in the future.
16+
export class UserHomeComponent implements OnInit {
17+
http = inject(HttpClient);
18+
19+
ngOnInit(): void {
20+
this.http.get(API_ENDPOINTS.AdminSettings).subscribe((res) => {
21+
console.log(res);
22+
});
23+
}
1624
}

0 commit comments

Comments
 (0)