valtech-components 4.0.80 → 4.0.83
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/esm2022/lib/components/molecules/feedback-form/feedback-form.component.mjs +88 -63
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +83 -60
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/feedback-form/feedback-form.component.d.ts +6 -3
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
|
|
|
56
56
|
* Current version of valtech-components.
|
|
57
57
|
* This is automatically updated during the publish process.
|
|
58
58
|
*/
|
|
59
|
-
const VERSION = '4.0.
|
|
59
|
+
const VERSION = '4.0.83';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -64193,19 +64193,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
64193
64193
|
* ```
|
|
64194
64194
|
*/
|
|
64195
64195
|
|
|
64196
|
+
const FEEDBACK_FORM_I18N = {
|
|
64197
|
+
es: {
|
|
64198
|
+
formTitle: 'Enviar feedback',
|
|
64199
|
+
formSubtitle: 'Cuéntanos qué piensas. Bugs, sugerencias y mejoras.',
|
|
64200
|
+
feedbackType: 'Tipo',
|
|
64201
|
+
title: 'Título',
|
|
64202
|
+
titlePlaceholder: 'Resumen corto (5–120 caracteres)',
|
|
64203
|
+
titleValidation: 'El título debe tener entre 5 y 120 caracteres',
|
|
64204
|
+
description: 'Descripción',
|
|
64205
|
+
descriptionPlaceholder: 'Describe el problema o sugerencia en detalle...',
|
|
64206
|
+
descriptionHint: 'Capturamos automáticamente tu navegador, SO y URL actual.',
|
|
64207
|
+
descriptionValidation: 'La descripción debe tener entre 10 y 2000 caracteres',
|
|
64208
|
+
submit: 'Enviar',
|
|
64209
|
+
feedbackSuccess: '¡Gracias por tu feedback!',
|
|
64210
|
+
feedbackError: 'No se pudo enviar el feedback. Inténtalo de nuevo.',
|
|
64211
|
+
},
|
|
64212
|
+
en: {
|
|
64213
|
+
formTitle: 'Send feedback',
|
|
64214
|
+
formSubtitle: 'Tell us what you think. Bugs, suggestions and improvements.',
|
|
64215
|
+
feedbackType: 'Type',
|
|
64216
|
+
title: 'Title',
|
|
64217
|
+
titlePlaceholder: 'Short summary (5–120 chars)',
|
|
64218
|
+
titleValidation: 'Title must be between 5 and 120 characters',
|
|
64219
|
+
description: 'Description',
|
|
64220
|
+
descriptionPlaceholder: 'Describe the problem or suggestion in detail...',
|
|
64221
|
+
descriptionHint: 'We automatically capture your browser, OS and current URL.',
|
|
64222
|
+
descriptionValidation: 'Description must be between 10 and 2000 characters',
|
|
64223
|
+
submit: 'Send',
|
|
64224
|
+
feedbackSuccess: 'Thanks for your feedback!',
|
|
64225
|
+
feedbackError: 'Could not send feedback. Please try again.',
|
|
64226
|
+
},
|
|
64227
|
+
};
|
|
64196
64228
|
class FeedbackFormComponent {
|
|
64197
64229
|
constructor() {
|
|
64198
64230
|
this.props = {};
|
|
64199
64231
|
this.onSubmit = new EventEmitter();
|
|
64200
64232
|
this.onCancel = new EventEmitter();
|
|
64233
|
+
this.onError = new EventEmitter();
|
|
64201
64234
|
this.i18n = inject(I18nService);
|
|
64202
64235
|
this.feedbackService = inject(FeedbackService);
|
|
64236
|
+
this.toast = inject(ToastService);
|
|
64237
|
+
this.errors = inject(ValtechErrorService);
|
|
64203
64238
|
this.typeOptions = DEFAULT_FEEDBACK_TYPE_OPTIONS;
|
|
64204
64239
|
this.isSubmitting = signal(false);
|
|
64205
|
-
this.
|
|
64206
|
-
this.error = signal(null);
|
|
64240
|
+
this.uploadFn = (file) => this.feedbackService.uploadAttachment(file);
|
|
64207
64241
|
this.currentAttachments = [];
|
|
64208
|
-
|
|
64242
|
+
this.i18n.registerDefaults('FeedbackForm', FEEDBACK_FORM_I18N);
|
|
64209
64243
|
}
|
|
64210
64244
|
ngOnInit() {
|
|
64211
64245
|
if (this.props.enabledTypes?.length) {
|
|
@@ -64228,7 +64262,7 @@ class FeedbackFormComponent {
|
|
|
64228
64262
|
fields.push({
|
|
64229
64263
|
token: 'feedback-type',
|
|
64230
64264
|
name: 'type',
|
|
64231
|
-
label: this.
|
|
64265
|
+
label: this.tt('feedbackType'),
|
|
64232
64266
|
hint: '',
|
|
64233
64267
|
placeholder: '',
|
|
64234
64268
|
type: InputType.SELECT,
|
|
@@ -64243,32 +64277,32 @@ class FeedbackFormComponent {
|
|
|
64243
64277
|
fields.push({
|
|
64244
64278
|
token: 'feedback-title',
|
|
64245
64279
|
name: 'title',
|
|
64246
|
-
label: this.props.titleLabel ?? this.
|
|
64280
|
+
label: this.props.titleLabel ?? this.tt('title'),
|
|
64247
64281
|
hint: '',
|
|
64248
|
-
placeholder: this.props.titlePlaceholder ?? this.
|
|
64282
|
+
placeholder: this.props.titlePlaceholder ?? this.tt('titlePlaceholder'),
|
|
64249
64283
|
type: InputType.TEXT,
|
|
64250
64284
|
order: 2,
|
|
64251
|
-
validators: [Validators.required, Validators.minLength(5), Validators.maxLength(
|
|
64285
|
+
validators: [Validators.required, Validators.minLength(5), Validators.maxLength(120)],
|
|
64252
64286
|
errors: {
|
|
64253
|
-
required: this.
|
|
64254
|
-
minlength: this.
|
|
64255
|
-
maxlength: this.
|
|
64287
|
+
required: this.tt('titleValidation'),
|
|
64288
|
+
minlength: this.tt('titleValidation'),
|
|
64289
|
+
maxlength: this.tt('titleValidation'),
|
|
64256
64290
|
},
|
|
64257
64291
|
state: ComponentStates.ENABLED,
|
|
64258
64292
|
}, {
|
|
64259
64293
|
token: 'feedback-description',
|
|
64260
64294
|
name: 'description',
|
|
64261
|
-
label: this.props.descriptionLabel ?? this.
|
|
64262
|
-
hint: '',
|
|
64263
|
-
placeholder: this.props.descriptionPlaceholder ?? this.
|
|
64295
|
+
label: this.props.descriptionLabel ?? this.tt('description'),
|
|
64296
|
+
hint: this.tt('descriptionHint'),
|
|
64297
|
+
placeholder: this.props.descriptionPlaceholder ?? this.tt('descriptionPlaceholder'),
|
|
64264
64298
|
type: InputType.TEXTAREA,
|
|
64265
64299
|
order: 3,
|
|
64266
64300
|
range: { min: 10, max: 2000 },
|
|
64267
64301
|
validators: [Validators.required, Validators.minLength(10), Validators.maxLength(2000)],
|
|
64268
64302
|
errors: {
|
|
64269
|
-
required: this.
|
|
64270
|
-
minlength: this.
|
|
64271
|
-
maxlength: this.
|
|
64303
|
+
required: this.tt('descriptionValidation'),
|
|
64304
|
+
minlength: this.tt('descriptionValidation'),
|
|
64305
|
+
maxlength: this.tt('descriptionValidation'),
|
|
64272
64306
|
},
|
|
64273
64307
|
state: ComponentStates.ENABLED,
|
|
64274
64308
|
});
|
|
@@ -64279,7 +64313,7 @@ class FeedbackFormComponent {
|
|
|
64279
64313
|
type: 'submit',
|
|
64280
64314
|
color: 'dark',
|
|
64281
64315
|
shape: 'round',
|
|
64282
|
-
text: this.props.submitButtonText ?? this.
|
|
64316
|
+
text: this.props.submitButtonText ?? this.tt('submit'),
|
|
64283
64317
|
state: ComponentStates.ENABLED,
|
|
64284
64318
|
expand: 'block',
|
|
64285
64319
|
},
|
|
@@ -64292,8 +64326,6 @@ class FeedbackFormComponent {
|
|
|
64292
64326
|
if (this.currentAttachments.some(a => a.status === 'uploading'))
|
|
64293
64327
|
return;
|
|
64294
64328
|
this.isSubmitting.set(true);
|
|
64295
|
-
this.error.set(null);
|
|
64296
|
-
this.isSuccess.set(false);
|
|
64297
64329
|
this.formProps.state = ComponentStates.WORKING;
|
|
64298
64330
|
this.formProps.actions.state = ComponentStates.WORKING;
|
|
64299
64331
|
try {
|
|
@@ -64302,11 +64334,21 @@ class FeedbackFormComponent {
|
|
|
64302
64334
|
const description = submitted.fields['description'];
|
|
64303
64335
|
const attachmentUrls = this.currentAttachments.filter(a => a.status === 'ready').map(a => a.url);
|
|
64304
64336
|
const response = await this.feedbackService.createAsync(type, title, description, attachmentUrls, this.props.contentRef);
|
|
64305
|
-
this.
|
|
64337
|
+
this.toast.show({
|
|
64338
|
+
message: this.props.successMessage ?? this.tt('feedbackSuccess'),
|
|
64339
|
+
duration: 2500,
|
|
64340
|
+
color: 'dark',
|
|
64341
|
+
position: 'top',
|
|
64342
|
+
});
|
|
64306
64343
|
this.onSubmit.emit({ response, type, title, attachmentUrls });
|
|
64307
64344
|
}
|
|
64308
64345
|
catch (err) {
|
|
64309
|
-
this.
|
|
64346
|
+
this.errors.handle(err, {
|
|
64347
|
+
context: 'feedback-form.submit',
|
|
64348
|
+
fallbackKey: 'feedbackError',
|
|
64349
|
+
i18nNamespace: 'FeedbackForm',
|
|
64350
|
+
});
|
|
64351
|
+
this.onError.emit(err);
|
|
64310
64352
|
}
|
|
64311
64353
|
finally {
|
|
64312
64354
|
this.isSubmitting.set(false);
|
|
@@ -64320,36 +64362,27 @@ class FeedbackFormComponent {
|
|
|
64320
64362
|
onCancelClick() {
|
|
64321
64363
|
this.onCancel.emit();
|
|
64322
64364
|
}
|
|
64365
|
+
tt(key) {
|
|
64366
|
+
return this.i18n.t(key, 'FeedbackForm');
|
|
64367
|
+
}
|
|
64323
64368
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeedbackFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
64324
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FeedbackFormComponent, isStandalone: true, selector: "val-feedback-form", inputs: { props: "props" }, outputs: { onSubmit: "onSubmit", onCancel: "onCancel" }, ngImport: i0, template: `
|
|
64369
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FeedbackFormComponent, isStandalone: true, selector: "val-feedback-form", inputs: { props: "props" }, outputs: { onSubmit: "onSubmit", onCancel: "onCancel", onError: "onError" }, ngImport: i0, template: `
|
|
64325
64370
|
<div class="feedback-form-wrapper" [class.compact]="props.compact" [ngClass]="props.cssClass">
|
|
64326
64371
|
@if (props.showTitle) {
|
|
64327
64372
|
<div class="form-header">
|
|
64328
|
-
<
|
|
64329
|
-
<
|
|
64373
|
+
<val-display [props]="{ size: 'small', color: 'dark', content: props.pageTitle || tt('formTitle') }" />
|
|
64374
|
+
<val-title
|
|
64375
|
+
[props]="{ size: 'large', color: 'dark', bold: false, content: props.pageSubtitle || tt('formSubtitle') }"
|
|
64376
|
+
/>
|
|
64330
64377
|
</div>
|
|
64331
64378
|
}
|
|
64332
64379
|
<val-form [props]="formProps" (onSubmit)="handleFormSubmit($event)">
|
|
64333
64380
|
@if (props.showAttachments !== false) {
|
|
64334
64381
|
<val-attachment-uploader
|
|
64335
|
-
[props]="{ maxFiles: 5 }"
|
|
64382
|
+
[props]="{ maxFiles: 5, uploadFn: uploadFn }"
|
|
64336
64383
|
(attachmentsChange)="onAttachmentsChange($event)"
|
|
64337
64384
|
></val-attachment-uploader>
|
|
64338
64385
|
}
|
|
64339
|
-
|
|
64340
|
-
@if (error()) {
|
|
64341
|
-
<div class="feedback-alert error">
|
|
64342
|
-
<ion-icon name="close-circle-outline" aria-hidden="true"></ion-icon>
|
|
64343
|
-
<span>{{ error() }}</span>
|
|
64344
|
-
</div>
|
|
64345
|
-
}
|
|
64346
|
-
|
|
64347
|
-
@if (isSuccess()) {
|
|
64348
|
-
<div class="feedback-alert success">
|
|
64349
|
-
<ion-icon name="checkmark-circle-outline" aria-hidden="true"></ion-icon>
|
|
64350
|
-
<span>{{ props.successMessage || i18n.t('feedbackSuccess') }}</span>
|
|
64351
|
-
</div>
|
|
64352
|
-
}
|
|
64353
64386
|
</val-form>
|
|
64354
64387
|
|
|
64355
64388
|
@if (props.cancelButtonText) {
|
|
@@ -64358,39 +64391,27 @@ class FeedbackFormComponent {
|
|
|
64358
64391
|
</ion-button>
|
|
64359
64392
|
}
|
|
64360
64393
|
</div>
|
|
64361
|
-
`, isInline: true, styles: [".feedback-form-wrapper{display:flex;flex-direction:column;gap:8px;&.compact{gap:4px}}.form-header{margin-bottom:8px}
|
|
64394
|
+
`, isInline: true, styles: [".feedback-form-wrapper{display:flex;flex-direction:column;gap:8px;&.compact{gap:4px}}.form-header{margin-bottom:8px}val-attachment-uploader{display:block;margin-top:16px;margin-bottom:8px}.cancel-button{margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: AttachmentUploaderComponent, selector: "val-attachment-uploader", inputs: ["props"], outputs: ["attachmentsChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] }); }
|
|
64362
64395
|
}
|
|
64363
64396
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FeedbackFormComponent, decorators: [{
|
|
64364
64397
|
type: Component,
|
|
64365
|
-
args: [{ selector: 'val-feedback-form', standalone: true, imports: [CommonModule, FormComponent, AttachmentUploaderComponent,
|
|
64398
|
+
args: [{ selector: 'val-feedback-form', standalone: true, imports: [CommonModule, FormComponent, AttachmentUploaderComponent, DisplayComponent, TitleComponent, IonButton], template: `
|
|
64366
64399
|
<div class="feedback-form-wrapper" [class.compact]="props.compact" [ngClass]="props.cssClass">
|
|
64367
64400
|
@if (props.showTitle) {
|
|
64368
64401
|
<div class="form-header">
|
|
64369
|
-
<
|
|
64370
|
-
<
|
|
64402
|
+
<val-display [props]="{ size: 'small', color: 'dark', content: props.pageTitle || tt('formTitle') }" />
|
|
64403
|
+
<val-title
|
|
64404
|
+
[props]="{ size: 'large', color: 'dark', bold: false, content: props.pageSubtitle || tt('formSubtitle') }"
|
|
64405
|
+
/>
|
|
64371
64406
|
</div>
|
|
64372
64407
|
}
|
|
64373
64408
|
<val-form [props]="formProps" (onSubmit)="handleFormSubmit($event)">
|
|
64374
64409
|
@if (props.showAttachments !== false) {
|
|
64375
64410
|
<val-attachment-uploader
|
|
64376
|
-
[props]="{ maxFiles: 5 }"
|
|
64411
|
+
[props]="{ maxFiles: 5, uploadFn: uploadFn }"
|
|
64377
64412
|
(attachmentsChange)="onAttachmentsChange($event)"
|
|
64378
64413
|
></val-attachment-uploader>
|
|
64379
64414
|
}
|
|
64380
|
-
|
|
64381
|
-
@if (error()) {
|
|
64382
|
-
<div class="feedback-alert error">
|
|
64383
|
-
<ion-icon name="close-circle-outline" aria-hidden="true"></ion-icon>
|
|
64384
|
-
<span>{{ error() }}</span>
|
|
64385
|
-
</div>
|
|
64386
|
-
}
|
|
64387
|
-
|
|
64388
|
-
@if (isSuccess()) {
|
|
64389
|
-
<div class="feedback-alert success">
|
|
64390
|
-
<ion-icon name="checkmark-circle-outline" aria-hidden="true"></ion-icon>
|
|
64391
|
-
<span>{{ props.successMessage || i18n.t('feedbackSuccess') }}</span>
|
|
64392
|
-
</div>
|
|
64393
|
-
}
|
|
64394
64415
|
</val-form>
|
|
64395
64416
|
|
|
64396
64417
|
@if (props.cancelButtonText) {
|
|
@@ -64399,13 +64420,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
64399
64420
|
</ion-button>
|
|
64400
64421
|
}
|
|
64401
64422
|
</div>
|
|
64402
|
-
`, styles: [".feedback-form-wrapper{display:flex;flex-direction:column;gap:8px;&.compact{gap:4px}}.form-header{margin-bottom:8px}
|
|
64423
|
+
`, styles: [".feedback-form-wrapper{display:flex;flex-direction:column;gap:8px;&.compact{gap:4px}}.form-header{margin-bottom:8px}val-attachment-uploader{display:block;margin-top:16px;margin-bottom:8px}.cancel-button{margin-top:8px}\n"] }]
|
|
64403
64424
|
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
64404
64425
|
type: Input
|
|
64405
64426
|
}], onSubmit: [{
|
|
64406
64427
|
type: Output
|
|
64407
64428
|
}], onCancel: [{
|
|
64408
64429
|
type: Output
|
|
64430
|
+
}], onError: [{
|
|
64431
|
+
type: Output
|
|
64409
64432
|
}] } });
|
|
64410
64433
|
|
|
64411
64434
|
class RequestService {
|