valtech-components 4.0.981 → 4.0.983
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/atoms/button/button.component.mjs +3 -1
- package/esm2022/lib/components/organisms/field-schema-editor/field-schema-editor.component.mjs +332 -0
- package/esm2022/lib/components/organisms/field-schema-editor/field-schema-editor.i18n.mjs +71 -0
- package/esm2022/lib/components/organisms/field-schema-editor/types.mjs +2 -0
- package/esm2022/lib/components/organisms/survey-builder/survey-builder.component.mjs +269 -131
- package/esm2022/lib/components/organisms/survey-builder/survey-builder.i18n.mjs +19 -7
- package/esm2022/lib/components/organisms/survey-builder/types.mjs +31 -2
- package/esm2022/lib/components/organisms/survey-response/survey-response.component.mjs +294 -26
- package/esm2022/lib/components/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/valtech-components.mjs +1056 -227
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/article/article.component.d.ts +1 -0
- package/lib/components/organisms/field-schema-editor/field-schema-editor.component.d.ts +90 -0
- package/lib/components/organisms/field-schema-editor/field-schema-editor.i18n.d.ts +2 -0
- package/lib/components/organisms/field-schema-editor/types.d.ts +60 -0
- package/lib/components/organisms/survey-builder/survey-builder.component.d.ts +26 -14
- package/lib/components/organisms/survey-builder/types.d.ts +23 -5
- package/lib/components/organisms/survey-response/survey-response.component.d.ts +42 -1
- package/lib/components/types.d.ts +6 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -70,7 +70,7 @@ import fixWebmDuration from 'fix-webm-duration';
|
|
|
70
70
|
* Current version of valtech-components.
|
|
71
71
|
* This is automatically updated during the publish process.
|
|
72
72
|
*/
|
|
73
|
-
const VERSION = '4.0.
|
|
73
|
+
const VERSION = '4.0.983';
|
|
74
74
|
|
|
75
75
|
function evaluateValtechAccess(rule, context, features = {}, visitedFeatures = new Set()) {
|
|
76
76
|
if (rule == null)
|
|
@@ -12998,6 +12998,7 @@ class ButtonComponent {
|
|
|
12998
12998
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ButtonComponent, isStandalone: true, selector: "val-button", inputs: { preset: "preset", props: "props" }, outputs: { onClick: "onClick" }, usesOnChanges: true, ngImport: i0, template: `
|
|
12999
12999
|
<ion-button
|
|
13000
13000
|
[attr.data-testid]="resolvedProps.token"
|
|
13001
|
+
[attr.aria-label]="resolvedProps.ariaLabel || null"
|
|
13001
13002
|
[type]="resolvedProps.type"
|
|
13002
13003
|
[color]="resolvedProps.color"
|
|
13003
13004
|
[expand]="resolvedProps.expand"
|
|
@@ -13027,6 +13028,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
13027
13028
|
args: [{ selector: 'val-button', standalone: true, imports: [CommonModule, RouterLink, IonButton, IonIcon, IonSpinner, IonText], template: `
|
|
13028
13029
|
<ion-button
|
|
13029
13030
|
[attr.data-testid]="resolvedProps.token"
|
|
13031
|
+
[attr.aria-label]="resolvedProps.ariaLabel || null"
|
|
13030
13032
|
[type]="resolvedProps.type"
|
|
13031
13033
|
[color]="resolvedProps.color"
|
|
13032
13034
|
[expand]="resolvedProps.expand"
|
|
@@ -38614,6 +38616,66 @@ const REQUEST_STATUSES = [
|
|
|
38614
38616
|
*/
|
|
38615
38617
|
const FIELD_TYPE_EMOJI_RATING = 'EMOJI_RATING';
|
|
38616
38618
|
|
|
38619
|
+
/**
|
|
38620
|
+
* Primitivo de campo de formulario: label (estilo val-form) + contenido proyectado.
|
|
38621
|
+
*
|
|
38622
|
+
* Usar cuando necesitás un campo fuera de val-form pero con el mismo estilo:
|
|
38623
|
+
* image-picker, date-picker, selectores custom, chips, etc.
|
|
38624
|
+
*
|
|
38625
|
+
* NOTA: para ion-input / ion-textarea NO usar ng-content projection — el Shadow DOM
|
|
38626
|
+
* de Ionic no responde al grid del host. Usá en cambio un `<div class="pf-field">`
|
|
38627
|
+
* plano en el template con `<p class="pf-label">` + ion-input directo.
|
|
38628
|
+
*
|
|
38629
|
+
* ```html
|
|
38630
|
+
* <val-form-field label="Imagen">
|
|
38631
|
+
* <app-image-picker ... />
|
|
38632
|
+
* </val-form-field>
|
|
38633
|
+
*
|
|
38634
|
+
* <!-- Para ion-input: NO val-form-field, usar div plano -->
|
|
38635
|
+
* <div class="pf-field">
|
|
38636
|
+
* <p class="pf-label">Nombre</p>
|
|
38637
|
+
* <ion-input fill="outline" ... />
|
|
38638
|
+
* </div>
|
|
38639
|
+
* ```
|
|
38640
|
+
*
|
|
38641
|
+
* El label usa el mismo val-title que val-form (size=small, color=dark, bold=false).
|
|
38642
|
+
* El spacing entre campos se controla con --val-form-field-gap (default 0.5rem).
|
|
38643
|
+
* El padding horizontal se hereda vía --val-form-field-padding (default 0).
|
|
38644
|
+
* Setearlo en el contenedor padre para consistencia sin override en cada campo:
|
|
38645
|
+
* `.my-card { --val-form-field-padding: 0 16px; }`
|
|
38646
|
+
*/
|
|
38647
|
+
class FormFieldComponent {
|
|
38648
|
+
constructor() {
|
|
38649
|
+
this.label = input('');
|
|
38650
|
+
this.titleProps = computed(() => ({
|
|
38651
|
+
content: this.label(),
|
|
38652
|
+
size: 'small',
|
|
38653
|
+
color: 'dark',
|
|
38654
|
+
bold: false,
|
|
38655
|
+
}));
|
|
38656
|
+
}
|
|
38657
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38658
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FormFieldComponent, isStandalone: true, selector: "val-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
38659
|
+
@if (label()) {
|
|
38660
|
+
<div class="vff-label">
|
|
38661
|
+
<val-title [props]="titleProps()" />
|
|
38662
|
+
</div>
|
|
38663
|
+
}
|
|
38664
|
+
<ng-content />
|
|
38665
|
+
`, isInline: true, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"], dependencies: [{ kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
38666
|
+
}
|
|
38667
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
38668
|
+
type: Component,
|
|
38669
|
+
args: [{ selector: 'val-form-field', standalone: true, imports: [TitleComponent], template: `
|
|
38670
|
+
@if (label()) {
|
|
38671
|
+
<div class="vff-label">
|
|
38672
|
+
<val-title [props]="titleProps()" />
|
|
38673
|
+
</div>
|
|
38674
|
+
}
|
|
38675
|
+
<ng-content />
|
|
38676
|
+
`, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"] }]
|
|
38677
|
+
}] });
|
|
38678
|
+
|
|
38617
38679
|
const SURVEY_RESPONSE_I18N = {
|
|
38618
38680
|
es: {
|
|
38619
38681
|
nameLabel: 'Tu nombre',
|
|
@@ -38653,7 +38715,9 @@ const SURVEY_RESPONSE_I18N = {
|
|
|
38653
38715
|
},
|
|
38654
38716
|
};
|
|
38655
38717
|
|
|
38656
|
-
const NAMESPACE$
|
|
38718
|
+
const NAMESPACE$3 = 'SurveyResponse';
|
|
38719
|
+
/** Tipos cuya respuesta es un booleano, no un texto. */
|
|
38720
|
+
const BOOLEAN_TYPES = ['CHECK', 'TOGGLE'];
|
|
38657
38721
|
/**
|
|
38658
38722
|
* val-survey-response
|
|
38659
38723
|
*
|
|
@@ -38683,14 +38747,22 @@ class SurveyResponseComponent {
|
|
|
38683
38747
|
this.requests = inject(RequestService);
|
|
38684
38748
|
this.errors = inject(ValtechErrorService);
|
|
38685
38749
|
this.emojiType = FIELD_TYPE_EMOJI_RATING;
|
|
38750
|
+
this.selectType = InputType.SELECT;
|
|
38686
38751
|
this.loading = signal(true);
|
|
38687
38752
|
this.loadError = signal(false);
|
|
38688
38753
|
this.sent = signal(false);
|
|
38689
38754
|
this.sending = signal(false);
|
|
38690
38755
|
this.typeConfig = signal(null);
|
|
38756
|
+
this.multiSelectError = signal(false);
|
|
38691
38757
|
this.nameControl = new FormControl('', { nonNullable: true });
|
|
38692
38758
|
this.emailControl = new FormControl('', { nonNullable: true });
|
|
38693
38759
|
this.form = new FormGroup({});
|
|
38760
|
+
/**
|
|
38761
|
+
* Una casilla por opción de cada pregunta MULTI_SELECT, indexada
|
|
38762
|
+
* `"<pregunta>::<opcion>"`. Viven fuera del `form` porque el valor que viaja
|
|
38763
|
+
* al backend es UNA lista por pregunta, no N booleanos: se arma al enviar.
|
|
38764
|
+
*/
|
|
38765
|
+
this.multiControls = new Map();
|
|
38694
38766
|
/** Preguntas ordenadas — el template las recorre en este orden. */
|
|
38695
38767
|
this.questions = computed(() => {
|
|
38696
38768
|
const cfg = this.typeConfig();
|
|
@@ -38715,8 +38787,8 @@ class SurveyResponseComponent {
|
|
|
38715
38787
|
this.i18n.lang();
|
|
38716
38788
|
return { variant: 'error', title: this.t('loginRequiredTitle'), description: this.t('loginRequiredBody') };
|
|
38717
38789
|
});
|
|
38718
|
-
if (!this.i18n.hasNamespace(NAMESPACE$
|
|
38719
|
-
this.i18n.registerDefaults(NAMESPACE$
|
|
38790
|
+
if (!this.i18n.hasNamespace(NAMESPACE$3)) {
|
|
38791
|
+
this.i18n.registerDefaults(NAMESPACE$3, SURVEY_RESPONSE_I18N);
|
|
38720
38792
|
}
|
|
38721
38793
|
}
|
|
38722
38794
|
async ngOnInit() {
|
|
@@ -38735,6 +38807,19 @@ class SurveyResponseComponent {
|
|
|
38735
38807
|
buildForm(cfg) {
|
|
38736
38808
|
const group = {};
|
|
38737
38809
|
for (const q of [...cfg.fieldSchema].sort((a, b) => a.order - b.order)) {
|
|
38810
|
+
if (q.type === 'MULTI_SELECT') {
|
|
38811
|
+
for (const opt of q.options ?? []) {
|
|
38812
|
+
this.multiControls.set(`${q.name}::${opt.id}`, new FormControl(false, { nonNullable: true }));
|
|
38813
|
+
}
|
|
38814
|
+
continue;
|
|
38815
|
+
}
|
|
38816
|
+
if (BOOLEAN_TYPES.includes(q.type)) {
|
|
38817
|
+
// Sin `required`: un booleano SIEMPRE tiene valor. Exigirlo obligaría a
|
|
38818
|
+
// marcarlo, que es otra cosa que responder — y dejaría el envío
|
|
38819
|
+
// bloqueado sin que se vea por qué.
|
|
38820
|
+
group[q.name] = new FormControl(false, { nonNullable: true });
|
|
38821
|
+
continue;
|
|
38822
|
+
}
|
|
38738
38823
|
group[q.name] = new FormControl({ value: '', disabled: false }, q.required ? [Validators.required] : []);
|
|
38739
38824
|
}
|
|
38740
38825
|
this.form = new FormGroup(group);
|
|
@@ -38752,6 +38837,74 @@ class SurveyResponseComponent {
|
|
|
38752
38837
|
questionControl(name) {
|
|
38753
38838
|
return this.form.get(name);
|
|
38754
38839
|
}
|
|
38840
|
+
booleanControl(name) {
|
|
38841
|
+
return this.form.get(name);
|
|
38842
|
+
}
|
|
38843
|
+
optionControl(name, optionId) {
|
|
38844
|
+
const key = `${name}::${optionId}`;
|
|
38845
|
+
let control = this.multiControls.get(key);
|
|
38846
|
+
if (!control) {
|
|
38847
|
+
control = new FormControl(false, { nonNullable: true });
|
|
38848
|
+
this.multiControls.set(key, control);
|
|
38849
|
+
}
|
|
38850
|
+
return control;
|
|
38851
|
+
}
|
|
38852
|
+
/** Opciones tal como las escribió quien creó la encuesta — no se traducen. */
|
|
38853
|
+
optionsOf(q) {
|
|
38854
|
+
return [...(q.options ?? [])]
|
|
38855
|
+
.map((o, index) => ({ id: o.id, name: o.name, order: o.order ?? index }))
|
|
38856
|
+
.sort((a, b) => a.order - b.order);
|
|
38857
|
+
}
|
|
38858
|
+
/**
|
|
38859
|
+
* `val-radio-input` pide un `InputMetadata` completo (no `Partial`), así que
|
|
38860
|
+
* se arma acá en vez de en el template.
|
|
38861
|
+
*/
|
|
38862
|
+
radioProps(q) {
|
|
38863
|
+
return {
|
|
38864
|
+
token: q.name,
|
|
38865
|
+
name: q.name,
|
|
38866
|
+
label: '',
|
|
38867
|
+
hint: '',
|
|
38868
|
+
placeholder: '',
|
|
38869
|
+
type: InputType.RADIO,
|
|
38870
|
+
order: q.order,
|
|
38871
|
+
validators: [],
|
|
38872
|
+
errors: {},
|
|
38873
|
+
state: ComponentStates.ENABLED,
|
|
38874
|
+
control: this.questionControl(q.name),
|
|
38875
|
+
options: this.optionsOf(q),
|
|
38876
|
+
};
|
|
38877
|
+
}
|
|
38878
|
+
placeholderOf(q) {
|
|
38879
|
+
return q.placeholderText || q.placeholder || '';
|
|
38880
|
+
}
|
|
38881
|
+
hintOf(q) {
|
|
38882
|
+
return q.hintText || q.hint || '';
|
|
38883
|
+
}
|
|
38884
|
+
/**
|
|
38885
|
+
* Tipo del `<input>` para las preguntas que se responden escribiendo. Nada de
|
|
38886
|
+
* `parseInputType` de `FormSchemaBuilderService`: ese mapea al enum de
|
|
38887
|
+
* `val-form`, y acá no hay `val-form` de por medio (ver el comentario de
|
|
38888
|
+
* clase). Un tipo desconocido cae a texto, que siempre se puede responder.
|
|
38889
|
+
*/
|
|
38890
|
+
inputTypeOf(type) {
|
|
38891
|
+
switch (type) {
|
|
38892
|
+
case 'EMAIL':
|
|
38893
|
+
return 'email';
|
|
38894
|
+
case 'NUMBER':
|
|
38895
|
+
return 'number';
|
|
38896
|
+
case 'PHONE':
|
|
38897
|
+
return 'tel';
|
|
38898
|
+
default:
|
|
38899
|
+
return 'text';
|
|
38900
|
+
}
|
|
38901
|
+
}
|
|
38902
|
+
/** Las opciones marcadas de una pregunta MULTI_SELECT, en el orden del schema. */
|
|
38903
|
+
selectedOptions(q) {
|
|
38904
|
+
return this.optionsOf(q)
|
|
38905
|
+
.filter(opt => this.multiControls.get(`${q.name}::${opt.id}`)?.value)
|
|
38906
|
+
.map(opt => opt.id);
|
|
38907
|
+
}
|
|
38755
38908
|
questionLabel(q) {
|
|
38756
38909
|
// Texto del CLIENTE (regla #4): quien creó la encuesta escribió el
|
|
38757
38910
|
// enunciado tal cual, no se traduce.
|
|
@@ -38773,8 +38926,20 @@ class SurveyResponseComponent {
|
|
|
38773
38926
|
const cfg = this.typeConfig();
|
|
38774
38927
|
if (!cfg)
|
|
38775
38928
|
return;
|
|
38929
|
+
// MULTI_SELECT no vive en el FormGroup, así que `form.invalid` no lo cubre:
|
|
38930
|
+
// una obligatoria sin nada marcado hay que frenarla acá o se envía vacía.
|
|
38931
|
+
const multiRequired = this.questions().filter(q => q.type === 'MULTI_SELECT' && q.required);
|
|
38932
|
+
if (multiRequired.some(q => !this.selectedOptions(q).length)) {
|
|
38933
|
+
this.multiSelectError.set(true);
|
|
38934
|
+
return;
|
|
38935
|
+
}
|
|
38936
|
+
this.multiSelectError.set(false);
|
|
38776
38937
|
this.sending.set(true);
|
|
38777
|
-
const fields = this.form.getRawValue();
|
|
38938
|
+
const fields = { ...this.form.getRawValue() };
|
|
38939
|
+
for (const q of this.questions()) {
|
|
38940
|
+
if (q.type === 'MULTI_SELECT')
|
|
38941
|
+
fields[q.name] = this.selectedOptions(q);
|
|
38942
|
+
}
|
|
38778
38943
|
const payload = {
|
|
38779
38944
|
type: cfg.typeId,
|
|
38780
38945
|
title: cfg.label,
|
|
@@ -38797,12 +38962,12 @@ class SurveyResponseComponent {
|
|
|
38797
38962
|
this.errors.handle(err, {
|
|
38798
38963
|
context: 'surveyResponse.submit',
|
|
38799
38964
|
fallbackKey: 'sendError',
|
|
38800
|
-
i18nNamespace: NAMESPACE$
|
|
38965
|
+
i18nNamespace: NAMESPACE$3,
|
|
38801
38966
|
});
|
|
38802
38967
|
}
|
|
38803
38968
|
}
|
|
38804
38969
|
t(key) {
|
|
38805
|
-
return this.i18n.t(key, NAMESPACE$
|
|
38970
|
+
return this.i18n.t(key, NAMESPACE$3);
|
|
38806
38971
|
}
|
|
38807
38972
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyResponseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38808
38973
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SurveyResponseComponent, isStandalone: true, selector: "val-survey-response", inputs: { props: "props" }, outputs: { submitted: "submitted" }, ngImport: i0, template: `
|
|
@@ -38839,21 +39004,97 @@ class SurveyResponseComponent {
|
|
|
38839
39004
|
|
|
38840
39005
|
@for (q of questions(); track q.name) {
|
|
38841
39006
|
<div class="survey-response__question">
|
|
38842
|
-
@
|
|
38843
|
-
|
|
38844
|
-
|
|
38845
|
-
|
|
38846
|
-
|
|
38847
|
-
|
|
38848
|
-
|
|
38849
|
-
|
|
38850
|
-
|
|
38851
|
-
|
|
38852
|
-
|
|
39007
|
+
@switch (q.type) {
|
|
39008
|
+
@case (emojiType) {
|
|
39009
|
+
<val-emoji-rating [props]="{ control: questionControl(q.name), label: questionLabel(q) }" />
|
|
39010
|
+
}
|
|
39011
|
+
@case ('TEXTAREA') {
|
|
39012
|
+
<val-textarea-input
|
|
39013
|
+
[props]="{
|
|
39014
|
+
control: questionControl(q.name),
|
|
39015
|
+
label: questionLabel(q),
|
|
39016
|
+
hint: hintOf(q),
|
|
39017
|
+
placeholder: placeholderOf(q),
|
|
39018
|
+
autoGrow: true,
|
|
39019
|
+
}"
|
|
39020
|
+
/>
|
|
39021
|
+
}
|
|
39022
|
+
@case ('SELECT') {
|
|
39023
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39024
|
+
<val-select-input
|
|
39025
|
+
[props]="{
|
|
39026
|
+
control: questionControl(q.name),
|
|
39027
|
+
type: selectType,
|
|
39028
|
+
placeholder: placeholderOf(q),
|
|
39029
|
+
options: optionsOf(q),
|
|
39030
|
+
}"
|
|
39031
|
+
/>
|
|
39032
|
+
</val-form-field>
|
|
39033
|
+
@if (hintOf(q)) {
|
|
39034
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39035
|
+
}
|
|
39036
|
+
}
|
|
39037
|
+
@case ('RADIO') {
|
|
39038
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39039
|
+
<val-radio-input [props]="radioProps(q)" />
|
|
39040
|
+
</val-form-field>
|
|
39041
|
+
@if (hintOf(q)) {
|
|
39042
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39043
|
+
}
|
|
39044
|
+
}
|
|
39045
|
+
@case ('MULTI_SELECT') {
|
|
39046
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39047
|
+
<div class="survey-response__options">
|
|
39048
|
+
@for (opt of optionsOf(q); track opt.id) {
|
|
39049
|
+
<val-check-input
|
|
39050
|
+
[props]="{ control: optionControl(q.name, opt.id), label: opt.name, labelPlacement: 'end' }"
|
|
39051
|
+
/>
|
|
39052
|
+
}
|
|
39053
|
+
</div>
|
|
39054
|
+
</val-form-field>
|
|
39055
|
+
@if (hintOf(q)) {
|
|
39056
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39057
|
+
}
|
|
39058
|
+
}
|
|
39059
|
+
@case ('CHECK') {
|
|
39060
|
+
<val-check-input
|
|
39061
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), labelPlacement: 'end' }"
|
|
39062
|
+
/>
|
|
39063
|
+
}
|
|
39064
|
+
@case ('TOGGLE') {
|
|
39065
|
+
<val-toggle-input
|
|
39066
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), justify: 'space-between' }"
|
|
39067
|
+
/>
|
|
39068
|
+
}
|
|
39069
|
+
@case ('DATE') {
|
|
39070
|
+
<val-date-picker
|
|
39071
|
+
[props]="{
|
|
39072
|
+
control: questionControl(q.name),
|
|
39073
|
+
label: questionLabel(q),
|
|
39074
|
+
hint: hintOf(q),
|
|
39075
|
+
placeholder: placeholderOf(q),
|
|
39076
|
+
}"
|
|
39077
|
+
/>
|
|
39078
|
+
}
|
|
39079
|
+
@default {
|
|
39080
|
+
<val-text-input
|
|
39081
|
+
[props]="{
|
|
39082
|
+
control: questionControl(q.name),
|
|
39083
|
+
label: questionLabel(q),
|
|
39084
|
+
hint: hintOf(q),
|
|
39085
|
+
placeholder: placeholderOf(q),
|
|
39086
|
+
inputType: inputTypeOf(q.type),
|
|
39087
|
+
}"
|
|
39088
|
+
/>
|
|
39089
|
+
}
|
|
38853
39090
|
}
|
|
38854
39091
|
</div>
|
|
38855
39092
|
}
|
|
38856
39093
|
|
|
39094
|
+
@if (multiSelectError()) {
|
|
39095
|
+
<p class="survey-response__error">{{ t('required') }}</p>
|
|
39096
|
+
}
|
|
39097
|
+
|
|
38857
39098
|
<val-button
|
|
38858
39099
|
[props]="{
|
|
38859
39100
|
token: 'survey-response-submit',
|
|
@@ -38872,7 +39113,7 @@ class SurveyResponseComponent {
|
|
|
38872
39113
|
}
|
|
38873
39114
|
}
|
|
38874
39115
|
}
|
|
38875
|
-
`, isInline: true, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__loading{min-height:120px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: EmojiRatingComponent, selector: "val-emoji-rating", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }] }); }
|
|
39116
|
+
`, isInline: true, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__options{display:flex;flex-direction:column;gap:4px}.survey-response__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}.survey-response__hint{display:block;margin-top:4px;font-size:.8125rem;color:var(--ion-color-medium, #92949c)}.survey-response__loading{min-height:120px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input", inputs: ["preset", "props"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: DatePickerComponent, selector: "val-date-picker", inputs: ["props"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: EmojiRatingComponent, selector: "val-emoji-rating", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }] }); }
|
|
38876
39117
|
}
|
|
38877
39118
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyResponseComponent, decorators: [{
|
|
38878
39119
|
type: Component,
|
|
@@ -38883,6 +39124,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38883
39124
|
TitleComponent,
|
|
38884
39125
|
TextInputComponent,
|
|
38885
39126
|
TextareaInputComponent,
|
|
39127
|
+
SearchSelectorComponent,
|
|
39128
|
+
RadioInputComponent,
|
|
39129
|
+
CheckInputComponent,
|
|
39130
|
+
ToggleInputComponent,
|
|
39131
|
+
DatePickerComponent,
|
|
39132
|
+
FormFieldComponent,
|
|
38886
39133
|
EmojiRatingComponent,
|
|
38887
39134
|
ButtonComponent,
|
|
38888
39135
|
EmptyStateComponent,
|
|
@@ -38920,21 +39167,97 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38920
39167
|
|
|
38921
39168
|
@for (q of questions(); track q.name) {
|
|
38922
39169
|
<div class="survey-response__question">
|
|
38923
|
-
@
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
|
|
38928
|
-
|
|
38929
|
-
|
|
38930
|
-
|
|
38931
|
-
|
|
38932
|
-
|
|
38933
|
-
|
|
39170
|
+
@switch (q.type) {
|
|
39171
|
+
@case (emojiType) {
|
|
39172
|
+
<val-emoji-rating [props]="{ control: questionControl(q.name), label: questionLabel(q) }" />
|
|
39173
|
+
}
|
|
39174
|
+
@case ('TEXTAREA') {
|
|
39175
|
+
<val-textarea-input
|
|
39176
|
+
[props]="{
|
|
39177
|
+
control: questionControl(q.name),
|
|
39178
|
+
label: questionLabel(q),
|
|
39179
|
+
hint: hintOf(q),
|
|
39180
|
+
placeholder: placeholderOf(q),
|
|
39181
|
+
autoGrow: true,
|
|
39182
|
+
}"
|
|
39183
|
+
/>
|
|
39184
|
+
}
|
|
39185
|
+
@case ('SELECT') {
|
|
39186
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39187
|
+
<val-select-input
|
|
39188
|
+
[props]="{
|
|
39189
|
+
control: questionControl(q.name),
|
|
39190
|
+
type: selectType,
|
|
39191
|
+
placeholder: placeholderOf(q),
|
|
39192
|
+
options: optionsOf(q),
|
|
39193
|
+
}"
|
|
39194
|
+
/>
|
|
39195
|
+
</val-form-field>
|
|
39196
|
+
@if (hintOf(q)) {
|
|
39197
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39198
|
+
}
|
|
39199
|
+
}
|
|
39200
|
+
@case ('RADIO') {
|
|
39201
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39202
|
+
<val-radio-input [props]="radioProps(q)" />
|
|
39203
|
+
</val-form-field>
|
|
39204
|
+
@if (hintOf(q)) {
|
|
39205
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39206
|
+
}
|
|
39207
|
+
}
|
|
39208
|
+
@case ('MULTI_SELECT') {
|
|
39209
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39210
|
+
<div class="survey-response__options">
|
|
39211
|
+
@for (opt of optionsOf(q); track opt.id) {
|
|
39212
|
+
<val-check-input
|
|
39213
|
+
[props]="{ control: optionControl(q.name, opt.id), label: opt.name, labelPlacement: 'end' }"
|
|
39214
|
+
/>
|
|
39215
|
+
}
|
|
39216
|
+
</div>
|
|
39217
|
+
</val-form-field>
|
|
39218
|
+
@if (hintOf(q)) {
|
|
39219
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39220
|
+
}
|
|
39221
|
+
}
|
|
39222
|
+
@case ('CHECK') {
|
|
39223
|
+
<val-check-input
|
|
39224
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), labelPlacement: 'end' }"
|
|
39225
|
+
/>
|
|
39226
|
+
}
|
|
39227
|
+
@case ('TOGGLE') {
|
|
39228
|
+
<val-toggle-input
|
|
39229
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), justify: 'space-between' }"
|
|
39230
|
+
/>
|
|
39231
|
+
}
|
|
39232
|
+
@case ('DATE') {
|
|
39233
|
+
<val-date-picker
|
|
39234
|
+
[props]="{
|
|
39235
|
+
control: questionControl(q.name),
|
|
39236
|
+
label: questionLabel(q),
|
|
39237
|
+
hint: hintOf(q),
|
|
39238
|
+
placeholder: placeholderOf(q),
|
|
39239
|
+
}"
|
|
39240
|
+
/>
|
|
39241
|
+
}
|
|
39242
|
+
@default {
|
|
39243
|
+
<val-text-input
|
|
39244
|
+
[props]="{
|
|
39245
|
+
control: questionControl(q.name),
|
|
39246
|
+
label: questionLabel(q),
|
|
39247
|
+
hint: hintOf(q),
|
|
39248
|
+
placeholder: placeholderOf(q),
|
|
39249
|
+
inputType: inputTypeOf(q.type),
|
|
39250
|
+
}"
|
|
39251
|
+
/>
|
|
39252
|
+
}
|
|
38934
39253
|
}
|
|
38935
39254
|
</div>
|
|
38936
39255
|
}
|
|
38937
39256
|
|
|
39257
|
+
@if (multiSelectError()) {
|
|
39258
|
+
<p class="survey-response__error">{{ t('required') }}</p>
|
|
39259
|
+
}
|
|
39260
|
+
|
|
38938
39261
|
<val-button
|
|
38939
39262
|
[props]="{
|
|
38940
39263
|
token: 'survey-response-submit',
|
|
@@ -38953,7 +39276,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38953
39276
|
}
|
|
38954
39277
|
}
|
|
38955
39278
|
}
|
|
38956
|
-
`, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__loading{min-height:120px}\n"] }]
|
|
39279
|
+
`, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__options{display:flex;flex-direction:column;gap:4px}.survey-response__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}.survey-response__hint{display:block;margin-top:4px;font-size:.8125rem;color:var(--ion-color-medium, #92949c)}.survey-response__loading{min-height:120px}\n"] }]
|
|
38957
39280
|
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
38958
39281
|
type: Input
|
|
38959
39282
|
}], submitted: [{
|
|
@@ -39170,6 +39493,395 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39170
39493
|
args: [{ providedIn: 'root' }]
|
|
39171
39494
|
}] });
|
|
39172
39495
|
|
|
39496
|
+
const FIELD_SCHEMA_EDITOR_I18N = {
|
|
39497
|
+
es: {
|
|
39498
|
+
presetsTitle: 'Empieza desde',
|
|
39499
|
+
labelLabel: 'Texto del campo',
|
|
39500
|
+
labelPlaceholder: 'Escribe lo que verá quien responde',
|
|
39501
|
+
typeLabel: 'Tipo de campo',
|
|
39502
|
+
placeholderLabel: 'Texto de ayuda dentro del campo',
|
|
39503
|
+
hintLabel: 'Nota bajo el campo',
|
|
39504
|
+
requiredLabel: 'Obligatorio',
|
|
39505
|
+
optionsTitle: 'Opciones',
|
|
39506
|
+
optionsHint: 'Estas son las alternativas que puede elegir quien responde.',
|
|
39507
|
+
optionsAdd: 'Agregar opción',
|
|
39508
|
+
optionsList: 'Opciones',
|
|
39509
|
+
optionsPlaceholder: 'Escribe una opción',
|
|
39510
|
+
optionsEmpty: 'Todavía no hay opciones.',
|
|
39511
|
+
optionsRemove: 'Quitar opción',
|
|
39512
|
+
optionsReorder: 'Reordenar opción',
|
|
39513
|
+
errorIncomplete: 'Ponle un texto al campo y elige su tipo.',
|
|
39514
|
+
errorOptionsRequired: 'Este tipo de campo necesita al menos una opción.',
|
|
39515
|
+
typeTEXT: 'Texto corto',
|
|
39516
|
+
typeTEXTAREA: 'Texto largo',
|
|
39517
|
+
typeEMAIL: 'Correo',
|
|
39518
|
+
typePHONE: 'Teléfono',
|
|
39519
|
+
typeNUMBER: 'Número',
|
|
39520
|
+
typeDATE: 'Fecha',
|
|
39521
|
+
typeSELECT: 'Lista desplegable',
|
|
39522
|
+
typeRADIO: 'Una sola opción',
|
|
39523
|
+
typeMULTI_SELECT: 'Varias opciones',
|
|
39524
|
+
typeCHECK: 'Casilla',
|
|
39525
|
+
typeTOGGLE: 'Sí o no',
|
|
39526
|
+
typeCURRENCY: 'Monto',
|
|
39527
|
+
typeATTACHMENT: 'Archivo adjunto',
|
|
39528
|
+
typeFILE: 'Archivo',
|
|
39529
|
+
typeEMOJI_RATING: 'Calificación con emoji',
|
|
39530
|
+
},
|
|
39531
|
+
en: {
|
|
39532
|
+
presetsTitle: 'Start from',
|
|
39533
|
+
labelLabel: 'Field text',
|
|
39534
|
+
labelPlaceholder: 'Write what the person will see',
|
|
39535
|
+
typeLabel: 'Field type',
|
|
39536
|
+
placeholderLabel: 'Helper text inside the field',
|
|
39537
|
+
hintLabel: 'Note below the field',
|
|
39538
|
+
requiredLabel: 'Required',
|
|
39539
|
+
optionsTitle: 'Options',
|
|
39540
|
+
optionsHint: 'These are the choices the person can pick.',
|
|
39541
|
+
optionsAdd: 'Add option',
|
|
39542
|
+
optionsList: 'Options',
|
|
39543
|
+
optionsPlaceholder: 'Write an option',
|
|
39544
|
+
optionsEmpty: 'No options yet.',
|
|
39545
|
+
optionsRemove: 'Remove option',
|
|
39546
|
+
optionsReorder: 'Reorder option',
|
|
39547
|
+
errorIncomplete: 'Give the field a text and pick its type.',
|
|
39548
|
+
errorOptionsRequired: 'This field type needs at least one option.',
|
|
39549
|
+
typeTEXT: 'Short text',
|
|
39550
|
+
typeTEXTAREA: 'Long text',
|
|
39551
|
+
typeEMAIL: 'Email',
|
|
39552
|
+
typePHONE: 'Phone',
|
|
39553
|
+
typeNUMBER: 'Number',
|
|
39554
|
+
typeDATE: 'Date',
|
|
39555
|
+
typeSELECT: 'Dropdown',
|
|
39556
|
+
typeRADIO: 'Single choice',
|
|
39557
|
+
typeMULTI_SELECT: 'Multiple choice',
|
|
39558
|
+
typeCHECK: 'Checkbox',
|
|
39559
|
+
typeTOGGLE: 'Yes or no',
|
|
39560
|
+
typeCURRENCY: 'Amount',
|
|
39561
|
+
typeATTACHMENT: 'Attachment',
|
|
39562
|
+
typeFILE: 'File',
|
|
39563
|
+
typeEMOJI_RATING: 'Emoji rating',
|
|
39564
|
+
},
|
|
39565
|
+
};
|
|
39566
|
+
|
|
39567
|
+
const NAMESPACE$2 = 'FieldSchemaEditor';
|
|
39568
|
+
/**
|
|
39569
|
+
* Tipos cuyo valor sale de una lista cerrada que define quien arma el
|
|
39570
|
+
* formulario — sin al menos una opción, el campo no se puede responder.
|
|
39571
|
+
* Espejo de `fieldRequiresOptions` que vivía duplicado en bingo.
|
|
39572
|
+
*/
|
|
39573
|
+
const FIELD_TYPES_WITH_OPTIONS = ['SELECT', 'RADIO', 'MULTI_SELECT'];
|
|
39574
|
+
let fieldUid = 0;
|
|
39575
|
+
/**
|
|
39576
|
+
* val-field-schema-editor
|
|
39577
|
+
*
|
|
39578
|
+
* Edita UN campo de un formulario dinámico: texto, tipo, placeholder, nota,
|
|
39579
|
+
* obligatoriedad y opciones. Es la pieza que faltaba en la lib — hasta ahora
|
|
39580
|
+
* el único editor de campos con este nivel vivía dentro de bingo
|
|
39581
|
+
* (`checkout-field-modal.component.ts`), invisible para el resto del factory,
|
|
39582
|
+
* y `val-survey-builder` había terminado con una versión pobre de lo mismo
|
|
39583
|
+
* (dos tipos fijos, sin placeholder ni opciones).
|
|
39584
|
+
*
|
|
39585
|
+
* Es agnóstico de dominio a propósito:
|
|
39586
|
+
* - el **catálogo de tipos** (`allowedTypes`) lo decide el consumer, porque es
|
|
39587
|
+
* él quien sabe qué sabe renderizar su formulario;
|
|
39588
|
+
* - los **presets** los pasa el consumer, porque "correo del comprador" es de
|
|
39589
|
+
* checkout y no significa nada en una encuesta.
|
|
39590
|
+
*
|
|
39591
|
+
* No trae cáscara de modal: el consumer lo envuelve en `val-modal-layout` (o
|
|
39592
|
+
* en lo que quiera) y dispara `submit()` desde su propio botón, igual que hace
|
|
39593
|
+
* `survey-create-modal` con `val-survey-builder`.
|
|
39594
|
+
*/
|
|
39595
|
+
class FieldSchemaEditorComponent {
|
|
39596
|
+
constructor() {
|
|
39597
|
+
this.props = { allowedTypes: ['TEXT'] };
|
|
39598
|
+
this.save = new EventEmitter();
|
|
39599
|
+
this.i18n = inject(I18nService);
|
|
39600
|
+
this.formSchemas = inject(FormSchemaBuilderService);
|
|
39601
|
+
this.labelControl = new FormControl('', { nonNullable: true });
|
|
39602
|
+
this.placeholderControl = new FormControl('', { nonNullable: true });
|
|
39603
|
+
this.hintControl = new FormControl('', { nonNullable: true });
|
|
39604
|
+
this.requiredControl = new FormControl(true, { nonNullable: true });
|
|
39605
|
+
this.typeControl = new FormControl('TEXT', { nonNullable: true });
|
|
39606
|
+
this.options = signal([]);
|
|
39607
|
+
this.validationError = signal('');
|
|
39608
|
+
this.selectedPresetId = signal('');
|
|
39609
|
+
/** Se refresca con cada cambio de tipo — `needsOptions` no puede leer el control directo. */
|
|
39610
|
+
this.currentType = signal('TEXT');
|
|
39611
|
+
/** Una vez que se toca el token a mano (o se edita un campo ya guardado) deja de derivarse del label. */
|
|
39612
|
+
this.nameLocked = false;
|
|
39613
|
+
this.name = '';
|
|
39614
|
+
this.fieldId = '';
|
|
39615
|
+
this.typeSelectProps = computed(() => {
|
|
39616
|
+
this.i18n.lang();
|
|
39617
|
+
return {
|
|
39618
|
+
control: this.typeControl,
|
|
39619
|
+
type: InputType.SELECT,
|
|
39620
|
+
state: this.state(),
|
|
39621
|
+
placeholder: this.t('typeLabel'),
|
|
39622
|
+
options: this.allowedTypes().map((type, order) => ({ id: type, name: this.typeLabel(type), order })),
|
|
39623
|
+
};
|
|
39624
|
+
});
|
|
39625
|
+
this.optionsEditorProps = computed(() => {
|
|
39626
|
+
this.i18n.lang();
|
|
39627
|
+
return {
|
|
39628
|
+
title: this.t('optionsTitle'),
|
|
39629
|
+
hint: this.t('optionsHint'),
|
|
39630
|
+
addLabel: this.t('optionsAdd'),
|
|
39631
|
+
optionsLabel: this.t('optionsList'),
|
|
39632
|
+
placeholder: this.t('optionsPlaceholder'),
|
|
39633
|
+
emptyText: this.t('optionsEmpty'),
|
|
39634
|
+
removeOptionLabel: this.t('optionsRemove'),
|
|
39635
|
+
reorderOptionLabel: this.t('optionsReorder'),
|
|
39636
|
+
state: this.state(),
|
|
39637
|
+
options: this.options(),
|
|
39638
|
+
};
|
|
39639
|
+
});
|
|
39640
|
+
if (!this.i18n.hasNamespace(NAMESPACE$2)) {
|
|
39641
|
+
this.i18n.registerDefaults(NAMESPACE$2, FIELD_SCHEMA_EDITOR_I18N);
|
|
39642
|
+
}
|
|
39643
|
+
this.typeControl.valueChanges.subscribe(value => this.currentType.set(value || 'TEXT'));
|
|
39644
|
+
this.labelControl.valueChanges.subscribe(value => {
|
|
39645
|
+
if (!this.nameLocked)
|
|
39646
|
+
this.name = this.formSchemas.toToken(value || '');
|
|
39647
|
+
});
|
|
39648
|
+
}
|
|
39649
|
+
ngOnInit() {
|
|
39650
|
+
const initial = this.props.field;
|
|
39651
|
+
if (initial) {
|
|
39652
|
+
this.fieldId = initial.id;
|
|
39653
|
+
this.nameLocked = true;
|
|
39654
|
+
this.name = initial.name;
|
|
39655
|
+
this.labelControl.setValue(initial.label ?? '');
|
|
39656
|
+
this.placeholderControl.setValue(initial.placeholderText ?? '');
|
|
39657
|
+
this.hintControl.setValue(initial.hintText ?? '');
|
|
39658
|
+
this.requiredControl.setValue(!!initial.required);
|
|
39659
|
+
this.typeControl.setValue(this.coerceType(initial.type));
|
|
39660
|
+
this.options.set(initial.options ?? []);
|
|
39661
|
+
return;
|
|
39662
|
+
}
|
|
39663
|
+
this.fieldId = `field-${++fieldUid}`;
|
|
39664
|
+
this.typeControl.setValue(this.coerceType(this.typeControl.value));
|
|
39665
|
+
const first = this.props.presets?.[0];
|
|
39666
|
+
if (first)
|
|
39667
|
+
this.selectPreset(first);
|
|
39668
|
+
}
|
|
39669
|
+
t(key) {
|
|
39670
|
+
this.i18n.lang();
|
|
39671
|
+
return this.i18n.t(key, NAMESPACE$2);
|
|
39672
|
+
}
|
|
39673
|
+
state() {
|
|
39674
|
+
return this.props.state ?? ComponentStates.ENABLED;
|
|
39675
|
+
}
|
|
39676
|
+
showPresets() {
|
|
39677
|
+
return this.props.mode !== 'edit' && !!this.props.presets?.length;
|
|
39678
|
+
}
|
|
39679
|
+
needsOptions() {
|
|
39680
|
+
return FIELD_TYPES_WITH_OPTIONS.includes(this.currentType());
|
|
39681
|
+
}
|
|
39682
|
+
typeLabel(type) {
|
|
39683
|
+
return this.props.typeLabels?.[type] || this.t(`type${type}`);
|
|
39684
|
+
}
|
|
39685
|
+
selectPreset(preset) {
|
|
39686
|
+
this.selectedPresetId.set(preset.id);
|
|
39687
|
+
const value = preset.field;
|
|
39688
|
+
// El preset fija el token: "correo del comprador" tiene que llamarse
|
|
39689
|
+
// `email` aunque después le cambien el texto visible.
|
|
39690
|
+
this.nameLocked = !!value.name;
|
|
39691
|
+
this.name = value.name || this.formSchemas.toToken(value.label || '');
|
|
39692
|
+
this.labelControl.setValue(value.label ?? '');
|
|
39693
|
+
this.placeholderControl.setValue(value.placeholderText ?? '');
|
|
39694
|
+
this.hintControl.setValue(value.hintText ?? '');
|
|
39695
|
+
this.requiredControl.setValue(!!value.required);
|
|
39696
|
+
this.typeControl.setValue(this.coerceType(value.type));
|
|
39697
|
+
this.options.set(value.options ?? []);
|
|
39698
|
+
}
|
|
39699
|
+
/**
|
|
39700
|
+
* Valida y emite. Público a propósito: lo llama el consumer desde el botón
|
|
39701
|
+
* de su propia cáscara (modal, página o acordeón).
|
|
39702
|
+
*/
|
|
39703
|
+
submit() {
|
|
39704
|
+
const field = this.value();
|
|
39705
|
+
if (!field.label || !field.name || !field.type) {
|
|
39706
|
+
this.validationError.set(this.t('errorIncomplete'));
|
|
39707
|
+
return false;
|
|
39708
|
+
}
|
|
39709
|
+
if (this.needsOptions() && !(field.options?.length ?? 0)) {
|
|
39710
|
+
this.validationError.set(this.t('errorOptionsRequired'));
|
|
39711
|
+
return false;
|
|
39712
|
+
}
|
|
39713
|
+
this.validationError.set('');
|
|
39714
|
+
this.save.emit(field);
|
|
39715
|
+
return true;
|
|
39716
|
+
}
|
|
39717
|
+
/** El campo tal como está en pantalla, sin validar. */
|
|
39718
|
+
value() {
|
|
39719
|
+
const label = (this.labelControl.value || '').trim();
|
|
39720
|
+
return {
|
|
39721
|
+
id: this.fieldId,
|
|
39722
|
+
name: this.formSchemas.toToken(this.name || label),
|
|
39723
|
+
label,
|
|
39724
|
+
placeholderText: (this.placeholderControl.value || '').trim(),
|
|
39725
|
+
hintText: (this.hintControl.value || '').trim(),
|
|
39726
|
+
type: this.coerceType(this.typeControl.value),
|
|
39727
|
+
required: this.requiredControl.value,
|
|
39728
|
+
options: this.needsOptions() ? this.options().map((option, index) => ({ ...option, order: index })) : undefined,
|
|
39729
|
+
};
|
|
39730
|
+
}
|
|
39731
|
+
allowedTypes() {
|
|
39732
|
+
return this.props.allowedTypes?.length ? this.props.allowedTypes : ['TEXT'];
|
|
39733
|
+
}
|
|
39734
|
+
/**
|
|
39735
|
+
* Un tipo fuera del catálogo del consumer cae al primero permitido. Pasa al
|
|
39736
|
+
* editar un campo guardado con un tipo que la app ya no ofrece (bingo lo
|
|
39737
|
+
* hacía con ATTACHMENT cuando el medio de pago no lo admite): sin esto, el
|
|
39738
|
+
* select queda en un valor que no está en su lista y se ve vacío.
|
|
39739
|
+
*/
|
|
39740
|
+
coerceType(type) {
|
|
39741
|
+
const allowed = this.allowedTypes();
|
|
39742
|
+
return allowed.includes(type) ? type : allowed[0];
|
|
39743
|
+
}
|
|
39744
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldSchemaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39745
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldSchemaEditorComponent, isStandalone: true, selector: "val-field-schema-editor", inputs: { props: "props" }, outputs: { save: "save" }, ngImport: i0, template: `
|
|
39746
|
+
<div class="field-schema-editor">
|
|
39747
|
+
@if (showPresets()) {
|
|
39748
|
+
<section class="field-schema-editor__presets">
|
|
39749
|
+
<span class="field-schema-editor__section-label">{{ props.presetsTitle || t('presetsTitle') }}</span>
|
|
39750
|
+
<div class="field-schema-editor__preset-grid">
|
|
39751
|
+
@for (preset of props.presets; track preset.id) {
|
|
39752
|
+
<button
|
|
39753
|
+
type="button"
|
|
39754
|
+
class="field-schema-editor__preset"
|
|
39755
|
+
[class.field-schema-editor__preset--selected]="selectedPresetId() === preset.id"
|
|
39756
|
+
(click)="selectPreset(preset)"
|
|
39757
|
+
>
|
|
39758
|
+
<strong>{{ preset.label }}</strong>
|
|
39759
|
+
@if (preset.description) {
|
|
39760
|
+
<span>{{ preset.description }}</span>
|
|
39761
|
+
}
|
|
39762
|
+
</button>
|
|
39763
|
+
}
|
|
39764
|
+
</div>
|
|
39765
|
+
</section>
|
|
39766
|
+
}
|
|
39767
|
+
|
|
39768
|
+
<val-form-field [label]="t('labelLabel')">
|
|
39769
|
+
<val-text-input [props]="{ control: labelControl, placeholder: t('labelPlaceholder'), state: state() }" />
|
|
39770
|
+
</val-form-field>
|
|
39771
|
+
|
|
39772
|
+
<val-form-field [label]="t('typeLabel')">
|
|
39773
|
+
<val-select-input [props]="typeSelectProps()" />
|
|
39774
|
+
</val-form-field>
|
|
39775
|
+
|
|
39776
|
+
@if (props.showPlaceholder !== false) {
|
|
39777
|
+
<val-form-field [label]="t('placeholderLabel')">
|
|
39778
|
+
<val-textarea-input [props]="{ control: placeholderControl, autoGrow: true, state: state() }" />
|
|
39779
|
+
</val-form-field>
|
|
39780
|
+
}
|
|
39781
|
+
|
|
39782
|
+
@if (props.showHint !== false) {
|
|
39783
|
+
<val-form-field [label]="t('hintLabel')">
|
|
39784
|
+
<val-textarea-input [props]="{ control: hintControl, autoGrow: true, state: state() }" />
|
|
39785
|
+
</val-form-field>
|
|
39786
|
+
}
|
|
39787
|
+
|
|
39788
|
+
<val-toggle-input
|
|
39789
|
+
[props]="{
|
|
39790
|
+
control: requiredControl,
|
|
39791
|
+
label: t('requiredLabel'),
|
|
39792
|
+
justify: 'space-between',
|
|
39793
|
+
state: state(),
|
|
39794
|
+
}"
|
|
39795
|
+
/>
|
|
39796
|
+
|
|
39797
|
+
@if (needsOptions()) {
|
|
39798
|
+
<val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="options.set($event)" />
|
|
39799
|
+
}
|
|
39800
|
+
|
|
39801
|
+
@if (validationError()) {
|
|
39802
|
+
<p class="field-schema-editor__error">{{ validationError() }}</p>
|
|
39803
|
+
}
|
|
39804
|
+
</div>
|
|
39805
|
+
`, isInline: true, styles: [":host{display:block}.field-schema-editor{display:flex;flex-direction:column;gap:12px}.field-schema-editor__presets{display:flex;flex-direction:column;gap:8px}.field-schema-editor__section-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}.field-schema-editor__preset{min-height:80px;padding:12px;border:1px solid var(--val-border-color, var(--ion-border-color, rgba(0, 0, 0, .1)));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-text-color);text-align:left;cursor:pointer}.field-schema-editor__preset strong,.field-schema-editor__preset span{display:block}.field-schema-editor__preset span{margin-top:4px;font-size:.8125rem;line-height:1.3;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset--selected{border-color:var(--ion-color-primary);box-shadow:0 0 0 2px rgba(var(--ion-color-primary-rgb, 255, 0, 178),.14)}.field-schema-editor__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: FieldOptionsEditorComponent, selector: "val-field-options-editor", inputs: ["props"], outputs: ["optionsChange"] }] }); }
|
|
39806
|
+
}
|
|
39807
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldSchemaEditorComponent, decorators: [{
|
|
39808
|
+
type: Component,
|
|
39809
|
+
args: [{ selector: 'val-field-schema-editor', standalone: true, imports: [
|
|
39810
|
+
CommonModule,
|
|
39811
|
+
ReactiveFormsModule,
|
|
39812
|
+
FormFieldComponent,
|
|
39813
|
+
TextInputComponent,
|
|
39814
|
+
TextareaInputComponent,
|
|
39815
|
+
SearchSelectorComponent,
|
|
39816
|
+
ToggleInputComponent,
|
|
39817
|
+
FieldOptionsEditorComponent,
|
|
39818
|
+
], template: `
|
|
39819
|
+
<div class="field-schema-editor">
|
|
39820
|
+
@if (showPresets()) {
|
|
39821
|
+
<section class="field-schema-editor__presets">
|
|
39822
|
+
<span class="field-schema-editor__section-label">{{ props.presetsTitle || t('presetsTitle') }}</span>
|
|
39823
|
+
<div class="field-schema-editor__preset-grid">
|
|
39824
|
+
@for (preset of props.presets; track preset.id) {
|
|
39825
|
+
<button
|
|
39826
|
+
type="button"
|
|
39827
|
+
class="field-schema-editor__preset"
|
|
39828
|
+
[class.field-schema-editor__preset--selected]="selectedPresetId() === preset.id"
|
|
39829
|
+
(click)="selectPreset(preset)"
|
|
39830
|
+
>
|
|
39831
|
+
<strong>{{ preset.label }}</strong>
|
|
39832
|
+
@if (preset.description) {
|
|
39833
|
+
<span>{{ preset.description }}</span>
|
|
39834
|
+
}
|
|
39835
|
+
</button>
|
|
39836
|
+
}
|
|
39837
|
+
</div>
|
|
39838
|
+
</section>
|
|
39839
|
+
}
|
|
39840
|
+
|
|
39841
|
+
<val-form-field [label]="t('labelLabel')">
|
|
39842
|
+
<val-text-input [props]="{ control: labelControl, placeholder: t('labelPlaceholder'), state: state() }" />
|
|
39843
|
+
</val-form-field>
|
|
39844
|
+
|
|
39845
|
+
<val-form-field [label]="t('typeLabel')">
|
|
39846
|
+
<val-select-input [props]="typeSelectProps()" />
|
|
39847
|
+
</val-form-field>
|
|
39848
|
+
|
|
39849
|
+
@if (props.showPlaceholder !== false) {
|
|
39850
|
+
<val-form-field [label]="t('placeholderLabel')">
|
|
39851
|
+
<val-textarea-input [props]="{ control: placeholderControl, autoGrow: true, state: state() }" />
|
|
39852
|
+
</val-form-field>
|
|
39853
|
+
}
|
|
39854
|
+
|
|
39855
|
+
@if (props.showHint !== false) {
|
|
39856
|
+
<val-form-field [label]="t('hintLabel')">
|
|
39857
|
+
<val-textarea-input [props]="{ control: hintControl, autoGrow: true, state: state() }" />
|
|
39858
|
+
</val-form-field>
|
|
39859
|
+
}
|
|
39860
|
+
|
|
39861
|
+
<val-toggle-input
|
|
39862
|
+
[props]="{
|
|
39863
|
+
control: requiredControl,
|
|
39864
|
+
label: t('requiredLabel'),
|
|
39865
|
+
justify: 'space-between',
|
|
39866
|
+
state: state(),
|
|
39867
|
+
}"
|
|
39868
|
+
/>
|
|
39869
|
+
|
|
39870
|
+
@if (needsOptions()) {
|
|
39871
|
+
<val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="options.set($event)" />
|
|
39872
|
+
}
|
|
39873
|
+
|
|
39874
|
+
@if (validationError()) {
|
|
39875
|
+
<p class="field-schema-editor__error">{{ validationError() }}</p>
|
|
39876
|
+
}
|
|
39877
|
+
</div>
|
|
39878
|
+
`, styles: [":host{display:block}.field-schema-editor{display:flex;flex-direction:column;gap:12px}.field-schema-editor__presets{display:flex;flex-direction:column;gap:8px}.field-schema-editor__section-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}.field-schema-editor__preset{min-height:80px;padding:12px;border:1px solid var(--val-border-color, var(--ion-border-color, rgba(0, 0, 0, .1)));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-text-color);text-align:left;cursor:pointer}.field-schema-editor__preset strong,.field-schema-editor__preset span{display:block}.field-schema-editor__preset span{margin-top:4px;font-size:.8125rem;line-height:1.3;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset--selected{border-color:var(--ion-color-primary);box-shadow:0 0 0 2px rgba(var(--ion-color-primary-rgb, 255, 0, 178),.14)}.field-schema-editor__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}\n"] }]
|
|
39879
|
+
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
39880
|
+
type: Input
|
|
39881
|
+
}], save: [{
|
|
39882
|
+
type: Output
|
|
39883
|
+
}] } });
|
|
39884
|
+
|
|
39173
39885
|
class RequestFormBuilderService extends FormSchemaBuilderService {
|
|
39174
39886
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestFormBuilderService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39175
39887
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestFormBuilderService, providedIn: 'root' }); }
|
|
@@ -39179,6 +39891,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39179
39891
|
args: [{ providedIn: 'root' }]
|
|
39180
39892
|
}] });
|
|
39181
39893
|
|
|
39894
|
+
/**
|
|
39895
|
+
* Tipos de pregunta que ofrece una encuesta.
|
|
39896
|
+
*
|
|
39897
|
+
* El corte no es estético: **todo tipo que esta lista ofrezca, `val-survey-response`
|
|
39898
|
+
* tiene que saber renderizarlo**, o la encuesta se guarda bien y se responde mal
|
|
39899
|
+
* (un rating dibujado como caja de texto). Ampliar acá obliga a ampliar el
|
|
39900
|
+
* renderer en la misma entrega.
|
|
39901
|
+
*
|
|
39902
|
+
* Los seis primeros son de respuesta cerrada — `closedAnswerTypes` en
|
|
39903
|
+
* `backend/go/services/request/aggregate.go` los cuenta por valor en el
|
|
39904
|
+
* dashboard. Los seis últimos son abiertos: el dashboard lista sus respuestas.
|
|
39905
|
+
*
|
|
39906
|
+
* `FILE`/`ATTACHMENT` quedan deliberadamente fuera: una encuesta es pública y
|
|
39907
|
+
* anónima por default, y aceptar subidas ahí es superficie de abuso sin un caso
|
|
39908
|
+
* de uso que lo pida.
|
|
39909
|
+
*/
|
|
39910
|
+
const SURVEY_QUESTION_TYPES = [
|
|
39911
|
+
'EMOJI_RATING',
|
|
39912
|
+
'SELECT',
|
|
39913
|
+
'RADIO',
|
|
39914
|
+
'MULTI_SELECT',
|
|
39915
|
+
'CHECK',
|
|
39916
|
+
'TOGGLE',
|
|
39917
|
+
'TEXT',
|
|
39918
|
+
'TEXTAREA',
|
|
39919
|
+
'NUMBER',
|
|
39920
|
+
'DATE',
|
|
39921
|
+
'EMAIL',
|
|
39922
|
+
'PHONE',
|
|
39923
|
+
];
|
|
39924
|
+
|
|
39182
39925
|
const SURVEY_BUILDER_I18N = {
|
|
39183
39926
|
es: {
|
|
39184
39927
|
titleLabel: 'Título',
|
|
@@ -39187,10 +39930,16 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39187
39930
|
subtitlePlaceholder: 'Ej: Ayúdanos a mejorar respondiendo estas preguntas',
|
|
39188
39931
|
questionsLabel: 'Preguntas',
|
|
39189
39932
|
questionLabelPlaceholder: 'Escribe la pregunta',
|
|
39190
|
-
typeEmoji: 'Emoji',
|
|
39191
|
-
typeText: 'Texto libre',
|
|
39192
39933
|
addQuestion: 'Agregar pregunta',
|
|
39193
|
-
removeQuestion: 'Quitar',
|
|
39934
|
+
removeQuestion: 'Quitar pregunta',
|
|
39935
|
+
editQuestion: 'Editar pregunta',
|
|
39936
|
+
duplicateQuestion: 'Duplicar pregunta',
|
|
39937
|
+
moveUp: 'Subir pregunta',
|
|
39938
|
+
moveDown: 'Bajar pregunta',
|
|
39939
|
+
doneEditing: 'Listo',
|
|
39940
|
+
untitledQuestion: 'Pregunta sin texto',
|
|
39941
|
+
requiredTag: 'Obligatoria',
|
|
39942
|
+
missingOptions: 'Hay preguntas de opciones sin ninguna opción cargada.',
|
|
39194
39943
|
save: 'Guardar encuesta',
|
|
39195
39944
|
noTitle: 'Ponle un título a la encuesta',
|
|
39196
39945
|
noQuestions: 'Agrega al menos una pregunta',
|
|
@@ -39205,10 +39954,16 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39205
39954
|
subtitlePlaceholder: 'E.g: Help us improve by answering these questions',
|
|
39206
39955
|
questionsLabel: 'Questions',
|
|
39207
39956
|
questionLabelPlaceholder: 'Write the question',
|
|
39208
|
-
typeEmoji: 'Emoji',
|
|
39209
|
-
typeText: 'Free text',
|
|
39210
39957
|
addQuestion: 'Add question',
|
|
39211
|
-
removeQuestion: 'Remove',
|
|
39958
|
+
removeQuestion: 'Remove question',
|
|
39959
|
+
editQuestion: 'Edit question',
|
|
39960
|
+
duplicateQuestion: 'Duplicate question',
|
|
39961
|
+
moveUp: 'Move question up',
|
|
39962
|
+
moveDown: 'Move question down',
|
|
39963
|
+
doneEditing: 'Done',
|
|
39964
|
+
untitledQuestion: 'Question with no text',
|
|
39965
|
+
requiredTag: 'Required',
|
|
39966
|
+
missingOptions: 'Some choice questions have no options set.',
|
|
39212
39967
|
save: 'Save survey',
|
|
39213
39968
|
noTitle: 'Give the survey a title',
|
|
39214
39969
|
noQuestions: 'Add at least one question',
|
|
@@ -39219,6 +39974,7 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39219
39974
|
};
|
|
39220
39975
|
|
|
39221
39976
|
const NAMESPACE$1 = 'SurveyBuilder';
|
|
39977
|
+
const EDITOR_NAMESPACE = 'FieldSchemaEditor';
|
|
39222
39978
|
const DEFAULT_TYPE_PREFIX = 'survey';
|
|
39223
39979
|
let rowUid = 0;
|
|
39224
39980
|
/**
|
|
@@ -39229,11 +39985,14 @@ let rowUid = 0;
|
|
|
39229
39985
|
* true` (cada respuesta se agrega, no se revisa una por una) y el `EntityRef`
|
|
39230
39986
|
* que le pasa el consumer (ej. el evento de bingo dueño de la encuesta).
|
|
39231
39987
|
*
|
|
39232
|
-
*
|
|
39233
|
-
*
|
|
39234
|
-
*
|
|
39235
|
-
*
|
|
39236
|
-
*
|
|
39988
|
+
* Cada pregunta se edita con `val-field-schema-editor`, el mismo editor que usa
|
|
39989
|
+
* el checkout de bingo — de ahí que una pregunta tenga tipo, placeholder, nota
|
|
39990
|
+
* y opciones, no solo texto. La v1 de este componente tenía su propio editor
|
|
39991
|
+
* pobre (dos tipos, sin opciones); la Fase 5 del ADR-092 lo reemplazó por el
|
|
39992
|
+
* organism compartido en vez de mejorarlo por duplicado.
|
|
39993
|
+
*
|
|
39994
|
+
* El catálogo que ofrece sale de `SURVEY_QUESTION_TYPES` — acotado a lo que
|
|
39995
|
+
* `val-survey-response` sabe renderizar, no a lo que el editor sabe editar.
|
|
39237
39996
|
*/
|
|
39238
39997
|
class SurveyBuilderComponent {
|
|
39239
39998
|
constructor() {
|
|
@@ -39243,15 +40002,21 @@ class SurveyBuilderComponent {
|
|
|
39243
40002
|
this.requests = inject(RequestService);
|
|
39244
40003
|
this.formBuilder = inject(RequestFormBuilderService);
|
|
39245
40004
|
this.errors = inject(ValtechErrorService);
|
|
39246
|
-
this.emojiType = FIELD_TYPE_EMOJI_RATING;
|
|
39247
40005
|
this.titleControl = new FormControl('', { nonNullable: true });
|
|
39248
40006
|
this.subtitleControl = new FormControl('', { nonNullable: true });
|
|
39249
40007
|
this.questions = signal([]);
|
|
40008
|
+
this.editingId = signal('');
|
|
40009
|
+
this.validationError = signal('');
|
|
39250
40010
|
this.saving = signal(false);
|
|
39251
|
-
this.rowControls = new Map();
|
|
39252
40011
|
if (!this.i18n.hasNamespace(NAMESPACE$1)) {
|
|
39253
40012
|
this.i18n.registerDefaults(NAMESPACE$1, SURVEY_BUILDER_I18N);
|
|
39254
40013
|
}
|
|
40014
|
+
// El nombre del tipo de cada pregunta se muestra en la fila colapsada, que
|
|
40015
|
+
// dibuja este componente y no el editor — si nadie montó un editor todavía,
|
|
40016
|
+
// el namespace no existiría y la fila mostraría la clave cruda.
|
|
40017
|
+
if (!this.i18n.hasNamespace(EDITOR_NAMESPACE)) {
|
|
40018
|
+
this.i18n.registerDefaults(EDITOR_NAMESPACE, FIELD_SCHEMA_EDITOR_I18N);
|
|
40019
|
+
}
|
|
39255
40020
|
}
|
|
39256
40021
|
async ngOnInit() {
|
|
39257
40022
|
if (!this.props.typeId)
|
|
@@ -39270,53 +40035,129 @@ class SurveyBuilderComponent {
|
|
|
39270
40035
|
});
|
|
39271
40036
|
}
|
|
39272
40037
|
}
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
this.
|
|
40038
|
+
t(key) {
|
|
40039
|
+
this.i18n.lang();
|
|
40040
|
+
return this.i18n.t(key, NAMESPACE$1);
|
|
40041
|
+
}
|
|
40042
|
+
typeLabel(type) {
|
|
40043
|
+
this.i18n.lang();
|
|
40044
|
+
return this.i18n.t(`type${type}`, EDITOR_NAMESPACE);
|
|
40045
|
+
}
|
|
40046
|
+
questionTypes() {
|
|
40047
|
+
return this.props.questionTypes?.length ? this.props.questionTypes : SURVEY_QUESTION_TYPES;
|
|
40048
|
+
}
|
|
40049
|
+
editorProps(row) {
|
|
40050
|
+
return { mode: 'edit', field: row, allowedTypes: this.questionTypes() };
|
|
40051
|
+
}
|
|
40052
|
+
iconAction(token, icon, label, disabled = false, color = 'dark') {
|
|
39276
40053
|
return {
|
|
39277
|
-
|
|
39278
|
-
|
|
39279
|
-
|
|
39280
|
-
|
|
40054
|
+
token,
|
|
40055
|
+
text: '',
|
|
40056
|
+
ariaLabel: label,
|
|
40057
|
+
color,
|
|
40058
|
+
fill: 'clear',
|
|
40059
|
+
shape: 'round',
|
|
40060
|
+
size: 'small',
|
|
40061
|
+
type: 'button',
|
|
40062
|
+
state: disabled ? ComponentStates.DISABLED : ComponentStates.ENABLED,
|
|
40063
|
+
icon: { name: icon, slot: 'icon-only' },
|
|
39281
40064
|
};
|
|
39282
40065
|
}
|
|
39283
|
-
rowLabelControl(row) {
|
|
39284
|
-
let control = this.rowControls.get(row.id);
|
|
39285
|
-
if (!control) {
|
|
39286
|
-
control = new FormControl(row.label, { nonNullable: true });
|
|
39287
|
-
this.rowControls.set(row.id, control);
|
|
39288
|
-
}
|
|
39289
|
-
return control;
|
|
39290
|
-
}
|
|
39291
40066
|
addQuestion() {
|
|
39292
|
-
const
|
|
39293
|
-
|
|
39294
|
-
|
|
40067
|
+
const row = {
|
|
40068
|
+
id: `row-${rowUid++}`,
|
|
40069
|
+
name: '',
|
|
40070
|
+
label: '',
|
|
40071
|
+
placeholderText: '',
|
|
40072
|
+
hintText: '',
|
|
40073
|
+
type: this.questionTypes()[0],
|
|
40074
|
+
required: true,
|
|
40075
|
+
};
|
|
40076
|
+
this.questions.update(rows => [...rows, row]);
|
|
40077
|
+
// Una pregunta recién agregada está vacía: abrirla es el único paso
|
|
40078
|
+
// siguiente posible, y dejarla cerrada la haría ver como una fila rota.
|
|
40079
|
+
this.editingId.set(row.id);
|
|
40080
|
+
}
|
|
40081
|
+
toggleEdit(row) {
|
|
40082
|
+
this.editingId.update(current => (current === row.id ? '' : row.id));
|
|
39295
40083
|
}
|
|
39296
40084
|
removeQuestion(row) {
|
|
39297
|
-
this.rowControls.delete(row.id);
|
|
39298
40085
|
this.questions.update(rows => rows.filter(r => r.id !== row.id));
|
|
40086
|
+
if (this.editingId() === row.id)
|
|
40087
|
+
this.editingId.set('');
|
|
40088
|
+
}
|
|
40089
|
+
duplicate(row) {
|
|
40090
|
+
const copy = {
|
|
40091
|
+
...row,
|
|
40092
|
+
id: `row-${rowUid++}`,
|
|
40093
|
+
// Sin token propio la copia pisaría las respuestas del original: dos
|
|
40094
|
+
// campos con el mismo `name` son el mismo campo para el backend.
|
|
40095
|
+
name: this.formBuilder.uniqueFieldName(row.name || row.label, this.questions()),
|
|
40096
|
+
options: row.options ? row.options.map(o => ({ ...o })) : undefined,
|
|
40097
|
+
};
|
|
40098
|
+
this.questions.update(rows => {
|
|
40099
|
+
const index = rows.findIndex(r => r.id === row.id);
|
|
40100
|
+
return [...rows.slice(0, index + 1), copy, ...rows.slice(index + 1)];
|
|
40101
|
+
});
|
|
40102
|
+
}
|
|
40103
|
+
move(index, delta) {
|
|
40104
|
+
const target = index + delta;
|
|
40105
|
+
this.questions.update(rows => {
|
|
40106
|
+
if (target < 0 || target >= rows.length)
|
|
40107
|
+
return rows;
|
|
40108
|
+
const next = [...rows];
|
|
40109
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
40110
|
+
return next;
|
|
40111
|
+
});
|
|
39299
40112
|
}
|
|
39300
|
-
|
|
39301
|
-
this.questions.update(rows => rows.map(r =>
|
|
40113
|
+
applyQuestion(field) {
|
|
40114
|
+
this.questions.update(rows => rows.map(r => r.id === field.id
|
|
40115
|
+
? {
|
|
40116
|
+
...field,
|
|
40117
|
+
name: this.formBuilder.uniqueFieldName(field.name || field.label, rows.filter(o => o.id !== r.id)),
|
|
40118
|
+
}
|
|
40119
|
+
: r));
|
|
40120
|
+
this.editingId.set('');
|
|
40121
|
+
this.validationError.set('');
|
|
39302
40122
|
}
|
|
39303
40123
|
async save() {
|
|
39304
40124
|
if (this.saving())
|
|
39305
40125
|
return;
|
|
40126
|
+
this.validationError.set('');
|
|
39306
40127
|
const title = this.titleControl.value.trim();
|
|
39307
40128
|
if (!title) {
|
|
39308
40129
|
this.titleControl.markAsTouched();
|
|
40130
|
+
this.validationError.set(this.t('noTitle'));
|
|
39309
40131
|
return;
|
|
39310
40132
|
}
|
|
39311
40133
|
const rows = this.questions();
|
|
39312
|
-
|
|
39313
|
-
|
|
40134
|
+
if (!rows.length) {
|
|
40135
|
+
this.validationError.set(this.t('noQuestions'));
|
|
40136
|
+
return;
|
|
40137
|
+
}
|
|
40138
|
+
if (rows.some(r => !r.label.trim())) {
|
|
40139
|
+
this.validationError.set(this.t('emptyQuestionLabel'));
|
|
39314
40140
|
return;
|
|
40141
|
+
}
|
|
40142
|
+
// El editor ya lo valida al cerrar cada pregunta, pero una pregunta abierta
|
|
40143
|
+
// (o cargada de una encuesta vieja) puede llegar acá sin opciones.
|
|
40144
|
+
if (rows.some(r => FIELD_TYPES_WITH_OPTIONS.includes(r.type) && !r.options?.length)) {
|
|
40145
|
+
this.validationError.set(this.t('missingOptions'));
|
|
40146
|
+
return;
|
|
40147
|
+
}
|
|
39315
40148
|
this.saving.set(true);
|
|
39316
40149
|
const fieldSchema = [];
|
|
39317
40150
|
rows.forEach((row, index) => {
|
|
39318
|
-
const name = this.formBuilder.uniqueFieldName(
|
|
39319
|
-
fieldSchema.push(this.formBuilder.createFieldSchema({
|
|
40151
|
+
const name = this.formBuilder.uniqueFieldName(row.name || row.label, fieldSchema);
|
|
40152
|
+
fieldSchema.push(this.formBuilder.createFieldSchema({
|
|
40153
|
+
name,
|
|
40154
|
+
label: row.label.trim(),
|
|
40155
|
+
type: row.type,
|
|
40156
|
+
required: row.required,
|
|
40157
|
+
placeholderText: row.placeholderText,
|
|
40158
|
+
hintText: row.hintText,
|
|
40159
|
+
options: row.options,
|
|
40160
|
+
}, index));
|
|
39320
40161
|
});
|
|
39321
40162
|
const typeId = this.props.typeId ?? `${this.props.typePrefix ?? DEFAULT_TYPE_PREFIX}:${this.formBuilder.toToken(title)}`;
|
|
39322
40163
|
const subtitle = this.subtitleControl.value.trim();
|
|
@@ -39346,64 +40187,84 @@ class SurveyBuilderComponent {
|
|
|
39346
40187
|
});
|
|
39347
40188
|
}
|
|
39348
40189
|
}
|
|
39349
|
-
|
|
39350
|
-
return
|
|
40190
|
+
rowFromField(f) {
|
|
40191
|
+
return {
|
|
40192
|
+
id: `row-${rowUid++}`,
|
|
40193
|
+
name: f.name,
|
|
40194
|
+
label: f.label ?? '',
|
|
40195
|
+
placeholderText: f.placeholderText ?? '',
|
|
40196
|
+
hintText: f.hintText ?? '',
|
|
40197
|
+
type: f.type,
|
|
40198
|
+
required: !!f.required,
|
|
40199
|
+
options: f.options,
|
|
40200
|
+
};
|
|
39351
40201
|
}
|
|
39352
40202
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39353
40203
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SurveyBuilderComponent, isStandalone: true, selector: "val-survey-builder", inputs: { props: "props" }, outputs: { saved: "saved" }, ngImport: i0, template: `
|
|
39354
40204
|
<div class="survey-builder">
|
|
39355
|
-
<val-
|
|
39356
|
-
|
|
39357
|
-
|
|
39358
|
-
|
|
40205
|
+
<val-form-field [label]="t('titleLabel')">
|
|
40206
|
+
<val-text-input [props]="{ control: titleControl, placeholder: t('titlePlaceholder') }" />
|
|
40207
|
+
</val-form-field>
|
|
40208
|
+
<val-form-field [label]="t('subtitleLabel')">
|
|
40209
|
+
<val-text-input [props]="{ control: subtitleControl, placeholder: t('subtitlePlaceholder') }" />
|
|
40210
|
+
</val-form-field>
|
|
39359
40211
|
|
|
39360
40212
|
<div class="survey-builder__questions">
|
|
39361
40213
|
<span class="survey-builder__questions-label">{{ t('questionsLabel') }}</span>
|
|
39362
40214
|
|
|
39363
|
-
@
|
|
40215
|
+
@if (!questions().length) {
|
|
40216
|
+
<p class="survey-builder__empty">{{ t('noQuestions') }}</p>
|
|
40217
|
+
}
|
|
40218
|
+
|
|
40219
|
+
@for (row of questions(); track row.id; let i = $index; let first = $first; let last = $last) {
|
|
39364
40220
|
<div class="survey-builder__row">
|
|
39365
|
-
<
|
|
39366
|
-
|
|
39367
|
-
|
|
39368
|
-
|
|
39369
|
-
|
|
39370
|
-
|
|
39371
|
-
|
|
39372
|
-
|
|
39373
|
-
|
|
39374
|
-
|
|
39375
|
-
|
|
39376
|
-
|
|
39377
|
-
|
|
39378
|
-
|
|
39379
|
-
|
|
39380
|
-
|
|
39381
|
-
|
|
39382
|
-
|
|
39383
|
-
|
|
39384
|
-
|
|
39385
|
-
|
|
39386
|
-
|
|
39387
|
-
|
|
39388
|
-
|
|
39389
|
-
|
|
39390
|
-
|
|
39391
|
-
|
|
39392
|
-
/>
|
|
39393
|
-
<val-button
|
|
39394
|
-
[props]="{
|
|
39395
|
-
token: 'q-remove-' + row.id,
|
|
39396
|
-
text: t('removeQuestion'),
|
|
39397
|
-
color: 'danger',
|
|
39398
|
-
fill: 'clear',
|
|
39399
|
-
shape: 'round',
|
|
39400
|
-
size: 'small',
|
|
39401
|
-
type: 'button',
|
|
39402
|
-
state: 'ENABLED',
|
|
39403
|
-
}"
|
|
39404
|
-
(onClick)="removeQuestion(row)"
|
|
39405
|
-
/>
|
|
40221
|
+
<div class="survey-builder__row-head">
|
|
40222
|
+
<div class="survey-builder__row-text">
|
|
40223
|
+
<strong>{{ row.label || t('untitledQuestion') }}</strong>
|
|
40224
|
+
<span>{{ typeLabel(row.type) }}{{ row.required ? ' · ' + t('requiredTag') : '' }}</span>
|
|
40225
|
+
</div>
|
|
40226
|
+
<div class="survey-builder__row-actions">
|
|
40227
|
+
<val-button
|
|
40228
|
+
[props]="iconAction('q-up-' + row.id, 'arrow-up-outline', t('moveUp'), first)"
|
|
40229
|
+
(onClick)="move(i, -1)"
|
|
40230
|
+
/>
|
|
40231
|
+
<val-button
|
|
40232
|
+
[props]="iconAction('q-down-' + row.id, 'arrow-down-outline', t('moveDown'), last)"
|
|
40233
|
+
(onClick)="move(i, 1)"
|
|
40234
|
+
/>
|
|
40235
|
+
<val-button
|
|
40236
|
+
[props]="iconAction('q-copy-' + row.id, 'copy-outline', t('duplicateQuestion'))"
|
|
40237
|
+
(onClick)="duplicate(row)"
|
|
40238
|
+
/>
|
|
40239
|
+
<val-button
|
|
40240
|
+
[props]="iconAction('q-edit-' + row.id, 'create-outline', t('editQuestion'))"
|
|
40241
|
+
(onClick)="toggleEdit(row)"
|
|
40242
|
+
/>
|
|
40243
|
+
<val-button
|
|
40244
|
+
[props]="iconAction('q-remove-' + row.id, 'trash-outline', t('removeQuestion'), false, 'danger')"
|
|
40245
|
+
(onClick)="removeQuestion(row)"
|
|
40246
|
+
/>
|
|
40247
|
+
</div>
|
|
39406
40248
|
</div>
|
|
40249
|
+
|
|
40250
|
+
@if (editingId() === row.id) {
|
|
40251
|
+
<div class="survey-builder__row-editor">
|
|
40252
|
+
<val-field-schema-editor #editor [props]="editorProps(row)" (save)="applyQuestion($event)" />
|
|
40253
|
+
<val-button
|
|
40254
|
+
[props]="{
|
|
40255
|
+
token: 'q-done-' + row.id,
|
|
40256
|
+
text: t('doneEditing'),
|
|
40257
|
+
color: 'dark',
|
|
40258
|
+
fill: 'solid',
|
|
40259
|
+
shape: 'round',
|
|
40260
|
+
size: 'default',
|
|
40261
|
+
type: 'button',
|
|
40262
|
+
state: 'ENABLED',
|
|
40263
|
+
}"
|
|
40264
|
+
(onClick)="editor.submit()"
|
|
40265
|
+
/>
|
|
40266
|
+
</div>
|
|
40267
|
+
}
|
|
39407
40268
|
</div>
|
|
39408
40269
|
}
|
|
39409
40270
|
|
|
@@ -39423,6 +40284,10 @@ class SurveyBuilderComponent {
|
|
|
39423
40284
|
/>
|
|
39424
40285
|
</div>
|
|
39425
40286
|
|
|
40287
|
+
@if (validationError()) {
|
|
40288
|
+
<p class="survey-builder__error">{{ validationError() }}</p>
|
|
40289
|
+
}
|
|
40290
|
+
|
|
39426
40291
|
<val-button
|
|
39427
40292
|
[props]="{
|
|
39428
40293
|
token: 'survey-builder-save',
|
|
@@ -39430,6 +40295,7 @@ class SurveyBuilderComponent {
|
|
|
39430
40295
|
color: 'dark',
|
|
39431
40296
|
fill: 'solid',
|
|
39432
40297
|
shape: 'round',
|
|
40298
|
+
size: 'large',
|
|
39433
40299
|
expand: 'block',
|
|
39434
40300
|
type: 'button',
|
|
39435
40301
|
state: saving() ? 'WORKING' : 'ENABLED',
|
|
@@ -39437,64 +40303,82 @@ class SurveyBuilderComponent {
|
|
|
39437
40303
|
(onClick)="save()"
|
|
39438
40304
|
/>
|
|
39439
40305
|
</div>
|
|
39440
|
-
`, isInline: true, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:
|
|
40306
|
+
`, isInline: true, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__empty{margin:0;font-size:.875rem;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:12px;padding:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff))}.survey-builder__row-head{display:flex;flex-direction:column;gap:8px}.survey-builder__row-text{display:flex;flex-direction:column;gap:2px;min-width:0}.survey-builder__row-text strong{color:var(--ion-text-color, #000);font-size:.9375rem}.survey-builder__row-text span{color:var(--ion-color-medium, #92949c);font-size:.8125rem}.survey-builder__row-actions{display:flex;gap:4px;flex-wrap:wrap}.survey-builder__row-editor{display:flex;flex-direction:column;gap:12px;padding-top:12px;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.survey-builder__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}@media (min-width: 576px){.survey-builder__row-head{flex-direction:row;align-items:flex-start;justify-content:space-between}.survey-builder__row-text{flex:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: FieldSchemaEditorComponent, selector: "val-field-schema-editor", inputs: ["props"], outputs: ["save"] }] }); }
|
|
39441
40307
|
}
|
|
39442
40308
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyBuilderComponent, decorators: [{
|
|
39443
40309
|
type: Component,
|
|
39444
|
-
args: [{ selector: 'val-survey-builder', standalone: true, imports: [
|
|
40310
|
+
args: [{ selector: 'val-survey-builder', standalone: true, imports: [
|
|
40311
|
+
CommonModule,
|
|
40312
|
+
ReactiveFormsModule,
|
|
40313
|
+
TextInputComponent,
|
|
40314
|
+
ButtonComponent,
|
|
40315
|
+
FormFieldComponent,
|
|
40316
|
+
FieldSchemaEditorComponent,
|
|
40317
|
+
], template: `
|
|
39445
40318
|
<div class="survey-builder">
|
|
39446
|
-
<val-
|
|
39447
|
-
|
|
39448
|
-
|
|
39449
|
-
|
|
40319
|
+
<val-form-field [label]="t('titleLabel')">
|
|
40320
|
+
<val-text-input [props]="{ control: titleControl, placeholder: t('titlePlaceholder') }" />
|
|
40321
|
+
</val-form-field>
|
|
40322
|
+
<val-form-field [label]="t('subtitleLabel')">
|
|
40323
|
+
<val-text-input [props]="{ control: subtitleControl, placeholder: t('subtitlePlaceholder') }" />
|
|
40324
|
+
</val-form-field>
|
|
39450
40325
|
|
|
39451
40326
|
<div class="survey-builder__questions">
|
|
39452
40327
|
<span class="survey-builder__questions-label">{{ t('questionsLabel') }}</span>
|
|
39453
40328
|
|
|
39454
|
-
@
|
|
40329
|
+
@if (!questions().length) {
|
|
40330
|
+
<p class="survey-builder__empty">{{ t('noQuestions') }}</p>
|
|
40331
|
+
}
|
|
40332
|
+
|
|
40333
|
+
@for (row of questions(); track row.id; let i = $index; let first = $first; let last = $last) {
|
|
39455
40334
|
<div class="survey-builder__row">
|
|
39456
|
-
<
|
|
39457
|
-
|
|
39458
|
-
|
|
39459
|
-
|
|
39460
|
-
|
|
39461
|
-
|
|
39462
|
-
|
|
39463
|
-
|
|
39464
|
-
|
|
39465
|
-
|
|
39466
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
|
|
39473
|
-
|
|
39474
|
-
|
|
39475
|
-
|
|
39476
|
-
|
|
39477
|
-
|
|
39478
|
-
|
|
39479
|
-
|
|
39480
|
-
|
|
39481
|
-
|
|
39482
|
-
|
|
39483
|
-
/>
|
|
39484
|
-
<val-button
|
|
39485
|
-
[props]="{
|
|
39486
|
-
token: 'q-remove-' + row.id,
|
|
39487
|
-
text: t('removeQuestion'),
|
|
39488
|
-
color: 'danger',
|
|
39489
|
-
fill: 'clear',
|
|
39490
|
-
shape: 'round',
|
|
39491
|
-
size: 'small',
|
|
39492
|
-
type: 'button',
|
|
39493
|
-
state: 'ENABLED',
|
|
39494
|
-
}"
|
|
39495
|
-
(onClick)="removeQuestion(row)"
|
|
39496
|
-
/>
|
|
40335
|
+
<div class="survey-builder__row-head">
|
|
40336
|
+
<div class="survey-builder__row-text">
|
|
40337
|
+
<strong>{{ row.label || t('untitledQuestion') }}</strong>
|
|
40338
|
+
<span>{{ typeLabel(row.type) }}{{ row.required ? ' · ' + t('requiredTag') : '' }}</span>
|
|
40339
|
+
</div>
|
|
40340
|
+
<div class="survey-builder__row-actions">
|
|
40341
|
+
<val-button
|
|
40342
|
+
[props]="iconAction('q-up-' + row.id, 'arrow-up-outline', t('moveUp'), first)"
|
|
40343
|
+
(onClick)="move(i, -1)"
|
|
40344
|
+
/>
|
|
40345
|
+
<val-button
|
|
40346
|
+
[props]="iconAction('q-down-' + row.id, 'arrow-down-outline', t('moveDown'), last)"
|
|
40347
|
+
(onClick)="move(i, 1)"
|
|
40348
|
+
/>
|
|
40349
|
+
<val-button
|
|
40350
|
+
[props]="iconAction('q-copy-' + row.id, 'copy-outline', t('duplicateQuestion'))"
|
|
40351
|
+
(onClick)="duplicate(row)"
|
|
40352
|
+
/>
|
|
40353
|
+
<val-button
|
|
40354
|
+
[props]="iconAction('q-edit-' + row.id, 'create-outline', t('editQuestion'))"
|
|
40355
|
+
(onClick)="toggleEdit(row)"
|
|
40356
|
+
/>
|
|
40357
|
+
<val-button
|
|
40358
|
+
[props]="iconAction('q-remove-' + row.id, 'trash-outline', t('removeQuestion'), false, 'danger')"
|
|
40359
|
+
(onClick)="removeQuestion(row)"
|
|
40360
|
+
/>
|
|
40361
|
+
</div>
|
|
39497
40362
|
</div>
|
|
40363
|
+
|
|
40364
|
+
@if (editingId() === row.id) {
|
|
40365
|
+
<div class="survey-builder__row-editor">
|
|
40366
|
+
<val-field-schema-editor #editor [props]="editorProps(row)" (save)="applyQuestion($event)" />
|
|
40367
|
+
<val-button
|
|
40368
|
+
[props]="{
|
|
40369
|
+
token: 'q-done-' + row.id,
|
|
40370
|
+
text: t('doneEditing'),
|
|
40371
|
+
color: 'dark',
|
|
40372
|
+
fill: 'solid',
|
|
40373
|
+
shape: 'round',
|
|
40374
|
+
size: 'default',
|
|
40375
|
+
type: 'button',
|
|
40376
|
+
state: 'ENABLED',
|
|
40377
|
+
}"
|
|
40378
|
+
(onClick)="editor.submit()"
|
|
40379
|
+
/>
|
|
40380
|
+
</div>
|
|
40381
|
+
}
|
|
39498
40382
|
</div>
|
|
39499
40383
|
}
|
|
39500
40384
|
|
|
@@ -39514,6 +40398,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39514
40398
|
/>
|
|
39515
40399
|
</div>
|
|
39516
40400
|
|
|
40401
|
+
@if (validationError()) {
|
|
40402
|
+
<p class="survey-builder__error">{{ validationError() }}</p>
|
|
40403
|
+
}
|
|
40404
|
+
|
|
39517
40405
|
<val-button
|
|
39518
40406
|
[props]="{
|
|
39519
40407
|
token: 'survey-builder-save',
|
|
@@ -39521,6 +40409,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39521
40409
|
color: 'dark',
|
|
39522
40410
|
fill: 'solid',
|
|
39523
40411
|
shape: 'round',
|
|
40412
|
+
size: 'large',
|
|
39524
40413
|
expand: 'block',
|
|
39525
40414
|
type: 'button',
|
|
39526
40415
|
state: saving() ? 'WORKING' : 'ENABLED',
|
|
@@ -39528,7 +40417,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39528
40417
|
(onClick)="save()"
|
|
39529
40418
|
/>
|
|
39530
40419
|
</div>
|
|
39531
|
-
`, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:
|
|
40420
|
+
`, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__empty{margin:0;font-size:.875rem;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:12px;padding:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff))}.survey-builder__row-head{display:flex;flex-direction:column;gap:8px}.survey-builder__row-text{display:flex;flex-direction:column;gap:2px;min-width:0}.survey-builder__row-text strong{color:var(--ion-text-color, #000);font-size:.9375rem}.survey-builder__row-text span{color:var(--ion-color-medium, #92949c);font-size:.8125rem}.survey-builder__row-actions{display:flex;gap:4px;flex-wrap:wrap}.survey-builder__row-editor{display:flex;flex-direction:column;gap:12px;padding-top:12px;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.survey-builder__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}@media (min-width: 576px){.survey-builder__row-head{flex-direction:row;align-items:flex-start;justify-content:space-between}.survey-builder__row-text{flex:1}}\n"] }]
|
|
39532
40421
|
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
39533
40422
|
type: Input
|
|
39534
40423
|
}], saved: [{
|
|
@@ -89150,66 +90039,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
89150
90039
|
* aporta la sesión de escaneo, el feedback y el historial.
|
|
89151
90040
|
*/
|
|
89152
90041
|
|
|
89153
|
-
/**
|
|
89154
|
-
* Primitivo de campo de formulario: label (estilo val-form) + contenido proyectado.
|
|
89155
|
-
*
|
|
89156
|
-
* Usar cuando necesitás un campo fuera de val-form pero con el mismo estilo:
|
|
89157
|
-
* image-picker, date-picker, selectores custom, chips, etc.
|
|
89158
|
-
*
|
|
89159
|
-
* NOTA: para ion-input / ion-textarea NO usar ng-content projection — el Shadow DOM
|
|
89160
|
-
* de Ionic no responde al grid del host. Usá en cambio un `<div class="pf-field">`
|
|
89161
|
-
* plano en el template con `<p class="pf-label">` + ion-input directo.
|
|
89162
|
-
*
|
|
89163
|
-
* ```html
|
|
89164
|
-
* <val-form-field label="Imagen">
|
|
89165
|
-
* <app-image-picker ... />
|
|
89166
|
-
* </val-form-field>
|
|
89167
|
-
*
|
|
89168
|
-
* <!-- Para ion-input: NO val-form-field, usar div plano -->
|
|
89169
|
-
* <div class="pf-field">
|
|
89170
|
-
* <p class="pf-label">Nombre</p>
|
|
89171
|
-
* <ion-input fill="outline" ... />
|
|
89172
|
-
* </div>
|
|
89173
|
-
* ```
|
|
89174
|
-
*
|
|
89175
|
-
* El label usa el mismo val-title que val-form (size=small, color=dark, bold=false).
|
|
89176
|
-
* El spacing entre campos se controla con --val-form-field-gap (default 0.5rem).
|
|
89177
|
-
* El padding horizontal se hereda vía --val-form-field-padding (default 0).
|
|
89178
|
-
* Setearlo en el contenedor padre para consistencia sin override en cada campo:
|
|
89179
|
-
* `.my-card { --val-form-field-padding: 0 16px; }`
|
|
89180
|
-
*/
|
|
89181
|
-
class FormFieldComponent {
|
|
89182
|
-
constructor() {
|
|
89183
|
-
this.label = input('');
|
|
89184
|
-
this.titleProps = computed(() => ({
|
|
89185
|
-
content: this.label(),
|
|
89186
|
-
size: 'small',
|
|
89187
|
-
color: 'dark',
|
|
89188
|
-
bold: false,
|
|
89189
|
-
}));
|
|
89190
|
-
}
|
|
89191
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
89192
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FormFieldComponent, isStandalone: true, selector: "val-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
89193
|
-
@if (label()) {
|
|
89194
|
-
<div class="vff-label">
|
|
89195
|
-
<val-title [props]="titleProps()" />
|
|
89196
|
-
</div>
|
|
89197
|
-
}
|
|
89198
|
-
<ng-content />
|
|
89199
|
-
`, isInline: true, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"], dependencies: [{ kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
89200
|
-
}
|
|
89201
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
89202
|
-
type: Component,
|
|
89203
|
-
args: [{ selector: 'val-form-field', standalone: true, imports: [TitleComponent], template: `
|
|
89204
|
-
@if (label()) {
|
|
89205
|
-
<div class="vff-label">
|
|
89206
|
-
<val-title [props]="titleProps()" />
|
|
89207
|
-
</div>
|
|
89208
|
-
}
|
|
89209
|
-
<ng-content />
|
|
89210
|
-
`, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"] }]
|
|
89211
|
-
}] });
|
|
89212
|
-
|
|
89213
90042
|
/**
|
|
89214
90043
|
* Token de inyeccion para la configuracion del Chat.
|
|
89215
90044
|
*/
|
|
@@ -92023,5 +92852,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
92023
92852
|
* Generated bundle index. Do not edit.
|
|
92024
92853
|
*/
|
|
92025
92854
|
|
|
92026
|
-
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CommsPreferencesService, CommsPreferencesSettingsComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMOJI_RATING_FACES, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmojiRatingComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeatureControlService, FeatureGuardDirective, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageBlockComponent, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrBrandValidationError, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RichEditorComponent, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SelectSearchPickerModalComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SurveyBuilderComponent, SurveyResponseComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMMS_PREFERENCES_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValCommentThreadComponent, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, VideoPlayerComponent, VideoUploadService, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, articleToTiptapDoc, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, defaultQrBrand, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechCommsPreferences, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, qrContrastRatio, qrErrorCorrectionFor, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, tiptapDocToArticle, tiptapDocToArticleElements, toArticle, validateQrBrand, validateRoutes };
|
|
92855
|
+
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CommsPreferencesService, CommsPreferencesSettingsComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMOJI_RATING_FACES, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmojiRatingComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FIELD_TYPES_WITH_OPTIONS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeatureControlService, FeatureGuardDirective, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FieldSchemaEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageBlockComponent, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrBrandValidationError, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RichEditorComponent, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SURVEY_QUESTION_TYPES, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SelectSearchPickerModalComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SurveyBuilderComponent, SurveyResponseComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMMS_PREFERENCES_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValCommentThreadComponent, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, VideoPlayerComponent, VideoUploadService, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, articleToTiptapDoc, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, defaultQrBrand, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechCommsPreferences, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, qrContrastRatio, qrErrorCorrectionFor, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, tiptapDocToArticle, tiptapDocToArticleElements, toArticle, validateQrBrand, validateRoutes };
|
|
92027
92856
|
//# sourceMappingURL=valtech-components.mjs.map
|