@avora-labs/meta-forge 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,57 +45,71 @@ class LoginComponent {
45
45
  config: { formId: 'loginForm' }
46
46
  });
47
47
  }
48
- onFormSubmit(values) {
48
+ async onFormSubmit(values) {
49
49
  if (!values.email || !values.password)
50
50
  return;
51
51
  this.loading.set(true);
52
- setTimeout(() => {
53
- this.loading.set(false);
54
- this.dispatcher.dispatch({
55
- type: 'open-modal',
56
- config: {
57
- title: 'Two-Step Verification',
58
- size: 'sm',
59
- content: {
60
- type: 'form',
61
- config: {
62
- fields: [
63
- {
64
- name: 'otp',
65
- label: 'Enter 6-digit PIN',
66
- type: 'otp',
67
- required: true,
68
- otpLength: 6,
69
- validation: { minLength: 6, maxLength: 6 }
70
- }
71
- ],
72
- submitLabel: 'Verify & Login',
73
- loadingLabel: 'Verifying...',
74
- onSubmit: {
75
- type: 'api',
76
- config: { endpointId: 'mock-login-otp', body: 'formValue' },
77
- then: {
78
- type: 'dispatch-multiple',
79
- config: {
80
- mode: 'parallel',
81
- actions: [
82
- { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },
83
- { type: 'close-modal' },
84
- {
85
- type: 'delay',
86
- config: { duration: 600 },
87
- then: { type: 'navigate', config: { path: '/dashboard' } }
88
- }
89
- ]
52
+ // Check if OTP is required by user preferences
53
+ const requireOtp = this.meta.auth?.builtInUI?.requireOtp === true;
54
+ try {
55
+ await this.auth.login(values, requireOtp);
56
+ if (requireOtp) {
57
+ this.dispatcher.dispatch({
58
+ type: 'open-modal',
59
+ config: {
60
+ title: 'Two-Step Verification',
61
+ size: 'sm',
62
+ content: {
63
+ type: 'form',
64
+ config: {
65
+ fields: [
66
+ {
67
+ name: 'otp',
68
+ label: 'Enter 6-digit PIN',
69
+ type: 'otp',
70
+ required: true,
71
+ otpLength: 6,
72
+ validation: { minLength: 6, maxLength: 6 }
90
73
  }
91
- },
92
- onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }
74
+ ],
75
+ submitLabel: 'Verify & Login',
76
+ loadingLabel: 'Verifying...',
77
+ onSubmit: {
78
+ type: 'api',
79
+ // In a real system this would hit a real OTP verify endpoint
80
+ config: { endpointId: 'mock-login-otp', body: 'formValue' },
81
+ then: {
82
+ type: 'dispatch-multiple',
83
+ config: {
84
+ mode: 'parallel',
85
+ actions: [
86
+ { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },
87
+ { type: 'close-modal' },
88
+ {
89
+ type: 'delay',
90
+ config: { duration: 600 },
91
+ then: { type: 'navigate', config: { path: '/dashboard' } }
92
+ }
93
+ ]
94
+ }
95
+ },
96
+ onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }
97
+ }
93
98
  }
94
99
  }
95
100
  }
96
- }
101
+ });
102
+ }
103
+ }
104
+ catch (err) {
105
+ this.dispatcher.dispatch({
106
+ type: 'notify',
107
+ config: { type: 'error', message: err.message || 'Login failed' }
97
108
  });
98
- }, 1200);
109
+ }
110
+ finally {
111
+ this.loading.set(false);
112
+ }
99
113
  }
100
114
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: LoginComponent, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Component });
101
115
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: LoginComponent, isStandalone: true, selector: "amf-login", ngImport: i0, template: `
@@ -178,4 +192,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
178
192
  }], ctorParameters: () => [{ type: i1.Router }] });
179
193
 
180
194
  export { LoginComponent };
181
- //# sourceMappingURL=avora-labs-meta-forge-login.page-BW-RWCQM.mjs.map
195
+ //# sourceMappingURL=avora-labs-meta-forge-login.page-D72_EUGF.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"avora-labs-meta-forge-login.page-BW-RWCQM.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/login.page.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\nimport { AuthService } from '../../../core/auth/auth.service';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\n@Component({\n selector: 'amf-login',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\" \n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'\">\n \n <div class=\"login-form-container\">\n <!-- AMF Data-Driven Form Definition -->\n <amf-form-renderer \n #renderer\n [config]=\"loginForm\" \n (formSubmit)=\"onFormSubmit($event)\">\n </amf-form-renderer>\n\n <!-- Custom Inline Options Row -->\n <div class=\"form-options\">\n <label class=\"remember-me\">\n <input type=\"checkbox\" name=\"remember\" [(ngModel)]=\"rememberMe\">\n <span class=\"custom-check\"></span>\n <span>Remember me</span>\n </label>\n <a routerLink=\"/forgot-password\" class=\"forgot-link\">Forgot password?</a>\n </div>\n\n <button type=\"button\" class=\"login-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading()\">\n @if (!loading()) {\n <span>Sign In</span>\n } @else {\n <div class=\"loader\"></div>\n }\n </button>\n </div>\n\n <div class=\"auth-footer-note\">\n Don't have an account? <a routerLink=\"/contact-support\">Contact Support</a>\n </div>\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n .login-form-container {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .login-form-container .amf-form {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-form-fields {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n ::ng-deep .login-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255, 255, 255, 0.08) !important;\n background: rgba(255, 255, 255, 0.04) !important;\n transition: all 0.3s !important;\n overflow: hidden;\n box-shadow: none !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255, 255, 255, 0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .login-form-container .field-input {\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: 1rem !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .login-form-container .field-input::placeholder {\n color: #64748b !important;\n }\n /* Adjust password eye toggle specifically for this glass look */\n ::ng-deep .login-form-container .pwd-toggle-btn {\n color: #64748b !important;\n }\n ::ng-deep .login-form-container .pwd-toggle-btn:hover {\n color: var(--app-primary, #6366f1) !important;\n }\n\n .form-options {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 0.875rem;\n }\n\n .remember-me {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n color: #94a3b8;\n }\n\n .remember-me input { display: none; }\n\n .custom-check {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n position: relative;\n transition: all 0.2s;\n }\n\n .remember-me input:checked + .custom-check {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n border-color: transparent;\n }\n\n .remember-me input:checked + .custom-check::after {\n content: '';\n position: absolute;\n left: 5px; top: 2px;\n width: 4px; height: 7px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .forgot-link {\n color: var(--app-primary, #6366f1);\n font-weight: 500;\n transition: all 0.2s;\n text-decoration: none;\n }\n\n .forgot-link:hover {\n text-shadow: 0 0 12px var(--app-glow, rgba(99,102,241,0.3));\n }\n\n .login-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: 14px;\n border: none;\n border-radius: 12px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .login-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n\n .login-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n transform: none;\n }\n\n .auth-footer-note {\n text-align: center;\n margin-top: 32px;\n font-size: 0.875rem;\n color: #64748b;\n }\n\n .auth-footer-note a {\n color: var(--app-primary, #6366f1);\n font-weight: 600;\n text-decoration: none;\n }\n\n .loader {\n width: 20px;\n height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top: 3px solid white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `]\n})\nexport class LoginComponent {\n private auth = inject(AuthService);\n private dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n rememberMe = false;\n\n // JSON Meta Definition replacing the hardcoded HTML fields\n loginForm: FormMeta = {\n id: 'loginForm',\n hideSubmit: true, // We provide our own exact-match custom button below\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'password',\n type: 'password',\n label: 'Password',\n placeholder: '••••••••',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor(private router: Router) { }\n\n triggerSubmit(): void {\n // Dispatches standard AMF action to submit the specific form\n this.dispatcher.dispatch({\n type: 'submit-form',\n config: { formId: 'loginForm' }\n });\n }\n\n onFormSubmit(values: any): void {\n if (!values.email || !values.password) return;\n\n this.loading.set(true);\n\n setTimeout(() => {\n this.loading.set(false);\n \n this.dispatcher.dispatch({\n type: 'open-modal',\n config: {\n title: 'Two-Step Verification',\n size: 'sm',\n content: {\n type: 'form',\n config: {\n fields: [\n {\n name: 'otp',\n label: 'Enter 6-digit PIN',\n type: 'otp',\n required: true,\n otpLength: 6,\n validation: { minLength: 6, maxLength: 6 }\n }\n ],\n submitLabel: 'Verify & Login',\n loadingLabel: 'Verifying...',\n onSubmit: {\n type: 'api',\n config: { endpointId: 'mock-login-otp', body: 'formValue' },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'parallel',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },\n { type: 'close-modal' },\n { \n type: 'delay', \n config: { duration: 600 }, \n then: { type: 'navigate', config: { path: '/dashboard' } } \n }\n ]\n }\n },\n onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }\n }\n }\n }\n }\n });\n }, 1200);\n }\n}\n"],"names":["i2"],"mappings":"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"}
1
+ {"version":3,"file":"avora-labs-meta-forge-login.page-D72_EUGF.mjs","sources":["../../../projects/avora-meta-forge/src/lib/avora-meta-forge/pages/auth/login.page.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router, RouterModule } from '@angular/router';\nimport { AuthService } from '../../../core/auth/auth.service';\nimport { ActionDispatcherService } from '../../core/action-dispatcher.service';\nimport { AmfAuthShellComponent } from '../../renderers/auth/amf-auth-shell.component';\nimport { FormRendererComponent } from '../../renderers/form/form-renderer.component';\nimport { FormMeta } from '../../models/meta.types';\nimport { APP_META_CONFIG_TOKEN } from '../../avora-meta-forge.provider';\n@Component({\n selector: 'amf-login',\n standalone: true,\n imports: [FormsModule, RouterModule, AmfAuthShellComponent, FormRendererComponent],\n template: `\n <amf-auth-shell \n [brandName]=\"meta.auth?.builtInUI?.brandName || meta.app.name\" \n [brandTagline]=\"meta.auth?.builtInUI?.brandTagline || 'Sign in to your account'\">\n \n <div class=\"login-form-container\">\n <!-- AMF Data-Driven Form Definition -->\n <amf-form-renderer \n #renderer\n [config]=\"loginForm\" \n (formSubmit)=\"onFormSubmit($event)\">\n </amf-form-renderer>\n\n <!-- Custom Inline Options Row -->\n <div class=\"form-options\">\n <label class=\"remember-me\">\n <input type=\"checkbox\" name=\"remember\" [(ngModel)]=\"rememberMe\">\n <span class=\"custom-check\"></span>\n <span>Remember me</span>\n </label>\n <a routerLink=\"/forgot-password\" class=\"forgot-link\">Forgot password?</a>\n </div>\n\n <button type=\"button\" class=\"login-btn\" (click)=\"triggerSubmit()\" [disabled]=\"loading()\">\n @if (!loading()) {\n <span>Sign In</span>\n } @else {\n <div class=\"loader\"></div>\n }\n </button>\n </div>\n\n <div class=\"auth-footer-note\">\n Don't have an account? <a routerLink=\"/contact-support\">Contact Support</a>\n </div>\n </amf-auth-shell>\n `,\n styles: [`\n :host { display: block; height: 100%; }\n\n .login-form-container {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n /* ── Map AMF Form classes to exactly match input-glass style ── */\n ::ng-deep .login-form-container .amf-form {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-form-fields {\n gap: 24px;\n }\n ::ng-deep .login-form-container .amf-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n ::ng-deep .login-form-container .field-label {\n font-size: 0.875rem !important;\n font-weight: 600 !important;\n color: #cbd5e1 !important;\n margin-bottom: 0 !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper {\n border-radius: 12px !important;\n border: 1px solid rgba(255, 255, 255, 0.08) !important;\n background: rgba(255, 255, 255, 0.04) !important;\n transition: all 0.3s !important;\n overflow: hidden;\n box-shadow: none !important;\n }\n ::ng-deep .login-form-container .field-input-wrapper:focus-within {\n border-color: var(--app-primary, #6366f1) !important;\n background: rgba(255, 255, 255, 0.06) !important;\n box-shadow: 0 0 20px var(--app-glow, rgba(99,102,241,0.3)) !important;\n }\n ::ng-deep .login-form-container .field-input {\n padding: 13px 16px !important;\n border: none !important;\n background: transparent !important;\n font-size: 1rem !important;\n color: #f1f5f9 !important;\n }\n ::ng-deep .login-form-container .field-input::placeholder {\n color: #64748b !important;\n }\n /* Adjust password eye toggle specifically for this glass look */\n ::ng-deep .login-form-container .pwd-toggle-btn {\n color: #64748b !important;\n }\n ::ng-deep .login-form-container .pwd-toggle-btn:hover {\n color: var(--app-primary, #6366f1) !important;\n }\n\n .form-options {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 0.875rem;\n }\n\n .remember-me {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n color: #94a3b8;\n }\n\n .remember-me input { display: none; }\n\n .custom-check {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n position: relative;\n transition: all 0.2s;\n }\n\n .remember-me input:checked + .custom-check {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n border-color: transparent;\n }\n\n .remember-me input:checked + .custom-check::after {\n content: '';\n position: absolute;\n left: 5px; top: 2px;\n width: 4px; height: 7px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .forgot-link {\n color: var(--app-primary, #6366f1);\n font-weight: 500;\n transition: all 0.2s;\n text-decoration: none;\n }\n\n .forgot-link:hover {\n text-shadow: 0 0 12px var(--app-glow, rgba(99,102,241,0.3));\n }\n\n .login-btn {\n background: linear-gradient(135deg, var(--app-primary, #6366f1), var(--app-accent, #c084fc));\n color: white;\n padding: 14px;\n border: none;\n border-radius: 12px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .login-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 30px -5px var(--app-glow, rgba(99,102,241,0.5));\n }\n\n .login-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n transform: none;\n }\n\n .auth-footer-note {\n text-align: center;\n margin-top: 32px;\n font-size: 0.875rem;\n color: #64748b;\n }\n\n .auth-footer-note a {\n color: var(--app-primary, #6366f1);\n font-weight: 600;\n text-decoration: none;\n }\n\n .loader {\n width: 20px;\n height: 20px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top: 3px solid white;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `]\n})\nexport class LoginComponent {\n private auth = inject(AuthService);\n private dispatcher = inject(ActionDispatcherService);\n protected meta: any = inject(APP_META_CONFIG_TOKEN, { optional: true }) || { app: { name: 'AvoraMetaForge' } };\n\n loading = signal(false);\n rememberMe = false;\n\n // JSON Meta Definition replacing the hardcoded HTML fields\n loginForm: FormMeta = {\n id: 'loginForm',\n hideSubmit: true, // We provide our own exact-match custom button below\n fields: [\n {\n key: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'name@company.com',\n validators: [{ type: 'required' }]\n },\n {\n key: 'password',\n type: 'password',\n label: 'Password',\n placeholder: '••••••••',\n validators: [{ type: 'required' }]\n }\n ]\n };\n\n constructor(private router: Router) { }\n\n triggerSubmit(): void {\n // Dispatches standard AMF action to submit the specific form\n this.dispatcher.dispatch({\n type: 'submit-form',\n config: { formId: 'loginForm' }\n });\n }\n\n async onFormSubmit(values: any): Promise<void> {\n if (!values.email || !values.password) return;\n\n this.loading.set(true);\n \n // Check if OTP is required by user preferences\n const requireOtp = this.meta.auth?.builtInUI?.requireOtp === true;\n\n try {\n await this.auth.login(values, requireOtp);\n \n if (requireOtp) {\n this.dispatcher.dispatch({\n type: 'open-modal',\n config: {\n title: 'Two-Step Verification',\n size: 'sm',\n content: {\n type: 'form',\n config: {\n fields: [\n {\n name: 'otp',\n label: 'Enter 6-digit PIN',\n type: 'otp',\n required: true,\n otpLength: 6,\n validation: { minLength: 6, maxLength: 6 }\n }\n ],\n submitLabel: 'Verify & Login',\n loadingLabel: 'Verifying...',\n onSubmit: {\n type: 'api',\n // In a real system this would hit a real OTP verify endpoint\n config: { endpointId: 'mock-login-otp', body: 'formValue' },\n then: {\n type: 'dispatch-multiple',\n config: {\n mode: 'parallel',\n actions: [\n { type: 'notify', config: { type: 'success', message: 'OTP Verified! Redirecting...' } },\n { type: 'close-modal' },\n { \n type: 'delay', \n config: { duration: 600 }, \n then: { type: 'navigate', config: { path: '/dashboard' } } \n }\n ]\n }\n },\n onError: { type: 'notify', config: { type: 'error', message: 'Invalid Verification Code' } }\n }\n }\n }\n }\n });\n }\n } catch (err: any) {\n this.dispatcher.dispatch({\n type: 'notify',\n config: { type: 'error', message: err.message || 'Login failed' }\n });\n } finally {\n this.loading.set(false);\n }\n }\n}\n"],"names":["i2"],"mappings":"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"}