@avora-labs/meta-forge 1.3.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.
- package/fesm2022/{avora-labs-meta-forge-login.page-BW-RWCQM.mjs → avora-labs-meta-forge-login.page-D72_EUGF.mjs} +58 -44
- package/fesm2022/{avora-labs-meta-forge-login.page-BW-RWCQM.mjs.map → avora-labs-meta-forge-login.page-D72_EUGF.mjs.map} +1 -1
- package/fesm2022/avora-labs-meta-forge.mjs +234 -387
- package/fesm2022/avora-labs-meta-forge.mjs.map +1 -1
- package/package.json +1 -1
- package/types/avora-labs-meta-forge.d.ts +54 -170
|
@@ -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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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-
|
|
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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"}
|