From a92f070cb02706c9268d846ac43b0f7c69e6c53e Mon Sep 17 00:00:00 2001 From: Neethika Date: Sat, 11 Apr 2026 17:27:16 -0400 Subject: [PATCH] feat(auth): add signup profile fields --- src/app/components/login/login.css | 22 +++++++++++++++++++ src/app/components/login/login.html | 23 ++++++++++++++++++++ src/app/components/login/login.spec.ts | 4 ++++ src/app/components/login/login.ts | 29 +++++++++++++++++++++++--- src/app/services/auth.ts | 16 ++++++++++++-- 5 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/app/components/login/login.css b/src/app/components/login/login.css index 556a354..87539da 100644 --- a/src/app/components/login/login.css +++ b/src/app/components/login/login.css @@ -218,12 +218,26 @@ h1 { animation: fadeIn 0.25s ease; } +.profile-grid { + display: grid; + grid-template-columns: 1fr; + gap: 10px; +} + .input-label { font-size: 13px; color: var(--muted); font-weight: 600; } +.optional-label { + display: inline-block; + margin-left: 4px; + font-weight: 500; + color: var(--muted); + letter-spacing: 0.01em; +} + .input-field { width: 100%; border: 1px solid var(--border); @@ -243,6 +257,13 @@ h1 { border-color: var(--error); } +.subtle-copy { + margin: -2px 0 4px; + color: var(--muted); + font-size: 13px; + line-height: 1.5; +} + .form-row { margin: 2px 0 6px; width: 100%; @@ -252,6 +273,7 @@ h1 { gap: 10px; } + .checkbox-wrapper { display: flex; align-items: center; diff --git a/src/app/components/login/login.html b/src/app/components/login/login.html index caf3036..99315bf 100644 --- a/src/app/components/login/login.html +++ b/src/app/components/login/login.html @@ -71,6 +71,11 @@

Welcome back

+ + + Welcome back +
+
+ + +
+ +
+ + +
+
+ +

These details help identify people across workspaces, signals, and integrations.

+ diff --git a/src/app/components/login/login.spec.ts b/src/app/components/login/login.spec.ts index 39daf48..2852bd6 100644 --- a/src/app/components/login/login.spec.ts +++ b/src/app/components/login/login.spec.ts @@ -130,6 +130,7 @@ describe('Login', () => { it('rejects registration when the email format is invalid', () => { component.activeTab = 'register'; + component.regFullName = 'Alex Rivera'; component.regEmail = 'invalid-email'; component.regPassword = 'secret'; @@ -140,6 +141,7 @@ describe('Login', () => { }); it('disables registration when the email format is invalid', () => { + component.regFullName = 'Alex Rivera'; component.regEmail = 'invalid-email'; component.regPassword = 'secret'; @@ -151,6 +153,7 @@ describe('Login', () => { throwError(() => new HttpErrorResponse({ status: 409, error: 'already exists' })) ); component.activeTab = 'register'; + component.regFullName = 'Alex Rivera'; component.regEmail = 'user@example.com'; component.regPassword = 'secret'; @@ -164,6 +167,7 @@ describe('Login', () => { spyOn(router, 'navigate'); mockAuthService.signup.and.returnValue(of(void 0)); component.activeTab = 'register'; + component.regFullName = 'Alex Rivera'; component.regEmail = 'new@example.com'; component.regPassword = 'secret'; diff --git a/src/app/components/login/login.ts b/src/app/components/login/login.ts index e3e2c38..686367b 100644 --- a/src/app/components/login/login.ts +++ b/src/app/components/login/login.ts @@ -25,8 +25,11 @@ export class Login implements OnInit { registerError = ''; forgotError = ''; + regFullName = ''; regEmail = ''; regPassword = ''; + regJobTitle = ''; + regOrganization = ''; forgotEmail = ''; @@ -116,7 +119,7 @@ export class Login implements OnInit { } handleRegister(): void { - if (!this.regEmail.trim() || !this.regPassword.trim()) { + if (!this.regFullName.trim() || !this.regEmail.trim() || !this.regPassword.trim()) { this.registerError = 'Invalid credentials'; return; } @@ -127,7 +130,11 @@ export class Login implements OnInit { this.isRegisterSubmitting = true; this.registerError = ''; - this.authService.signup(this.regEmail.trim(), this.regPassword).pipe( + this.authService.signup(this.regEmail.trim(), this.regPassword, { + fullName: this.regFullName.trim(), + jobTitle: this.regJobTitle.trim(), + organization: this.regOrganization.trim(), + }).pipe( timeout(8000), finalize(() => { this.isRegisterSubmitting = false; @@ -135,8 +142,12 @@ export class Login implements OnInit { }) ).subscribe({ next: () => { + this.regFullName = ''; this.regPassword = ''; + this.regJobTitle = ''; + this.regOrganization = ''; this.loginEmail = this.regEmail.trim(); + this.regEmail = ''; this.showForgot = false; this.loginError = ''; this.registerError = ''; @@ -199,7 +210,7 @@ export class Login implements OnInit { } get isRegisterDisabled(): boolean { - return !this.regEmail.trim() || !this.regPassword || !this.isValidEmail(this.regEmail); + return !this.regFullName.trim() || !this.regEmail.trim() || !this.regPassword || !this.isValidEmail(this.regEmail); } get isAuthFormVisible(): boolean { @@ -234,10 +245,22 @@ export class Login implements OnInit { this.registerError = ''; } + onRegisterFullNameInput(): void { + this.registerError = ''; + } + onRegisterPasswordInput(): void { this.registerError = ''; } + onRegisterJobTitleInput(): void { + this.registerError = ''; + } + + onRegisterOrganizationInput(): void { + this.registerError = ''; + } + onForgotEmailInput(): void { this.forgotError = ''; } diff --git a/src/app/services/auth.ts b/src/app/services/auth.ts index 2f58e01..ec73b11 100644 --- a/src/app/services/auth.ts +++ b/src/app/services/auth.ts @@ -6,6 +6,12 @@ interface AuthResponse { token: string; } +export interface SignupProfile { + fullName: string; + jobTitle?: string; + organization?: string; +} + @Injectable({ providedIn: 'root', }) @@ -14,8 +20,14 @@ export class AuthService { private apiUrl = '/api'; private tokenKey = 'sentinent_token'; - signup(email: string, password: string): Observable { - return this.http.post(`${this.apiUrl}/signup`, { email, password }, { + signup(email: string, password: string, profile?: SignupProfile): Observable { + return this.http.post(`${this.apiUrl}/signup`, { + email, + password, + full_name: profile?.fullName ?? '', + job_title: profile?.jobTitle ?? '', + organization: profile?.organization ?? '', + }, { observe: 'response', responseType: 'text' }).pipe(