- Formulario hero: validación por campo con estado touched/submitted, mensajes de error inline, máscara de moneda en cuota, autocomplete flotante para dirección y categorías con clearInput, chips para categorías y palabras clave, campos banco/CLABE/RFC - Estilos globales: border-radius y sombra en ion-button, borde para botones light sobre fondo claro, sin borde en toolbars de color - OneSignal: reescritura del servicio con login/logout, addTag y routing por título de notificación usando NgZone - FAQ: color primary en acordeón activo/desplegado Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
134 lines
7.7 KiB
HTML
Executable File
134 lines
7.7 KiB
HTML
Executable File
<ion-header>
|
|
<ion-toolbar color="primary">
|
|
<ion-buttons slot="start">
|
|
<ion-button color="light" (click)="dismissHero()">
|
|
<ion-icon name="arrow-back"></ion-icon>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
<ion-title>{{'hero.header' | translate}}</ion-title>
|
|
</ion-toolbar>
|
|
</ion-header>
|
|
|
|
<ion-content class="ion-padding">
|
|
<ion-item [class.ion-invalid]="(submitted || touched['name']) && !name" [class.ion-touched]="submitted || touched['name']">
|
|
<ion-label position="floating">{{'hero.name' | translate}}</ion-label>
|
|
<ion-input [(ngModel)]="name" (ionBlur)="markTouched('name')"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['name']) && !name">{{'hero.required' | translate}}</span>
|
|
|
|
<ion-item [class.ion-invalid]="(submitted || touched['rfc']) && !rfc" [class.ion-touched]="submitted || touched['rfc']">
|
|
<ion-label position="floating">RFC</ion-label>
|
|
<ion-input [(ngModel)]="rfc" (ionBlur)="markTouched('rfc')"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['rfc']) && !rfc">{{'hero.required' | translate}}</span>
|
|
|
|
<!-- CATEGORÍAS CON CHIPS -->
|
|
<div class="dropdown-container">
|
|
<ion-item class="tags-item" [class.ion-invalid]="(submitted || touched['categories']) && categories_input.length === 0" [class.ion-touched]="submitted || touched['categories']">
|
|
<div class="tags-row">
|
|
<span class="chip-section-label">{{'hero.categories' | translate}}</span>
|
|
<ion-chip *ngFor="let cat of categories_input" color="primary">
|
|
<ion-label>{{cat}}</ion-label>
|
|
<ion-icon name="close-circle" (click)="removeCategory(cat)"></ion-icon>
|
|
</ion-chip>
|
|
<ion-input
|
|
[(ngModel)]="categorySearchText"
|
|
(ionInput)="filterCategories($event)"
|
|
(ionBlur)="hideCategoryList()"
|
|
[clearInput]="true"
|
|
placeholder="{{'hero.categories_placeholder' | translate}}">
|
|
</ion-input>
|
|
</div>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['categories']) && categories_input.length === 0">Selecciona al menos una categoría</span>
|
|
<ion-list *ngIf="showCategoryDropdown && filteredCategories.length > 0" class="dropdown-list">
|
|
<ion-item *ngFor="let category of filteredCategories" button (click)="selectCategory(category)">
|
|
{{category}}
|
|
</ion-item>
|
|
</ion-list>
|
|
</div>
|
|
|
|
<!-- PALABRAS CLAVE CON CHIPS -->
|
|
<ion-item class="tags-item">
|
|
<div class="tags-row">
|
|
<span class="chip-section-label">{{'hero.keywords' | translate}}</span>
|
|
<ion-chip *ngFor="let keyword of keywords" color="primary">
|
|
<ion-label>{{keyword}}</ion-label>
|
|
<ion-icon name="close-circle" (click)="removeKeyword(keyword)"></ion-icon>
|
|
</ion-chip>
|
|
<ion-input
|
|
[(ngModel)]="keywordInput"
|
|
(keydown)="onKeywordKeydown($event)"
|
|
(ionBlur)="addKeyword($event)"
|
|
placeholder="{{'hero.keywords_placeholder' | translate}}">
|
|
</ion-input>
|
|
</div>
|
|
</ion-item>
|
|
<ion-note class="ion-padding">{{'hero.keywords_hint' | translate}}</ion-note>
|
|
|
|
<!-- DIRECCIÓN CON AUTOCOMPLETE FLOTANTE -->
|
|
<div class="dropdown-container">
|
|
<ion-item [class.ion-invalid]="(submitted || touched['address']) && !myAddress" [class.ion-touched]="submitted || touched['address']">
|
|
<ion-label position="floating">{{'categories.address' | translate}}</ion-label>
|
|
<ion-input [(ngModel)]="addressAutocomplete" (ionInput)="autocomplete($event)" (ionFocus)="showlist()" (ionBlur)="blurAddressList()" [clearInput]="true"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['address']) && !myAddress">{{'alerts.valid_address' | translate}}</span>
|
|
<ion-list *ngIf="showif && placesSearch?.length" class="dropdown-list">
|
|
<ion-item button=true (click)="geoloc(places.place_id, places.description, places.terms[1].value)" *ngFor="let places of placesSearch" class="place">
|
|
{{ places.description }}
|
|
</ion-item>
|
|
</ion-list>
|
|
</div>
|
|
|
|
<ion-item class="ion-hide">
|
|
<ion-label position="fixed">Latitud</ion-label>
|
|
<ion-input value="{{ myPosition.latitude }}" disabled></ion-input>
|
|
</ion-item>
|
|
<ion-item class="ion-hide">
|
|
<ion-label position="fixed">Longitud</ion-label>
|
|
<ion-input value="{{ myPosition.longitude }}" disabled></ion-input>
|
|
</ion-item>
|
|
|
|
<ion-item [class.ion-invalid]="(submitted || touched['bank']) && selectedBank === null" [class.ion-touched]="submitted || touched['bank']">
|
|
<ion-label>{{'hero.bank' | translate}}</ion-label>
|
|
<ion-select [(ngModel)]="selectedBank" placeholder="{{'hero.select' | translate}}" okText="Aceptar" cancelText="Cancelar" (ionBlur)="markTouched('bank')">
|
|
<ion-select-option *ngFor="let bank of banks" [value]="bank.id">{{bank.name}}</ion-select-option>
|
|
</ion-select>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['bank']) && selectedBank === null">{{'hero.required' | translate}}</span>
|
|
|
|
<ion-item [class.ion-invalid]="(submitted || touched['bankAccount']) && !bankAccount" [class.ion-touched]="submitted || touched['bankAccount']">
|
|
<ion-label position="floating">{{'hero.bank_account' | translate}}</ion-label>
|
|
<ion-input [(ngModel)]="bankAccount" type="number" (ionBlur)="markTouched('bankAccount')"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['bankAccount']) && !bankAccount">{{'hero.required' | translate}}</span>
|
|
|
|
<ion-item [class.ion-invalid]="(submitted || touched['fee']) && fee === null" [class.ion-touched]="submitted || touched['fee']">
|
|
<ion-label position="floating">{{'hero.fee' | translate}}</ion-label>
|
|
<ion-input [(ngModel)]="feeDisplay" (ionInput)="onFeeInput($event)" (ionBlur)="markTouched('fee')" type="text" inputmode="decimal"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['fee']) && fee === null">{{'hero.required' | translate}}</span>
|
|
|
|
<ion-item [class.ion-invalid]="(submitted || touched['reference']) && !selectedReference" [class.ion-touched]="submitted || touched['reference']">
|
|
<ion-label>{{'hero.discover' | translate}}</ion-label>
|
|
<ion-select [(ngModel)]="selectedReference" placeholder="{{'hero.select' | translate}}" okText="Aceptar" cancelText="Cancelar" (ionChange)="selected_reference($event)" (ionBlur)="markTouched('reference')">
|
|
<ion-select-option [value]="1">{{'hero.radio' | translate}}</ion-select-option>
|
|
<ion-select-option [value]="2">{{'hero.tv' | translate}}</ion-select-option>
|
|
<ion-select-option [value]="3">{{'hero.social' | translate}}</ion-select-option>
|
|
<ion-select-option [value]="4">{{'hero.friends' | translate}}</ion-select-option>
|
|
<ion-select-option [value]="5">{{'hero.other' | translate}}</ion-select-option>
|
|
</ion-select>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['reference']) && !selectedReference">{{'hero.required' | translate}}</span>
|
|
|
|
<ion-item *ngIf="showinput" [class.ion-invalid]="(submitted || touched['referenceDetail']) && !reference" [class.ion-touched]="submitted || touched['referenceDetail']">
|
|
<ion-label position="floating">{{'hero.discover_details' | translate}}</ion-label>
|
|
<ion-input [(ngModel)]="reference" (ionBlur)="markTouched('referenceDetail')"></ion-input>
|
|
</ion-item>
|
|
<span class="error-msg" *ngIf="(submitted || touched['referenceDetail']) && showinput && !reference">{{'hero.required' | translate}}</span>
|
|
|
|
<br>
|
|
<br>
|
|
<ion-button type="submit" expand="full" color="secondary" (click)="addHero()">{{'hero.signup' | translate}}</ion-button>
|
|
</ion-content>
|